UNPKG

dmn-js

Version:

A dmn toolkit and web modeler

41,548 lines 1.38 MB
/*!
 * dmn-js - dmn-viewer v17.11.0
 *
 * Copyright (c) 2014-present, camunda Services GmbH
 *
 * Released under the bpmn.io license
 * http://bpmn.io/license
 *
 * Source Code: https://github.com/bpmn-io/dmn-js
 *
 * Date: 2026-09-21
 */
(function (global, factory) {
  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
  typeof define === 'function' && define.amd ? define(factory) :
  (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.DmnJS = factory());
})(this, (function () { 'use strict';

  /**
   * Flatten array, one level deep.
   *
   * @template T
   *
   * @param {T[][] | T[] | null} [arr]
   *
   * @return {T[]}
   */
  const nativeToString = Object.prototype.toString;
  const nativeHasOwnProperty = Object.prototype.hasOwnProperty;
  function isUndefined$2(obj) {
    return obj === undefined;
  }
  function isDefined(obj) {
    return obj !== undefined;
  }
  function isNil(obj) {
    return obj == null;
  }
  function isArray$2(obj) {
    return nativeToString.call(obj) === '[object Array]';
  }
  function isObject$1(obj) {
    return nativeToString.call(obj) === '[object Object]';
  }
  function isNumber$1(obj) {
    return nativeToString.call(obj) === '[object Number]';
  }

  /**
   * @param {any} obj
   *
   * @return {boolean}
   */
  function isFunction$1(obj) {
    const tag = nativeToString.call(obj);
    return tag === '[object Function]' || tag === '[object AsyncFunction]' || tag === '[object GeneratorFunction]' || tag === '[object AsyncGeneratorFunction]' || tag === '[object Proxy]';
  }
  function isString$1(obj) {
    return nativeToString.call(obj) === '[object String]';
  }

  /**
   * Return true, if target owns a property with the given key.
   *
   * @param {Object} target
   * @param {String} key
   *
   * @return {Boolean}
   */
  function has(target, key) {
    return !isNil(target) && nativeHasOwnProperty.call(target, key);
  }

  /**
   * @template T
   * @typedef { (
   *   ((e: T) => boolean) |
   *   ((e: T, idx: number) => boolean) |
   *   ((e: T, key: string) => boolean) |
   *   string |
   *   number
   * ) } Matcher
   */

  /**
   * @template T
   * @template U
   *
   * @typedef { (
   *   ((e: T) => U) | string | number
   * ) } Extractor
   */

  /**
   * @template T
   * @typedef { (val: T, key: any) => boolean } MatchFn
   */

  /**
   * @template T
   * @typedef { T[] } ArrayCollection
   */

  /**
   * @template T
   * @typedef { { [key: string]: T } } StringKeyValueCollection
   */

  /**
   * @template T
   * @typedef { { [key: number]: T } } NumberKeyValueCollection
   */

  /**
   * @template T
   * @typedef { StringKeyValueCollection<T> | NumberKeyValueCollection<T> } KeyValueCollection
   */

  /**
   * @template T
   * @typedef { KeyValueCollection<T> | ArrayCollection<T> } Collection
   */

  /**
   * Find element in collection.
   *
   * @template T
   * @param {Collection<T>} collection
   * @param {Matcher<T>} matcher
   *
   * @return {Object}
   */
  function find$1(collection, matcher) {
    const matchFn = toMatcher(matcher);
    let match;
    forEach(collection, function (val, key) {
      if (matchFn(val, key)) {
        match = val;
        return false;
      }
    });
    return match;
  }

  /**
   * Find element index in collection.
   *
   * @template T
   * @param {Collection<T>} collection
   * @param {Matcher<T>} matcher
   *
   * @return {number | string | undefined}
   */
  function findIndex(collection, matcher) {
    const matchFn = toMatcher(matcher);
    let idx = isArray$2(collection) ? -1 : undefined;
    forEach(collection, function (val, key) {
      if (matchFn(val, key)) {
        idx = key;
        return false;
      }
    });
    return idx;
  }

  /**
   * Filter elements in collection.
   *
   * @template T
   * @param {Collection<T>} collection
   * @param {Matcher<T>} matcher
   *
   * @return {T[]} result
   */
  function filter(collection, matcher) {
    const matchFn = toMatcher(matcher);
    let result = [];
    forEach(collection, function (val, key) {
      if (matchFn(val, key)) {
        result.push(val);
      }
    });
    return result;
  }

  /**
   * Iterate over collection; returning something
   * (non-undefined) will stop iteration.
   *
   * @template T
   * @param {Collection<T>} collection
   * @param { ((item: T, idx: number) => (boolean|void)) | ((item: T, key: string) => (boolean|void)) } iterator
   *
   * @return {T} return result that stopped the iteration
   */
  function forEach(collection, iterator) {
    let val, result;
    if (isUndefined$2(collection)) {
      return;
    }
    const convertKey = isArray$2(collection) ? toNum : identity;
    for (let key in collection) {
      if (has(collection, key)) {
        val = collection[key];
        result = iterator(val, convertKey(key));
        if (result === false) {
          return val;
        }
      }
    }
  }

  /**
   * Reduce collection, returning a single result.
   *
   * @template T
   * @template V
   *
   * @param {Collection<T>} collection
   * @param {(result: V, entry: T, index: any) => V} iterator
   * @param {V} result
   *
   * @return {V} result returned from last iterator
   */
  function reduce(collection, iterator, result) {
    forEach(collection, function (value, idx) {
      result = iterator(result, value, idx);
    });
    return result;
  }

  /**
   * Return true if every element in the collection
   * matches the criteria.
   *
   * @param  {Object|Array} collection
   * @param  {Function} matcher
   *
   * @return {Boolean}
   */
  function every(collection, matcher) {
    return !!reduce(collection, function (matches, val, key) {
      return matches && matcher(val, key);
    }, true);
  }

  /**
   * Transform a collection into another collection
   * by piping each member through the given fn.
   *
   * @param  {Object|Array}   collection
   * @param  {Function} fn
   *
   * @return {Array} transformed collection
   */
  function map(collection, fn) {
    let result = [];
    forEach(collection, function (val, key) {
      result.push(fn(val, key));
    });
    return result;
  }

  /**
   * Create an object pattern matcher.
   *
   * @example
   *
   * ```javascript
   * const matcher = matchPattern({ id: 1 });
   *
   * let element = find(elements, matcher);
   * ```
   *
   * @template T
   *
   * @param {T} pattern
   *
   * @return { (el: any) =>  boolean } matcherFn
   */
  function matchPattern(pattern) {
    return function (el) {
      return every(pattern, function (val, key) {
        return el[key] === val;
      });
    };
  }

  /**
   * @template T
   * @param {Matcher<T>} matcher
   *
   * @return {MatchFn<T>}
   */
  function toMatcher(matcher) {
    return isFunction$1(matcher) ? matcher : e => {
      return e === matcher;
    };
  }
  function identity(arg) {
    return arg;
  }
  function toNum(arg) {
    return Number(arg);
  }

  /**
   * @template {(...args: any[]) => any} T
   * @typedef { {
   *   (...args: Parameters<T>): void;
   *   flush: () => void;
   *   cancel: () => void;
   * } } DebouncedFunction
   */

  /**
   * Debounce fn, calling it only once if the given time
   * elapsed between calls.
   *
   * Lodash-style the function exposes methods to `#clear`
   * and `#flush` to control internal behavior.
   *
   * @template {(...args: any[]) => any} T
   *
   * @param  {T} fn
   * @param  {number} timeout
   *
   * @return {DebouncedFunction<T>} debounced function
   */
  function debounce(fn, timeout) {
    let timer;
    let lastArgs;
    let lastThis;
    let lastNow;
    function fire(force) {
      let now = Date.now();
      let scheduledDiff = force ? 0 : lastNow + timeout - now;
      if (scheduledDiff > 0) {
        return schedule(scheduledDiff);
      }
      fn.apply(lastThis, lastArgs);
      clear();
    }
    function schedule(timeout) {
      timer = setTimeout(fire, timeout);
    }
    function clear() {
      if (timer) {
        clearTimeout(timer);
      }
      timer = lastNow = lastArgs = lastThis = undefined;
    }
    function flush() {
      if (timer) {
        fire(true);
      }
      clear();
    }

    /**
     * @type {DebouncedFunction<T>}
     */
    function callback(...args) {
      lastNow = Date.now();
      lastArgs = args;
      lastThis = this;

      // ensure an execution is scheduled
      if (!timer) {
        schedule(timeout);
      }
    }
    callback.flush = flush;
    callback.cancel = clear;
    return callback;
  }

  /**
   * Throttle fn, calling at most once
   * in the given interval.
   *
   * @template {(...args: any[]) => any} T
   *
   * @param  {T} fn
   * @param  {number} interval
   *
   * @return {(...args: Parameters<T>) => void} throttled function
   */
  function throttle(fn, interval) {
    let throttling = false;
    return function (...args) {
      if (throttling) {
        return;
      }
      fn(...args);
      throttling = true;
      setTimeout(() => {
        throttling = false;
      }, interval);
    };
  }

  /**
   * Bind function against target <this>.
   *
   * @param  {Function} fn
   * @param  {Object}   target
   *
   * @return {Function} bound function
   */
  function bind$1(fn, target) {
    return fn.bind(target);
  }

  /**
   * Convenience wrapper for `Object.assign`.
   *
   * @param {Object} target
   * @param {...Object} others
   *
   * @return {Object} the target
   */
  function assign$1(target, ...others) {
    return Object.assign(target, ...others);
  }

  /**
   * Sets a nested property of a given object to the specified value.
   *
   * This mutates the object and returns it.
   *
   * @template T
   *
   * @param {T} target The target of the set operation.
   * @param {(string|number)[]} path The path to the nested value.
   * @param {any} value The value to set.
   *
   * @return {T}
   */
  function set(target, path, value) {
    let currentTarget = target;
    forEach(path, function (key, idx) {
      if (typeof key !== 'number' && typeof key !== 'string') {
        throw new Error('illegal key type: ' + typeof key + '. Key should be of type number or string.');
      }
      if (key === 'constructor') {
        throw new Error('illegal key: constructor');
      }
      if (key === '__proto__') {
        throw new Error('illegal key: __proto__');
      }
      let nextKey = path[idx + 1];
      let nextTarget = currentTarget[key];
      if (isDefined(nextKey) && isNil(nextTarget)) {
        nextTarget = currentTarget[key] = isNaN(+nextKey) ? {} : [];
      }
      if (isUndefined$2(nextKey)) {
        if (isUndefined$2(value)) {
          delete currentTarget[key];
        } else {
          currentTarget[key] = value;
        }
      } else {
        currentTarget = nextTarget;
      }
    });
    return target;
  }

  /**
   * Pick properties from the given target.
   *
   * @template T
   * @template {any[]} V
   *
   * @param {T} target
   * @param {V} properties
   *
   * @return Pick<T, V>
   */
  function pick(target, properties) {
    let result = {};
    let obj = Object(target);
    forEach(properties, function (prop) {
      if (prop in obj) {
        result[prop] = target[prop];
      }
    });
    return result;
  }

  var FN_REF = '__fn';
  var DEFAULT_PRIORITY$2 = 1000;
  var slice = Array.prototype.slice;

  /**
   * @typedef { {
   *   stopPropagation(): void;
   *   preventDefault(): void;
   *   cancelBubble: boolean;
   *   defaultPrevented: boolean;
   *   returnValue: any;
   * } } Event
   */

  /**
   * @template E
   *
   * @typedef { (event: E & Event, ...any) => any } EventBusEventCallback
   */

  /**
   * @typedef { {
   *  priority: number;
   *  next: EventBusListener | null;
   *  callback: EventBusEventCallback<any>;
   * } } EventBusListener
   */

  /**
   * A general purpose event bus.
   *
   * This component is used to communicate across a diagram instance.
   * Other parts of a diagram can use it to listen to and broadcast events.
   *
   *
   * ## Registering for Events
   *
   * The event bus provides the {@link EventBus#on} and {@link EventBus#once}
   * methods to register for events. {@link EventBus#off} can be used to
   * remove event registrations. Listeners receive an instance of {@link Event}
   * as the first argument. It allows them to hook into the event execution.
   *
   * ```javascript
   *
   * // listen for event
   * eventBus.on('foo', function(event) {
   *
   *   // access event type
   *   event.type; // 'foo'
   *
   *   // stop propagation to other listeners
   *   event.stopPropagation();
   *
   *   // prevent event default
   *   event.preventDefault();
   * });
   *
   * // listen for event with custom payload
   * eventBus.on('bar', function(event, payload) {
   *   console.log(payload);
   * });
   *
   * // listen for event returning value
   * eventBus.on('foobar', function(event) {
   *
   *   // stop event propagation + prevent default
   *   return false;
   *
   *   // stop event propagation + return custom result
   *   return {
   *     complex: 'listening result'
   *   };
   * });
   *
   *
   * // listen with custom priority (default=1000, higher is better)
   * eventBus.on('priorityfoo', 1500, function(event) {
   *   console.log('invoked first!');
   * });
   *
   *
   * // listen for event and pass the context (`this`)
   * eventBus.on('foobar', function(event) {
   *   this.foo();
   * }, this);
   * ```
   *
   *
   * ## Emitting Events
   *
   * Events can be emitted via the event bus using {@link EventBus#fire}.
   *
   * ```javascript
   *
   * // false indicates that the default action
   * // was prevented by listeners
   * if (eventBus.fire('foo') === false) {
   *   console.log('default has been prevented!');
   * };
   *
   *
   * // custom args + return value listener
   * eventBus.on('sum', function(event, a, b) {
   *   return a + b;
   * });
   *
   * // you can pass custom arguments + retrieve result values.
   * var sum = eventBus.fire('sum', 1, 2);
   * console.log(sum); // 3
   * ```
   *
   * @template [EventMap=null]
   */
  function EventBus() {
    /**
     * @type { Record<string, EventBusListener> }
     */
    this._listeners = {};

    // cleanup on destroy on lowest priority to allow
    // message passing until the bitter end
    this.on('diagram.destroy', 1, this._destroy, this);
  }

  /**
   * @overlord
   *
   * Register an event listener for events with the given name.
   *
   * The callback will be invoked with `event, ...additionalArguments`
   * that have been passed to {@link EventBus#fire}.
   *
   * Returning false from a listener will prevent the events default action
   * (if any is specified). To stop an event from being processed further in
   * other listeners execute {@link Event#stopPropagation}.
   *
   * Returning anything but `undefined` from a listener will stop the listener propagation.
   *
   * @template {keyof EventMap} EventName
   *
   * @param {EventName} events to subscribe to
   * @param {number} [priority=1000] listen priority
   * @param {EventBusEventCallback<EventMap[EventName]>} callback
   * @param {any} [that] callback context
   */
  /**
   * Register an event listener for events with the given name.
   *
   * The callback will be invoked with `event, ...additionalArguments`
   * that have been passed to {@link EventBus#fire}.
   *
   * Returning false from a listener will prevent the events default action
   * (if any is specified). To stop an event from being processed further in
   * other listeners execute {@link Event#stopPropagation}.
   *
   * Returning anything but `undefined` from a listener will stop the listener propagation.
   *
   * @template T
   *
   * @param {string|string[]} events to subscribe to
   * @param {number} [priority=1000] listen priority
   * @param {EventBusEventCallback<T>} callback
   * @param {any} [that] callback context
   */
  EventBus.prototype.on = function (events, priority, callback, that) {
    events = isArray$2(events) ? events : [events];
    if (isFunction$1(priority)) {
      that = callback;
      callback = priority;
      priority = DEFAULT_PRIORITY$2;
    }
    if (!isNumber$1(priority)) {
      throw new Error('priority must be a number');
    }
    var actualCallback = callback;
    if (that) {
      actualCallback = bind$1(callback, that);

      // make sure we remember and are able to remove
      // bound callbacks via {@link #off} using the original
      // callback
      actualCallback[FN_REF] = callback[FN_REF] || callback;
    }
    var self = this;
    events.forEach(function (e) {
      self._addListener(e, {
        priority: priority,
        callback: actualCallback,
        next: null
      });
    });
  };

  /**
   * @overlord
   *
   * Register an event listener that is called only once.
   *
   * @template {keyof EventMap} EventName
   *
   * @param {EventName} events to subscribe to
   * @param {number} [priority=1000] listen priority
   * @param {EventBusEventCallback<EventMap[EventName]>} callback
   * @param {any} [that] callback context
   */
  /**
   * Register an event listener that is called only once.
   *
   * @template T
   *
   * @param {string|string[]} events to subscribe to
   * @param {number} [priority=1000] the listen priority
   * @param {EventBusEventCallback<T>} callback
   * @param {any} [that] callback context
   */
  EventBus.prototype.once = function (events, priority, callback, that) {
    var self = this;
    if (isFunction$1(priority)) {
      that = callback;
      callback = priority;
      priority = DEFAULT_PRIORITY$2;
    }
    if (!isNumber$1(priority)) {
      throw new Error('priority must be a number');
    }
    function wrappedCallback() {
      wrappedCallback.__isTomb = true;
      var result = callback.apply(that, arguments);
      self.off(events, wrappedCallback);
      return result;
    }

    // make sure we remember and are able to remove
    // bound callbacks via {@link #off} using the original
    // callback
    wrappedCallback[FN_REF] = callback;
    this.on(events, priority, wrappedCallback);
  };

  /**
   * Removes event listeners by event and callback.
   *
   * If no callback is given, all listeners for a given event name are being removed.
   *
   * @param {string|string[]} events
   * @param {EventBusEventCallback<unknown>} [callback]
   */
  EventBus.prototype.off = function (events, callback) {
    events = isArray$2(events) ? events : [events];
    var self = this;
    events.forEach(function (event) {
      self._removeListener(event, callback);
    });
  };

  /**
   * Create an event recognized be the event bus.
   *
   * @param {Object} data Event data.
   *
   * @return {Event} An event that will be recognized by the event bus.
   */
  EventBus.prototype.createEvent = function (data) {
    var event = new InternalEvent();
    event.init(data);
    return event;
  };

  /**
   * Fires an event.
   *
   * @example
   *
   * ```javascript
   * // fire event by name
   * events.fire('foo');
   *
   * // fire event object with nested type
   * var event = { type: 'foo' };
   * events.fire(event);
   *
   * // fire event with explicit type
   * var event = { x: 10, y: 20 };
   * events.fire('element.moved', event);
   *
   * // pass additional arguments to the event
   * events.on('foo', function(event, bar) {
   *   alert(bar);
   * });
   *
   * events.fire({ type: 'foo' }, 'I am bar!');
   * ```
   *
   * @param {string} [type] event type
   * @param {Object} [data] event or event data
   * @param {...any} [args] additional arguments the callback will be called with.
   *
   * @return {any} The return value. Will be set to `false` if the default was prevented.
   */
  EventBus.prototype.fire = function (type, data) {
    var event, firstListener, returnValue, args;
    args = slice.call(arguments);
    if (typeof type === 'object') {
      data = type;
      type = data.type;
    }
    if (!type) {
      throw new Error('no event type specified');
    }
    firstListener = this._listeners[type];
    if (!firstListener) {
      return;
    }

    // we make sure we fire instances of our home made
    // events here. We wrap them only once, though
    if (data instanceof InternalEvent) {
      // we are fine, we alread have an event
      event = data;
    } else {
      event = this.createEvent(data);
    }

    // ensure we pass the event as the first parameter
    args[0] = event;

    // original event type (in case we delegate)
    var originalType = event.type;

    // update event type before delegation
    if (type !== originalType) {
      event.type = type;
    }
    try {
      returnValue = this._invokeListeners(event, args, firstListener);
    } finally {
      // reset event type after delegation
      if (type !== originalType) {
        event.type = originalType;
      }
    }

    // set the return value to false if the event default
    // got prevented and no other return value exists
    if (returnValue === undefined && event.defaultPrevented) {
      returnValue = false;
    }
    return returnValue;
  };

  /**
   * Handle an error by firing an event.
   *
   * @param {Error} error The error to be handled.
   *
   * @return {boolean} Whether the error was handled.
   */
  EventBus.prototype.handleError = function (error) {
    return this.fire('error', {
      error: error
    }) === false;
  };
  EventBus.prototype._destroy = function () {
    this._listeners = {};
  };

  /**
   * @param {Event} event
   * @param {any[]} args
   * @param {EventBusListener} listener
   *
   * @return {any}
   */
  EventBus.prototype._invokeListeners = function (event, args, listener) {
    var returnValue;
    while (listener) {
      // handle stopped propagation
      if (event.cancelBubble) {
        break;
      }
      returnValue = this._invokeListener(event, args, listener);
      listener = listener.next;
    }
    return returnValue;
  };

  /**
   * @param {Event} event
   * @param {any[]} args
   * @param {EventBusListener} listener
   *
   * @return {any}
   */
  EventBus.prototype._invokeListener = function (event, args, listener) {
    var returnValue;
    if (listener.callback.__isTomb) {
      return returnValue;
    }
    try {
      // returning false prevents the default action
      returnValue = invokeFunction(listener.callback, args);

      // stop propagation on return value
      if (returnValue !== undefined) {
        event.returnValue = returnValue;
        event.stopPropagation();
      }

      // prevent default on return false
      if (returnValue === false) {
        event.preventDefault();
      }
    } catch (error) {
      if (!this.handleError(error)) {
        console.error('unhandled error in event listener', error);
        throw error;
      }
    }
    return returnValue;
  };

  /**
   * Add new listener with a certain priority to the list
   * of listeners (for the given event).
   *
   * The semantics of listener registration / listener execution are
   * first register, first serve: New listeners will always be inserted
   * after existing listeners with the same priority.
   *
   * Example: Inserting two listeners with priority 1000 and 1300
   *
   *    * before: [ 1500, 1500, 1000, 1000 ]
   *    * after: [ 1500, 1500, (new=1300), 1000, 1000, (new=1000) ]
   *
   * @param {string} event
   * @param {EventBusListener} newListener
   */
  EventBus.prototype._addListener = function (event, newListener) {
    var listener = this._getListeners(event),
      previousListener;

    // no prior listeners
    if (!listener) {
      this._setListeners(event, newListener);
      return;
    }

    // ensure we order listeners by priority from
    // 0 (high) to n > 0 (low)
    while (listener) {
      if (listener.priority < newListener.priority) {
        newListener.next = listener;
        if (previousListener) {
          previousListener.next = newListener;
        } else {
          this._setListeners(event, newListener);
        }
        return;
      }
      previousListener = listener;
      listener = listener.next;
    }

    // add new listener to back
    previousListener.next = newListener;
  };

  /**
   * @param {string} name
   *
   * @return {EventBusListener}
   */
  EventBus.prototype._getListeners = function (name) {
    return this._listeners[name];
  };

  /**
   * @param {string} name
   * @param {EventBusListener} listener
   */
  EventBus.prototype._setListeners = function (name, listener) {
    this._listeners[name] = listener;
  };
  EventBus.prototype._removeListener = function (event, callback) {
    var listener = this._getListeners(event),
      nextListener,
      previousListener,
      listenerCallback;
    if (!callback) {
      // clear listeners
      this._setListeners(event, null);
      return;
    }
    while (listener) {
      nextListener = listener.next;
      listenerCallback = listener.callback;
      if (listenerCallback === callback || listenerCallback[FN_REF] === callback) {
        if (previousListener) {
          previousListener.next = nextListener;
        } else {
          // new first listener
          this._setListeners(event, nextListener);
        }
      }
      previousListener = listener;
      listener = nextListener;
    }
  };

  /**
   * A event that is emitted via the event bus.
   */
  function InternalEvent() {}
  InternalEvent.prototype.stopPropagation = function () {
    this.cancelBubble = true;
  };
  InternalEvent.prototype.preventDefault = function () {
    this.defaultPrevented = true;
  };
  InternalEvent.prototype.init = function (data) {
    assign$1(this, data || {});
  };

  /**
   * Invoke function. Be fast...
   *
   * @param {Function} fn
   * @param {any[]} args
   *
   * @return {any}
   */
  function invokeFunction(fn, args) {
    return fn.apply(null, args);
  }

  /**
   * Moddle base element.
   */
  function Base$1() {}

  /**
   * @template { keyof this } K
   *
   * Get property value (typed)
   *
   * @overload
   *
   * @param {K} name
   *
   * @return { this[K] }
   */
  /**
   * @template T
   *
   * Get property value
   *
   * @overload
   *
   * @param {string} name
   *
   * @return {T}
   */
  /**
   * Get property value
   *
   * @overload
   *
   * @param {string} name
   *
   * @return {unknown}
   */
  Base$1.prototype.get = function (name) {
    return this.$model.properties.get(this, name);
  };

  /**
   * @template { keyof this } K
   * @template { this[K] } V
   *
   * Set property value
   *
   * @overload
   *
   * @param {K} name
   * @param {V} value
   */
  /**
   * @template { string } S
   *
   * Set property value
   *
   * @overload
   *
   * @param { S extends keyof this ? never : S } name
   * @param { any } value
   */
  Base$1.prototype.set = function (name, value) {
    this.$model.properties.set(this, name, value);
  };

  /**
   * @typedef {import('./ns.js').Namespace} Namespace
   * @typedef {import('./moddle.js').default} Moddle
   * @typedef {import('./properties.js').default} Properties
   * @typedef {import('./registry.js').EffectiveDescriptor} EffectiveDescriptor
   * @typedef {import('./base.js').default} BaseElement
   * @typedef {import('./descriptor-builder.js').AnyTypeDescriptor} AnyTypeDescriptor
   */

  /**
   * @template [T=Record<string,any>]
   * @typedef {{
   *   new(attrs?: Partial<T>): ModdleElement<T>;
   *   prototype: ModdleElement<T>;
   *   readonly $model: Moddle;
   *   readonly $descriptor: EffectiveDescriptor;
   * }} ModdleElementType
   */

  /**
   * @template [T=Record<string,any>]
   * @typedef {BaseElement & T & {
   *   readonly $model: Moddle;
   *   readonly $descriptor: EffectiveDescriptor;
   *   readonly $type: Namespace['name'];
   *   readonly $attrs: Record<string, any>;
   *   $parent?: ModdleElement | AnyModdleElement;
   *   hasType: Moddle['hasType'];
   *   $instanceOf: Moddle['hasType'];
   * }} ModdleElement
   */

  /**
   * @template [T=Record<string,any>]
   * @typedef {BaseElement & T & {
   *   $type: string;
   *   $instanceOf: (type: string) => boolean;
   *   $parent?: ModdleElement | AnyModdleElement;
   *   readonly $model: Moddle;
   *   readonly $descriptor: AnyTypeDescriptor;
   * }} AnyModdleElement
   */

  /**
   * A model element factory.
   *
   * @param {Moddle} model
   * @param {Properties} properties
   */
  function Factory(model, properties) {
    /**
     * @private
     */
    this.model = model;

    /**
     * @private
     */
    this.properties = properties;
  }

  /**
   * @template [T=Record<string,any>]
   * @param {EffectiveDescriptor} descriptor
   * @return {ModdleElementType<T>}
   */
  Factory.prototype.createType = function (descriptor) {
    var model = this.model;
    var props = this.properties,
      prototype = Object.create(Base$1.prototype);

    // initialize default values
    forEach(descriptor.properties, function (p) {
      if (!p.isMany && p.default !== undefined) {
        prototype[p.name] = p.default;
      }
    });
    props.defineModel(prototype, model);
    props.defineDescriptor(prototype, descriptor);
    var name = descriptor.ns.name;

    /**
     * The new type constructor
     *
     * @type { ModdleElementType }
     */
    function ModdleElement(attrs) {
      props.define(this, '$type', {
        value: name,
        enumerable: true
      });
      props.define(this, '$attrs', {
        value: {}
      });
      props.define(this, '$parent', {
        writable: true
      });
      forEach(attrs, bind$1(function (val, key) {
        this.set(key, val);
      }, this));
    }
    ModdleElement.prototype = prototype;
    ModdleElement.hasType = prototype.$instanceOf = this.model.hasType;

    // static links
    props.defineModel(ModdleElement, model);
    props.defineDescriptor(ModdleElement, descriptor);
    return ModdleElement;
  };

  /**
   * Built-in moddle types
   */
  var BUILTINS = assign$1(Object.create(null), {
    String: true,
    Boolean: true,
    Integer: true,
    Real: true,
    Element: true
  });

  /**
   * Converters for built-in types from string representations
   */
  var TYPE_CONVERTERS = assign$1(Object.create(null), {
    String: function (s) {
      return s;
    },
    Boolean: function (s) {
      return s === 'true';
    },
    Integer: function (s) {
      return parseInt(s, 10);
    },
    Real: function (s) {
      return parseFloat(s);
    }
  });

  /**
   * @typedef {'String'} StringType
   * @typedef {'Boolean'} BooleanType
   * @typedef {'Integer'} IntegerType
   * @typedef {'Real'} RealType
   * @typedef {'Element'} ElementType
   * @typedef {StringType | BooleanType | IntegerType | RealType} BuiltInSimpleType
   * @typedef {BuiltInSimpleType | ElementType} BuiltInType
   */

  /**
   * Convert given value to string
   * @overlord
   * @param {StringType} type
   * @param {any} value
   * @return {string}
   */
  /**
   * Convert given value to boolean
   * @overlord
   * @param {BooleanType} type
   * @param {any} value
   * @return {boolean}
   */
  /**
   * Convert given value to number
   * @overlord
   * @param {IntegerType | RealType} type
   * @param {any} value
   * @return {number}
   */
  /**
   * Convert a type to its real representation
   * @template T
   * @overlord
   * @param {Exclude<string,BuiltInSimpleType>} type
   * @param {T} value
   * @return {T}
   */
  function coerceType(type, value) {
    var converter = TYPE_CONVERTERS[type];
    if (converter) {
      return converter(value);
    } else {
      return value;
    }
  }

  /**
   * Return whether the given type is built-in
   * @overload
   * @param {BuiltInType} type
   * @return {true}
   */
  /**
   * Return whether the given type is built-in
   * @overload
   * @param {Exclude<string,BuiltInType>} type
   * @return {false}
   */
  function isBuiltIn(type) {
    return !!BUILTINS[type];
  }

  /**
   * Return true if the given type is simple
   * @overload
   * @param {BuiltInSimpleType} type
   * @return {true}
   */
  /**
   * Return false the given type is not simple
   * @overload
   * @param {Exclude<string,BuiltInSimpleType>} type
   * @return {false}
   */
  function isSimple(type) {
    return !!TYPE_CONVERTERS[type];
  }

  /**
   * @typedef {{
   *   name: string;
   *   prefix: string;
   *   localName: string;
   * }} Namespace
   */

  /**
   * Parses a namespaced attribute name of the form (ns:)localName to an object,
   * given a default prefix to assume in case no explicit namespace is given.
   *
   * @param {String} name
   * @param {String} [defaultPrefix] the default prefix to take, if none is present.
   *
   * @return {Namespace} the parsed name
   */
  function parseName(name, defaultPrefix) {
    var parts = name.split(/:/),
      localName,
      prefix;

    // no prefix (i.e. only local name)
    if (parts.length === 1) {
      localName = name;
      prefix = defaultPrefix;
    }

    // prefix + local name
    else if (parts.length === 2) {
      localName = parts[1];
      prefix = parts[0];
    } else {
      throw new Error('expected <prefix:localName> or <localName>, got ' + name);
    }
    name = (prefix ? prefix + ':' : '') + localName;
    return {
      name: name,
      prefix: prefix,
      localName: localName
    };
  }

  /**
   * @typedef {import('./ns.js').Namespace} Namespace
   * @typedef {import('./registry.js').RegisteredPackage} RegisteredPackage
   * @typedef {import('./registry.js').RegisteredTypeDef} RegisteredTypeDef
   * @typedef {import('./registry.js').RegisteredPropertyDef} RegisteredPropertyDef
   */

  /**
   * Effective element descriptor
   * aka element type descriptor
   * aka element descriptor
   * @typedef {{
   *   readonly ns: Namespace;
   *   readonly name: Namespace['name'];
   *   readonly allTypes: Array<RegisteredTypeDef>;
   *   readonly allTypesByName: Record<string, RegisteredTypeDef>;
   *   readonly properties: Array<PropertyDescriptor>;
   *   readonly propertiesByName: Record<string, PropertyDescriptor>;
   *   readonly bodyProperty?: PropertyDescriptor;
   *   readonly idProperty?: PropertyDescriptor;
   *   readonly $pkg?: RegisteredPackage;
   * }} EffectiveDescriptor
   */

  /**
   * Property descriptor
   * @typedef {RegisteredPropertyDef & {
   *   localName: Namespace['localName'];
   *   inherited?: boolean;
   *   definedBy?: RegisteredTypeDef;
   * }} PropertyDescriptor
   */

  /**
   * @typedef {{
   *   name: string;
   *   isGeneric: true;
   *   ns: {
   *     prefix: string;
   *     localName: string;
   *     uri: string;
   *   };
   * }} AnyTypeDescriptor
   */

  /**
   * A utility to build element descriptors.
   * @class DescriptorBuilder
   * @param {Namespace} nameNs
   */
  function DescriptorBuilder(nameNs) {
    /**
     * @private
     * @type {Namespace}
     */
    this.ns = nameNs;

    /**
     * @private
     * @type {Namespace['name']}
     */
    this.name = nameNs.name;

    /**
     * @private
     * @type {Array<RegisteredTypeDef>}
     */
    this.allTypes = [];

    /**
     * @private
     * @type {Record<string, RegisteredTypeDef>}
     */
    this.allTypesByName = Object.create(null);

    /**
     * @private
     * @type {Array<PropertyDescriptor>}
     */
    this.properties = [];

    /**
     * @private
     * @type {Record<string, PropertyDescriptor>}
     */
    this.propertiesByName = Object.create(null);
  }

  /**
   * @return {EffectiveDescriptor}
   */
  DescriptorBuilder.prototype.build = function () {
    return pick(this, ['ns', 'name', 'allTypes', 'allTypesByName', 'properties', 'propertiesByName', 'bodyProperty', 'idProperty']);
  };

  /**
   * Add property at given index.
   *
   * @param {PropertyDescriptor} p
   * @param {Number} [idx]
   * @param {Boolean} [validate=true]
   */
  DescriptorBuilder.prototype.addProperty = function (p, idx, validate) {
    if (typeof idx === 'boolean') {
      validate = idx;
      idx = undefined;
    }
    this.addNamedProperty(p, validate !== false);
    var properties = this.properties;
    if (idx !== undefined) {
      properties.splice(idx, 0, p);
    } else {
      properties.push(p);
    }
  };

  /**
   * @param {PropertyDescriptor} oldProperty
   * @param {PropertyDescriptor} newProperty
   * @param {string} replace
   */
  DescriptorBuilder.prototype.replaceProperty = function (oldProperty, newProperty, replace) {
    var oldNameNs = oldProperty.ns;
    var props = this.properties,
      propertiesByName = this.propertiesByName,
      rename = oldProperty.name !== newProperty.name;
    if (oldProperty.isId) {
      if (!newProperty.isId) {
        throw new Error('property <' + newProperty.ns.name + '> must be id property ' + 'to refine <' + oldProperty.ns.name + '>');
      }
      this.setIdProperty(newProperty, false);
    }
    if (oldProperty.isBody) {
      if (!newProperty.isBody) {
        throw new Error('property <' + newProperty.ns.name + '> must be body property ' + 'to refine <' + oldProperty.ns.name + '>');
      }

      // TODO: Check compatibility
      this.setBodyProperty(newProperty, false);
    }

    // validate existence and get location of old property
    var idx = props.indexOf(oldProperty);
    if (idx === -1) {
      throw new Error('property <' + oldNameNs.name + '> not found in property list');
    }

    // remove old property
    props.splice(idx, 1);

    // replacing the named property is intentional
    //
    //  * validate only if this is a "rename" operation
    //  * add at specific index unless we "replace"
    //
    this.addProperty(newProperty, replace ? undefined : idx, rename);

    // make new property available under old name
    propertiesByName[oldNameNs.name] = propertiesByName[oldNameNs.localName] = newProperty;
  };

  /**
   * @param {PropertyDescriptor} p
   * @param {string} targetPropertyName
   * @param {string} replace
   */
  DescriptorBuilder.prototype.redefineProperty = function (p, targetPropertyName, replace) {
    var nsPrefix = p.ns.prefix;
    var parts = targetPropertyName.split('#');
    var name = parseName(parts[0], nsPrefix);
    var attrName = parseName(parts[1], name.prefix).name;
    var redefinedProperty = this.propertiesByName[attrName];
    if (!redefinedProperty) {
      throw new Error('refined property <' + attrName + '> not found');
    } else {
      this.replaceProperty(redefinedProperty, p, replace);
    }
    delete p.redefines;
  };

  /**
   * @param {PropertyDescriptor} p
   * @param {boolean} validate
   */
  DescriptorBuilder.prototype.addNamedProperty = function (p, validate) {
    var ns = p.ns,
      propsByName = this.propertiesByName;
    if (validate) {
      this.assertNotDefined(p, ns.name);
      this.assertNotDefined(p, ns.localName);
    }
    propsByName[ns.name] = propsByName[ns.localName] = p;
  };

  /**
   * @param {RegisteredPropertyDef} p
   */
  DescriptorBuilder.prototype.removeNamedProperty = function (p) {
    var ns = p.ns,
      propsByName = this.propertiesByName;
    delete propsByName[ns.name];
    delete propsByName[ns.localName];
  };

  /**
   * @param {PropertyDescriptor} p
   * @param {boolean} [validate]
   */
  DescriptorBuilder.prototype.setBodyProperty = function (p, validate) {
    if (validate && this.bodyProperty) {
      throw new Error('body property defined multiple times ' + '(<' + this.bodyProperty.ns.name + '>, <' + p.ns.name + '>)');
    }
    this.bodyProperty = p;
  };

  /**
   * @param {PropertyDescriptor} p
   * @param {boolean} [validate]
   */
  DescriptorBuilder.prototype.setIdProperty = function (p, validate) {
    if (validate && this.idProperty) {
      throw new Error('id property defined multiple times ' + '(<' + this.idProperty.ns.name + '>, <' + p.ns.name + '>)');
    }
    this.idProperty = p;
  };

  /**
   * @param {RegisteredTypeDef} typeDescriptor
   */
  DescriptorBuilder.prototype.assertNotTrait = function (typeDescriptor) {
    const _extends = typeDescriptor.extends || [];
    if (_extends.length) {
      throw new Error(`cannot create <${typeDescriptor.name}> extending <${typeDescriptor.extends}>`);
    }
  };

  /**
   * @param {PropertyDescriptor} p
   */
  DescriptorBuilder.prototype.assertNotDefined = function (p, name) {
    var propertyName = p.name,
      definedProperty = this.propertiesByName[propertyName];
    if (definedProperty) {
      throw new Error('property <' + propertyName + '> already defined; ' + 'override of <' + definedProperty.definedBy.ns.name + '#' + definedProperty.ns.name + '> by ' + '<' + p.definedBy.ns.name + '#' + p.ns.name + '> not allowed without redefines');
    }
  };

  /**
   * @param {string} name
   * @return {PropertyDescriptor}
   */
  DescriptorBuilder.prototype.hasProperty = function (name) {
    return this.propertiesByName[name];
  };

  /**
   * @param {RegisteredTypeDef} t
   * @param {boolean} inherited
   */
  DescriptorBuilder.prototype.addTrait = function (t, inherited) {
    if (inherited) {
      this.assertNotTrait(t);
    }
    var typesByName = this.allTypesByName,
      types = this.allTypes;
    var typeName = t.name;
    if (typeName in typesByName) {
      return;
    }
    forEach(t.properties, bind$1(function (p) {
      // clone property to allow extensions
      p = assign$1({}, p, {
        name: p.ns.localName,
        inherited: inherited
      });
      Object.defineProperty(p, 'definedBy', {
        value: t
      });
      var replaces = p.replaces,
        redefines = p.redefines;

      // add replace/redefine support
      if (replaces || redefines) {
        this.redefineProperty(p, replaces || redefines, replaces);
      } else {
        if (p.isBody) {
          this.setBodyProperty(p);
        }
        if (p.isId) {
          this.setIdProperty(p);
        }
        this.addProperty(p);
      }
    }, this));
    types.push(t);
    typesByName[typeName] = t;
  };

  /**
   * @typedef {import('./ns.js').Namespace} Namespace
   * @typedef {import('./moddle.js').PackageDefinition} PackageDefinition
   * @typedef {import('./moddle.js').TypeDefinition} TypeDefinition
   * @typedef {import('./moddle.js').PropertyDefinition} PropertyDefinition
   * @typedef {import('./properties.js').default} Properties
   * @typedef {import('./descriptor-builder.js').EffectiveDescriptor} EffectiveDescriptor
   */

  /**
   * Registered package definition
   * @typedef {Omit<PackageDefinition, 'types'> & {
   *   types?: Array<RegisteredTypeDef>;
   * }} RegisteredPackage
   */

  /**
   * Registered type definition
   * @typedef {Omit<TypeDefinition, 'properties'> & {
   *   properties?: Array<RegisteredPropertyDef>;
   *   propertiesByName?: Record<string, RegisteredPropertyDef>;
   *   superClass?: Array<string>;
   *   extends?: Array<string>;
   *   meta?: Record<string, *>;
   *   traits?: Array<string>;
   *   ns?: Namespace;
   *   readonly $pkg?: RegisteredPackage;
   * }} RegisteredTypeDef
   */

  /**
   * Registered property definition
   * @typedef {PropertyDefinition & { ns: Namespace }} RegisteredPropertyDef
   */

  /**
   * A registry of Moddle packages.
   *
   * @param {Array<PackageDefinition> | Record<string,PackageDefinition>} packages
   * @param {Properties} properties
   */
  function Registry(packages, properties) {
    /**
     * @private
     * @type {Record<string, RegisteredPackage>} registered packages map
     */
    this.packageMap = Object.create(null);

    /**
     * @type {Record<string,RegisteredTypeDef>}
     */
    this.typeMap = Object.create(null);

    /**
     * @private
     * @type {Array<RegisteredPackage>} all registered packages
     */
    this.packages = [];

    /**
     * @private
     * @type {Properties}
     */
    this.properties = properties;
    forEach(packages, bind$1(this.registerPackage, this));
  }

  /**
   * @param {string} uriOrPrefix uri or prefix of package
   * @return {RegisteredPackage} registered package
   */
  Registry.prototype.getPackage = function (uriOrPrefix) {
    return this.packageMap[uriOrPrefix];
  };

  /**
   * @return {Array<RegisteredPackage>} all registered packages
   */
  Registry.prototype.getPackages = function () {
    return this.packages;
  };

  /**
   * @private
   * @param {PackageDefinition} pkg registering package
   */
  Registry.prototype.registerPackage = function (pkg) {
    // copy package
    pkg = assign$1({}, pkg);
    var pkgMap = this.packageMap;
    ensureAvailable(pkgMap, pkg, 'prefix');
    ensureAvailable(pkgMap, pkg, 'uri');

    // register types
    forEach(pkg.types, bind$1(function (descriptor) {
      this.registerType(descriptor, pkg);
    }, this));
    pkgMap[pkg.uri] = pkgMap[pkg.prefix] = pkg;
    this.packages.push(pkg);
  };

  /**
   * @private
   * Register a type from a specific package with us
   * @param {TypeDefinition} type
   * @param {RegisteredPackage} pkg
   */
  Registry.prototype.registerType = function (type, pkg) {
    type = assign$1({}, type, {
      superClass: (type.superClass || []).slice(),
      extends: (type.extends || []).slice(),
      properties: (type.properties || []).slice(),
      meta: assign$1({}, type.meta || {})
    });
    var ns = parseName(type.name, pkg.prefix),
      name = ns.name,
      /** @type {Record<string, RegisteredPropertyDef>} */propertiesByName = Object.create(null);

    // parse properties
    forEach(type.properties, bind$1(function (p) {
      // namespace property names
      var propertyNs = parseName(p.name, ns.prefix),
        propertyName = propertyNs.name;

      // namespace property types
      if (!isBuiltIn(p.type)) {
        p.type = parseName(p.type, propertyNs.prefix).name;
      }
      assign$1(p, {
        ns: propertyNs,
        name: propertyName
      });
      propertiesByName[propertyName] = p;
    }, this));

    // update ns + name
    assign$1(type, {
      ns: ns,
      name: name,
      propertiesByName: propertiesByName
    });
    forEach(type.extends, bind$1(function (extendsName) {
      var extendsNameNs = parseName(extendsName, ns.prefix);
      var extended = this.typeMap[extendsNameNs.name];
      extended.traits = extended.traits || [];
      extended.traits.push(name);
    }, this));

    // link to package
    this.definePackage(type, pkg);

    // register
    this.typeMap[name] = type;
  };

  /**
   * @callback IteratorFn
   * @param {RegisteredTypeDef} type
   * @param {boolean} inherited
   */

  /**
   * Traverse the type hierarchy from bottom to top,
   * calling iterator with (type, inherited) for all elements in
   * the inheritance chain.
   * @private
   * @param {Namespace} nsName
   * @param {IteratorFn} iterator
   * @param {Boolean} [trait=false]
   */
  Registry.prototype.mapTypes = function (nsName, iterator, trait) {
    /** @type {RegisteredTypeDef} */
    var type = isBuiltIn(nsName.name) ? {
      name: nsName.name
    } : this.typeMap[nsName.name];
    var self = this;

    /**
     * Traverse the selected super type or trait
     *
     * @param {String} cls
     * @param {Boolean} [trait=false]
     */
    function traverse(cls, trait) {
      var parentNs = parseName(cls, isBuiltIn(cls) ? '' : nsName.prefix);
      self.mapTypes(parentNs, iterator, trait);
    }

    /**
     * Traverse the selected trait.
     *
     * @param {String} cls
     */
    function traverseTrait(cls) {
      return traverse(cls, true);
    }

    /**
     * Traverse the selected super type
     *
     * @param {String} cls
     */
    function traverseSuper(cls) {
      return traverse(cls, false);
    }
    if (!type) {
      throw new Error('unknown type <' + nsName.name + '>');
    }
    forEach(type.superClass, trait ? traverseTrait : traverseSuper);

    // call iterator with (type, inherited=!trait)
    iterator(type, !trait);
    forEach(type.traits, traverseTrait);
  };

  /**
   * Returns the effective descriptor for a type.
   * @param  {Namespace['name']} name the namespaced name (ns:localName) of the type
   * @return {EffectiveDescriptor} the resulting effective descriptor
   */
  Registry.prototype.getEffectiveDescriptor = function (name) {
    var nsName = parseName(name);
    var builder = new DescriptorBuilder(nsName);
    this.mapTypes(nsName, function (type, inherited) {
      builder.addTrait(type, inherited);
    });
    var descriptor = builder.build();

    // define package link
    this.definePackage(descriptor, descriptor.allTypes[descriptor.allTypes.length - 1].$pkg);
    return descriptor;
  };

  /**
   * @private
   * @param {RegisteredTypeDef | EffectiveDescriptor} target
   * @param {RegisteredPackage} pkg
   */
  Registry.prototype.definePackage = function (target, pkg) {
    this.properties.define(target, '$pkg', {
      value: pkg
    });
  };

  // helpers ////////////////////////////

  /**
   * Checking already defined packages
   * @param {Record<string, RegisteredPackage>} packageMap
   * @param {PackageDefinition} pkg
   * @param {'prefix' | 'uri'} identifierKey
   */
  function ensureAvailable(packageMap, pkg, identifierKey) {
    var value = pkg[identifierKey];
    if (value in packageMap) {
      throw new Error('package with ' + identifierKey + ' <' + value + '> already defined');
    }
  }

  /**
   * @typedef {import('./moddle.js').default} Moddle
   * @typedef {import('./descriptor-builder.js').PropertyDescriptor} PropertyDesc
   * @typedef {import('./registry.js').EffectiveDescriptor} EffectiveDescriptor
   * @typedef {import('./factory.js').ModdleElement} ModdleElement
   * @typedef {import('./descriptor-builder.js').AnyTypeDescriptor} AnyTypeDescriptor
   */

  /**
   * A utility that gets and sets properties of model elements.
   *
   * @param {Moddle} model
   */
  function Properties(model) {
    /** @type {Moddle} */
    this.model = model;
  }

  /**
   * Sets a named property on the target element.
   * If the value is undefined, the property gets deleted.
   *
   * @param {ModdleElement} target
   * @param {String} name
   * @param {Object} value
   */
  Properties.prototype.set = function (target, name, value) {
    if (!isString$1(name) || !name.length) {
      throw new TypeError('property name must be a non-empty string');
    }
    var property = this.getProperty(target, name);
    var propertyName = property && property.name;
    if (isUndefined$1(value)) {
      // unset the property, if the specified value is undefined;
      // delete from $attrs (for extensions) or the target itself
      if (property) {
        delete target[propertyName];
      } else {
        delete target.$attrs[stripGlobal(name)];
      }
    } else {
      // set the property, defining well defined properties on the fly
      // or simply updating them in target.$attrs (for extensions)
      if (property) {
        if (propertyName in target) {
          target[propertyName] = value;
        } else {
          defineProperty$2(target, property, value);
        }
      } else {
        target.$attrs[stripGlobal(name)] = value;
      }
    }
  };

  /**
   * Returns the named property of the given element
   *
   * @param  {ModdleElement} target
   * @param  {String} name
   *
   * @return {Object}
   */
  Properties.prototype.get = function (target, name) {
    var property = this.getProperty(target, name);
    if (!property) {
      return target.$attrs[stripGlobal(name)];
    }
    var propertyName = property.name;

    // check if access to collection property and lazily initialize it
    if (!target[propertyName] && property.isMany) {
      defineProperty$2(target, property, []);
    }
    return target[propertyName];
  };

  /**
   * Define a property on the target element
   * @template [T=any]
   * @param  {NonNullable<T>} target
   * @param  {String} name
   * @param  {PropertyDescriptor} options
   */
  Properties.prototype.define = function (target, name, options) {
    if (!options.writable) {
      var value = options.value;

      // use getters for read-only variables to support ES6 proxies
      // cf. https://github.com/bpmn-io/internal-docs/issues/386
      options = assign$1({}, options, {
        get: function () {
          return value;
        }
      });
      delete options.value;
    }
    Object.defineProperty(target, name, options);
  };

  /**
   * Define the descriptor for an element
   * @template [T=any]
   * @param {NonNullable<T>} target
   * @param {EffectiveDescriptor | AnyTypeDescriptor} descriptor
   */
  Properties.prototype.defineDescriptor = function (target, descriptor) {
    this.define(target, '$descriptor', {
      value: descriptor
    });
  };

  /**
   * Define the model for an element
   * @template [T=any]
   * @param {NonNullable<T>} target
   * @param {Moddle} model
   */
  Properties.prototype.defineModel = function (target, model) {
    this.define(target, '$model', {
      value: model
    });
  };

  /**
   * Return property with the given name on the element.
   *
   * @param {ModdleElement} target
   * @param {string} name
   *
   * @return {PropertyDesc | null} property
   */
  Properties.prototype.getProperty = function (target, name) {
    var model = this.model;
    var property = model.getPropertyDescriptor(target, name);
    if (property) {
      return property;
    }
    if (name.includes(':')) {
      return null;
    }
    const strict = model.config.strict;
    if (typeof strict !== 'undefined') {
      const error = new TypeError(`unknown property <${name}> on <${target.$type}>`);
      if (strict) {
        throw error;
      } else {
        typeof console !== 'undefined' && console.warn(error);
      }
    }
    return null;
  };
  function isUndefined$1(val) {
    return typeof val === 'undefined';
  }
  function defineProperty$2(target, property, value) {
    Object.defineProperty(target, property.name, {
      enumerable: !property.isReference,
      writable: true,
      value: value,
      configurable: true
    });
  }
  function stripGlobal(name) {
    return name.replace(/^:/, '');
  }

  /**
   * @typedef {import('./registry.js').RegisteredTypeDef} RegisteredTypeDef
   * @typedef {import('./registry.js').RegisteredPackage} RegisteredPackage
   * @typedef {import('./base.js').default} BaseElement
   * @typedef {import('./descriptor-builder.js').EffectiveDescriptor} EffectiveDescriptor
   * @typedef {import('./descriptor-builder.js').AnyTypeDescriptor} AnyTypeDescriptor
   * @typedef {import('./descriptor-builder.js').PropertyDescriptor} PropertyDescriptor
   */

  /**
   * @template [T=Record<string,any>]
   * @typedef {import('./factory.js').ModdleElement<T>} ModdleElement
   * @typedef {import('./factory.js').ModdleElementType<T>} ModdleElementType
   * @typedef {import('./factory.js').AnyModdleElement<T>} AnyModdleElement
   */

  /**
   * Package definition
   * @typedef {{
   *   $schema?: string;
   *   name: string;
   *   prefix: string;
   *   types?: Array<TypeDefinition>;
   *   [key: string]: any;
   * } & PackageDefinitionXmlExtension} PackageDefinition
   */

  /**
   * Set of extended parameters for package definition used in moddle-xml.
   * @typedef {{
   *   uri?: string;
   *   xml?: {
   *     tagAlias?: 'lowerCase';
   *     typePrefix?: string;
   *   };
   * }} PackageDefinitionXmlExtension
   */

  /**
   * Type definition in declaration in package
   * @typedef {{
   *   name: string;
   *   isAbstract?: boolean;
   *   properties?: Array<PropertyDefinition>;
   *   superClass?: Array<string>;
   *   extends?: Array<string>;
   *   meta?: Record<string, *>;
   *   [key: string]: any;
   * }} TypeDefinition
   */

  /**
   * Set of extended parameters for property definition used in moddle-xml.
   * @typedef {{
   *   isBody?: boolean;
   *   isAttr?: boolean;
   *   xml?: {
   *     serialize?: string;
   *   };
   * }} PropertyDefinitionXmlExtension
   */

  /**
   * Property definition of type definition
   * @typedef {{
   *   name: string;
   *   type: 'String' | 'Boolean' | 'Integer' | 'Real' | string;
   *   default?: string | boolean | number;
   *   isMany?: boolean;
   *   isReference?: boolean;
   *   isId?: boolean;
   *   redefines?: string;
   *   replaces?: string;
   *   [key: string]: any;
   * } & PropertyDefinitionXmlExtension} PropertyDefinition
   */

  // Moddle implementation /////////////////////////////////////////////////

  /**
   * @class Moddle
   *
   * A model that can be used to create elements of a specific type.
   *
   * @example
   *
   * import Moddle from 'moddle';
   *
   * var pkg = {
   *   name: 'mypackage',
   *   prefix: 'my',
   *   types: [
   *     { name: 'Root' }
   *   ]
   * };
   *
   * var moddle = new Moddle([pkg]);
   *
   * @param {Array<PackageDefinition> | Record<string,PackageDefinition>} packages the packages to contain
   * @param {{ strict?: boolean }} [config={}] moddle configuration
   */
  function Moddle(packages, config = {}) {
    /** @type Readonly<Properties> */
    this.properties = new Properties(this);

    /** @type Readonly<Factory> */
    this.factory = new Factory(this, this.properties);

    /** @type Readonly<Registry> */
    this.registry = new Registry(packages, this.properties);

    /**
     * @type {Record<string,ModdleElementType>}
     */
    this.typeCache = Object.create(null);

    /**
     * @type {Readonly<{readonly strict?: boolean}>}
     */
    this.config = config;
  }

  /**
   * Create an instance of the specified type.
   *
   * @method Moddle#create
   *
   * @example
   *
   * var foo = moddle.create('my:Foo');
   * var bar = moddle.create('my:Bar', { id: 'BAR_1' });
   *
   * @template [T=Record<string,any>]
   * @param  {String|EffectiveDescriptor} descriptor the type descriptor or name know to the model
   * @param  {Partial<T>} [attrs] a number of attributes to initialize the model instance with
   * @return {ModdleElement<T>} model instance
   */
  Moddle.prototype.create = function (descriptor, attrs) {
    var Type = this.getType(descriptor);
    if (!Type) {
      throw new Error('unknown type <' + descriptor + '>');
    }
    return new Type(attrs);
  };

  /**
   * Returns the type representing a given descriptor
   *
   * @method Moddle#getType
   *
   * @example
   *
   * var Foo = moddle.getType('my:Foo');
   * var foo = new Foo({ 'id' : 'FOO_1' });
   *
   * @template [T=Record<string,any>]
   * @param  {String|EffectiveDescriptor} descriptor the type descriptor or name know to the model
   * @return {ModdleElementType<T>} the type representing the descriptor
   */
  Moddle.prototype.getType = function (descriptor) {
    var cache = this.typeCache;
    var name = isString$1(descriptor) ? descriptor : descriptor.ns.name;
    var type = cache[name];
    if (!type) {
      descriptor = this.registry.getEffectiveDescriptor(name);
      type = cache[name] = this.factory.createType(descriptor);
    }
    return type;
  };

  /**
   * Creates an any-element type to be used within model instances.
   *
   * This can be used to create custom elements that lie outside the meta-model.
   * The created element contains all the meta-data required to serialize it
   * as part of meta-model elements.
   *
   * @method Moddle#createAny
   *
   * @example
   *
   * var foo = moddle.createAny('vendor:Foo', 'http://vendor', {
   *   value: 'bar'
   * });
   *
   * var container = moddle.create('my:Container', 'http://my', {
   *   any: [ foo ]
   * });
   *
   * // go ahead and serialize the stuff
   *
   * @template [T=Record<string, any>]
   * @param  {String} name  the name of the element
   * @param  {String} nsUri the namespace uri of the element
   * @param  {T} [properties] a map of properties to initialize the instance with
   * @return {AnyModdleElement<T>} the any type instance
   */
  Moddle.prototype.createAny = function (name, nsUri, properties) {
    var nameNs = parseName(name);

    /** @type AnyModdleElement */
    var element = {
      $type: name,
      $instanceOf: function (type) {
        return type === this.$type;
      },
      get: function (key) {
        return this[key];
      },
      set: function (key, value) {
        set(this, [key], value);
      }
    };

    /** @type AnyTypeDescriptor */
    var descriptor = {
      name: name,
      isGeneric: true,
      ns: {
        prefix: nameNs.prefix,
        localName: nameNs.localName,
        uri: nsUri
      }
    };
    this.properties.defineDescriptor(element, descriptor);
    this.properties.defineModel(element, this);
    this.properties.define(element, 'get', {
      enumerable: false,
      writable: true
    });
    this.properties.define(element, 'set', {
      enumerable: false,
      writable: true
    });
    this.properties.define(element, '$parent', {
      enumerable: false,
      writable: true
    });
    this.properties.define(element, '$instanceOf', {
      enumerable: false,
      writable: true
    });
    forEach(properties, function (a, key) {
      if (isObject$1(a) && a.value !== undefined) {
        element[a.name] = a.value;
      } else {
        element[key] = a;
      }
    });
    return element;
  };

  /**
   * Returns a registered package by uri or prefix
   * @param {string} uriOrPrefix
   * @return {RegisteredPackage} the package
   */
  Moddle.prototype.getPackage = function (uriOrPrefix) {
    return this.registry.getPackage(uriOrPrefix);
  };

  /**
   * Returns a snapshot of all known packages
   *
   * @return {Readonly<Array<RegisteredPackage>>} the package
   */
  Moddle.prototype.getPackages = function () {
    return this.registry.getPackages();
  };

  /**
   * Returns the descriptor for an element
   * @param {ModdleElement | ModdleElementType} element
   * @return {EffectiveDescriptor}
   */
  Moddle.prototype.getElementDescriptor = function (element) {
    return element.$descriptor;
  };

  /**
   * @overload
   * Returns true if the given descriptor or instance
   * represents the given type.
   * @param {ModdleElement | ModdleElementType} element
   * @param {string} type
   * @return {boolean}
   */
  /**
   * @overload
   * @param {string} type
   * @return {boolean}
   */
  Moddle.prototype.hasType = function (element, type) {
    if (type === undefined) {
      type = element;
      element = this;
    }
    var descriptor = element.$model.getElementDescriptor(element);
    return type in descriptor.allTypesByName;
  };

  /**
   * Returns the descriptor of an elements named property
   * @param {ModdleElement | ModdleElementType} element
   * @param {string} property
   * @return {PropertyDescriptor}
   */
  Moddle.prototype.getPropertyDescriptor = function (element, property) {
    return this.getElementDescriptor(element).propertiesByName[property];
  };

  /**
   * Return registered type definition
   * @param {string} type
   * @return {RegisteredTypeDef}
   */
  Moddle.prototype.getTypeDescriptor = function (type) {
    return this.registry.typeMap[type];
  };

  var fromCharCode = String.fromCharCode;
  var hasOwnProperty$1 = Object.prototype.hasOwnProperty;
  var ENTITY_PATTERN = /&#(\d+);|&#x([0-9a-f]+);|&(\w+);/ig;
  var ENTITY_MAPPING = {
    'amp': '&',
    'apos': '\'',
    'gt': '>',
    'lt': '<',
    'quot': '"'
  };

  // map UPPERCASE variants of supported special chars
  Object.keys(ENTITY_MAPPING).forEach(function (k) {
    ENTITY_MAPPING[k.toUpperCase()] = ENTITY_MAPPING[k];
  });
  function replaceEntities(_, d, x, z) {
    // reserved names, i.e. &nbsp;
    if (z) {
      if (hasOwnProperty$1.call(ENTITY_MAPPING, z)) {
        return ENTITY_MAPPING[z];
      } else {
        // fall back to original value
        return '&' + z + ';';
      }
    }

    // decimal encoded char
    if (d) {
      return fromCharCode(d);
    }

    // hex encoded char
    return fromCharCode(parseInt(x, 16));
  }

  /**
   * A basic entity decoder that can decode a minimal
   * sub-set of reserved names (&amp;) as well as
   * hex (&#xaaf;) and decimal (&#1231;) encoded characters.
   *
   * @param {string} s
   *
   * @return {string} decoded string
   */
  function decodeEntities(s) {
    if (s.length > 3 && s.indexOf('&') !== -1) {
      return s.replace(ENTITY_PATTERN, replaceEntities);
    }
    return s;
  }
  var NON_WHITESPACE_OUTSIDE_ROOT_NODE = 'non-whitespace outside of root node';
  function error$1(msg) {
    return new Error(msg);
  }
  function missingNamespaceForPrefix(prefix) {
    return 'missing namespace for prefix <' + prefix + '>';
  }
  function getter(getFn) {
    return {
      'get': getFn,
      'enumerable': true
    };
  }

  /**
   * Set a namespace matrix entry, recording the previous
   * value on the given change log for later restoration.
   *
   * @param {Object} nsMatrix
   * @param {Object<string, ?string>} changes
   * @param {string} key
   * @param {string} value
   */
  function setNsEntry(nsMatrix, changes, key, value) {
    if (!(key in changes)) {
      changes[key] = key in nsMatrix ? nsMatrix[key] : null;
    }
    nsMatrix[key] = value;
  }

  /**
   * Restore a namespace matrix, applying the given change log.
   *
   * @param {Object} nsMatrix
   * @param {Object<string, ?string>} changes
   */
  function restoreNsMatrix(nsMatrix, changes) {
    var key, value;
    for (key in changes) {
      value = changes[key];
      if (value === null) {
        delete nsMatrix[key];
      } else {
        nsMatrix[key] = value;
      }
    }
  }
  function uriPrefix(prefix) {
    return prefix + '$uri';
  }
  function buildNsMatrix(nsUriToPrefix) {
    var nsMatrix = Object.create(null),
      uri,
      prefix;
    for (uri in nsUriToPrefix) {
      prefix = nsUriToPrefix[uri];
      nsMatrix[prefix] = prefix;
      nsMatrix[uriPrefix(prefix)] = uri;
    }
    return nsMatrix;
  }
  function noopGetContext() {
    return {
      line: 0,
      column: 0
    };
  }
  function throwFunc(err) {
    throw err;
  }

  /**
   * Creates a new parser with the given options.
   *
   * @constructor
   *
   * @param  {!Object<string, ?>=} options
   */
  function Parser$1(options) {
    if (!this) {
      return new Parser$1(options);
    }
    var proxy = options && options['proxy'];
    var onText,
      onOpenTag,
      onCloseTag,
      onCDATA,
      onError = throwFunc,
      onWarning,
      onComment,
      onQuestion,
      onAttention;
    var getContext = noopGetContext;

    /**
     * Are we currently consuming a chunked stream of XML,
     * i.e. is a `write` call in progress that may be followed
     * by more chunks?
     *
     * @type {boolean}
     */
    var streaming = false;

    /**
     * Did we already encounter the root tag?
     *
     * Persisted across `write` calls so we can detect a missing
     * start tag once the stream ends.
     *
     * @type {boolean}
     */
    var rootTagFound = false;

    /**
     * Not yet parsed remainder of the previously written chunk,
     * i.e. an incomplete token that awaits more input.
     *
     * @type {string}
     */
    var leftoverXml = '';

    /**
     * Do we need to parse the current elements attributes for namespaces?
     *
     * @type {boolean}
     */
    var maybeNS = false;

    /**
     * Do we process namespaces at all?
     *
     * @type {boolean}
     */
    var isNamespace = false;

    /**
     * The caught error returned on parse end
     *
     * @type {Error}
     */
    var returnError = null;

    /**
     * Should we stop parsing?
     *
     * @type {boolean}
     */
    var parseStop = false;

    /**
     * Namespace + node state shared across (streamed) parse runs.
     */
    var nsChangesStack, nsMatrix, nodeStack;

    /**
     * A map of { uri: prefix } used by the parser.
     *
     * This map will ensure we can normalize prefixes during processing;
     * for each uri, only one prefix will be exposed to the handlers.
     *
     * @type {!Object<string, string>}}
     */
    var nsUriToPrefix;

    /**
     * Handle parse error.
     *
     * @param  {string|Error} err
     */
    function handleError(err) {
      if (!(err instanceof Error)) {
        err = error$1(err);
      }
      returnError = err;
      onError(err, getContext);
    }

    /**
     * Handle parse error.
     *
     * @param  {string|Error} err
     */
    function handleWarning(err) {
      if (!onWarning) {
        return;
      }
      if (!(err instanceof Error)) {
        err = error$1(err);
      }
      onWarning(err, getContext);
    }

    /**
     * Register parse listener.
     *
     * @param  {string}   name
     * @param  {Function} cb
     *
     * @return {Parser}
     */
    this['on'] = function (name, cb) {
      if (typeof cb !== 'function') {
        throw error$1('required args <name, cb>');
      }
      switch (name) {
        case 'openTag':
          onOpenTag = cb;
          break;
        case 'text':
          onText = cb;
          break;
        case 'closeTag':
          onCloseTag = cb;
          break;
        case 'error':
          onError = cb;
          break;
        case 'warn':
          onWarning = cb;
          break;
        case 'cdata':
          onCDATA = cb;
          break;
        case 'attention':
          onAttention = cb;
          break;
        // <!XXXXX zzzz="eeee">
        case 'question':
          onQuestion = cb;
          break;
        // <? ....  ?>
        case 'comment':
          onComment = cb;
          break;
        default:
          throw error$1('unsupported event: ' + name);
      }
      return this;
    };

    /**
     * Set the namespace to prefix mapping.
     *
     * @example
     *
     * parser.ns({
     *   'http://foo': 'foo',
     *   'http://bar': 'bar'
     * });
     *
     * @param  {!Object<string, string>} nsMap
     *
     * @return {Parser}
     */
    this['ns'] = function (nsMap) {
      if (typeof nsMap === 'undefined') {
        nsMap = {};
      }
      if (typeof nsMap !== 'object') {
        throw error$1('required args <nsMap={}>');
      }
      var _nsUriToPrefix = Object.create(null),
        k;
      for (k in nsMap) {
        _nsUriToPrefix[k] = nsMap[k];
      }
      isNamespace = true;
      nsUriToPrefix = _nsUriToPrefix;
      return this;
    };

    /**
     * Reset the parser state before a (streamed) parse run.
     */
    function resetState() {
      nsChangesStack = isNamespace ? [] : null;
      nsMatrix = isNamespace ? buildNsMatrix(nsUriToPrefix) : null;
      nodeStack = [];
      getContext = noopGetContext;
      parseStop = false;
      returnError = null;
      rootTagFound = false;
      leftoverXml = '';
    }

    /**
     * Parse a complete xml string.
     *
     * @param  {string} xml
     *
     * @return {Error} returnError, if not thrown
     */
    this['parse'] = function (xml) {
      if (typeof xml !== 'string') {
        throw error$1('required args <xml=string>');
      }
      if (streaming) {
        throw error$1('parse during stream; call end() first');
      }
      resetState();
      parse(xml);
      getContext = noopGetContext;
      parseStop = false;
      return returnError;
    };

    /**
     * Write the next chunk of a streamed xml string.
     *
     * Parse events are emitted for all complete tokens; an
     * incomplete trailing token is buffered until the next
     * `write` or, ultimately, reported as an error on `end`.
     *
     * @param  {string} xml
     *
     * @return {Parser} self
     */
    this['write'] = function (xml) {
      if (typeof xml !== 'string') {
        throw error$1('required args <xml=string>');
      }
      if (!streaming) {
        resetState();
        streaming = true;
      }
      if (!returnError) {
        leftoverXml = parse(leftoverXml + xml, true) || '';
      }
      return this;
    };

    /**
     * Finish parsing a streamed xml string, i.e. signal that
     * no more chunks will be written.
     *
     * @return {Error} returnError, if not thrown
     */
    this['end'] = function () {
      if (!streaming) {
        resetState();
      }

      // flush the buffered remainder, now treating an incomplete
      // trailing token as a hard error
      streaming = false;
      if (!returnError) {
        parse(leftoverXml);
      }
      leftoverXml = '';
      getContext = noopGetContext;
      parseStop = false;
      return returnError;
    };

    /**
     * Stop parsing.
     */
    this['stop'] = function () {
      parseStop = true;
    };

    /**
     * Parse string, invoking configured listeners on element.
     *
     * Namespace and node stack state is shared across (streamed)
     * invocations via the enclosing parser scope.
     *
     * Internal note: while `streaming`, an incomplete trailing token
     * is not treated as an error but returned so `write` can buffer it
     * and prepend it to the next chunk. This buffered remainder is an
     * implementation detail of the streaming buffer, not a public API;
     * outside of that case the return value is `undefined`.
     *
     * @param {string} xml
     * @param {boolean} streaming
     *
     * @return {string|undefined} buffered remainder, streaming internal use only
     */
    function parse(xml, streaming = false) {
      var elNameCache = null;
      var nsChanges,
        nsSnapshot,
        anonymousNsCount = 0,
        tagStart = false,
        tagEnd = false,
        i = 0,
        j = 0,
        x,
        y,
        q,
        w,
        v,
        xmlns,
        elementName,
        _elementName,
        elementProxy;
      var attrsString = '',
        attrsStart = 0,
        cachedAttrs // false = parsed with errors, null = needs parsing
  ;

      /**
       * Normalize a namespaced attribute name against the current
       * namespace matrix.
       *
       * @param {string} name
       * @param {string|boolean} defaultAlias
       *
       * @return {string|null} normalized name, or `null` when the prefix
       *                       has no namespace (a warning is emitted)
       */
      function normalizeAttrName(name, defaultAlias) {
        var w = name.indexOf(':');
        if (w === -1) {
          return name;
        }

        // normalize ns attribute name
        var nsName = nsMatrix[name.substring(0, w)];
        if (!nsName) {
          handleWarning(missingNamespaceForPrefix(name.substring(0, w)));
          return null;
        }
        return defaultAlias === nsName ? name.substr(w + 1) : nsName + name.substr(w);
      }

      /**
       * Parse attributes on demand and returns the parsed attributes.
       *
       * Return semantics: (1) `false` on attribute parse error,
       * (2) object hash on extracted attrs.
       *
       * @return {boolean|Object}
       */
      function getAttrs() {
        if (cachedAttrs !== null) {
          return cachedAttrs;
        }
        var nsUri,
          nsUriPrefix,
          defaultAlias = isNamespace && nsMatrix['xmlns'],
          attrList = isNamespace && maybeNS ? [] : null,
          i = attrsStart,
          s = attrsString,
          l = s.length,
          newalias,
          value,
          alias,
          name,
          attrs = {},
          seenAttrs = new Set(),
          skipAttr,
          w,
          j;
        parseAttr: for (; i < l; i++) {
          skipAttr = false;
          w = s.charCodeAt(i);
          if (w === 32 || w < 14 && w > 8) {
            // WHITESPACE={ \f\n\r\t\v}
            continue;
          }

          // wait for non whitespace character
          if (w < 65 || w > 122 || w > 90 && w < 97) {
            if (w !== 95 && w !== 58) {
              // char 95"_" 58":"
              handleWarning('illegal first char attribute name');
              skipAttr = true;
            }
          }

          // parse attribute name
          for (j = i + 1; j < l; j++) {
            w = s.charCodeAt(j);
            if (w > 96 && w < 123 || w > 64 && w < 91 || w > 47 && w < 59 || w === 46 ||
            // '.'
            w === 45 ||
            // '-'
            w === 95 // '_'
            ) {
              continue;
            }

            // unexpected whitespace
            if (w === 32 || w < 14 && w > 8) {
              // WHITESPACE
              handleWarning('missing attribute value');
              i = j;
              continue parseAttr;
            }

            // expected "="
            if (w === 61) {
              // "=" == 61
              break;
            }
            handleWarning('illegal attribute name char');
            skipAttr = true;
          }
          name = s.substring(i, j);

          // by definition bound to `xmlns`, must not be declared - https://www.w3.org/TR/xml-names/#ns-decl
          if (name === 'xmlns:xmlns') {
            handleWarning('illegal declaration of xmlns');
            skipAttr = true;
          }
          w = s.charCodeAt(j + 1);
          if (w === 34) {
            // '"'
            j = s.indexOf('"', i = j + 2);
            if (j === -1) {
              j = s.indexOf('\'', i);
              if (j !== -1) {
                handleWarning('attribute value quote missmatch');
                skipAttr = true;
              }
            }
          } else if (w === 39) {
            // "'"
            j = s.indexOf('\'', i = j + 2);
            if (j === -1) {
              j = s.indexOf('"', i);
              if (j !== -1) {
                handleWarning('attribute value quote missmatch');
                skipAttr = true;
              }
            }
          } else {
            handleWarning('missing attribute value quotes');
            skipAttr = true;

            // skip to next space
            for (j = j + 1; j < l; j++) {
              w = s.charCodeAt(j + 1);
              if (w === 32 || w < 14 && w > 8) {
                // WHITESPACE
                break;
              }
            }
          }
          if (j === -1) {
            handleWarning('missing closing quotes');
            j = l;
            skipAttr = true;
          }
          if (!skipAttr) {
            value = s.substring(i, j);
          }

          // namespace fixed, must not be re-declared - https://www.w3.org/TR/xml-names/#ns-decl
          if (name === 'xmlns:xml' && value !== 'http://www.w3.org/XML/1998/namespace') {
            handleError('illegal value of xmlns:xml');
          }
          i = j;

          // ensure SPACE follows attribute
          // skip illegal content otherwise
          // example a="b"c
          for (; j + 1 < l; j++) {
            w = s.charCodeAt(j + 1);
            if (w === 32 || w < 14 && w > 8) {
              // WHITESPACE
              break;
            }

            // FIRST ILLEGAL CHAR
            if (i === j) {
              handleWarning('illegal character after attribute end');
              skipAttr = true;
            }
          }

          // advance cursor to next attribute
          i = j + 1;
          if (skipAttr) {
            continue parseAttr;
          }

          // check attribute re-declaration
          if (seenAttrs.has(name)) {
            handleWarning('attribute <' + name + '> already defined');
            continue;
          }
          seenAttrs.add(name);
          if (!isNamespace) {
            attrs[name] = value;
            continue;
          }

          // try to extract namespace information
          if (maybeNS) {
            newalias = name === 'xmlns' ? 'xmlns' : name.charCodeAt(0) === 120 && name.substr(0, 6) === 'xmlns:' ? name.substr(6) : null;

            // handle xmlns(:alias) assignment
            if (newalias !== null) {
              nsUri = decodeEntities(value);
              nsUriPrefix = uriPrefix(newalias);
              alias = nsUriToPrefix[nsUri];
              if (!alias) {
                // no prefix defined or prefix collision
                if (newalias === 'xmlns' || nsUriPrefix in nsMatrix && nsMatrix[nsUriPrefix] !== nsUri) {
                  // alocate free ns prefix
                  do {
                    alias = 'ns' + anonymousNsCount++;
                  } while (typeof nsMatrix[alias] !== 'undefined');
                } else {
                  alias = newalias;
                }
                nsUriToPrefix[nsUri] = alias;
              }
              if (nsMatrix[newalias] !== alias) {
                // mutate matrix in place, tracking changes
                // for restoration once the element closes;
                // null prototype guards against special keys
                if (!nsChanges) {
                  nsChanges = Object.create(null);
                }

                // invalidate cached element names + ns snapshot
                elNameCache = null;
                nsSnapshot = null;
                setNsEntry(nsMatrix, nsChanges, newalias, alias);
                if (newalias === 'xmlns') {
                  setNsEntry(nsMatrix, nsChanges, uriPrefix(alias), nsUri);
                  defaultAlias = alias;
                }
                setNsEntry(nsMatrix, nsChanges, nsUriPrefix, nsUri);
              }

              // expose xmlns(:asd)="..." in attributes
              attrs[name] = value;
              continue;
            }

            // collect attributes until all namespace
            // declarations are processed
            attrList.push(name, value);
            continue;
          } /** end if (maybeNs) */

          // handle attributes on element without
          // namespace declarations
          name = normalizeAttrName(name, defaultAlias);
          if (name === null) {
            continue;
          }
          attrs[name] = value;
        }

        // handle deferred, possibly namespaced attributes
        if (maybeNS) {
          // normalize captured attributes
          for (i = 0, l = attrList.length; i < l; i++) {
            name = normalizeAttrName(attrList[i++], defaultAlias);
            value = attrList[i];
            if (name === null) {
              continue;
            }
            attrs[name] = value;
          }

          // end: normalize captured attributes
        }
        return cachedAttrs = attrs;
      }

      /**
       * Extract the parse context { line, column, part }
       * from the current parser position.
       *
       * @return {Object} parse context
       */
      function getParseContext() {
        var splitsRe = /(\r\n|\r|\n)/g;
        var line = 0;
        var column = 0;
        var startOfLine = 0;
        var endOfLine = j;
        var match;
        var data;
        while (i >= startOfLine) {
          match = splitsRe.exec(xml);
          if (!match) {
            break;
          }

          // end of line = (break idx + break chars)
          endOfLine = match[0].length + match.index;
          if (endOfLine > i) {
            break;
          }

          // advance to next line
          line += 1;
          startOfLine = endOfLine;
        }

        // EOF errors
        if (i == -1) {
          column = endOfLine;
          data = xml.substring(j);
        } else
          // start errors
          if (j === 0) {
            data = xml.substring(j, i);
          }

          // other errors
          else {
            column = i - startOfLine;
            data = j == -1 ? xml.substring(i) : xml.substring(i, j + 1);
          }
        return {
          'data': data,
          'line': line,
          'column': column
        };
      }
      getContext = getParseContext;
      if (proxy) {
        elementProxy = Object.create({}, {
          'name': getter(function () {
            return elementName;
          }),
          'originalName': getter(function () {
            return _elementName;
          }),
          'attrs': getter(getAttrs),
          'ns': getter(function () {
            // expose a stable snapshot of the current namespace
            // matrix, cached until the matrix changes
            if (!nsSnapshot) {
              nsSnapshot = Object.assign(Object.create(null), nsMatrix);
            }
            return nsSnapshot;
          })
        });
      }

      // actual parse logic
      while (j !== -1) {
        if (xml.charCodeAt(j) === 60) {
          // "<"
          i = j;
        } else {
          i = xml.indexOf('<', j);
        }

        // no (more) tags found
        if (i === -1) {
          // buffer the remainder for the next chunk
          if (streaming) {
            return xml.substring(j);
          }
          if (nodeStack.length) {
            return handleError('unexpected end of file');
          }
          if (!rootTagFound) {
            return handleError('missing start tag');
          }
          if (j < xml.length) {
            if (xml.substring(j).trim()) {
              handleWarning(NON_WHITESPACE_OUTSIDE_ROOT_NODE);
            }
          }
          return;
        }

        // remember that we saw the root tag
        if (!rootTagFound) {
          rootTagFound = true;
        }

        // parse text
        if (j !== i) {
          if (nodeStack.length) {
            if (onText) {
              onText(xml.substring(j, i), decodeEntities, getContext);
              if (parseStop) {
                return;
              }
            }
          } else {
            if (xml.substring(j, i).trim()) {
              handleWarning(NON_WHITESPACE_OUTSIDE_ROOT_NODE);
              if (parseStop) {
                return;
              }
            }
          }
        }
        w = xml.charCodeAt(i + 1);

        // parse comments + CDATA
        if (w === 33) {
          // "!"
          q = xml.charCodeAt(i + 2);

          // CDATA section
          if (q === 91 && xml.substr(i + 3, 6) === 'CDATA[') {
            // 91 == "["
            j = xml.indexOf(']]>', i);
            if (j === -1) {
              if (streaming) {
                return xml.substring(i);
              }
              return handleError('unclosed cdata');
            }
            if (onCDATA) {
              onCDATA(xml.substring(i + 9, j), getContext);
              if (parseStop) {
                return;
              }
            }
            j += 3;
            continue;
          }

          // comment
          if (q === 45 && xml.charCodeAt(i + 3) === 45) {
            // 45 == "-"
            j = xml.indexOf('-->', i);
            if (j === -1) {
              if (streaming) {
                return xml.substring(i);
              }
              return handleError('unclosed comment');
            }
            if (onComment) {
              onComment(xml.substring(i + 4, j), decodeEntities, getContext);
              if (parseStop) {
                return;
              }
            }
            j += 3;
            continue;
          }
        }

        // parse question <? ... ?>
        if (w === 63) {
          // "?"
          j = xml.indexOf('?>', i);
          if (j === -1) {
            if (streaming) {
              return xml.substring(i);
            }
            return handleError('unclosed question');
          }
          if (onQuestion) {
            onQuestion(xml.substring(i, j + 2), getContext);
            if (parseStop) {
              return;
            }
          }
          j += 2;
          continue;
        }

        // find matching closing tag for attention or standard tags
        // for that we must skip through attribute values
        // (enclosed in single or double quotes)
        for (x = i + 1;; x++) {
          v = xml.charCodeAt(x);
          if (isNaN(v)) {
            if (streaming) {
              return xml.substring(i);
            }
            j = -1;
            return handleError('unclosed tag');
          }

          // [10] AttValue ::= '"' ([^<&"] | Reference)* '"' | "'" ([^<&'] | Reference)* "'"
          // skips the quoted string
          // (double quotes) does not appear in a literal enclosed by (double quotes)
          // (single quote) does not appear in a literal enclosed by (single quote)
          if (v === 34) {
            //  '"'
            q = xml.indexOf('"', x + 1);
            x = q !== -1 ? q : x;
          } else if (v === 39) {
            // "'"
            q = xml.indexOf("'", x + 1);
            x = q !== -1 ? q : x;
          } else if (v === 62) {
            // '>'
            j = x;
            break;
          }
        }

        // parse attention <! ...>
        // previously comment and CDATA have already been parsed
        if (w === 33) {
          // "!"

          if (onAttention) {
            onAttention(xml.substring(i, j + 1), decodeEntities, getContext);
            if (parseStop) {
              return;
            }
          }
          j += 1;
          continue;
        }

        // don't process attributes;
        // there are none
        cachedAttrs = {};

        // if (xml.charCodeAt(i+1) === 47) { // </...
        if (w === 47) {
          // </...
          tagStart = false;
          tagEnd = true;
          if (!nodeStack.length) {
            return handleError('missing open tag');
          }

          // verify open <-> close tag match
          x = elementName = nodeStack.pop();
          q = i + 2 + x.length;
          if (xml.substring(i + 2, q) !== x) {
            return handleError('closing tag mismatch');
          }

          // verify chars in close tag
          for (; q < j; q++) {
            w = xml.charCodeAt(q);
            if (w === 32 || w > 8 && w < 14) {
              // \f\n\r\t\v space
              continue;
            }
            return handleError('close tag');
          }
        } else {
          if (xml.charCodeAt(j - 1) === 47) {
            // .../>
            x = elementName = xml.substring(i + 1, j - 1);
            tagStart = true;
            tagEnd = true;
          } else {
            x = elementName = xml.substring(i + 1, j);
            tagStart = true;
            tagEnd = false;
          }
          if (!(w > 96 && w < 123 || w > 64 && w < 91 || w === 95 || w === 58)) {
            // char 95"_" 58":"
            return handleError('illegal first char nodeName');
          }
          for (q = 1, y = x.length; q < y; q++) {
            w = x.charCodeAt(q);
            if (w > 96 && w < 123 || w > 64 && w < 91 || w > 47 && w < 59 || w === 45 || w === 95 || w == 46) {
              continue;
            }
            if (w === 32 || w < 14 && w > 8) {
              // \f\n\r\t\v space
              elementName = x.substring(0, q);

              // maybe there are attributes
              cachedAttrs = null;
              break;
            }
            return handleError('invalid nodeName');
          }
          if (!tagEnd) {
            nodeStack.push(elementName);
          }
        }
        if (isNamespace) {
          if (tagStart) {
            // track namespace changes on this element
            // for later restoration
            nsChanges = null;
            if (cachedAttrs === null) {
              // quick check, whether there may be namespace
              // declarations on the node; if that is the case
              // we need to eagerly parse the node attributes
              if (maybeNS = x.indexOf('xmlns', q) !== -1) {
                attrsStart = q;
                attrsString = x;
                getAttrs();
                maybeNS = false;
              }
            }

            // remember changes made by this element
            // unless we're self-closing
            if (!tagEnd) {
              nsChangesStack.push(nsChanges);
            }
          }
          _elementName = elementName;

          // memoize normalized names per namespace state; tag names
          // typically repeat heavily and the matrix rarely changes.
          // the cache is rebuilt whenever the matrix changed.
          if (elNameCache === null) {
            elNameCache = Object.create(null);
          }
          var _cachedName = elNameCache[elementName];
          if (_cachedName !== undefined) {
            elementName = _cachedName;
          } else {
            w = elementName.indexOf(':');
            if (w !== -1) {
              xmlns = nsMatrix[elementName.substring(0, w)];

              // prefix given; namespace must exist
              if (!xmlns) {
                return handleError('missing namespace on <' + _elementName + '>');
              }
              elementName = elementName.substr(w + 1);
            } else {
              xmlns = nsMatrix['xmlns'];

              // if no default namespace is defined,
              // we'll import the element as anonymous.
              //
              // it is up to users to correct that to the document defined
              // targetNamespace, or whatever their undersanding of the
              // XML spec mandates.
            }

            // adjust namespace prefixs as configured
            if (xmlns) {
              elementName = xmlns + ':' + elementName;
            }
            elNameCache[_elementName] = elementName;
          }
        }
        if (tagStart) {
          attrsStart = q;
          attrsString = x;
          if (onOpenTag) {
            if (proxy) {
              onOpenTag(elementProxy, decodeEntities, tagEnd, getContext);
            } else {
              onOpenTag(elementName, getAttrs, decodeEntities, tagEnd, getContext);
            }
            if (parseStop) {
              return;
            }
          }
        }
        if (tagEnd) {
          if (onCloseTag) {
            onCloseTag(proxy ? elementProxy : elementName, decodeEntities, tagStart, getContext);
            if (parseStop) {
              return;
            }
          }

          // restore old namespace
          if (isNamespace) {
            if (!tagStart) {
              nsChanges = nsChangesStack.pop();
            }
            if (nsChanges) {
              restoreNsMatrix(nsMatrix, nsChanges);
              nsChanges = null;

              // invalidate cached element names + ns snapshot
              elNameCache = null;
              nsSnapshot = null;
            }
          }
        }
        j += 1;
      }
    } /** end parse */
  }

  function hasLowerCaseAlias(pkg) {
    return pkg.xml && pkg.xml.tagAlias === 'lowerCase';
  }
  var DEFAULT_NS_MAP = {
    'xsi': 'http://www.w3.org/2001/XMLSchema-instance',
    'xml': 'http://www.w3.org/XML/1998/namespace'
  };
  var SERIALIZE_PROPERTY = 'property';
  function getSerialization(element) {
    return element.xml && element.xml.serialize;
  }
  function getSerializationType(element) {
    const type = getSerialization(element);
    return type !== SERIALIZE_PROPERTY && (type || null);
  }
  function capitalize(str) {
    return str.charAt(0).toUpperCase() + str.slice(1);
  }
  function aliasToName(aliasNs, pkg) {
    if (!hasLowerCaseAlias(pkg)) {
      return aliasNs.name;
    }
    return aliasNs.prefix + ':' + capitalize(aliasNs.localName);
  }

  /**
   * Un-prefix a potentially prefixed type name.
   *
   * @param {NsName} nameNs
   * @param {Object} [pkg]
   *
   * @return {string}
   */
  function prefixedToName(nameNs, pkg) {
    var name = nameNs.name,
      localName = nameNs.localName;
    var typePrefix = pkg && pkg.xml && pkg.xml.typePrefix;
    if (typePrefix && localName.indexOf(typePrefix) === 0) {
      return nameNs.prefix + ':' + localName.slice(typePrefix.length);
    } else {
      return name;
    }
  }
  function normalizeTypeName(name, nsMap, model) {
    // normalize against actual NS
    const nameNs = parseName(name, nsMap.xmlns);
    const normalizedName = `${nsMap[nameNs.prefix] || nameNs.prefix}:${nameNs.localName}`;
    const normalizedNameNs = parseName(normalizedName);

    // determine actual type name, based on package-defined prefix
    var pkg = model.getPackage(normalizedNameNs.prefix);
    return prefixedToName(normalizedNameNs, pkg);
  }
  function error(message) {
    return new Error(message);
  }

  /**
   * Get the moddle descriptor for a given instance or type.
   *
   * @param  {ModdleElement|Function} element
   *
   * @return {Object} the moddle descriptor
   */
  function getModdleDescriptor(element) {
    return element.$descriptor;
  }

  /**
   * A parse context.
   *
   * @class
   *
   * @param {Object} options
   * @param {ElementHandler} options.rootHandler the root handler for parsing a document
   * @param {boolean} [options.lax=false] whether or not to ignore invalid elements
   */
  function Context(options) {
    /**
     * @property {ElementHandler} rootHandler
     */

    /**
     * @property {Boolean} lax
     */

    assign$1(this, options);
    this.elementsById = {};
    this.references = [];
    this.warnings = [];

    /**
     * Add an unresolved reference.
     *
     * @param {Object} reference
     */
    this.addReference = function (reference) {
      this.references.push(reference);
    };

    /**
     * Add a processed element.
     *
     * @param {ModdleElement} element
     */
    this.addElement = function (element) {
      if (!element) {
        throw error('expected element');
      }
      var elementsById = this.elementsById;
      var descriptor = getModdleDescriptor(element);
      var idProperty = descriptor.idProperty,
        id;
      if (idProperty) {
        id = element.get(idProperty.name);
        if (id) {
          // for QName validation as per http://www.w3.org/TR/REC-xml/#NT-NameChar
          if (!/^([a-z][\w-.]*:)?[a-z_][\w-.]*$/i.test(id)) {
            throw new Error('illegal ID <' + id + '>');
          }
          if (elementsById[id]) {
            throw error('duplicate ID <' + id + '>');
          }
          elementsById[id] = element;
        }
      }
    };

    /**
     * Add an import warning.
     *
     * @param {Object} warning
     * @param {String} warning.message
     * @param {Error} [warning.error]
     */
    this.addWarning = function (warning) {
      this.warnings.push(warning);
    };
  }
  function BaseHandler() {}
  BaseHandler.prototype.handleEnd = function () {};
  BaseHandler.prototype.handleText = function () {};
  BaseHandler.prototype.handleNode = function () {};

  /**
   * A simple pass through handler that does nothing except for
   * ignoring all input it receives.
   *
   * This is used to ignore unknown elements and
   * attributes.
   */
  function NoopHandler() {}
  NoopHandler.prototype = Object.create(BaseHandler.prototype);
  NoopHandler.prototype.handleNode = function () {
    return this;
  };
  function BodyHandler() {}
  BodyHandler.prototype = Object.create(BaseHandler.prototype);
  BodyHandler.prototype.handleText = function (text) {
    this.body = (this.body || '') + text;
  };
  function ReferenceHandler(property, context) {
    this.property = property;
    this.context = context;
  }
  ReferenceHandler.prototype = Object.create(BodyHandler.prototype);
  ReferenceHandler.prototype.handleNode = function (node) {
    if (this.element) {
      throw error('expected no sub nodes');
    } else {
      this.element = this.createReference(node);
    }
    return this;
  };
  ReferenceHandler.prototype.handleEnd = function () {
    this.element.id = this.body;
  };
  ReferenceHandler.prototype.createReference = function (node) {
    return {
      property: this.property.ns.name,
      id: ''
    };
  };
  function ValueHandler(propertyDesc, element) {
    this.element = element;
    this.propertyDesc = propertyDesc;
  }
  ValueHandler.prototype = Object.create(BodyHandler.prototype);
  ValueHandler.prototype.handleEnd = function () {
    var value = this.body || '',
      element = this.element,
      propertyDesc = this.propertyDesc;
    value = coerceType(propertyDesc.type, value);
    if (propertyDesc.isMany) {
      element.get(propertyDesc.name).push(value);
    } else {
      element.set(propertyDesc.name, value);
    }
  };
  function BaseElementHandler() {}
  BaseElementHandler.prototype = Object.create(BodyHandler.prototype);
  BaseElementHandler.prototype.handleNode = function (node) {
    var parser = this,
      element = this.element;
    if (!element) {
      element = this.element = this.createElement(node);
      this.context.addElement(element);
    } else {
      parser = this.handleChild(node);
    }
    return parser;
  };

  /**
   * @class Reader.ElementHandler
   *
   */
  function ElementHandler(model, typeName, context) {
    this.model = model;
    this.type = model.getType(typeName);
    this.context = context;
  }
  ElementHandler.prototype = Object.create(BaseElementHandler.prototype);
  ElementHandler.prototype.addReference = function (reference) {
    this.context.addReference(reference);
  };
  ElementHandler.prototype.handleText = function (text) {
    var element = this.element,
      descriptor = getModdleDescriptor(element),
      bodyProperty = descriptor.bodyProperty;
    if (!bodyProperty) {
      throw error('unexpected body text <' + text + '>');
    }
    BodyHandler.prototype.handleText.call(this, text);
  };
  ElementHandler.prototype.handleEnd = function () {
    var value = this.body,
      element = this.element,
      descriptor = getModdleDescriptor(element),
      bodyProperty = descriptor.bodyProperty;
    if (bodyProperty && value !== undefined) {
      value = coerceType(bodyProperty.type, value);
      element.set(bodyProperty.name, value);
    }
  };

  /**
   * Create an instance of the model from the given node.
   *
   * @param  {Element} node the xml node
   */
  ElementHandler.prototype.createElement = function (node) {
    var attributes = node.attributes,
      Type = this.type,
      descriptor = getModdleDescriptor(Type),
      context = this.context,
      instance = new Type({}),
      model = this.model,
      propNameNs;
    forEach(attributes, function (value, name) {
      var prop = descriptor.propertiesByName[name],
        values;
      if (prop && prop.isReference) {
        if (!prop.isMany) {
          context.addReference({
            element: instance,
            property: prop.ns.name,
            id: value
          });
        } else {
          // IDREFS: parse references as whitespace-separated list
          values = value.split(' ');
          forEach(values, function (v) {
            context.addReference({
              element: instance,
              property: prop.ns.name,
              id: v
            });
          });
        }
      } else {
        if (prop) {
          value = coerceType(prop.type, value);
        } else if (name === 'xmlns') {
          name = ':' + name;
        } else {
          propNameNs = parseName(name, descriptor.ns.prefix);

          // check whether attribute is defined in a well-known namespace
          // if that is the case we emit a warning to indicate potential misuse
          if (model.getPackage(propNameNs.prefix)) {
            context.addWarning({
              message: 'unknown attribute <' + name + '>',
              element: instance,
              property: name,
              value: value
            });
          }
        }
        instance.set(name, value);
      }
    });
    return instance;
  };
  ElementHandler.prototype.getPropertyForNode = function (node) {
    var name = node.name;
    var nameNs = parseName(name);
    var type = this.type,
      model = this.model,
      descriptor = getModdleDescriptor(type);
    var propertyName = nameNs.name,
      property = descriptor.propertiesByName[propertyName];

    // search for properties by name first

    if (property && !property.isAttr) {
      const serializationType = getSerializationType(property);
      if (serializationType) {
        const elementTypeName = node.attributes[serializationType];

        // type is optional, if it does not exists the
        // default type is assumed
        if (elementTypeName) {
          // convert the prefix used to the mapped form, but also
          // take possible type prefixes from XML
          // into account, i.e.: xsi:type="t{ActualType}",
          const normalizedTypeName = normalizeTypeName(elementTypeName, node.ns, model);
          const elementType = model.getType(normalizedTypeName);
          return assign$1({}, property, {
            effectiveType: getModdleDescriptor(elementType).name
          });
        }
      }

      // search for properties by name first
      return property;
    }
    var pkg = model.getPackage(nameNs.prefix);
    if (pkg) {
      const elementTypeName = aliasToName(nameNs, pkg);
      const elementType = model.getType(elementTypeName);

      // search for collection members later
      property = find$1(descriptor.properties, function (p) {
        return !p.isVirtual && !p.isReference && !p.isAttribute && elementType.hasType(p.type);
      });
      if (property) {
        return assign$1({}, property, {
          effectiveType: getModdleDescriptor(elementType).name
        });
      }
    } else {
      // parse unknown element (maybe extension)
      property = find$1(descriptor.properties, function (p) {
        return !p.isReference && !p.isAttribute && p.type === 'Element';
      });
      if (property) {
        return property;
      }
    }
    throw error('unrecognized element <' + nameNs.name + '>');
  };
  ElementHandler.prototype.toString = function () {
    return 'ElementDescriptor[' + getModdleDescriptor(this.type).name + ']';
  };
  ElementHandler.prototype.valueHandler = function (propertyDesc, element) {
    return new ValueHandler(propertyDesc, element);
  };
  ElementHandler.prototype.referenceHandler = function (propertyDesc) {
    return new ReferenceHandler(propertyDesc, this.context);
  };
  ElementHandler.prototype.handler = function (type) {
    if (type === 'Element') {
      return new GenericElementHandler(this.model, type, this.context);
    } else {
      return new ElementHandler(this.model, type, this.context);
    }
  };

  /**
   * Handle the child element parsing
   *
   * @param  {Element} node the xml node
   */
  ElementHandler.prototype.handleChild = function (node) {
    var propertyDesc, type, element, childHandler;
    propertyDesc = this.getPropertyForNode(node);
    element = this.element;
    type = propertyDesc.effectiveType || propertyDesc.type;
    if (isSimple(type)) {
      return this.valueHandler(propertyDesc, element);
    }
    if (propertyDesc.isReference) {
      childHandler = this.referenceHandler(propertyDesc).handleNode(node);
    } else {
      childHandler = this.handler(type).handleNode(node);
    }
    var newElement = childHandler.element;

    // child handles may decide to skip elements
    // by not returning anything
    if (newElement !== undefined) {
      if (propertyDesc.isMany) {
        element.get(propertyDesc.name).push(newElement);
      } else {
        element.set(propertyDesc.name, newElement);
      }
      if (propertyDesc.isReference) {
        assign$1(newElement, {
          element: element
        });
        this.context.addReference(newElement);
      } else {
        // establish child -> parent relationship
        newElement.$parent = element;
      }
    }
    return childHandler;
  };

  /**
   * An element handler that performs special validation
   * to ensure the node it gets initialized with matches
   * the handlers type (namespace wise).
   *
   * @param {Moddle} model
   * @param {String} typeName
   * @param {Context} context
   */
  function RootElementHandler(model, typeName, context) {
    ElementHandler.call(this, model, typeName, context);
  }
  RootElementHandler.prototype = Object.create(ElementHandler.prototype);
  RootElementHandler.prototype.createElement = function (node) {
    var name = node.name,
      nameNs = parseName(name),
      model = this.model,
      type = this.type,
      pkg = model.getPackage(nameNs.prefix),
      typeName = pkg && aliasToName(nameNs, pkg) || name;

    // verify the correct namespace if we parse
    // the first element in the handler tree
    //
    // this ensures we don't mistakenly import wrong namespace elements
    if (!type.hasType(typeName)) {
      throw error('unexpected element <' + node.originalName + '>');
    }
    return ElementHandler.prototype.createElement.call(this, node);
  };
  function GenericElementHandler(model, typeName, context) {
    this.model = model;
    this.context = context;
  }
  GenericElementHandler.prototype = Object.create(BaseElementHandler.prototype);
  GenericElementHandler.prototype.createElement = function (node) {
    var name = node.name,
      ns = parseName(name),
      prefix = ns.prefix,
      uri = node.ns[prefix + '$uri'],
      attributes = node.attributes;
    return this.model.createAny(name, uri, attributes);
  };
  GenericElementHandler.prototype.handleChild = function (node) {
    var handler = new GenericElementHandler(this.model, 'Element', this.context).handleNode(node),
      element = this.element;
    var newElement = handler.element,
      children;
    if (newElement !== undefined) {
      children = element.$children = element.$children || [];
      children.push(newElement);

      // establish child -> parent relationship
      newElement.$parent = element;
    }
    return handler;
  };
  GenericElementHandler.prototype.handleEnd = function () {
    if (this.body) {
      this.element.$body = this.body;
    }
  };

  /**
   * A reader for a meta-model
   *
   * @param {Object} options
   * @param {Model} options.model used to read xml files
   * @param {Boolean} options.lax whether to make parse errors warnings
   */
  function Reader(options) {
    if (options instanceof Moddle) {
      options = {
        model: options
      };
    }
    assign$1(this, {
      lax: false
    }, options);
  }

  /**
   * The fromXML result.
   *
   * @typedef {Object} ParseResult
   *
   * @property {ModdleElement} rootElement
   * @property {Array<Object>} references
   * @property {Array<Error>} warnings
   * @property {Object} elementsById - a mapping containing each ID -> ModdleElement
   */

  /**
   * The fromXML result.
   *
   * @typedef {Error} ParseError
   *
   * @property {Array<Error>} warnings
   */

  /**
   * Parse the given XML into a moddle document tree.
   *
   * @param {String} xml
   * @param {ElementHandler|Object} options or rootHandler
   *
   * @returns {Promise<ParseResult, ParseError>}
   */
  Reader.prototype.fromXML = function (xml, options, done) {
    var rootHandler = options.rootHandler;
    if (options instanceof ElementHandler) {
      // root handler passed via (xml, { rootHandler: ElementHandler }, ...)
      rootHandler = options;
      options = {};
    } else {
      if (typeof options === 'string') {
        // rootHandler passed via (xml, 'someString', ...)
        rootHandler = this.handler(options);
        options = {};
      } else if (typeof rootHandler === 'string') {
        // rootHandler passed via (xml, { rootHandler: 'someString' }, ...)
        rootHandler = this.handler(rootHandler);
      }
    }
    var model = this.model,
      lax = this.lax;
    var context = new Context(assign$1({}, options, {
        rootHandler: rootHandler
      })),
      parser = new Parser$1({
        proxy: true
      }),
      stack = createStack();
    rootHandler.context = context;

    // push root handler
    stack.push(rootHandler);

    /**
     * Handle error.
     *
     * @param  {Error} err
     * @param  {Function} getContext
     * @param  {boolean} lax
     *
     * @return {boolean} true if handled
     */
    function handleError(err, getContext, lax) {
      var ctx = getContext();
      var line = ctx.line,
        column = ctx.column,
        data = ctx.data;

      // we receive the full context data here,
      // for elements trim down the information
      // to the tag name, only
      if (data.charAt(0) === '<' && data.indexOf(' ') !== -1) {
        data = data.slice(0, data.indexOf(' ')) + '>';
      }
      var message = 'unparsable content ' + (data ? data + ' ' : '') + 'detected\n\t' + 'line: ' + line + '\n\t' + 'column: ' + column + '\n\t' + 'nested error: ' + err.message;
      if (lax) {
        context.addWarning({
          message: message,
          error: err
        });
        return true;
      } else {
        throw error(message);
      }
    }
    function handleWarning(err, getContext) {
      // just like handling errors in <lax=true> mode
      return handleError(err, getContext, true);
    }

    /**
     * Resolve collected references on parse end.
     */
    function resolveReferences() {
      var elementsById = context.elementsById;
      var references = context.references;
      var i, r;
      for (i = 0; r = references[i]; i++) {
        var element = r.element;
        var reference = elementsById[r.id];
        var property = getModdleDescriptor(element).propertiesByName[r.property];
        if (!reference) {
          context.addWarning({
            message: 'unresolved reference <' + r.id + '>',
            element: r.element,
            property: r.property,
            value: r.id
          });
        }
        if (property.isMany) {
          var collection = element.get(property.name),
            idx = collection.indexOf(r);

          // we replace an existing place holder (idx != -1) or
          // append to the collection instead
          if (idx === -1) {
            idx = collection.length;
          }
          if (!reference) {
            // remove unresolvable reference
            collection.splice(idx, 1);
          } else {
            // add or update reference in collection
            collection[idx] = reference;
          }
        } else {
          element.set(property.name, reference);
        }
      }
    }
    function handleClose() {
      stack.pop().handleEnd();
    }
    var PREAMBLE_START_PATTERN = /^<\?xml /i;
    var ENCODING_PATTERN = / encoding="([^"]+)"/i;
    var UTF_8_PATTERN = /^utf-8$/i;
    function handleQuestion(question) {
      if (!PREAMBLE_START_PATTERN.test(question)) {
        return;
      }
      var match = ENCODING_PATTERN.exec(question);
      var encoding = match && match[1];
      if (!encoding || UTF_8_PATTERN.test(encoding)) {
        return;
      }
      context.addWarning({
        message: 'unsupported document encoding <' + encoding + '>, ' + 'falling back to UTF-8'
      });
    }
    function handleOpen(node, getContext) {
      var handler = stack.peek();
      try {
        stack.push(handler.handleNode(node));
      } catch (err) {
        if (handleError(err, getContext, lax)) {
          stack.push(new NoopHandler());
        }
      }
    }
    function handleCData(text, getContext) {
      try {
        stack.peek().handleText(text);
      } catch (err) {
        handleWarning(err, getContext);
      }
    }
    function handleText(text, getContext) {
      // strip whitespace only nodes, i.e. before
      // <!CDATA[ ... ]> sections and in between tags

      if (!text.trim()) {
        return;
      }
      handleCData(text, getContext);
    }
    var uriMap = model.getPackages().reduce(function (uriMap, p) {
      uriMap[p.uri] = p.prefix;
      return uriMap;
    }, Object.entries(DEFAULT_NS_MAP).reduce(function (map, [prefix, url]) {
      map[url] = prefix;
      return map;
    }, model.config && model.config.nsMap || {}));
    parser.ns(uriMap).on('openTag', function (obj, decodeStr, selfClosing, getContext) {
      // gracefully handle unparsable attributes (attrs=false)
      var attrs = obj.attrs || {};
      var decodedAttrs = Object.keys(attrs).reduce(function (d, key) {
        var value = decodeStr(attrs[key]);
        d[key] = value;
        return d;
      }, {});
      var node = {
        name: obj.name,
        originalName: obj.originalName,
        attributes: decodedAttrs,
        ns: obj.ns
      };
      handleOpen(node, getContext);
    }).on('question', handleQuestion).on('closeTag', handleClose).on('cdata', handleCData).on('text', function (text, decodeEntities, getContext) {
      handleText(decodeEntities(text), getContext);
    }).on('error', handleError).on('warn', handleWarning);

    // async XML parsing to make sure the execution environment
    // (node or brower) is kept responsive and that certain optimization
    // strategies can kick in.
    return new Promise(function (resolve, reject) {
      var err;
      try {
        parser.parse(xml);
        resolveReferences();
      } catch (e) {
        err = e;
      }
      var rootElement = rootHandler.element;
      if (!err && !rootElement) {
        err = error('failed to parse document as <' + rootHandler.type.$descriptor.name + '>');
      }
      var warnings = context.warnings;
      var references = context.references;
      var elementsById = context.elementsById;
      if (err) {
        err.warnings = warnings;
        return reject(err);
      } else {
        return resolve({
          rootElement: rootElement,
          elementsById: elementsById,
          references: references,
          warnings: warnings
        });
      }
    });
  };
  Reader.prototype.handler = function (name) {
    return new RootElementHandler(this.model, name);
  };

  // helpers //////////////////////////

  function createStack() {
    var stack = [];
    Object.defineProperty(stack, 'peek', {
      value: function () {
        return this[this.length - 1];
      }
    });
    return stack;
  }
  var XML_PREAMBLE = '<?xml version="1.0" encoding="UTF-8"?>\n';
  var ESCAPE_ATTR_CHARS = /<|>|'|"|&|\n\r|\n/g;
  var ESCAPE_CHARS = /<|>|&/g;
  function Namespaces(parent) {
    this.prefixMap = {};
    this.uriMap = {};
    this.used = {};
    this.wellknown = [];
    this.custom = [];
    this.parent = parent;
    this.defaultPrefixMap = parent && parent.defaultPrefixMap || {};
  }
  Namespaces.prototype.mapDefaultPrefixes = function (defaultPrefixMap) {
    this.defaultPrefixMap = defaultPrefixMap;
  };
  Namespaces.prototype.defaultUriByPrefix = function (prefix) {
    return this.defaultPrefixMap[prefix];
  };

  /**
   * Return the first truthy `fn(scope)` walking this scope and its ancestors.
   *
   * @param {(scope: Namespaces) => any} fn
   *
   * @return {any}
   */
  Namespaces.prototype.resolve = function (fn) {
    var scope = this;
    while (scope) {
      var resolved = fn(scope);
      if (resolved) {
        return resolved;
      }
      scope = scope.parent;
    }
  };

  /**
   * Call `fn(scope)` for this scope and each of its ancestors.
   *
   * @param {(scope: Namespaces) => void} fn
   */
  Namespaces.prototype.eachScope = function (fn) {
    var scope = this;
    while (scope) {
      fn(scope);
      scope = scope.parent;
    }
  };
  Namespaces.prototype.byUri = function (uri) {
    return this.resolve(function (scope) {
      return scope.uriMap[uri];
    });
  };
  Namespaces.prototype.add = function (ns, isWellknown) {
    this.uriMap[ns.uri] = ns;
    if (isWellknown) {
      this.wellknown.push(ns);
    } else {
      this.custom.push(ns);
    }
    this.mapPrefix(ns.prefix, ns.uri);
  };
  Namespaces.prototype.uriByPrefix = function (prefix) {
    var key = prefix || 'xmlns';
    return this.resolve(function (scope) {
      return scope.prefixMap[key];
    });
  };
  Namespaces.prototype.mapPrefix = function (prefix, uri) {
    this.prefixMap[prefix || 'xmlns'] = uri;
  };
  Namespaces.prototype.getNSKey = function (ns) {
    return ns.prefix !== undefined ? ns.uri + '|' + ns.prefix : ns.uri;
  };
  Namespaces.prototype.logUsed = function (ns) {
    var uri = ns.uri;
    var nsKey = this.getNSKey(ns);
    this.eachScope(function (scope) {
      scope.used[nsKey] = scope.byUri(uri);
    });
  };
  Namespaces.prototype.getUsed = function (ns) {
    var allNs = [].concat(this.wellknown, this.custom);
    return allNs.filter(ns => {
      var nsKey = this.getNSKey(ns);
      return this.used[nsKey];
    });
  };
  function lower(string) {
    return string.charAt(0).toLowerCase() + string.slice(1);
  }
  function nameToAlias(name, pkg) {
    if (hasLowerCaseAlias(pkg)) {
      return lower(name);
    } else {
      return name;
    }
  }
  function inherits(ctor, superCtor) {
    ctor.super_ = superCtor;
    ctor.prototype = Object.create(superCtor.prototype, {
      constructor: {
        value: ctor,
        enumerable: false,
        writable: true,
        configurable: true
      }
    });
  }
  function nsName(ns) {
    if (isString$1(ns)) {
      return ns;
    } else {
      return (ns.prefix ? ns.prefix + ':' : '') + ns.localName;
    }
  }
  function getNsAttrs(namespaces) {
    return namespaces.getUsed().filter(function (ns) {
      // do not serialize built in <xml> namespace
      return ns.prefix !== 'xml';
    }).map(function (ns) {
      var name = 'xmlns' + (ns.prefix ? ':' + ns.prefix : '');
      return {
        name: name,
        value: ns.uri
      };
    });
  }
  function getElementNs(ns, descriptor) {
    if (descriptor.isGeneric) {
      return assign$1({
        localName: descriptor.ns.localName
      }, ns);
    } else {
      return assign$1({
        localName: nameToAlias(descriptor.ns.localName, descriptor.$pkg)
      }, ns);
    }
  }
  function getPropertyNs(ns, descriptor) {
    return assign$1({
      localName: descriptor.ns.localName
    }, ns);
  }
  function getSerializableProperties(element) {
    var descriptor = element.$descriptor;
    return filter(descriptor.properties, function (p) {
      var name = p.name;
      if (p.isVirtual) {
        return false;
      }

      // do not serialize defaults
      if (!has(element, name)) {
        return false;
      }
      var value = element[name];

      // do not serialize default equals
      if (value === p.default) {
        return false;
      }

      // do not serialize null properties
      if (value === null) {
        return false;
      }
      return p.isMany ? value.length : true;
    });
  }
  var ESCAPE_ATTR_MAP = {
    '\n': '#10',
    '\n\r': '#10',
    '"': '#34',
    '\'': '#39',
    '<': '#60',
    '>': '#62',
    '&': '#38'
  };
  var ESCAPE_MAP = {
    '<': 'lt',
    '>': 'gt',
    '&': 'amp'
  };
  function escape$1(str, charPattern, replaceMap) {
    // ensure we are handling strings here
    str = isString$1(str) ? str : '' + str;
    return str.replace(charPattern, function (s) {
      return '&' + replaceMap[s] + ';';
    });
  }

  /**
   * Escape a string attribute to not contain any bad values (line breaks, '"', ...)
   *
   * @param {String} str the string to escape
   * @return {String} the escaped string
   */
  function escapeAttr(str) {
    return escape$1(str, ESCAPE_ATTR_CHARS, ESCAPE_ATTR_MAP);
  }
  function escapeBody(str) {
    return escape$1(str, ESCAPE_CHARS, ESCAPE_MAP);
  }
  function filterAttributes(props) {
    return filter(props, function (p) {
      return p.isAttr;
    });
  }
  function filterContained(props) {
    return filter(props, function (p) {
      return !p.isAttr;
    });
  }
  function ReferenceSerializer(tagName) {
    this.tagName = tagName;
  }
  ReferenceSerializer.prototype.build = function (element) {
    this.element = element;
    return this;
  };
  ReferenceSerializer.prototype.serializeTo = function (writer) {
    writer.appendIndent().append('<' + this.tagName + '>' + this.element.id + '</' + this.tagName + '>').appendNewLine();
  };
  function BodySerializer() {}
  BodySerializer.prototype.serializeValue = BodySerializer.prototype.serializeTo = function (writer) {
    writer.append(this.escape ? escapeBody(this.value) : this.value);
  };
  BodySerializer.prototype.build = function (prop, value) {
    this.value = value;
    if (prop.type === 'String' && value.search(ESCAPE_CHARS) !== -1) {
      this.escape = true;
    }
    return this;
  };
  function ValueSerializer(tagName) {
    this.tagName = tagName;
  }
  inherits(ValueSerializer, BodySerializer);
  ValueSerializer.prototype.serializeTo = function (writer) {
    writer.appendIndent().append('<' + this.tagName + '>');
    this.serializeValue(writer);
    writer.append('</' + this.tagName + '>').appendNewLine();
  };
  function ElementSerializer(parent, propertyDescriptor) {
    this.body = [];
    this.attrs = [];
    this.parent = parent;
    this.propertyDescriptor = propertyDescriptor;
  }
  ElementSerializer.prototype.build = function (element) {
    buildTree$1(this, element);
    return this;
  };

  /**
   * Enter the element during the build walk: register its namespaces, tag
   * name and attributes, then return the deferred, ordered work to build its
   * child nodes (empty when it has none).
   *
   * @param {Object} element
   *
   * @return {Array<Object>} ordered, deferred work items to build the children
   */
  ElementSerializer.prototype.enter = function (element) {
    this.element = element;
    var elementDescriptor = element.$descriptor,
      propertyDescriptor = this.propertyDescriptor;
    var isGeneric = elementDescriptor.isGeneric;
    if (isGeneric) {
      this.otherAttrs = this.parseGenericNsAttributes(element);
    } else {
      this.otherAttrs = this.parseNsAttributes(element);
    }
    if (propertyDescriptor) {
      this.ns = this.nsPropertyTagName(propertyDescriptor);
    } else {
      this.ns = this.nsTagName(elementDescriptor);
    }
    this.tagName = this.addTagName(this.ns);
    if (isGeneric) {
      return this.collectGenericContainments(element);
    }
    var properties = getSerializableProperties(element);
    this.parseAttributes(filterAttributes(properties));
    return this.collectContainments(filterContained(properties));
  };

  /**
   * Exit the element during the build walk: register its generic attributes,
   * which must happen after the children so namespace usage is logged in
   * document order.
   */
  ElementSerializer.prototype.exit = function () {
    this.parseGenericAttributes(this.element, this.otherAttrs);
  };
  ElementSerializer.prototype.nsTagName = function (descriptor) {
    var effectiveNs = this.logNamespaceUsed(descriptor.ns);
    return getElementNs(effectiveNs, descriptor);
  };
  ElementSerializer.prototype.nsPropertyTagName = function (descriptor) {
    var effectiveNs = this.logNamespaceUsed(descriptor.ns);
    return getPropertyNs(effectiveNs, descriptor);
  };
  ElementSerializer.prototype.isLocalNs = function (ns) {
    return ns.uri === this.ns.uri;
  };

  /**
   * Get the actual ns attribute name for the given element.
   *
   * @param {Object} element
   * @param {Boolean} [element.inherited=false]
   *
   * @return {Object} nsName
   */
  ElementSerializer.prototype.nsAttributeName = function (element) {
    var ns;
    if (isString$1(element)) {
      ns = parseName(element);
    } else {
      ns = element.ns;
    }

    // return just local name for inherited attributes
    if (element.inherited) {
      return {
        localName: ns.localName
      };
    }

    // parse + log effective ns
    var effectiveNs = this.logNamespaceUsed(ns);

    // LOG ACTUAL namespace use
    this.getNamespaces().logUsed(effectiveNs);

    // strip prefix if same namespace like parent
    if (this.isLocalNs(effectiveNs)) {
      return {
        localName: ns.localName
      };
    } else {
      return assign$1({
        localName: ns.localName
      }, effectiveNs);
    }
  };
  ElementSerializer.prototype.parseGenericNsAttributes = function (element) {
    return Object.entries(element).filter(([key, value]) => !key.startsWith('$') && this.parseNsAttribute(element, key, value)).map(([key, value]) => ({
      name: key,
      value: value
    }));
  };
  ElementSerializer.prototype.collectGenericContainments = function (element) {
    var self = this,
      children = [];
    var bodyText = element.$body;
    if (bodyText) {
      children.push({
        create: function () {
          return new BodySerializer().build({
            type: 'String'
          }, bodyText);
        }
      });
    }
    var genericChildren = element.$children;
    if (genericChildren) {
      forEach(genericChildren, function (child) {
        children.push({
          create: function () {
            return new ElementSerializer(self);
          },
          element: child
        });
      });
    }
    return children;
  };
  ElementSerializer.prototype.parseNsAttribute = function (element, name, value) {
    var model = element.$model;
    var nameNs = parseName(name);
    var ns;

    // parse xmlns:foo="http://foo.bar"
    if (nameNs.prefix === 'xmlns') {
      ns = {
        prefix: nameNs.localName,
        uri: value
      };
    }

    // parse xmlns="http://foo.bar"
    if (!nameNs.prefix && nameNs.localName === 'xmlns') {
      ns = {
        uri: value
      };
    }
    if (!ns) {
      return {
        name: name,
        value: value
      };
    }
    if (model && model.getPackage(value)) {
      // register well known namespace
      this.logNamespace(ns, true, true);
    } else {
      // log custom namespace directly as used
      var actualNs = this.logNamespaceUsed(ns, true);
      this.getNamespaces().logUsed(actualNs);
    }
  };

  /**
   * Parse namespaces and return a list of left over generic attributes
   *
   * @param  {Object} element
   * @return {Array<Object>}
   */
  ElementSerializer.prototype.parseNsAttributes = function (element) {
    var self = this;
    var genericAttrs = element.$attrs;
    var attributes = [];

    // parse namespace attributes first
    // and log them. push non namespace attributes to a list
    // and process them later
    forEach(genericAttrs, function (value, name) {
      var nonNsAttr = self.parseNsAttribute(element, name, value);
      if (nonNsAttr) {
        attributes.push(nonNsAttr);
      }
    });
    return attributes;
  };
  ElementSerializer.prototype.parseGenericAttributes = function (element, attributes) {
    var self = this;
    forEach(attributes, function (attr) {
      try {
        self.addAttribute(self.nsAttributeName(attr.name), attr.value);
      } catch (e) {
        typeof console !== 'undefined' && console.warn(`missing namespace information for <${attr.name}=${attr.value}> on`, element, e);
      }
    });
  };
  ElementSerializer.prototype.collectContainments = function (properties) {
    var self = this,
      element = this.element,
      children = [];
    forEach(properties, function (p) {
      var value = element.get(p.name),
        isReference = p.isReference,
        isMany = p.isMany;
      if (!isMany) {
        value = [value];
      }
      if (p.isBody) {
        children.push({
          create: function () {
            return new BodySerializer().build(p, value[0]);
          }
        });
      } else if (isSimple(p.type)) {
        forEach(value, function (v) {
          children.push({
            create: function () {
              return new ValueSerializer(self.addTagName(self.nsPropertyTagName(p))).build(p, v);
            }
          });
        });
      } else if (isReference) {
        forEach(value, function (v) {
          children.push({
            create: function () {
              return new ReferenceSerializer(self.addTagName(self.nsPropertyTagName(p))).build(v);
            }
          });
        });
      } else {
        // allow serialization via type
        // rather than element name
        var serialization = getSerialization(p);
        forEach(value, function (v) {
          children.push({
            create: function () {
              if (serialization) {
                if (serialization === SERIALIZE_PROPERTY) {
                  return new ElementSerializer(self, p);
                }
                return new TypeSerializer(self, p, serialization);
              }
              return new ElementSerializer(self);
            },
            element: v
          });
        });
      }
    });
    return children;
  };
  ElementSerializer.prototype.getNamespaces = function (local) {
    var namespaces = this.namespaces;
    if (!namespaces) {
      var parentNamespaces = this.getParentNamespaces();
      if (local || !parentNamespaces) {
        this.namespaces = namespaces = new Namespaces(parentNamespaces);
      } else {
        namespaces = parentNamespaces;
      }
    }
    return namespaces;
  };

  /**
   * Resolve, and memoize, the namespaces scope owned by the closest
   * ancestor serializer.
   *
   * @return {Namespaces|null}
   */
  ElementSerializer.prototype.getParentNamespaces = function () {
    if (this.parentNamespaces !== undefined) {
      return this.parentNamespaces;
    }
    var scope = null,
      ancestor = this.parent;
    while (ancestor) {
      if (ancestor.namespaces) {
        scope = ancestor.namespaces;
        break;
      }
      if (ancestor.parentNamespaces !== undefined) {
        scope = ancestor.parentNamespaces;
        break;
      }
      ancestor = ancestor.parent;
    }
    return this.parentNamespaces = scope;
  };
  ElementSerializer.prototype.logNamespace = function (ns, wellknown, local) {
    var namespaces = this.getNamespaces(local);
    var nsUri = ns.uri,
      nsPrefix = ns.prefix;
    var existing = namespaces.byUri(nsUri);
    if (!existing || local) {
      namespaces.add(ns, wellknown);
    }
    namespaces.mapPrefix(nsPrefix, nsUri);
    return ns;
  };
  ElementSerializer.prototype.logNamespaceUsed = function (ns, local) {
    var namespaces = this.getNamespaces(local);

    // ns may be
    //
    //   * prefix only
    //   * prefix:uri
    //   * localName only

    var prefix = ns.prefix,
      uri = ns.uri,
      newPrefix,
      idx,
      wellknownUri;

    // handle anonymous namespaces (elementForm=unqualified), cf. #23
    if (!prefix && !uri) {
      return {
        localName: ns.localName
      };
    }
    wellknownUri = namespaces.defaultUriByPrefix(prefix);
    uri = uri || wellknownUri || namespaces.uriByPrefix(prefix);
    if (!uri) {
      throw new Error('no namespace uri given for prefix <' + prefix + '>');
    }
    ns = namespaces.byUri(uri);

    // register new default prefix <xmlns> in local scope
    if (!ns && !prefix) {
      ns = this.logNamespace({
        uri
      }, wellknownUri === uri, true);
    }
    if (!ns) {
      newPrefix = prefix;
      idx = 1;

      // find a prefix that is not mapped yet
      while (namespaces.uriByPrefix(newPrefix)) {
        newPrefix = prefix + '_' + idx++;
      }
      ns = this.logNamespace({
        prefix: newPrefix,
        uri: uri
      }, wellknownUri === uri);
    }
    if (prefix) {
      namespaces.mapPrefix(prefix, uri);
    }
    return ns;
  };
  ElementSerializer.prototype.parseAttributes = function (properties) {
    var self = this,
      element = this.element;
    forEach(properties, function (p) {
      var value = element.get(p.name);
      if (p.isReference) {
        if (!p.isMany) {
          value = value.id;
        } else {
          var values = [];
          forEach(value, function (v) {
            values.push(v.id);
          });

          // IDREFS is a whitespace-separated list of references.
          value = values.join(' ');
        }
      }
      self.addAttribute(self.nsAttributeName(p), value);
    });
  };
  ElementSerializer.prototype.addTagName = function (nsTagName) {
    var actualNs = this.logNamespaceUsed(nsTagName);
    this.getNamespaces().logUsed(actualNs);
    return nsName(nsTagName);
  };
  ElementSerializer.prototype.addAttribute = function (name, value) {
    var attrs = this.attrs;
    if (isString$1(value)) {
      value = escapeAttr(value);
    }

    // de-duplicate attributes
    // https://github.com/bpmn-io/moddle-xml/issues/66
    var idx = findIndex(attrs, function (element) {
      return element.name.localName === name.localName && element.name.uri === name.uri && element.name.prefix === name.prefix;
    });
    var attr = {
      name: name,
      value: value
    };
    if (idx !== -1) {
      attrs.splice(idx, 1, attr);
    } else {
      attrs.push(attr);
    }
  };
  ElementSerializer.prototype.serializeAttributes = function (writer) {
    var attrs = this.attrs,
      namespaces = this.namespaces;
    if (namespaces) {
      attrs = getNsAttrs(namespaces).concat(attrs);
    }
    forEach(attrs, function (a) {
      writer.append(' ').append(nsName(a.name)).append('="').append(a.value).append('"');
    });
  };
  ElementSerializer.prototype.serializeTo = function (writer) {
    serializeTree(this, writer);
  };

  /**
   * Serialize the serializer tree rooted at the given element serializer to
   * the writer, using an explicit stack to stay flat for nested documents.
   *
   * @param {ElementSerializer} root
   * @param {Object} writer
   */
  function serializeTree(root, writer) {
    var stack = [{
      serializer: root,
      index: 0,
      opened: false,
      indent: false
    }];
    while (stack.length) {
      var frame = stack[stack.length - 1],
        serializer = frame.serializer;
      if (!frame.opened) {
        var firstBody = serializer.body[0];
        frame.indent = firstBody && firstBody.constructor !== BodySerializer;
        writer.appendIndent().append('<' + serializer.tagName);
        serializer.serializeAttributes(writer);
        writer.append(firstBody ? '>' : ' />');
        frame.opened = true;
        if (!firstBody) {
          writer.appendNewLine();
          stack.pop();
          continue;
        }
        if (frame.indent) {
          writer.appendNewLine().indent();
        }
      }
      if (frame.index < serializer.body.length) {
        var child = serializer.body[frame.index++];
        if (child instanceof ElementSerializer) {
          stack.push({
            serializer: child,
            index: 0,
            opened: false,
            indent: false
          });
        } else {
          child.serializeTo(writer);
        }
        continue;
      }
      if (frame.indent) {
        writer.unindent().appendIndent();
      }
      writer.append('</' + serializer.tagName + '>').appendNewLine();
      stack.pop();
    }
  }

  /**
   * A serializer for types that handles serialization of data types
   */
  function TypeSerializer(parent, propertyDescriptor, serialization) {
    ElementSerializer.call(this, parent, propertyDescriptor);
    this.serialization = serialization;
  }
  inherits(TypeSerializer, ElementSerializer);
  TypeSerializer.prototype.parseNsAttributes = function (element) {
    // extracted attributes with serialization attribute
    // <type=typeName> stripped; it may be later
    var attributes = ElementSerializer.prototype.parseNsAttributes.call(this, element).filter(attr => attr.name !== this.serialization);
    var descriptor = element.$descriptor;

    // only serialize <type=typeName> if necessary
    if (descriptor.name === this.propertyDescriptor.type) {
      return attributes;
    }
    var typeNs = this.typeNs = this.nsTagName(descriptor);
    this.getNamespaces().logUsed(this.typeNs);

    // add xsi:type attribute to represent the elements
    // actual type

    var pkg = element.$model.getPackage(typeNs.uri),
      typePrefix = pkg.xml && pkg.xml.typePrefix || '';
    this.addAttribute(this.nsAttributeName(this.serialization), (typeNs.prefix ? typeNs.prefix + ':' : '') + typePrefix + descriptor.ns.localName);
    return attributes;
  };
  TypeSerializer.prototype.isLocalNs = function (ns) {
    return ns.uri === (this.typeNs || this.ns).uri;
  };
  function SavingWriter() {
    this.value = '';
    this.write = function (str) {
      this.value += str;
    };
  }
  function FormatingWriter(out, format) {
    var indent = [''];
    this.append = function (str) {
      out.write(str);
      return this;
    };
    this.appendNewLine = function () {
      if (format) {
        out.write('\n');
      }
      return this;
    };
    this.appendIndent = function () {
      if (format) {
        out.write(indent.join('  '));
      }
      return this;
    };
    this.indent = function () {
      indent.push('');
      return this;
    };
    this.unindent = function () {
      indent.pop();
      return this;
    };
  }

  /**
   * A writer for meta-model backed document trees
   *
   * @param {Object} options output options to pass into the writer
   */
  function Writer(options) {
    options = assign$1({
      format: false,
      preamble: true
    }, options || {});
    function toXML(tree, writer) {
      var internalWriter = writer || new SavingWriter();
      var formatingWriter = new FormatingWriter(internalWriter, options.format);
      if (options.preamble) {
        formatingWriter.append(XML_PREAMBLE);
      }
      var serializer = new ElementSerializer();
      var model = tree.$model;
      serializer.getNamespaces().mapDefaultPrefixes(getDefaultPrefixMappings(model));
      serializer.build(tree).serializeTo(formatingWriter);
      if (!writer) {
        return internalWriter.value;
      }
    }
    return {
      toXML: toXML
    };
  }

  // helpers ///////////

  /**
   * Build the serializer tree for the given root element, iterating an
   * explicit stack rather than recursing so deeply nested documents stay
   * flat.
   *
   * Elements are visited pre-order so namespaces register in document order:
   * `enter` opens an element and returns its children, `exit` runs once its
   * subtree is built.
   *
   * @param {ElementSerializer} rootSerializer
   * @param {Object} rootElement
   */
  function buildTree$1(rootSerializer, rootElement) {
    var stack = [{
      serializer: rootSerializer,
      children: rootSerializer.enter(rootElement),
      index: 0
    }];
    while (stack.length) {
      var frame = stack[stack.length - 1];
      if (frame.index >= frame.children.length) {
        frame.serializer.exit();
        stack.pop();
        continue;
      }
      var child = frame.children[frame.index++];
      var childSerializer = child.create();
      frame.serializer.body.push(childSerializer);
      if (child.element) {
        stack.push({
          serializer: childSerializer,
          children: childSerializer.enter(child.element),
          index: 0
        });
      }
    }
  }

  /**
   * @param {Moddle} model
   *
   * @return { Record<string, string> } map from prefix to URI
   */
  function getDefaultPrefixMappings(model) {
    const nsMap = model.config && model.config.nsMap || {};
    const prefixMap = {};

    // { prefix -> uri }
    for (const prefix in DEFAULT_NS_MAP) {
      prefixMap[prefix] = DEFAULT_NS_MAP[prefix];
    }

    // { uri -> prefix }
    for (const uri in nsMap) {
      const prefix = nsMap[uri];
      prefixMap[prefix] = uri;
    }
    for (const pkg of model.getPackages()) {
      prefixMap[pkg.prefix] = pkg.uri;
    }
    return prefixMap;
  }

  /**
   * A sub class of {@link Moddle} with support for import and export of DMN xml files.
   *
   * @class DmnModdle
   * @extends Moddle
   *
   * @param {Object|Array} packages to use for instantiating the model
   * @param {Object} [options] additional options to pass over
   */
  function DmnModdle(packages, options) {
    Moddle.call(this, packages, options);
  }
  DmnModdle.prototype = Object.create(Moddle.prototype);

  /**
   * The fromXML result.
   *
   * @typedef {Object} ParseResult
   *
   * @property {ModdleElement} rootElement
   * @property {Array<Object>} references
   * @property {Array<Error>} warnings
   * @property {Object} elementsById - a mapping containing each ID -> ModdleElement
   */

  /**
   * The fromXML error.
   *
   * @typedef {Error} ParseError
   *
   * @property {Array<Error>} warnings
   */

  /**
   * Instantiates a DMN model tree from a given xml string.
   *
   * @param {String}   xmlStr
   * @param {String}   [typeName='dmn:Definitions'] name of the root element
   * @param {Object}   [options]  options to pass to the underlying reader
   *
   * @returns {Promise<ParseResult, ParseError>}
   */
  DmnModdle.prototype.fromXML = function (xmlStr, typeName, options) {
    if (!isString$1(typeName)) {
      options = typeName;
      typeName = 'dmn:Definitions';
    }
    var reader = new Reader(assign$1({
      model: this,
      lax: true
    }, options));
    var rootHandler = reader.handler(typeName);
    return reader.fromXML(xmlStr, rootHandler);
  };

  /**
   * The toXML result.
   *
   * @typedef {Object} SerializationResult
   *
   * @property {String} xml
   */

  /**
   * Serializes a DMN object tree to XML.
   *
   * @param {String}   element    the root element, typically an instance of `Definitions`
   * @param {Object}   [options]  to pass to the underlying writer
   *
   * @returns {Promise<SerializationResult, Error>}
   */
  DmnModdle.prototype.toXML = function (element, options) {
    var writer = new Writer(options);
    return new Promise(function (resolve, reject) {
      try {
        var result = writer.toXML(element);
        return resolve({
          xml: result
        });
      } catch (err) {
        return reject(err);
      }
    });
  };
  var name$4 = "DC";
  var prefix$4 = "dc";
  var uri$4 = "http://www.omg.org/spec/DMN/20180521/DC/";
  var types$4 = [{
    name: "Dimension",
    properties: [{
      name: "width",
      isAttr: true,
      type: "Real"
    }, {
      name: "height",
      isAttr: true,
      type: "Real"
    }]
  }, {
    name: "Bounds",
    properties: [{
      name: "height",
      isAttr: true,
      type: "Real"
    }, {
      name: "width",
      isAttr: true,
      type: "Real"
    }, {
      name: "x",
      isAttr: true,
      type: "Real"
    }, {
      name: "y",
      isAttr: true,
      type: "Real"
    }]
  }, {
    name: "Point",
    properties: [{
      name: "x",
      isAttr: true,
      type: "Real"
    }, {
      name: "y",
      isAttr: true,
      type: "Real"
    }]
  }, {
    name: "Color",
    properties: [{
      name: "red",
      type: "UML_Standard_Profile.mdzip:eee_1045467100323_917313_65"
    }, {
      name: "green",
      type: "UML_Standard_Profile.mdzip:eee_1045467100323_917313_65"
    }, {
      name: "blue",
      type: "UML_Standard_Profile.mdzip:eee_1045467100323_917313_65"
    }]
  }];
  var associations$3 = [];
  var enumerations$3 = [{
    name: "AlignmentKind",
    literalValues: [{
      name: "start"
    }, {
      name: "center"
    }, {
      name: "end"
    }]
  }];
  var DcPackage = {
    name: name$4,
    prefix: prefix$4,
    uri: uri$4,
    types: types$4,
    associations: associations$3,
    enumerations: enumerations$3
  };
  var name$3 = "DI";
  var prefix$3 = "di";
  var uri$3 = "http://www.omg.org/spec/DMN/20180521/DI/";
  var types$3 = [{
    name: "DiagramElement",
    isAbstract: true,
    properties: [{
      name: "extension",
      type: "Extension"
    }, {
      name: "id",
      isAttr: true,
      isId: true,
      type: "String"
    }, {
      name: "style",
      isReference: true,
      type: "Style",
      xml: {
        serialize: "property"
      }
    }, {
      name: "sharedStyle",
      isReference: true,
      isVirtual: true,
      type: "Style"
    }]
  }, {
    name: "Diagram",
    superClass: ["DiagramElement"],
    properties: [{
      name: "name",
      isAttr: true,
      type: "String"
    }, {
      name: "documentation",
      isAttr: true,
      type: "String"
    }, {
      name: "resolution",
      isAttr: true,
      type: "Real"
    }]
  }, {
    name: "Shape",
    isAbstract: true,
    properties: [{
      name: "bounds",
      type: "dc:Bounds"
    }],
    superClass: ["DiagramElement"]
  }, {
    name: "Edge",
    isAbstract: true,
    properties: [{
      name: "waypoint",
      type: "dc:Point",
      isMany: true,
      xml: {
        serialize: "property"
      }
    }],
    superClass: ["DiagramElement"]
  }, {
    name: "Style",
    isAbstract: true,
    properties: [{
      name: "id",
      isAttr: true,
      isId: true,
      type: "String"
    }]
  }, {
    name: "Extension",
    properties: [{
      name: "values",
      isMany: true,
      type: "Element"
    }]
  }];
  var associations$2 = [];
  var enumerations$2 = [];
  var xml$2 = {
    tagAlias: "lowerCase"
  };
  var DiPackage = {
    name: name$3,
    prefix: prefix$3,
    uri: uri$3,
    types: types$3,
    associations: associations$2,
    enumerations: enumerations$2,
    xml: xml$2
  };
  var name$2 = "DMN";
  var prefix$2 = "dmn";
  var uri$2 = "https://www.omg.org/spec/DMN/20191111/MODEL/";
  var types$2 = [{
    name: "AuthorityRequirement",
    superClass: ["DMNElement"],
    properties: [{
      name: "requiredAuthority",
      type: "DMNElementReference",
      xml: {
        serialize: "property"
      }
    }, {
      name: "requiredDecision",
      type: "DMNElementReference",
      xml: {
        serialize: "property"
      }
    }, {
      name: "requiredInput",
      type: "DMNElementReference",
      xml: {
        serialize: "property"
      }
    }]
  }, {
    name: "ItemDefinition",
    superClass: ["NamedElement"],
    properties: [{
      name: "typeRef",
      type: "String"
    }, {
      name: "allowedValues",
      type: "UnaryTests",
      xml: {
        serialize: "property"
      }
    }, {
      name: "typeLanguage",
      type: "String",
      isAttr: true
    }, {
      name: "itemComponent",
      type: "ItemDefinition",
      isMany: true,
      xml: {
        serialize: "property"
      }
    }, {
      name: "functionItem",
      type: "FunctionItem"
    }, {
      name: "isCollection",
      isAttr: true,
      type: "Boolean"
    }]
  }, {
    name: "Definitions",
    superClass: ["NamedElement"],
    properties: [{
      name: "import",
      type: "Import",
      isMany: true
    }, {
      name: "itemDefinition",
      type: "ItemDefinition",
      isMany: true
    }, {
      name: "drgElement",
      type: "DRGElement",
      isMany: true
    }, {
      name: "artifact",
      type: "Artifact",
      isMany: true
    }, {
      name: "elementCollection",
      type: "ElementCollection",
      isMany: true
    }, {
      name: "businessContextElement",
      type: "BusinessContextElement",
      isMany: true
    }, {
      name: "namespace",
      type: "String",
      isAttr: true
    }, {
      name: "expressionLanguage",
      type: "String",
      isAttr: true
    }, {
      name: "typeLanguage",
      type: "String",
      isAttr: true
    }, {
      name: "exporter",
      isAttr: true,
      type: "String"
    }, {
      name: "exporterVersion",
      isAttr: true,
      type: "String"
    }, {
      name: "dmnDI",
      type: "dmndi:DMNDI"
    }]
  }, {
    name: "KnowledgeSource",
    superClass: ["DRGElement"],
    properties: [{
      name: "authorityRequirement",
      type: "AuthorityRequirement",
      isMany: true
    }, {
      name: "type",
      type: "String"
    }, {
      name: "owner",
      type: "DMNElementReference",
      xml: {
        serialize: "property"
      }
    }, {
      name: "locationURI",
      type: "String",
      isAttr: true
    }]
  }, {
    name: "DecisionRule",
    superClass: ["DMNElement"],
    properties: [{
      name: "inputEntry",
      type: "UnaryTests",
      isMany: true,
      xml: {
        serialize: "property"
      }
    }, {
      name: "outputEntry",
      type: "LiteralExpression",
      isMany: true,
      xml: {
        serialize: "property"
      }
    }, {
      name: "annotationEntry",
      type: "RuleAnnotation",
      isMany: true,
      xml: {
        serialize: "property"
      }
    }]
  }, {
    name: "Expression",
    isAbstract: true,
    superClass: ["DMNElement"],
    properties: [{
      name: "typeRef",
      isAttr: true,
      type: "String"
    }]
  }, {
    name: "InformationItem",
    superClass: ["NamedElement"],
    properties: [{
      name: "typeRef",
      isAttr: true,
      type: "String"
    }]
  }, {
    name: "Decision",
    superClass: ["DRGElement"],
    properties: [{
      name: "question",
      type: "String",
      xml: {
        serialize: "property"
      }
    }, {
      name: "allowedAnswers",
      type: "String",
      xml: {
        serialize: "property"
      }
    }, {
      name: "variable",
      type: "InformationItem",
      xml: {
        serialize: "property"
      }
    }, {
      name: "informationRequirement",
      type: "InformationRequirement",
      isMany: true
    }, {
      name: "knowledgeRequirement",
      type: "KnowledgeRequirement",
      isMany: true
    }, {
      name: "authorityRequirement",
      type: "AuthorityRequirement",
      isMany: true
    }, {
      name: "supportedObjective",
      isMany: true,
      type: "DMNElementReference",
      xml: {
        serialize: "property"
      }
    }, {
      name: "impactedPerformanceIndicator",
      type: "DMNElementReference",
      isMany: true,
      xml: {
        serialize: "property"
      }
    }, {
      name: "decisionMaker",
      type: "DMNElementReference",
      isMany: true,
      xml: {
        serialize: "property"
      }
    }, {
      name: "decisionOwner",
      type: "DMNElementReference",
      isMany: true,
      xml: {
        serialize: "property"
      }
    }, {
      name: "usingProcess",
      isMany: true,
      type: "DMNElementReference",
      xml: {
        serialize: "property"
      }
    }, {
      name: "usingTask",
      isMany: true,
      type: "DMNElementReference",
      xml: {
        serialize: "property"
      }
    }, {
      name: "decisionLogic",
      type: "Expression"
    }]
  }, {
    name: "Invocation",
    superClass: ["Expression"],
    properties: [{
      name: "calledFunction",
      type: "Expression"
    }, {
      name: "binding",
      type: "Binding",
      isMany: true
    }]
  }, {
    name: "OrganisationalUnit",
    superClass: ["BusinessContextElement"],
    properties: [{
      name: "decisionMade",
      type: "Decision",
      isReference: true,
      isMany: true
    }, {
      name: "decisionOwned",
      type: "Decision",
      isReference: true,
      isMany: true
    }]
  }, {
    name: "Import",
    superClass: ["NamedElement"],
    properties: [{
      name: "importType",
      type: "String",
      isAttr: true
    }, {
      name: "locationURI",
      type: "String",
      isAttr: true
    }, {
      name: "namespace",
      type: "String",
      isAttr: true
    }]
  }, {
    name: "InformationRequirement",
    superClass: ["DMNElement"],
    properties: [{
      name: "requiredDecision",
      type: "DMNElementReference",
      xml: {
        serialize: "property"
      }
    }, {
      name: "requiredInput",
      type: "DMNElementReference",
      xml: {
        serialize: "property"
      }
    }]
  }, {
    name: "ElementCollection",
    superClass: ["NamedElement"],
    properties: [{
      name: "drgElement",
      type: "DMNElementReference",
      isMany: true,
      xml: {
        serialize: "property"
      }
    }]
  }, {
    name: "DRGElement",
    isAbstract: true,
    superClass: ["NamedElement"],
    properties: []
  }, {
    name: "InputData",
    superClass: ["DRGElement"],
    properties: [{
      name: "variable",
      type: "InformationItem",
      xml: {
        serialize: "property"
      }
    }]
  }, {
    name: "DMNElement",
    isAbstract: true,
    properties: [{
      name: "description",
      type: "String"
    }, {
      name: "extensionElements",
      type: "ExtensionElements"
    }, {
      name: "id",
      type: "String",
      isAttr: true,
      isId: true
    }, {
      name: "extensionAttribute",
      type: "ExtensionAttribute",
      isMany: true
    }, {
      name: "label",
      isAttr: true,
      type: "String"
    }]
  }, {
    name: "InputClause",
    superClass: ["DMNElement"],
    properties: [{
      name: "inputExpression",
      type: "LiteralExpression",
      xml: {
        serialize: "property"
      }
    }, {
      name: "inputValues",
      type: "UnaryTests",
      xml: {
        serialize: "property"
      }
    }]
  }, {
    name: "DecisionTable",
    superClass: ["Expression"],
    properties: [{
      name: "input",
      type: "InputClause",
      isMany: true,
      xml: {
        serialize: "property"
      }
    }, {
      name: "output",
      type: "OutputClause",
      isMany: true,
      xml: {
        serialize: "property"
      }
    }, {
      name: "annotation",
      type: "RuleAnnotationClause",
      isMany: true,
      xml: {
        serialize: "property"
      }
    }, {
      name: "rule",
      type: "DecisionRule",
      isMany: true,
      xml: {
        serialize: "property"
      }
    }, {
      name: "hitPolicy",
      type: "HitPolicy",
      isAttr: true,
      "default": "UNIQUE"
    }, {
      name: "aggregation",
      type: "BuiltinAggregator",
      isAttr: true
    }, {
      name: "preferredOrientation",
      type: "DecisionTableOrientation",
      isAttr: true
    }, {
      name: "outputLabel",
      isAttr: true,
      type: "String"
    }]
  }, {
    name: "LiteralExpression",
    superClass: ["Expression"],
    properties: [{
      name: "expressionLanguage",
      type: "String",
      isAttr: true
    }, {
      name: "text",
      type: "String"
    }, {
      name: "importedValues",
      type: "ImportedValues"
    }]
  }, {
    name: "Binding",
    properties: [{
      name: "parameter",
      type: "InformationItem",
      xml: {
        serialize: "property"
      }
    }, {
      name: "bindingFormula",
      type: "Expression"
    }]
  }, {
    name: "KnowledgeRequirement",
    superClass: ["DMNElement"],
    properties: [{
      name: "requiredKnowledge",
      type: "DMNElementReference",
      xml: {
        serialize: "property"
      }
    }]
  }, {
    name: "BusinessKnowledgeModel",
    superClass: ["Invocable"],
    properties: [{
      name: "encapsulatedLogic",
      type: "FunctionDefinition",
      xml: {
        serialize: "property"
      }
    }, {
      name: "knowledgeRequirement",
      type: "KnowledgeRequirement",
      isMany: true
    }, {
      name: "authorityRequirement",
      type: "AuthorityRequirement",
      isMany: true
    }]
  }, {
    name: "BusinessContextElement",
    isAbstract: true,
    superClass: ["NamedElement"],
    properties: [{
      name: "URI",
      type: "String",
      isAttr: true
    }]
  }, {
    name: "PerformanceIndicator",
    superClass: ["BusinessContextElement"],
    properties: [{
      name: "impactingDecision",
      type: "DMNElementReference",
      isMany: true,
      xml: {
        serialize: "property"
      }
    }]
  }, {
    name: "FunctionDefinition",
    superClass: ["Expression"],
    properties: [{
      name: "formalParameter",
      type: "InformationItem",
      isMany: true,
      xml: {
        serialize: "property"
      }
    }, {
      name: "body",
      type: "Expression"
    }, {
      name: "kind",
      type: "FunctionKind",
      isAttr: true
    }]
  }, {
    name: "Context",
    superClass: ["Expression"],
    properties: [{
      name: "contextEntry",
      type: "ContextEntry",
      isMany: true
    }]
  }, {
    name: "ContextEntry",
    superClass: ["DMNElement"],
    properties: [{
      name: "variable",
      type: "InformationItem",
      xml: {
        serialize: "property"
      }
    }, {
      name: "value",
      type: "Expression"
    }]
  }, {
    name: "List",
    superClass: ["Expression"],
    properties: [{
      name: "elements",
      isMany: true,
      type: "Expression"
    }]
  }, {
    name: "Relation",
    superClass: ["Expression"],
    properties: [{
      name: "column",
      type: "InformationItem",
      isMany: true,
      xml: {
        serialize: "property"
      }
    }, {
      name: "row",
      type: "List",
      isMany: true,
      xml: {
        serialize: "property"
      }
    }]
  }, {
    name: "OutputClause",
    superClass: ["DMNElement"],
    properties: [{
      name: "outputValues",
      type: "UnaryTests",
      xml: {
        serialize: "property"
      }
    }, {
      name: "defaultOutputEntry",
      type: "LiteralExpression",
      xml: {
        serialize: "property"
      }
    }, {
      name: "name",
      isAttr: true,
      type: "String"
    }, {
      name: "typeRef",
      isAttr: true,
      type: "String"
    }]
  }, {
    name: "UnaryTests",
    superClass: ["Expression"],
    properties: [{
      name: "text",
      type: "String"
    }, {
      name: "expressionLanguage",
      type: "String",
      isAttr: true
    }]
  }, {
    name: "NamedElement",
    isAbstract: true,
    superClass: ["DMNElement"],
    properties: [{
      name: "name",
      isAttr: true,
      type: "String"
    }]
  }, {
    name: "ImportedValues",
    superClass: ["Import"],
    properties: [{
      name: "importedElement",
      type: "String"
    }, {
      name: "expressionLanguage",
      type: "String",
      isAttr: true
    }]
  }, {
    name: "DecisionService",
    superClass: ["Invocable"],
    properties: [{
      name: "outputDecision",
      type: "DMNElementReference",
      isMany: true,
      xml: {
        serialize: "property"
      }
    }, {
      name: "encapsulatedDecision",
      type: "DMNElementReference",
      isMany: true,
      xml: {
        serialize: "property"
      }
    }, {
      name: "inputDecision",
      type: "DMNElementReference",
      isMany: true,
      xml: {
        serialize: "property"
      }
    }, {
      name: "inputData",
      type: "DMNElementReference",
      isMany: true,
      xml: {
        serialize: "property"
      }
    }]
  }, {
    name: "ExtensionElements",
    properties: [{
      name: "values",
      type: "Element",
      isMany: true
    }]
  }, {
    name: "ExtensionAttribute",
    properties: [{
      name: "value",
      type: "Element"
    }, {
      name: "valueRef",
      type: "Element",
      isAttr: true,
      isReference: true
    }, {
      name: "name",
      isAttr: true,
      type: "String"
    }]
  }, {
    name: "Element",
    isAbstract: true,
    properties: [{
      name: "extensionAttribute",
      type: "ExtensionAttribute",
      isAttr: true,
      isReference: true
    }, {
      name: "elements",
      type: "ExtensionElements",
      isAttr: true,
      isReference: true
    }]
  }, {
    name: "Artifact",
    isAbstract: true,
    superClass: ["DMNElement"],
    properties: []
  }, {
    name: "Association",
    superClass: ["Artifact"],
    properties: [{
      name: "sourceRef",
      type: "DMNElementReference",
      xml: {
        serialize: "property"
      }
    }, {
      name: "targetRef",
      type: "DMNElementReference",
      xml: {
        serialize: "property"
      }
    }, {
      name: "associationDirection",
      type: "AssociationDirection",
      isAttr: true
    }]
  }, {
    name: "TextAnnotation",
    superClass: ["Artifact"],
    properties: [{
      name: "text",
      type: "String"
    }, {
      name: "textFormat",
      isAttr: true,
      type: "String",
      "default": "text/plain"
    }]
  }, {
    name: "RuleAnnotationClause",
    properties: [{
      name: "name",
      isAttr: true,
      type: "String"
    }]
  }, {
    name: "RuleAnnotation",
    properties: [{
      name: "text",
      type: "String"
    }]
  }, {
    name: "Invocable",
    isAbstract: true,
    superClass: ["DRGElement"],
    properties: [{
      name: "variable",
      type: "InformationItem",
      xml: {
        serialize: "property"
      }
    }]
  }, {
    name: "Group",
    superClass: ["Artifact"],
    properties: [{
      name: "name",
      isAttr: true,
      type: "String"
    }]
  }, {
    name: "FunctionItem",
    superClass: ["DMNElement"],
    properties: [{
      name: "parameters",
      isMany: true,
      type: "InformationItem",
      xml: {
        serialize: "property"
      }
    }, {
      name: "outputTypeRef",
      isAttr: true,
      type: "String"
    }]
  }, {
    name: "DMNElementReference",
    properties: [{
      isAttr: true,
      name: "href",
      type: "String"
    }]
  }];
  var enumerations$1 = [{
    name: "HitPolicy",
    literalValues: [{
      name: "UNIQUE"
    }, {
      name: "FIRST"
    }, {
      name: "PRIORITY"
    }, {
      name: "ANY"
    }, {
      name: "COLLECT"
    }, {
      name: "RULE ORDER"
    }, {
      name: "OUTPUT ORDER"
    }]
  }, {
    name: "BuiltinAggregator",
    literalValues: [{
      name: "SUM"
    }, {
      name: "COUNT"
    }, {
      name: "MIN"
    }, {
      name: "MAX"
    }]
  }, {
    name: "DecisionTableOrientation",
    literalValues: [{
      name: "Rule-as-Row"
    }, {
      name: "Rule-as-Column"
    }, {
      name: "CrossTable"
    }]
  }, {
    name: "AssociationDirection",
    literalValues: [{
      name: "None"
    }, {
      name: "One"
    }, {
      name: "Both"
    }]
  }, {
    name: "FunctionKind",
    literalValues: [{
      name: "FEEL"
    }, {
      name: "Java"
    }, {
      name: "PMML"
    }]
  }];
  var associations$1 = [];
  var xml$1 = {
    tagAlias: "lowerCase"
  };
  var DmnPackage = {
    name: name$2,
    prefix: prefix$2,
    uri: uri$2,
    types: types$2,
    enumerations: enumerations$1,
    associations: associations$1,
    xml: xml$1
  };
  var name$1 = "DMNDI";
  var prefix$1 = "dmndi";
  var uri$1 = "https://www.omg.org/spec/DMN/20191111/DMNDI/";
  var types$1$1 = [{
    name: "DMNDI",
    properties: [{
      name: "diagrams",
      type: "DMNDiagram",
      isMany: true
    }, {
      name: "styles",
      type: "DMNStyle",
      isMany: true
    }]
  }, {
    name: "DMNStyle",
    superClass: ["di:Style"],
    properties: [{
      name: "fillColor",
      type: "dc:Color",
      isAttr: true
    }, {
      name: "strokeColor",
      type: "dc:Color",
      isAttr: true
    }, {
      name: "fontColor",
      type: "dc:Color",
      isAttr: true
    }, {
      name: "fontSize",
      isAttr: true,
      type: "Real"
    }, {
      name: "fontFamily",
      isAttr: true,
      type: "String"
    }, {
      name: "fontItalic",
      isAttr: true,
      type: "Boolean"
    }, {
      name: "fontBold",
      isAttr: true,
      type: "Boolean"
    }, {
      name: "fontUnderline",
      isAttr: true,
      type: "Boolean"
    }, {
      name: "fontStrikeThrough",
      isAttr: true,
      type: "Boolean"
    }, {
      name: "labelHorizontalAlignment",
      type: "dc:AlignmentKind",
      isAttr: true
    }, {
      name: "labelVerticalAlignment",
      type: "dc:AlignmentKind",
      isAttr: true
    }]
  }, {
    name: "DMNDiagram",
    superClass: ["di:Diagram"],
    properties: [{
      name: "dmnElementRef",
      type: "dmn:DMNElement",
      isAttr: true,
      isReference: true
    }, {
      name: "size",
      type: "Size"
    }, {
      name: "localStyle",
      type: "DMNStyle",
      isVirtual: true
    }, {
      name: "sharedStyle",
      type: "DMNStyle",
      isVirtual: true,
      isReference: true,
      redefines: "di:DiagramElement#sharedStyle"
    }, {
      name: "diagramElements",
      type: "DMNDiagramElement",
      isMany: true
    }]
  }, {
    name: "DMNDiagramElement",
    isAbstract: true,
    superClass: ["di:DiagramElement"],
    properties: [{
      name: "dmnElementRef",
      type: "dmn:DMNElement",
      isAttr: true,
      isReference: true
    }, {
      name: "sharedStyle",
      type: "DMNStyle",
      isVirtual: true,
      isReference: true,
      redefines: "di:DiagramElement#sharedStyle"
    }, {
      name: "localStyle",
      type: "DMNStyle",
      isVirtual: true
    }, {
      name: "label",
      type: "DMNLabel"
    }]
  }, {
    name: "DMNLabel",
    superClass: ["di:Shape"],
    properties: [{
      name: "text",
      type: "Text"
    }]
  }, {
    name: "DMNShape",
    superClass: ["di:Shape", "DMNDiagramElement"],
    properties: [{
      name: "isListedInputData",
      isAttr: true,
      type: "Boolean"
    }, {
      name: "decisionServiceDividerLine",
      type: "DMNDecisionServiceDividerLine"
    }, {
      name: "isCollapsed",
      isAttr: true,
      type: "Boolean"
    }]
  }, {
    name: "DMNEdge",
    superClass: ["di:Edge", "DMNDiagramElement"],
    properties: [{
      name: "sourceElement",
      type: "DMNDiagramElement",
      isAttr: true,
      isReference: true
    }, {
      name: "targetElement",
      type: "DMNDiagramElement",
      isAttr: true,
      isReference: true
    }]
  }, {
    name: "DMNDecisionServiceDividerLine",
    superClass: ["di:Edge"]
  }, {
    name: "Text",
    properties: [{
      name: "text",
      isBody: true,
      type: "String"
    }]
  }, {
    name: "Size",
    superClass: ["dc:Dimension"]
  }];
  var associations = [];
  var enumerations = [];
  var DmnDiPackage = {
    name: name$1,
    prefix: prefix$1,
    uri: uri$1,
    types: types$1$1,
    associations: associations,
    enumerations: enumerations
  };
  var name$5 = "bpmn.io DI for DMN";
  var uri = "http://bpmn.io/schema/dmn/biodi/2.0";
  var prefix = "biodi";
  var xml = {
    tagAlias: "lowerCase"
  };
  var types$5 = [{
    name: "DecisionTable",
    isAbstract: true,
    "extends": ["dmn:DecisionTable"],
    properties: [{
      name: "annotationsWidth",
      isAttr: true,
      type: "Integer"
    }]
  }, {
    name: "OutputClause",
    isAbstract: true,
    "extends": ["dmn:OutputClause"],
    properties: [{
      name: "width",
      isAttr: true,
      type: "Integer"
    }]
  }, {
    name: "InputClause",
    isAbstract: true,
    "extends": ["dmn:InputClause"],
    properties: [{
      name: "width",
      isAttr: true,
      type: "Integer"
    }]
  }];
  var BioDiPackage = {
    name: name$5,
    uri: uri,
    prefix: prefix,
    xml: xml,
    types: types$5
  };
  var packages = {
    dc: DcPackage,
    di: DiPackage,
    dmn: DmnPackage,
    dmndi: DmnDiPackage,
    biodi: BioDiPackage
  };
  function simple(additionalPackages, options) {
    var pks = assign$1({}, packages, additionalPackages);
    return new DmnModdle(pks, options);
  }

  /* eslint-disable no-multi-assign */

  const wrapMap = {
    legend: [1, '<fieldset>', '</fieldset>'],
    tr: [2, '<table><tbody>', '</tbody></table>'],
    col: [2, '<table><tbody></tbody><colgroup>', '</colgroup></table>'],
    _default: [0, '', '']
  };
  wrapMap.td = wrapMap.th = [3, '<table><tbody><tr>', '</tr></tbody></table>'];
  wrapMap.option = wrapMap.optgroup = [1, '<select multiple="multiple">', '</select>'];
  wrapMap.thead = wrapMap.tbody = wrapMap.colgroup = wrapMap.caption = wrapMap.tfoot = [1, '<table>', '</table>'];
  wrapMap.polyline = wrapMap.ellipse = wrapMap.polygon = wrapMap.circle = wrapMap.text = wrapMap.line = wrapMap.path = wrapMap.rect = wrapMap.g = [1, '<svg xmlns="http://www.w3.org/2000/svg" version="1.1">', '</svg>'];
  function domify(htmlString, document = globalThis.document) {
    if (typeof htmlString !== 'string') {
      throw new TypeError('String expected');
    }

    // Handle comment nodes
    const commentMatch = /^<!--(.*?)-->$/s.exec(htmlString);
    if (commentMatch) {
      return document.createComment(commentMatch[1]);
    }
    const tagName = /<([\w:]+)/.exec(htmlString)?.[1];
    if (!tagName) {
      return document.createTextNode(htmlString);
    }
    htmlString = htmlString.trim();

    // Body support
    if (tagName === 'body') {
      const element = document.createElement('html');
      element.innerHTML = htmlString;
      const {
        lastChild
      } = element;
      lastChild.remove();
      return lastChild;
    }

    // Wrap map
    let [depth, prefix, suffix] = Object.hasOwn(wrapMap, tagName) ? wrapMap[tagName] : wrapMap._default;
    let element = document.createElement('div');
    element.innerHTML = prefix + htmlString + suffix;
    while (depth--) {
      element = element.lastChild;
    }

    // One element
    if (element.firstChild === element.lastChild) {
      const {
        firstChild
      } = element;
      firstChild.remove();
      return firstChild;
    }

    // Several elements
    const fragment = document.createDocumentFragment();
    fragment.append(...element.childNodes);
    return fragment;
  }

  function _mergeNamespaces$1(n, m) {
    m.forEach(function (e) {
      e && typeof e !== 'string' && !Array.isArray(e) && Object.keys(e).forEach(function (k) {
        if (k !== 'default' && !(k in n)) {
          var d = Object.getOwnPropertyDescriptor(e, k);
          Object.defineProperty(n, k, d.get ? d : {
            enumerable: true,
            get: function () {
              return e[k];
            }
          });
        }
      });
    });
    return Object.freeze(n);
  }

  /**
   * Assigns style attributes in a style-src compliant way.
   *
   * @param {Element} element
   * @param {...Object} styleSources
   *
   * @return {Element} the element
   */
  function assign(element, ...styleSources) {
    const target = element.style;
    forEach(styleSources, function (style) {
      if (!style) {
        return;
      }
      forEach(style, function (value, key) {
        target[key] = value;
      });
    });
    return element;
  }

  /**
   * Set attribute `name` to `val`, or get attr `name`.
   *
   * @param {Element} el
   * @param {String} name
   * @param {String} [val]
   * @api public
   */
  function attr$1(el, name, val) {
    // get
    if (arguments.length == 2) {
      return el.getAttribute(name);
    }

    // remove
    if (val === null) {
      return el.removeAttribute(name);
    }

    // set
    el.setAttribute(name, val);
    return el;
  }

  /**
   * Taken from https://github.com/component/classes
   *
   * Without the component bits.
   */

  /**
   * toString reference.
   */

  const toString$1 = Object.prototype.toString;

  /**
   * Wrap `el` in a `ClassList`.
   *
   * @param {Element} el
   * @return {ClassList}
   * @api public
   */

  function classes$1(el) {
    return new ClassList$1(el);
  }

  /**
   * Initialize a new ClassList for `el`.
   *
   * @param {Element} el
   * @api private
   */

  function ClassList$1(el) {
    if (!el || !el.nodeType) {
      throw new Error('A DOM element reference is required');
    }
    this.el = el;
    this.list = el.classList;
  }

  /**
   * Add class `name` if not already present.
   *
   * @param {String} name
   * @return {ClassList}
   * @api public
   */

  ClassList$1.prototype.add = function (name) {
    this.list.add(name);
    return this;
  };

  /**
   * Remove class `name` when present, or
   * pass a regular expression to remove
   * any which match.
   *
   * @param {String|RegExp} name
   * @return {ClassList}
   * @api public
   */

  ClassList$1.prototype.remove = function (name) {
    if ('[object RegExp]' == toString$1.call(name)) {
      return this.removeMatching(name);
    }
    this.list.remove(name);
    return this;
  };

  /**
   * Remove all classes matching `re`.
   *
   * @param {RegExp} re
   * @return {ClassList}
   * @api private
   */

  ClassList$1.prototype.removeMatching = function (re) {
    const arr = this.array();
    for (let i = 0; i < arr.length; i++) {
      if (re.test(arr[i])) {
        this.remove(arr[i]);
      }
    }
    return this;
  };

  /**
   * Toggle class `name`, can force state via `force`.
   *
   * For browsers that support classList, but do not support `force` yet,
   * the mistake will be detected and corrected.
   *
   * @param {String} name
   * @param {Boolean} force
   * @return {ClassList}
   * @api public
   */

  ClassList$1.prototype.toggle = function (name, force) {
    if ('undefined' !== typeof force) {
      if (force !== this.list.toggle(name, force)) {
        this.list.toggle(name); // toggle again to correct
      }
    } else {
      this.list.toggle(name);
    }
    return this;
  };

  /**
   * Return an array of classes.
   *
   * @return {Array}
   * @api public
   */

  ClassList$1.prototype.array = function () {
    return Array.from(this.list);
  };

  /**
   * Check if class `name` is present.
   *
   * @param {String} name
   * @return {ClassList}
   * @api public
   */

  ClassList$1.prototype.has = ClassList$1.prototype.contains = function (name) {
    return this.list.contains(name);
  };

  /**
   * Clear utility
   */

  /**
   * Removes all children from the given element
   *
   * @param {Element} element
   *
   * @return {Element} the element (for chaining)
   */
  function clear(element) {
    var child;
    while (child = element.firstChild) {
      element.removeChild(child);
    }
    return element;
  }

  /**
   * Closest
   *
   * @param {Element} el
   * @param {string} selector
   * @param {boolean} checkYourSelf (optional)
   */
  function closest(element, selector, checkYourSelf) {
    var actualElement = checkYourSelf ? element : element.parentNode;
    return actualElement && typeof actualElement.closest === 'function' && actualElement.closest(selector) || null;
  }
  function getDefaultExportFromCjs$1(x) {
    return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
  }
  var componentEvent = {};
  var hasRequiredComponentEvent;
  function requireComponentEvent() {
    if (hasRequiredComponentEvent) return componentEvent;
    hasRequiredComponentEvent = 1;
    var bind, unbind, prefix;
    function detect() {
      bind = window.addEventListener ? 'addEventListener' : 'attachEvent';
      unbind = window.removeEventListener ? 'removeEventListener' : 'detachEvent';
      prefix = bind !== 'addEventListener' ? 'on' : '';
    }

    /**
     * Bind `el` event `type` to `fn`.
     *
     * @param {Element} el
     * @param {String} type
     * @param {Function} fn
     * @param {Boolean} capture
     * @return {Function}
     * @api public
     */

    componentEvent.bind = function (el, type, fn, capture) {
      if (!bind) detect();
      el[bind](prefix + type, fn, capture || false);
      return fn;
    };

    /**
     * Unbind `el` event `type`'s callback `fn`.
     *
     * @param {Element} el
     * @param {String} type
     * @param {Function} fn
     * @param {Boolean} capture
     * @return {Function}
     * @api public
     */

    componentEvent.unbind = function (el, type, fn, capture) {
      if (!unbind) detect();
      el[unbind](prefix + type, fn, capture || false);
      return fn;
    };
    return componentEvent;
  }
  var componentEventExports = requireComponentEvent();
  var index = /*@__PURE__*/getDefaultExportFromCjs$1(componentEventExports);
  var event = /*#__PURE__*/_mergeNamespaces$1({
    __proto__: null,
    default: index
  }, [componentEventExports]);

  /**
   * Module dependencies.
   */

  /**
   * Delegate event `type` to `selector`
   * and invoke `fn(e)`. A callback function
   * is returned which may be passed to `.unbind()`.
   *
   * @param {Element} el
   * @param {String} selector
   * @param {String} type
   * @param {Function} fn
   * @param {Boolean} capture
   * @return {Function}
   * @api public
   */

  // Some events don't bubble, so we want to bind to the capture phase instead
  // when delegating.
  var forceCaptureEvents = ['focus', 'blur'];
  function bind(el, selector, type, fn, capture) {
    if (forceCaptureEvents.indexOf(type) !== -1) {
      capture = true;
    }
    return event.bind(el, type, function (e) {
      var target = e.target || e.srcElement;
      e.delegateTarget = closest(target, selector, true);
      if (e.delegateTarget) {
        fn.call(el, e);
      }
    }, capture);
  }

  /**
   * Unbind event `type`'s callback `fn`.
   *
   * @param {Element} el
   * @param {String} type
   * @param {Function} fn
   * @param {Boolean} capture
   * @api public
   */
  function unbind(el, type, fn, capture) {
    if (forceCaptureEvents.indexOf(type) !== -1) {
      capture = true;
    }
    return event.unbind(el, type, fn, capture);
  }
  var delegate = {
    bind,
    unbind
  };
  function query(selector, el) {
    el = el || document;
    return el.querySelector(selector);
  }
  function all(selector, el) {
    el = el || document;
    return el.querySelectorAll(selector);
  }
  function remove$4(el) {
    el.parentNode && el.parentNode.removeChild(el);
  }

  // TODO: remove with future dmn-js version

  /**
   * Wraps APIs to check:
   *
   * 1) If a callback is passed -> Warn users about callback deprecation.
   * 2) If Promise class is implemented in current environment.
   *
   * @private
   */
  function wrapForCompatibility(api) {
    return function () {
      if (!window.Promise) {
        throw new Error('Promises is not supported in this environment.' + ' Please polyfill Promise.');
      }
      var argLen = arguments.length;
      if (argLen >= 1 && isFunction$1(arguments[argLen - 1])) {
        var callback = arguments[argLen - 1];
        console.warn(new Error('Passing callbacks to ' + replaceBoundPrefix(api.name) + ' is deprecated and will be removed in a future major release. ' + 'Please switch to promises: https://bpmn.io/l/moving-to-promises.html'));
        var argsWithoutCallback = Array.prototype.slice.call(arguments, 0, -1);
        api.apply(this, argsWithoutCallback).then(function (result) {
          var firstKey = Object.keys(result)[0];

          // The APIs we are wrapping all resolve a single item depending on the API.
          // For instance, importXML resolves { warnings } and saveXML returns { xml }.
          // That's why we can call the callback with the first item of result.
          return callback(null, result[firstKey]);

          // Passing a second paramter instead of catch because we don't want to
          // catch errors thrown by callback().
        }, function (err) {
          return callback(err, err.warnings);
        });
      } else {
        return api.apply(this, arguments);
      }
    };
  }

  // helper ////////

  /**
   * replaceBoundPrefix - replace the <bound > prefix from a string. Can be used
   * when logging the name of an API, not being sure whether is was bound or not.
   *
   * @param  {string} string
   * @return {string} the string without the <bound > prefix. If no <bound > prefix
   * was present, the same string will be returned.
   */
  function replaceBoundPrefix(string) {
    return string.replace('bound ', '');
  }

  /**
   * @typedef {import('./View').OpenResult} OpenResult
   */

  /**
   * @typedef {import('./View').OpenError} OpenError
   */

  const DEFAULT_CONTAINER_OPTIONS = {
    width: '100%',
    height: '100%',
    position: 'relative'
  };

  /**
   * The base class for DMN viewers and editors.
   *
   * @abstract
   */
  class Manager {
    /**
     * Create a new instance with the given options.
     *
     * @param  {Object} options
     *
     * @return {Manager}
     */
    constructor(options = {}) {
      this._eventBus = new EventBus();
      this._viewsChanged = debounce(this._viewsChanged, 0);
      this._views = [];
      this._viewers = {};

      // keep support for callbacks
      this.open = wrapForCompatibility(this.open.bind(this));
      this.importXML = wrapForCompatibility(this.importXML.bind(this));
      this.saveXML = wrapForCompatibility(this.saveXML.bind(this));
      this._init(options);
    }

    /**
    * The importXML result.
    *
    * @typedef {Object} ImportXMLResult
    *
    * @property {Array<string>} warnings
    */

    /**
    * The importXML error.
    *
    * @typedef {Error} ImportXMLError
    *
    * @property {Array<string>} warnings
    */

    /**
     * Parse and render a DMN diagram.
     *
     * Once finished the viewer reports back the result to the
     * provided callback function with (err, warnings).
     *
     * ## Life-Cycle Events
     *
     * During import the viewer will fire life-cycle events:
     *
     *   * import.parse.start (about to read model from xml)
     *   * import.parse.complete (model read; may have worked or not)
     *   * import.render.start (graphical import start)
     *   * import.render.complete (graphical import finished)
     *   * import.done (everything done)
     *
     * You can use these events to hook into the life-cycle.
     *
     * @param {string} xml the DMN xml
     * @param {Object} [options]
     * @param {boolean} [options.open=true]
     *
     * @return {Promise<ImportXMLResult, ImportXMLError>}
     */
    importXML(xml, options) {
      var self = this;
      options = options || {
        open: true
      };
      return new Promise(function (resolve, reject) {
        var previousActiveView = self._activeView;

        // clean up previously rendered diagram before new import
        self._clear().then(() => {
          // hook in pre-parse listeners +
          // allow xml manipulation
          xml = self._emit('import.parse.start', {
            xml: xml
          }) || xml;
          var parseWarnings;
          self._moddle.fromXML(xml, 'dmn:Definitions').then(parseResult => {
            var definitions = parseResult.rootElement;
            var references = parseResult.references;
            var elementsById = parseResult.elementsById;
            parseWarnings = parseResult.warnings;

            // hook in post parse listeners +
            // allow definitions manipulation
            definitions = self._emit('import.parse.complete', ParseCompleteEvent({
              error: null,
              definitions: definitions,
              elementsById: elementsById,
              references: references,
              warnings: parseWarnings
            })) || definitions;
            self._setDefinitions(definitions);
            if (!options.open) {
              self._emit('import.done', {
                error: null,
                warnings: parseWarnings
              });
              resolve({
                warnings: parseWarnings
              });
              return;
            }

            // open either previously active view or view of the same type if available
            var view = self._getInitialView(self._views, previousActiveView);
            if (!view) {
              var noDisplayableContentsErr = new Error('no displayable contents');
              self._emit('import.done', {
                error: noDisplayableContentsErr,
                warnings: parseWarnings
              });
              noDisplayableContentsErr.warnings = parseWarnings;
              return reject(noDisplayableContentsErr);
            }
            self.open(view).then(result => ({
              warnings: result.warnings
            })).catch(error => ({
              error: error,
              warnings: error.warnings
            })).then(result => {
              var allWarnings = [].concat(parseWarnings, result.warnings);
              self._emit('import.done', {
                error: result.error,
                warnings: allWarnings
              });
              if (result.error) {
                result.error.warnings = allWarnings;
                reject(result.error);
              } else {
                resolve({
                  warnings: allWarnings
                });
              }
            });
          }).catch(parseError => {
            parseWarnings = parseError.warnings;
            parseError = checkDMNCompatibilityError(parseError, xml) || checkValidationError(parseError) || parseError;
            self._emit('import.parse.complete', ParseCompleteEvent({
              error: parseError,
              warnings: parseWarnings
            }));
            self._emit('import.done', {
              error: parseError,
              warnings: parseWarnings
            });
            parseError.warnings = parseWarnings;
            return reject(parseError);
          });
        }).catch(clearError => {
          self._emit('import.done', {
            error: clearError,
            warnings: []
          });
          clearError.warnings = [];
          return reject(clearError);
        });
      });

      // TODO: remove with future dmn-js version
      function ParseCompleteEvent(data) {
        var event = self._eventBus.createEvent(data);
        Object.defineProperty(event, 'context', {
          enumerable: true,
          get: function () {
            console.warn(new Error('import.parse.complete <context> is deprecated ' + 'and will be removed in future library versions'));
            return {
              warnings: data.warnings,
              references: data.references,
              elementsById: data.elementsById
            };
          }
        });
        return event;
      }
    }
    getDefinitions() {
      return this._definitions;
    }

    /**
     * Return active view.
     *
     * @return {View}
     */
    getActiveView() {
      return this._activeView;
    }

    /**
     * Get the currently active viewer instance.
     *
     * @return {View}
     */
    getActiveViewer() {
      var activeView = this.getActiveView();
      return activeView && this._getViewer(activeView);
    }
    getView(element) {
      return this._views.filter(function (v) {
        return v.element === element;
      })[0];
    }
    getViews() {
      return this._views;
    }

    /**
     * The saveXML result.
     *
     * @typedef {Object} SaveXMLResult
     *
     * @property {string} xml
     */

    /**
     * Export the currently displayed DMN diagram as
     * a DMN XML document.
     *
     * ## Life-Cycle Events
     *
     * During XML saving the viewer will fire life-cycle events:
     *
     *   * saveXML.start (before serialization)
     *   * saveXML.serialized (after xml generation)
     *   * saveXML.done (everything done)
     *
     * You can use these events to hook into the life-cycle.
     *
     * @param {Object} [options] export options
     * @param {boolean} [options.format=false] output formated XML
     * @param {boolean} [options.preamble=true] output preamble
     *
     * @return {Promise<SaveXMLResult, Error>}
     */
    saveXML(options) {
      var self = this;
      options = options || {};
      var definitions = this._definitions;
      return new Promise(function (resolve, reject) {
        if (!definitions) {
          reject(new Error('no definitions loaded'));
          return;
        }

        // allow to fiddle around with definitions
        definitions = self._emit('saveXML.start', {
          definitions: definitions
        }) || definitions;
        self._moddle.toXML(definitions, options).then(function (result) {
          var xml = result.xml;
          xml = self._emit('saveXML.serialized', {
            xml: xml
          }) || xml;
          return {
            xml
          };
        }).catch(error => ({
          error
        })).then(result => {
          self._emit('saveXML.done', result);
          if (result.error) {
            reject(result.error);
          } else {
            resolve({
              xml: result.xml
            });
          }
        });
      });
    }

    /**
     * Register an event listener
     *
     * Remove a previously added listener via {@link #off(event, callback)}.
     *
     * @param {string} event
     * @param {number} [priority]
     * @param {Function} callback
     * @param {Object} [that]
     */
    on(...args) {
      this._eventBus.on(...args);
    }

    /**
     * De-register an event listener
     *
     * @param {string} event
     * @param {Function} callback
     */
    off(...args) {
      this._eventBus.off(...args);
    }

    /**
     * Register a listener to be invoked once only.
     *
     * @param {string} event
     * @param {number} [priority]
     * @param {Function} callback
     * @param {Object} [that]
     */
    once(...args) {
      this._eventBus.once(...args);
    }
    attachTo(parentNode) {
      // unwrap jQuery if provided
      if (parentNode.get && parentNode.constructor.prototype.jquery) {
        parentNode = parentNode.get(0);
      }
      if (typeof parentNode === 'string') {
        parentNode = query(parentNode);
      }
      parentNode.appendChild(this._container);
      this._emit('attach', {});
    }
    detach() {
      this._emit('detach', {});
      remove$4(this._container);
    }
    destroy() {
      Object.keys(this._viewers).forEach(viewerId => {
        var viewer = this._viewers[viewerId];
        safeExecute(viewer, 'destroy');
      });
      remove$4(this._container);
    }
    _init(options) {
      this._options = options;
      this._moddle = this._createModdle(options);
      this._viewers = {};
      this._views = [];
      const container = domify('<div class="dmn-js-parent"></div>');
      const containerOptions = assign$1({}, DEFAULT_CONTAINER_OPTIONS, options);
      assign$1(container.style, {
        width: ensureUnit(containerOptions.width),
        height: ensureUnit(containerOptions.height),
        position: containerOptions.position
      });
      this._container = container;
      if (options.container) {
        this.attachTo(options.container);
      }
    }
    _clear() {
      return this._switchView(null);
    }

    /**
     * Open diagram view.
     *
     * @param  {View} view
     * @returns {Promise} Resolves with {OpenResult} when successful
     * or rejects with {OpenError}
     */
    open(view) {
      return this._switchView(view);
    }
    _setDefinitions(definitions) {
      this._definitions = definitions;
      this._updateViews();
    }
    _viewsChanged = () => {
      this._emit('views.changed', {
        views: this._views,
        activeView: this._activeView
      });
    };

    /**
     * Recompute changed views after elements in
     * the DMN diagram have changed.
     */
    _updateViews() {
      var definitions = this._definitions;
      if (!definitions) {
        this._views = [];
        this._switchView(null);
        return;
      }
      var viewProviders = this._getViewProviders();
      var displayableElements = [definitions, ...(definitions.drgElement || [])];

      // compute list of available views
      var views = this._views,
        newViews = [];
      for (var element of displayableElements) {
        var provider = find$1(viewProviders, function (provider) {
          if (typeof provider.opens === 'string') {
            return provider.opens === element.$type;
          } else {
            return provider.opens(element);
          }
        });
        if (!provider) {
          continue;
        }
        var view = {
          element,
          id: element.id,
          name: element.name,
          type: provider.id
        };
        newViews.push(view);
      }
      var activeView = this._activeView,
        newActiveView;
      if (activeView) {
        // check the new active view
        newActiveView = find$1(newViews, function (view) {
          return viewsEqual(activeView, view);
        }) || this._getInitialView(newViews);
        if (!newActiveView) {
          this._switchView(null);
          return;
        }
      }

      // Views have changed if
      // active view has changed OR
      // number of views has changed OR
      // not all views equal
      var activeViewChanged = !viewsEqual(activeView, newActiveView) || viewNameChanged(activeView, newActiveView);
      var viewsChanged = views.length !== newViews.length || !every(newViews, function (newView) {
        return find$1(views, function (view) {
          return viewsEqual(view, newView) && !viewNameChanged(view, newView);
        });
      });
      this._activeView = newActiveView;
      this._views = newViews;
      if (activeViewChanged || viewsChanged) {
        this._viewsChanged();
      }
    }
    _getInitialView(views, preferredView) {
      var initialView;
      if (preferredView) {
        initialView = find$1(views, function (view) {
          return viewsEqual(view, preferredView);
        }) || find$1(views, function (view) {
          return view.type === preferredView;
        });
      }
      return initialView || views[0];
    }

    /**
     * Switch to another view.
     *
     * @param  {View} newView
     * @returns {Promise} Resolves with {OpenResult} when successful
     * or rejects with {OpenError}
     */
    _switchView(newView) {
      var self = this;
      return new Promise(function (resolve, reject) {
        var complete = (openError, openResult) => {
          self._viewsChanged();
          if (openError) {
            reject(openError);
          } else {
            resolve(openResult);
          }
        };
        var activeView = self.getActiveView(),
          activeViewer;
        var newViewer = newView && self._getViewer(newView),
          element = newView && newView.element;
        if (activeView) {
          activeViewer = self._getViewer(activeView);
          if (activeViewer !== newViewer) {
            safeExecute(activeViewer, 'clear');
            activeViewer.detach();
          }
        }
        self._activeView = newView;
        if (newViewer) {
          if (activeViewer !== newViewer) {
            newViewer.attachTo(self._container);
          }
          self._emit('import.render.start', {
            view: newView,
            element: element
          });
          newViewer.open(element).then(result => {
            self._emit('import.render.complete', {
              view: newView,
              error: null,
              warnings: result.warnings
            });
            complete(null, result);
          }).catch(error => {
            self._emit('import.render.complete', {
              view: newView,
              error: error,
              warnings: error.warnings
            });
            complete(error, null);
          });
          return;
        }

        // no active view
        complete();
      });
    }
    _getViewer(view) {
      var type = view.type;
      var viewer = this._viewers[type];
      if (!viewer) {
        viewer = this._viewers[type] = this._createViewer(view.type);
        this._emit('viewer.created', {
          type: type,
          viewer: viewer
        });
      }
      return viewer;
    }
    _createViewer(id) {
      var provider = find$1(this._getViewProviders(), function (provider) {
        return provider.id === id;
      });
      if (!provider) {
        throw new Error('no provider for view type <' + id + '>');
      }
      var Viewer = provider.constructor;
      var providerOptions = this._options[id] || {};
      var commonOptions = this._options.common || {};
      return new Viewer({
        ...commonOptions,
        ...providerOptions,
        additionalModules: [...(providerOptions.additionalModules || []), {
          _parent: ['value', this],
          moddle: ['value', this._moddle]
        }]
      });
    }

    /**
     * Emit an event.
     */
    _emit(...args) {
      return this._eventBus.fire(...args);
    }
    _createModdle(options) {
      return new simple(options.moddleExtensions);
    }

    /**
     * Return the list of available view providers.
     *
     * @abstract
     *
     * @return {Array<ViewProvider>}
     */
    _getViewProviders() {
      return [];
    }
  }

  // helpers //////////////////////

  /**
   * Ensure the passed argument is a proper unit (defaulting to px)
   */
  function ensureUnit(val) {
    return val + (isNumber$1(val) ? 'px' : '');
  }
  function checkDMNCompatibilityError(err, xml) {
    // check if we can indicate opening of old DMN 1.1 or DMN 1.2 diagrams

    if (err.message !== 'failed to parse document as <dmn:Definitions>') {
      return null;
    }
    var olderDMNVersion = xml.indexOf('"http://www.omg.org/spec/DMN/20151101/dmn.xsd"') !== -1 && '1.1' || xml.indexOf('"http://www.omg.org/spec/DMN/20180521/MODEL/"') !== -1 && '1.2';
    if (!olderDMNVersion) {
      return null;
    }
    err = new Error('unsupported DMN ' + olderDMNVersion + ' file detected; ' + 'only DMN 1.3 files can be opened');
    console.error('Cannot open what looks like a DMN ' + olderDMNVersion + ' diagram. ' + 'Please refer to https://bpmn.io/l/dmn-compatibility.html ' + 'to learn how to make the toolkit compatible with older DMN files', err);
    return err;
  }
  function checkValidationError(err) {
    // check if we can help the user by indicating wrong DMN 1.3 xml
    // (in case he or the exporting tool did not get that right)

    var pattern = /unparsable content <([^>]+)> detected([\s\S]*)$/,
      match = pattern.exec(err.message);
    if (!match) {
      return null;
    }
    err.message = 'unparsable content <' + match[1] + '> detected; ' + 'this may indicate an invalid DMN 1.3 diagram file' + match[2];
    return err;
  }
  function viewsEqual(a, b) {
    if (!isDefined(a)) {
      if (!isDefined(b)) {
        return true;
      } else {
        return false;
      }
    }
    if (!isDefined(b)) {
      return false;
    }

    // compare by element OR element ID equality
    return a.element === b.element || a.id === b.id;
  }
  function viewNameChanged(a, b) {
    return !a || !b || a.name !== b.name;
  }
  function safeExecute(viewer, method) {
    if (isFunction$1(viewer[method])) {
      viewer[method]();
    }
  }

  const CLASS_PATTERN = /^class[ {]/;

  /**
   * @param {function} fn
   *
   * @return {boolean}
   */
  function isClass(fn) {
    return CLASS_PATTERN.test(fn.toString());
  }

  /**
   * @param {any} obj
   *
   * @return {boolean}
   */
  function isArray$1(obj) {
    return Array.isArray(obj);
  }

  /**
   * @param {any} obj
   * @param {string} prop
   *
   * @return {boolean}
   */
  function hasOwnProp(obj, prop) {
    return Object.prototype.hasOwnProperty.call(obj, prop);
  }

  /**
   * @typedef {import('./index.js').InjectAnnotated } InjectAnnotated
   */

  /**
   * @template T
   *
   * @params {[...string[], T] | ...string[], T} args
   *
   * @return {T & InjectAnnotated}
   */
  function annotate(...args) {
    if (args.length === 1 && isArray$1(args[0])) {
      args = args[0];
    }
    args = [...args];
    const fn = args.pop();
    fn.$inject = args;
    return fn;
  }

  // Current limitations:
  // - can't put into "function arg" comments
  // function /* (no parenthesis like this) */ (){}
  // function abc( /* xx (no parenthesis like this) */ a, b) {}
  //
  // Just put the comment before function or inside:
  // /* (((this is fine))) */ function(a, b) {}
  // function abc(a) { /* (((this is fine))) */}
  //
  // - can't reliably auto-annotate constructor; we'll match the
  // first constructor(...) pattern found which may be the one
  // of a nested class, too.

  const CONSTRUCTOR_ARGS = /constructor\s*[^(]*\(\s*([^)]*)\)/m;
  const FN_ARGS = /^(?:async\s+)?(?:function\s*[^(]*)?(?:\(\s*([^)]*)\)|(\w+))/m;
  const FN_ARG = /\/\*([^*]*)\*\//m;

  /**
   * @param {unknown} fn
   *
   * @return {string[]}
   */
  function parseAnnotations(fn) {
    if (typeof fn !== 'function') {
      throw new Error(`Cannot annotate "${fn}". Expected a function!`);
    }
    const match = fn.toString().match(isClass(fn) ? CONSTRUCTOR_ARGS : FN_ARGS);

    // may parse class without constructor
    if (!match) {
      return [];
    }
    const args = match[1] || match[2];
    return args && args.split(',').map(arg => {
      const argMatch = arg.match(FN_ARG);
      return (argMatch && argMatch[1] || arg).trim();
    }) || [];
  }

  /**
   * @typedef { import('./index.js').ModuleDeclaration } ModuleDeclaration
   * @typedef { import('./index.js').ModuleDefinition } ModuleDefinition
   * @typedef { import('./index.js').InjectorContext } InjectorContext
   *
   * @typedef { import('./index.js').TypedDeclaration<any, any> } TypedDeclaration
   */

  /**
   * Create a new injector with the given modules.
   *
   * @param {ModuleDefinition[]} modules
   * @param {InjectorContext} [_parent]
   */
  function Injector(modules, _parent) {
    const parent = _parent || (/** @type InjectorContext */{
      get: function (name, strict) {
        currentlyResolving.push(name);
        if (strict === false) {
          return null;
        } else {
          throw error(`No provider for "${name}"!`);
        }
      }
    });
    const currentlyResolving = [];
    const providers = this._providers = Object.create(parent._providers || null);
    const instances = this._instances = Object.create(null);
    const self = instances.injector = this;
    const error = function (msg) {
      const stack = currentlyResolving.join(' -> ');
      currentlyResolving.length = 0;
      return new Error(stack ? `${msg} (Resolving: ${stack})` : msg);
    };

    /**
     * Return a named service.
     *
     * @param {string} name
     * @param {boolean} [strict=true] if false, resolve missing services to null
     *
     * @return {any}
     */
    function get(name, strict) {
      if (!providers[name] && name.includes('.')) {
        const parts = name.split('.');
        let pivot = get(/** @type { string } */parts.shift());
        while (parts.length) {
          pivot = pivot[(/** @type { string } */parts.shift())];
        }
        return pivot;
      }
      if (hasOwnProp(instances, name)) {
        return instances[name];
      }
      if (hasOwnProp(providers, name)) {
        if (currentlyResolving.indexOf(name) !== -1) {
          currentlyResolving.push(name);
          throw error('Cannot resolve circular dependency!');
        }
        currentlyResolving.push(name);
        instances[name] = providers[name][0](providers[name][1]);
        currentlyResolving.pop();
        return instances[name];
      }
      return parent.get(name, strict);
    }
    function fnDef(fn, locals) {
      if (typeof locals === 'undefined') {
        locals = {};
      }
      if (typeof fn !== 'function') {
        if (isArray$1(fn)) {
          fn = annotate(fn.slice());
        } else {
          throw error(`Cannot invoke "${fn}". Expected a function!`);
        }
      }

      /**
       * @type {string[]}
       */
      const inject = fn.$inject || parseAnnotations(fn);
      const dependencies = inject.map(dep => {
        if (hasOwnProp(locals, dep)) {
          return locals[dep];
        } else {
          return get(dep);
        }
      });
      return {
        fn: fn,
        dependencies
      };
    }

    /**
     * Instantiate the given type, injecting dependencies.
     *
     * @template T
     *
     * @param { Function | [...string[], Function ]} type
     *
     * @return T
     */
    function instantiate(type) {
      const {
        fn,
        dependencies
      } = fnDef(type);

      // instantiate var args constructor
      const Constructor = Function.prototype.bind.call(fn, null, ...dependencies);
      return new Constructor();
    }

    /**
     * Invoke the given function, injecting dependencies. Return the result.
     *
     * @template T
     *
     * @param { Function | [...string[], Function ]} func
     * @param { Object } [context]
     * @param { Object } [locals]
     *
     * @return {T} invocation result
     */
    function invoke(func, context, locals) {
      const {
        fn,
        dependencies
      } = fnDef(func, locals);
      return fn.apply(context, dependencies);
    }

    /**
     * @param {Injector} childInjector
     *
     * @return {Function}
     */
    function createPrivateInjectorFactory(childInjector) {
      return annotate(key => childInjector.get(key));
    }

    /**
     * @param {ModuleDefinition[]} modules
     * @param {string[]} [forceNewInstances]
     *
     * @return {Injector}
     */
    function createChild(modules, forceNewInstances) {
      if (forceNewInstances && forceNewInstances.length) {
        const fromParentModule = Object.create(null);
        const matchedScopes = Object.create(null);
        const privateInjectorsCache = [];
        const privateChildInjectors = [];
        const privateChildFactories = [];
        let provider;
        let cacheIdx;
        let privateChildInjector;
        let privateChildInjectorFactory;
        for (let name in providers) {
          provider = providers[name];
          if (forceNewInstances.indexOf(name) !== -1) {
            if (provider[2] === 'private') {
              cacheIdx = privateInjectorsCache.indexOf(provider[3]);
              if (cacheIdx === -1) {
                privateChildInjector = provider[3].createChild([], forceNewInstances);
                privateChildInjectorFactory = createPrivateInjectorFactory(privateChildInjector);
                privateInjectorsCache.push(provider[3]);
                privateChildInjectors.push(privateChildInjector);
                privateChildFactories.push(privateChildInjectorFactory);
                fromParentModule[name] = [privateChildInjectorFactory, name, 'private', privateChildInjector];
              } else {
                fromParentModule[name] = [privateChildFactories[cacheIdx], name, 'private', privateChildInjectors[cacheIdx]];
              }
            } else {
              fromParentModule[name] = [provider[2], provider[1]];
            }
            matchedScopes[name] = true;
          }
          if ((provider[2] === 'factory' || provider[2] === 'type') && provider[1].$scope) {
            /* jshint -W083 */
            forceNewInstances.forEach(scope => {
              if (provider[1].$scope.indexOf(scope) !== -1) {
                fromParentModule[name] = [provider[2], provider[1]];
                matchedScopes[scope] = true;
              }
            });
          }
        }
        forceNewInstances.forEach(scope => {
          if (!matchedScopes[scope]) {
            throw new Error('No provider for "' + scope + '". Cannot use provider from the parent!');
          }
        });
        modules.unshift(fromParentModule);
      }
      return new Injector(modules, self);
    }
    const factoryMap = {
      factory: invoke,
      type: instantiate,
      value: function (value) {
        return value;
      }
    };

    /**
     * @param {ModuleDefinition} moduleDefinition
     * @param {Injector} injector
     */
    function createInitializer(moduleDefinition, injector) {
      const initializers = moduleDefinition.__init__ || [];
      return function () {
        initializers.forEach(initializer => {
          // eagerly resolve component (fn or string)
          if (typeof initializer === 'string') {
            injector.get(initializer);
          } else {
            injector.invoke(initializer);
          }
        });
      };
    }

    /**
     * @param {ModuleDefinition} moduleDefinition
     */
    function loadModule(moduleDefinition) {
      const moduleExports = moduleDefinition.__exports__;

      // private module
      if (moduleExports) {
        const nestedModules = moduleDefinition.__modules__;
        const clonedModule = Object.keys(moduleDefinition).reduce((clonedModule, key) => {
          if (key !== '__exports__' && key !== '__modules__' && key !== '__init__' && key !== '__depends__') {
            clonedModule[key] = moduleDefinition[key];
          }
          return clonedModule;
        }, Object.create(null));
        const childModules = (nestedModules || []).concat(clonedModule);
        const privateInjector = createChild(childModules);
        const getFromPrivateInjector = annotate(function (key) {
          return privateInjector.get(key);
        });
        moduleExports.forEach(function (key) {
          providers[key] = [getFromPrivateInjector, key, 'private', privateInjector];
        });

        // ensure child injector initializes
        const initializers = (moduleDefinition.__init__ || []).slice();
        initializers.unshift(function () {
          privateInjector.init();
        });
        moduleDefinition = Object.assign({}, moduleDefinition, {
          __init__: initializers
        });
        return createInitializer(moduleDefinition, privateInjector);
      }

      // normal module
      Object.keys(moduleDefinition).forEach(function (key) {
        if (key === '__init__' || key === '__depends__') {
          return;
        }
        const typeDeclaration = /** @type { TypedDeclaration } */
        moduleDefinition[key];
        if (typeDeclaration[2] === 'private') {
          providers[key] = typeDeclaration;
          return;
        }
        const type = typeDeclaration[0];
        const value = typeDeclaration[1];
        providers[key] = [factoryMap[type], arrayUnwrap(type, value), type];
      });
      return createInitializer(moduleDefinition, self);
    }

    /**
     * @param {ModuleDefinition[]} moduleDefinitions
     * @param {ModuleDefinition} moduleDefinition
     *
     * @return {ModuleDefinition[]}
     */
    function resolveDependencies(moduleDefinitions, moduleDefinition) {
      if (moduleDefinitions.indexOf(moduleDefinition) !== -1) {
        return moduleDefinitions;
      }
      moduleDefinitions = (moduleDefinition.__depends__ || []).reduce(resolveDependencies, moduleDefinitions);
      if (moduleDefinitions.indexOf(moduleDefinition) !== -1) {
        return moduleDefinitions;
      }
      return moduleDefinitions.concat(moduleDefinition);
    }

    /**
     * @param {ModuleDefinition[]} moduleDefinitions
     *
     * @return { () => void } initializerFn
     */
    function bootstrap(moduleDefinitions) {
      const initializers = moduleDefinitions.reduce(resolveDependencies, []).map(loadModule);
      let initialized = false;
      return function () {
        if (initialized) {
          return;
        }
        initialized = true;
        initializers.forEach(initializer => initializer());
      };
    }

    // public API
    this.get = get;
    this.invoke = invoke;
    this.instantiate = instantiate;
    this.createChild = createChild;

    // setup
    this.init = bootstrap(modules);
  }

  // helpers ///////////////

  function arrayUnwrap(type, value) {
    if (type !== 'value' && isArray$1(value)) {
      value = annotate(value.slice());
    }
    return value;
  }

  function e(e, t) {
    t && (e.super_ = t, e.prototype = Object.create(t.prototype, {
      constructor: {
        value: e,
        enumerable: false,
        writable: true,
        configurable: true
      }
    }));
  }

  var DEFAULT_RENDER_PRIORITY$1 = 1000;

  /**
   * @typedef {import('../core/Types.js').ElementLike} Element
   * @typedef {import('../core/Types.js').ConnectionLike} Connection
   * @typedef {import('../core/Types.js').ShapeLike} Shape
   *
   * @typedef {import('../core/EventBus.js').default} EventBus
   */

  /**
   * The base implementation of shape and connection renderers.
   *
   * @param {EventBus} eventBus
   * @param {number} [renderPriority=1000]
   */
  function BaseRenderer(eventBus, renderPriority) {
    var self = this;
    renderPriority = renderPriority || DEFAULT_RENDER_PRIORITY$1;
    eventBus.on(['render.shape', 'render.connection'], renderPriority, function (evt, context) {
      var type = evt.type,
        element = context.element,
        visuals = context.gfx,
        attrs = context.attrs;
      if (self.canRender(element)) {
        if (type === 'render.shape') {
          return self.drawShape(visuals, element, attrs);
        } else {
          return self.drawConnection(visuals, element, attrs);
        }
      }
    });
    eventBus.on(['render.getShapePath', 'render.getConnectionPath'], renderPriority, function (evt, element) {
      if (self.canRender(element)) {
        if (evt.type === 'render.getShapePath') {
          return self.getShapePath(element);
        } else {
          return self.getConnectionPath(element);
        }
      }
    });
  }

  /**
   * Checks whether an element can be rendered.
   *
   * @param {Element} element The element to be rendered.
   *
   * @return {boolean} Whether the element can be rendered.
   */
  BaseRenderer.prototype.canRender = function (element) {};

  /**
   * Draws a shape.
   *
   * @param {SVGElement} visuals The SVG element to draw the shape into.
   * @param {Shape} shape The shape to be drawn.
   *
   * @return {SVGElement} The SVG element of the shape drawn.
   */
  BaseRenderer.prototype.drawShape = function (visuals, shape) {};

  /**
   * Draws a connection.
   *
   * @param {SVGElement} visuals The SVG element to draw the connection into.
   * @param {Connection} connection The connection to be drawn.
   *
   * @return {SVGElement} The SVG element of the connection drawn.
   */
  BaseRenderer.prototype.drawConnection = function (visuals, connection) {};

  /**
   * Gets the SVG path of the graphical representation of a shape.
   *
   * @param {Shape} shape The shape.
   *
   * @return {string} The SVG path of the shape.
   */
  BaseRenderer.prototype.getShapePath = function (shape) {};

  /**
   * Gets the SVG path of the graphical representation of a connection.
   *
   * @param {Connection} connection The connection.
   *
   * @return {string} The SVG path of the connection.
   */
  BaseRenderer.prototype.getConnectionPath = function (connection) {};

  function ensureImported(element, target) {
    if (element.ownerDocument !== target.ownerDocument) {
      try {
        // may fail on webkit
        return target.ownerDocument.importNode(element, true);
      } catch (e) {

        // ignore
      }
    }
    return element;
  }

  /**
   * appendTo utility
   */

  /**
   * Append a node to a target element and return the appended node.
   *
   * @param  {SVGElement} element
   * @param  {SVGElement} target
   *
   * @return {SVGElement} the appended node
   */
  function appendTo(element, target) {
    return target.appendChild(ensureImported(element, target));
  }

  /**
   * append utility
   */

  /**
   * Append a node to an element
   *
   * @param  {SVGElement} element
   * @param  {SVGElement} node
   *
   * @return {SVGElement} the element
   */
  function append(target, node) {
    appendTo(node, target);
    return target;
  }

  /**
   * attribute accessor utility
   */

  var LENGTH_ATTR = 2;
  var CSS_PROPERTIES = {
    'alignment-baseline': 1,
    'baseline-shift': 1,
    'clip': 1,
    'clip-path': 1,
    'clip-rule': 1,
    'color': 1,
    'color-interpolation': 1,
    'color-interpolation-filters': 1,
    'color-profile': 1,
    'color-rendering': 1,
    'cursor': 1,
    'direction': 1,
    'display': 1,
    'dominant-baseline': 1,
    'enable-background': 1,
    'fill': 1,
    'fill-opacity': 1,
    'fill-rule': 1,
    'filter': 1,
    'flood-color': 1,
    'flood-opacity': 1,
    'font': 1,
    'font-family': 1,
    'font-size': LENGTH_ATTR,
    'font-size-adjust': 1,
    'font-stretch': 1,
    'font-style': 1,
    'font-variant': 1,
    'font-weight': 1,
    'glyph-orientation-horizontal': 1,
    'glyph-orientation-vertical': 1,
    'image-rendering': 1,
    'kerning': 1,
    'letter-spacing': 1,
    'lighting-color': 1,
    'marker': 1,
    'marker-end': 1,
    'marker-mid': 1,
    'marker-start': 1,
    'mask': 1,
    'opacity': 1,
    'overflow': 1,
    'pointer-events': 1,
    'shape-rendering': 1,
    'stop-color': 1,
    'stop-opacity': 1,
    'stroke': 1,
    'stroke-dasharray': 1,
    'stroke-dashoffset': 1,
    'stroke-linecap': 1,
    'stroke-linejoin': 1,
    'stroke-miterlimit': 1,
    'stroke-opacity': 1,
    'stroke-width': LENGTH_ATTR,
    'text-anchor': 1,
    'text-decoration': 1,
    'text-rendering': 1,
    'unicode-bidi': 1,
    'visibility': 1,
    'word-spacing': 1,
    'writing-mode': 1
  };
  function getAttribute(node, name) {
    if (CSS_PROPERTIES[name]) {
      return node.style[name];
    } else {
      return node.getAttributeNS(null, name);
    }
  }
  function setAttribute(node, name, value) {
    var hyphenated = name.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
    var type = CSS_PROPERTIES[hyphenated];
    if (type) {
      // append pixel unit, unless present
      if (type === LENGTH_ATTR && typeof value === 'number') {
        value = String(value) + 'px';
      }
      node.style[hyphenated] = value;
    } else {
      node.setAttributeNS(null, name, value);
    }
  }
  function setAttributes(node, attrs) {
    var names = Object.keys(attrs),
      i,
      name;
    for (i = 0, name; name = names[i]; i++) {
      setAttribute(node, name, attrs[name]);
    }
  }

  /**
   * Gets or sets raw attributes on a node.
   *
   * @param  {SVGElement} node
   * @param  {Object} [attrs]
   * @param  {String} [name]
   * @param  {String} [value]
   *
   * @return {String}
   */
  function attr(node, name, value) {
    if (typeof name === 'string') {
      if (value !== undefined) {
        setAttribute(node, name, value);
      } else {
        return getAttribute(node, name);
      }
    } else {
      setAttributes(node, name);
    }
    return node;
  }

  /**
   * Taken from https://github.com/component/classes
   *
   * Without the component bits.
   */

  /**
   * toString reference.
   */

  const toString = Object.prototype.toString;

  /**
    * Wrap `el` in a `ClassList`.
    *
    * @param {Element} el
    * @return {ClassList}
    * @api public
    */

  function classes(el) {
    return new ClassList(el);
  }
  function ClassList(el) {
    if (!el || !el.nodeType) {
      throw new Error('A DOM element reference is required');
    }
    this.el = el;
    this.list = el.classList;
  }

  /**
    * Add class `name` if not already present.
    *
    * @param {String} name
    * @return {ClassList}
    * @api public
    */

  ClassList.prototype.add = function (name) {
    this.list.add(name);
    return this;
  };

  /**
    * Remove class `name` when present, or
    * pass a regular expression to remove
    * any which match.
    *
    * @param {String|RegExp} name
    * @return {ClassList}
    * @api public
    */

  ClassList.prototype.remove = function (name) {
    if ('[object RegExp]' == toString.call(name)) {
      return this.removeMatching(name);
    }
    this.list.remove(name);
    return this;
  };

  /**
    * Remove all classes matching `re`.
    *
    * @param {RegExp} re
    * @return {ClassList}
    * @api private
    */

  ClassList.prototype.removeMatching = function (re) {
    const arr = this.array();
    for (let i = 0; i < arr.length; i++) {
      if (re.test(arr[i])) {
        this.remove(arr[i]);
      }
    }
    return this;
  };

  /**
    * Toggle class `name`, can force state via `force`.
    *
    * For browsers that support classList, but do not support `force` yet,
    * the mistake will be detected and corrected.
    *
    * @param {String} name
    * @param {Boolean} force
    * @return {ClassList}
    * @api public
    */

  ClassList.prototype.toggle = function (name, force) {
    if ('undefined' !== typeof force) {
      if (force !== this.list.toggle(name, force)) {
        this.list.toggle(name); // toggle again to correct
      }
    } else {
      this.list.toggle(name);
    }
    return this;
  };

  /**
    * Return an array of classes.
    *
    * @return {Array}
    * @api public
    */

  ClassList.prototype.array = function () {
    return Array.from(this.list);
  };

  /**
    * Check if class `name` is present.
    *
    * @param {String} name
    * @return {ClassList}
    * @api public
    */

  ClassList.prototype.has = ClassList.prototype.contains = function (name) {
    return this.list.contains(name);
  };
  var ns = {
    svg: 'http://www.w3.org/2000/svg'
  };

  /**
   * DOM parsing utility
   */

  var SVG_START = '<svg xmlns="' + ns.svg + '"';
  function parse(svg) {
    var unwrap = false;

    // ensure we import a valid svg document
    if (svg.substring(0, 4) === '<svg') {
      if (svg.indexOf(ns.svg) === -1) {
        svg = SVG_START + svg.substring(4);
      }
    } else {
      // namespace svg
      svg = SVG_START + '>' + svg + '</svg>';
      unwrap = true;
    }
    var parsed = parseDocument(svg);
    if (!unwrap) {
      return parsed;
    }
    var fragment = document.createDocumentFragment();
    var parent = parsed.firstChild;
    while (parent.firstChild) {
      fragment.appendChild(parent.firstChild);
    }
    return fragment;
  }
  function parseDocument(svg) {
    var parser;

    // parse
    parser = new DOMParser();
    parser.async = false;
    return parser.parseFromString(svg, 'text/xml');
  }

  /**
   * Create utility for SVG elements
   */

  /**
   * Create a specific type from name or SVG markup.
   *
   * @param {String} name the name or markup of the element
   * @param {Object} [attrs] attributes to set on the element
   *
   * @returns {SVGElement}
   */
  function create$2(name, attrs) {
    var element;
    name = name.trim();
    if (name.charAt(0) === '<') {
      element = parse(name).firstChild;
      element = document.importNode(element, true);
    } else {
      element = document.createElementNS(ns.svg, name);
    }
    if (attrs) {
      attr(element, attrs);
    }
    return element;
  }

  /**
   * Geometry helpers
   */

  // fake node used to instantiate svg geometry elements
  var node = null;
  function getNode() {
    if (node === null) {
      node = create$2('svg');
    }
    return node;
  }
  function extend$1(object, props) {
    var i,
      k,
      keys = Object.keys(props);
    for (i = 0; k = keys[i]; i++) {
      object[k] = props[k];
    }
    return object;
  }

  /**
   * Create matrix via args.
   *
   * @example
   *
   * createMatrix({ a: 1, b: 1 });
   * createMatrix();
   * createMatrix(1, 2, 0, 0, 30, 20);
   *
   * @return {SVGMatrix}
   */
  function createMatrix(a, b, c, d, e, f) {
    var matrix = getNode().createSVGMatrix();
    switch (arguments.length) {
      case 0:
        return matrix;
      case 1:
        return extend$1(matrix, a);
      case 6:
        return extend$1(matrix, {
          a: a,
          b: b,
          c: c,
          d: d,
          e: e,
          f: f
        });
    }
  }
  function createTransform(matrix) {
    {
      return getNode().createSVGTransform();
    }
  }

  /**
   * Serialization util
   */

  var TEXT_ENTITIES = /([&<>]{1})/g;
  var ATTR_ENTITIES = /([&<>\n\r"]{1})/g;
  var ENTITY_REPLACEMENT = {
    '&': '&amp;',
    '<': '&lt;',
    '>': '&gt;',
    '"': '\''
  };
  function escape(str, pattern) {
    function replaceFn(match, entity) {
      return ENTITY_REPLACEMENT[entity] || entity;
    }
    return str.replace(pattern, replaceFn);
  }
  function serialize(node, output) {
    var i, len, attrMap, attrNode, childNodes;
    switch (node.nodeType) {
      // TEXT
      case 3:
        // replace special XML characters
        output.push(escape(node.textContent, TEXT_ENTITIES));
        break;

      // ELEMENT
      case 1:
        output.push('<', node.tagName);
        if (node.hasAttributes()) {
          attrMap = node.attributes;
          for (i = 0, len = attrMap.length; i < len; ++i) {
            attrNode = attrMap.item(i);
            output.push(' ', attrNode.name, '="', escape(attrNode.value, ATTR_ENTITIES), '"');
          }
        }
        if (node.hasChildNodes()) {
          output.push('>');
          childNodes = node.childNodes;
          for (i = 0, len = childNodes.length; i < len; ++i) {
            serialize(childNodes.item(i), output);
          }
          output.push('</', node.tagName, '>');
        } else {
          output.push('/>');
        }
        break;

      // COMMENT
      case 8:
        output.push('<!--', escape(node.nodeValue, TEXT_ENTITIES), '-->');
        break;

      // CDATA
      case 4:
        output.push('<![CDATA[', node.nodeValue, ']]>');
        break;
      default:
        throw new Error('unable to handle node ' + node.nodeType);
    }
    return output;
  }
  function get(element) {
    var child = element.firstChild,
      output = [];
    while (child) {
      serialize(child, output);
      child = child.nextSibling;
    }
    return output.join('');
  }
  function innerSVG(element, svg) {
    {
      return get(element);
    }
  }
  function remove$3(element) {
    var parent = element.parentNode;
    if (parent) {
      parent.removeChild(element);
    }
    return element;
  }

  /**
   * transform accessor utility
   */

  function wrapMatrix(transformList, transform) {
    if (transform instanceof SVGMatrix) {
      return transformList.createSVGTransformFromMatrix(transform);
    }
    return transform;
  }
  function setTransforms(transformList, transforms) {
    var i, t;
    transformList.clear();
    for (i = 0; t = transforms[i]; i++) {
      transformList.appendItem(wrapMatrix(transformList, t));
    }
  }

  /**
   * Get or set the transforms on the given node.
   *
   * @param {SVGElement} node
   * @param  {SVGTransform|SVGMatrix|Array<SVGTransform|SVGMatrix>} [transforms]
   *
   * @return {SVGTransform} the consolidated transform
   */
  function transform(node, transforms) {
    var transformList = node.transform.baseVal;
    if (transforms) {
      if (!Array.isArray(transforms)) {
        transforms = [transforms];
      }
      setTransforms(transformList, transforms);
    }
    return transformList.consolidate();
  }

  /**
   * @typedef {(string|number)[]} Component
   *
   * @typedef {import('./Types.js').Point} Point
   */

  /**
   * @param {Component[] | Component[][]} elements
   *
   * @return {string}
   */
  function componentsToPath(elements) {
    return elements.flat().join(',').replace(/,?([A-Za-z]),?/g, '$1');
  }

  /**
   * @param {Point} point
   *
   * @return {Component[]}
   */
  function move(point) {
    return ['M', point.x, point.y];
  }

  /**
   * @param {Point} point
   *
   * @return {Component[]}
   */
  function lineTo(point) {
    return ['L', point.x, point.y];
  }

  /**
   * @param {Point} p1
   * @param {Point} p2
   * @param {Point} p3
   *
   * @return {Component[]}
   */
  function curveTo(p1, p2, p3) {
    return ['C', p1.x, p1.y, p2.x, p2.y, p3.x, p3.y];
  }

  /**
   * @param {Point[]} waypoints
   * @param {number} [cornerRadius]
   * @return {Component[][]}
   */
  function drawPath(waypoints, cornerRadius) {
    const pointCount = waypoints.length;
    const path = [move(waypoints[0])];
    for (let i = 1; i < pointCount; i++) {
      const pointBefore = waypoints[i - 1];
      const point = waypoints[i];
      const pointAfter = waypoints[i + 1];
      if (!pointAfter || !cornerRadius) {
        path.push(lineTo(point));
        continue;
      }
      const effectiveRadius = Math.min(cornerRadius, vectorLength(point.x - pointBefore.x, point.y - pointBefore.y), vectorLength(pointAfter.x - point.x, pointAfter.y - point.y));
      if (!effectiveRadius) {
        path.push(lineTo(point));
        continue;
      }
      const beforePoint = getPointAtLength(point, pointBefore, effectiveRadius);
      const beforePoint2 = getPointAtLength(point, pointBefore, effectiveRadius * .5);
      const afterPoint = getPointAtLength(point, pointAfter, effectiveRadius);
      const afterPoint2 = getPointAtLength(point, pointAfter, effectiveRadius * .5);
      path.push(lineTo(beforePoint));
      path.push(curveTo(beforePoint2, afterPoint2, afterPoint));
    }
    return path;
  }
  function getPointAtLength(start, end, length) {
    const deltaX = end.x - start.x;
    const deltaY = end.y - start.y;
    const totalLength = vectorLength(deltaX, deltaY);
    const percent = length / totalLength;
    return {
      x: start.x + deltaX * percent,
      y: start.y + deltaY * percent
    };
  }
  function vectorLength(x, y) {
    return Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
  }

  /**
   * @param {Point[]} points
   * @param {number|Object} [attrs]
   * @param {number} [radius]
   *
   * @return {SVGElement}
   */
  function createLine(points, attrs, radius) {
    if (isNumber$1(attrs)) {
      radius = attrs;
      attrs = null;
    }
    if (!attrs) {
      attrs = {};
    }
    const line = create$2('path', attrs);
    if (isNumber$1(radius)) {
      line.dataset.cornerRadius = String(radius);
    }
    return updateLine(line, points);
  }

  /**
   * @param {SVGElement} gfx
   * @param {Point[]} points
   *
   * @return {SVGElement}
   */
  function updateLine(gfx, points) {
    const cornerRadius = parseInt(gfx.dataset.cornerRadius, 10) || 0;
    attr(gfx, {
      d: componentsToPath(drawPath(points, cornerRadius))
    });
    return gfx;
  }

  /**
   * Returns the surrounding bbox for all elements in
   * the array or the element primitive.
   *
   * @param {Element|Element[]} elements
   * @param {boolean} [stopRecursion=false]
   *
   * @return {Rect}
   */
  function getBBox(elements, stopRecursion) {
    stopRecursion = !!stopRecursion;
    if (!isArray$2(elements)) {
      elements = [elements];
    }
    var minX, minY, maxX, maxY;
    forEach(elements, function (element) {
      // If element is a connection the bbox must be computed first
      var bbox = element;
      if (element.waypoints && !stopRecursion) {
        bbox = getBBox(element.waypoints, true);
      }
      var x = bbox.x,
        y = bbox.y,
        height = bbox.height || 0,
        width = bbox.width || 0;
      if (x < minX || minX === undefined) {
        minX = x;
      }
      if (y < minY || minY === undefined) {
        minY = y;
      }
      if (x + width > maxX || maxX === undefined) {
        maxX = x + width;
      }
      if (y + height > maxY || maxY === undefined) {
        maxY = y + height;
      }
    });
    return {
      x: minX,
      y: minY,
      height: maxY - minY,
      width: maxX - minX
    };
  }

  /**
   * Get the element's type
   *
   * @param {Element} element
   *
   * @return {'connection' | 'shape' | 'root'}
   */
  function getType(element) {
    if ('waypoints' in element) {
      return 'connection';
    }
    if ('x' in element) {
      return 'shape';
    }
    return 'root';
  }

  /**
   * @param {Element} element
   *
   * @return {boolean}
   */
  function isFrameElement(element) {
    return !!(element && element.isFrame);
  }

  /**
   * @typedef {import('../core/EventBus.js').default} EventBus
   * @typedef {import('./Styles.js').default} Styles
   */

  // apply default renderer with lowest possible priority
  // so that it only kicks in if noone else could render
  var DEFAULT_RENDER_PRIORITY = 1;

  /**
   * The default renderer used for shapes and connections.
   *
   * @param {EventBus} eventBus
   * @param {Styles} styles
   */
  function DefaultRenderer(eventBus, styles) {
    BaseRenderer.call(this, eventBus, DEFAULT_RENDER_PRIORITY);
    this.CONNECTION_STYLE = styles.style(['no-fill'], {
      strokeWidth: 5,
      stroke: 'fuchsia'
    });
    this.SHAPE_STYLE = styles.style({
      fill: 'white',
      stroke: 'fuchsia',
      strokeWidth: 2
    });
    this.FRAME_STYLE = styles.style(['no-fill'], {
      stroke: 'fuchsia',
      strokeDasharray: 4,
      strokeWidth: 2
    });
  }
  e(DefaultRenderer, BaseRenderer);

  /**
   * @private
   */
  DefaultRenderer.prototype.canRender = function () {
    return true;
  };

  /**
   * @private
   */
  DefaultRenderer.prototype.drawShape = function drawShape(visuals, element, attrs) {
    var rect = create$2('rect');
    attr(rect, {
      x: 0,
      y: 0,
      width: element.width || 0,
      height: element.height || 0
    });
    if (isFrameElement(element)) {
      attr(rect, assign$1({}, this.FRAME_STYLE, attrs || {}));
    } else {
      attr(rect, assign$1({}, this.SHAPE_STYLE, attrs || {}));
    }
    append(visuals, rect);
    return rect;
  };

  /**
   * @private
   */
  DefaultRenderer.prototype.drawConnection = function drawConnection(visuals, connection, attrs) {
    var line = createLine(connection.waypoints, assign$1({}, this.CONNECTION_STYLE, attrs || {}));
    append(visuals, line);
    return line;
  };

  /**
   * @private
   */
  DefaultRenderer.prototype.getShapePath = function getShapePath(shape) {
    var x = shape.x,
      y = shape.y,
      width = shape.width,
      height = shape.height;
    var shapePath = [['M', x, y], ['l', width, 0], ['l', 0, height], ['l', -width, 0], ['z']];
    return componentsToPath(shapePath);
  };

  /**
   * @private
   */
  DefaultRenderer.prototype.getConnectionPath = function getConnectionPath(connection) {
    var waypoints = connection.waypoints;
    var idx,
      point,
      connectionPath = [];
    for (idx = 0; point = waypoints[idx]; idx++) {
      // take invisible docking into account
      // when creating the path
      point = point.original || point;
      connectionPath.push([idx === 0 ? 'M' : 'L', point.x, point.y]);
    }
    return componentsToPath(connectionPath);
  };
  DefaultRenderer.$inject = ['eventBus', 'styles'];

  /**
   * A component that manages shape styles
   */
  function Styles() {
    var defaultTraits = {
      'no-fill': {
        fill: 'none'
      },
      'no-border': {
        strokeOpacity: 0.0
      },
      'no-events': {
        pointerEvents: 'none'
      }
    };
    var self = this;

    /**
     * Builds a style definition from a className, a list of traits and an object
     * of additional attributes.
     *
     * @param {string} className
     * @param {string[]} [traits]
     * @param {Object} [additionalAttrs]
     *
     * @return {Object} the style definition
     */
    this.cls = function (className, traits, additionalAttrs) {
      var attrs = this.style(traits, additionalAttrs);
      return assign$1(attrs, {
        'class': className
      });
    };

    /**
     * Builds a style definition from a list of traits and an object of additional
     * attributes.
     *
     * @param {string[]} [traits]
     * @param {Object} additionalAttrs
     *
     * @return {Object} the style definition
     */
    this.style = function (traits, additionalAttrs) {
      if (!isArray$2(traits) && !additionalAttrs) {
        additionalAttrs = traits;
        traits = [];
      }
      var attrs = reduce(traits, function (attrs, t) {
        return assign$1(attrs, defaultTraits[t] || {});
      }, {});
      return additionalAttrs ? assign$1(attrs, additionalAttrs) : attrs;
    };

    /**
     * Computes a style definition from a list of traits and an object of
     * additional attributes, with custom style definition object.
     *
     * @param {Object} custom
     * @param {string[]} [traits]
     * @param {Object} defaultStyles
     *
     * @return {Object} the style definition
     */
    this.computeStyle = function (custom, traits, defaultStyles) {
      if (!isArray$2(traits)) {
        defaultStyles = traits;
        traits = [];
      }
      return self.style(traits || [], assign$1({}, defaultStyles, custom || {}));
    };
  }

  /**
   * @type { import('didi').ModuleDeclaration }
   */
  var DrawModule$1 = {
    __init__: ['defaultRenderer'],
    defaultRenderer: ['type', DefaultRenderer],
    styles: ['type', Styles]
  };

  /**
   * Failsafe remove an element from a collection
   *
   * @param {Array<Object>} [collection]
   * @param {Object} [element]
   *
   * @return {number} the previous index of the element
   */
  function remove$2(collection, element) {
    if (!collection || !element) {
      return -1;
    }
    var idx = collection.indexOf(element);
    if (idx !== -1) {
      collection.splice(idx, 1);
    }
    return idx;
  }

  /**
   * Fail save add an element to the given connection, ensuring
   * it does not yet exist.
   *
   * @param {Array<Object>} collection
   * @param {Object} element
   * @param {number} [idx]
   */
  function add$2(collection, element, idx) {
    if (!collection || !element) {
      return;
    }
    if (typeof idx !== 'number') {
      idx = -1;
    }
    var currentIdx = collection.indexOf(element);
    if (currentIdx !== -1) {
      if (currentIdx === idx) {
        // nothing to do, position has not changed
        return;
      } else {
        if (idx !== -1) {
          // remove from current position
          collection.splice(currentIdx, 1);
        } else {
          // already exists in collection
          return;
        }
      }
    }
    if (idx !== -1) {
      // insert at specified position
      collection.splice(idx, 0, element);
    } else {
      // push to end
      collection.push(element);
    }
  }

  /**
   * Convert the given bounds to a { top, left, bottom, right } descriptor.
   *
   * @param {Point|Rect} bounds
   *
   * @return {RectTRBL}
   */
  function asTRBL(bounds) {
    return {
      top: bounds.y,
      right: bounds.x + (bounds.width || 0),
      bottom: bounds.y + (bounds.height || 0),
      left: bounds.x
    };
  }

  /**
   * @typedef {import('./Types.js').ConnectionLike} ConnectionLike
   * @typedef {import('./Types.js').RootLike} RootLike
   * @typedef {import('./Types.js').ParentLike } ParentLike
   * @typedef {import('./Types.js').ShapeLike} ShapeLike
   *
   * @typedef {ShapeLike|ConnectionLike|RootLike|string} ElementOrIdentifier
   *
   * @typedef { {
   *   container?: HTMLElement;
   *   deferUpdate?: boolean;
   *   width?: number;
   *   height?: number;
   *   autoFocus?: boolean;
   * } } CanvasConfig
   * @typedef { {
   *   group: SVGElement;
   *   index: number;
   *   visible: boolean;
   * } } CanvasLayer
   * @typedef { {
   *   [key: string]: CanvasLayer;
   * } } CanvasLayers
   * @typedef { {
   *   rootElement: ShapeLike;
   *   layer: CanvasLayer;
   * } } CanvasPlane
   * @typedef { {
   *   scale: number;
   *   inner: Rect;
   *   outer: Dimensions;
   * } & Rect } CanvasViewbox
   *
   * @typedef {import('./ElementRegistry.js').default} ElementRegistry
   * @typedef {import('./EventBus.js').default} EventBus
   * @typedef {import('./GraphicsFactory.js').default} GraphicsFactory
   *
   * @typedef {import('../util/Types.js').Dimensions} Dimensions
   * @typedef {import('../util/Types.js').Point} Point
   * @typedef {import('../util/Types.js').Rect} Rect
   * @typedef {import('../util/Types.js').RectTRBL} RectTRBL
   * @typedef {import('../util/Types.js').ScrollDelta} ScrollDelta
   */

  function round(number, resolution) {
    return Math.round(number * resolution) / resolution;
  }
  function ensurePx(number) {
    return isNumber$1(number) ? number + 'px' : number;
  }
  function findRoot(element) {
    while (element.parent) {
      element = element.parent;
    }
    return element;
  }

  /**
   * Creates a HTML container element for a SVG element with
   * the given configuration
   *
   * @param {CanvasConfig} options
   *
   * @return {HTMLElement} the container element
   */
  function createContainer(options) {
    options = assign$1({}, {
      width: '100%',
      height: '100%'
    }, options);
    const container = options.container || document.body;

    // create a <div> around the svg element with the respective size
    // this way we can always get the correct container size
    // (this is impossible for <svg> elements at the moment)
    const parent = document.createElement('div');
    parent.setAttribute('class', 'djs-container djs-parent');
    assign(parent, {
      position: 'relative',
      overflow: 'hidden',
      width: ensurePx(options.width),
      height: ensurePx(options.height)
    });
    container.appendChild(parent);
    return parent;
  }
  function createGroup(parent, cls, childIndex) {
    const group = create$2('g');
    classes(group).add(cls);
    const index = childIndex !== undefined ? childIndex : parent.childNodes.length - 1;

    // must ensure second argument is node or _null_
    // cf. https://developer.mozilla.org/en-US/docs/Web/API/Node/insertBefore
    parent.insertBefore(group, parent.childNodes[index] || null);
    return group;
  }
  const BASE_LAYER = 'base';

  // render plane contents behind utility layers
  const PLANE_LAYER_INDEX = 0;
  const UTILITY_LAYER_INDEX = 1;
  const REQUIRED_MODEL_ATTRS = {
    shape: ['x', 'y', 'width', 'height'],
    connection: ['waypoints']
  };

  /**
   * The main drawing canvas.
   *
   * @class
   * @constructor
   *
   * @emits Canvas#canvas.init
   *
   * @param {CanvasConfig|null} config
   * @param {EventBus} eventBus
   * @param {GraphicsFactory} graphicsFactory
   * @param {ElementRegistry} elementRegistry
   */
  function Canvas(config, eventBus, graphicsFactory, elementRegistry) {
    this._eventBus = eventBus;
    this._elementRegistry = elementRegistry;
    this._graphicsFactory = graphicsFactory;

    /**
     * @type {number}
     */
    this._rootsIdx = 0;

    /**
     * @type {CanvasLayers}
     */
    this._layers = {};

    /**
     * @type {CanvasPlane[]}
     */
    this._planes = [];

    /**
     * @type {RootLike|null}
     */
    this._rootElement = null;

    /**
     * @type {boolean}
     */
    this._focused = false;
    this._init(config || {});
  }
  Canvas.$inject = ['config.canvas', 'eventBus', 'graphicsFactory', 'elementRegistry'];

  /**
   * Creates a <svg> element that is wrapped into a <div>.
   * This way we are always able to correctly figure out the size of the svg element
   * by querying the parent node.

   * (It is not possible to get the size of a svg element cross browser @ 2014-04-01)

   * <div class="djs-container" style="width: {desired-width}, height: {desired-height}">
   *   <svg width="100%" height="100%">
   *    ...
   *   </svg>
   * </div>
   *
   * @param {CanvasConfig} config
   */
  Canvas.prototype._init = function (config) {
    const eventBus = this._eventBus;

    // html container
    const container = this._container = createContainer(config);
    const svg = this._svg = create$2('svg');
    attr(svg, {
      width: '100%',
      height: '100%'
    });
    attr$1(svg, 'tabindex', 0);
    config.autoFocus && eventBus.on('element.hover', () => {
      this.restoreFocus();
    });
    eventBus.on('element.mousedown', 500, event => {
      this.focus();
    });
    svg.addEventListener('focusin', () => {
      this._setFocused(true);
    });
    svg.addEventListener('focusout', () => {
      this._setFocused(false);
    });
    svg.addEventListener('mouseover', () => {
      this._eventBus.fire('canvas.mouseover');
    });
    svg.addEventListener('mouseout', () => {
      this._eventBus.fire('canvas.mouseout');
    });
    append(container, svg);
    const viewport = this._viewport = createGroup(svg, 'viewport');

    // debounce canvas.viewbox.changed events when deferUpdate is set
    // to help with potential performance issues
    if (config.deferUpdate) {
      this._viewboxChanged = debounce(this._viewboxChanged, 300);
    }

    /**
     * Schedule focus restoration.
     *
     * @type {import('min-dash').DebouncedFunction<typeof this.restoreFocus>}
     */
    this._restoreFocus = debounce(this._restoreFocus, 0);
    eventBus.on('diagram.init', () => {
      /**
       * An event indicating that the canvas is ready to be drawn on.
       *
       * @memberOf Canvas
       *
       * @event canvas.init
       *
       * @type {Object}
       * @property {SVGElement} svg the created svg element
       * @property {SVGElement} viewport the direct parent of diagram elements and shapes
       */
      eventBus.fire('canvas.init', {
        svg: svg,
        viewport: viewport
      });
    });

    // reset viewbox on shape changes to
    // recompute the viewbox
    eventBus.on(['shape.added', 'connection.added', 'shape.removed', 'connection.removed', 'elements.changed', 'root.set'], () => {
      delete this._cachedViewbox;
    });
    eventBus.on('diagram.destroy', 500, this._destroy, this);
    eventBus.on('diagram.clear', 500, this._clear, this);
  };
  Canvas.prototype._destroy = function () {
    this._restoreFocus.cancel();
    this._eventBus.fire('canvas.destroy', {
      svg: this._svg,
      viewport: this._viewport
    });
    const parent = this._container.parentNode;
    if (parent) {
      parent.removeChild(this._container);
    }
    delete this._svg;
    delete this._container;
    delete this._layers;
    delete this._planes;
    delete this._rootElement;
    delete this._viewport;
  };
  Canvas.prototype._setFocused = function (focused) {
    if (focused == this._focused) {
      return;
    }
    this._focused = focused;
    this._eventBus.fire('canvas.focus.changed', {
      focused
    });
  };
  Canvas.prototype._clear = function () {
    const allElements = this._elementRegistry.getAll();

    // remove all elements
    allElements.forEach(element => {
      const type = getType(element);
      if (type === 'root') {
        this.removeRootElement(element);
      } else {
        this._removeElement(element, type);
      }
    });

    // remove all planes
    this._planes = [];
    this._rootElement = null;

    // force recomputation of view box
    delete this._cachedViewbox;
  };

  /**
   * Sets focus on the canvas SVG element.
   */
  Canvas.prototype.focus = function () {
    this._svg.focus({
      preventScroll: true
    });
    this._setFocused(true);
  };

  /**
   * Restores focus on the canvas SVG element if `document.body` is
   * currently focused.
   *
   * Safely executes on the next render cycle - never prevents pending
   * (in flight) user clicks.
   */
  Canvas.prototype.restoreFocus = function () {
    this._restoreFocus();
  };
  Canvas.prototype._restoreFocus = function () {
    if (document.activeElement === document.body) {
      this.focus();
    }
  };

  /**
  * Returns true if the canvas is focused.
  *
  * @return {boolean}
  */
  Canvas.prototype.isFocused = function () {
    return this._focused;
  };

  /**
   * Returns the default layer on which
   * all elements are drawn.
   *
   * @return {SVGElement}  The SVG element of the layer.
   */
  Canvas.prototype.getDefaultLayer = function () {
    return this.getLayer(BASE_LAYER, PLANE_LAYER_INDEX);
  };

  /**
   * Returns a layer that is used to draw elements
   * or annotations on it.
   *
   * Non-existing layers retrieved through this method
   * will be created. During creation, the optional index
   * may be used to create layers below or above existing layers.
   * A layer with a certain index is always created above all
   * existing layers with the same index.
   *
   * @param {string} name The name of the layer.
   * @param {number} [index] The index of the layer.
   *
   * @return {SVGElement} The SVG element of the layer.
   */
  Canvas.prototype.getLayer = function (name, index) {
    if (!name) {
      throw new Error('must specify a name');
    }
    let layer = this._layers[name];
    if (!layer) {
      layer = this._layers[name] = this._createLayer(name, index);
    }

    // throw an error if layer creation / retrival is
    // requested on different index
    if (typeof index !== 'undefined' && layer.index !== index) {
      throw new Error('layer <' + name + '> already created at index <' + index + '>');
    }
    return layer.group;
  };

  /**
   * For a given index, return the number of layers that have a higher index and
   * are visible.
   *
   * This is used to determine the node a layer should be inserted at.
   *
   * @param {number} index
   *
   * @return {number}
   */
  Canvas.prototype._getChildIndex = function (index) {
    return reduce(this._layers, function (childIndex, layer) {
      if (layer.visible && index >= layer.index) {
        childIndex++;
      }
      return childIndex;
    }, 0);
  };

  /**
   * Creates a given layer and returns it.
   *
   * @param {string} name
   * @param {number} [index=0]
   *
   * @return {CanvasLayer}
   */
  Canvas.prototype._createLayer = function (name, index) {
    if (typeof index === 'undefined') {
      index = UTILITY_LAYER_INDEX;
    }
    const childIndex = this._getChildIndex(index);
    return {
      group: createGroup(this._viewport, 'layer-' + name, childIndex),
      index: index,
      visible: true
    };
  };

  /**
   * Shows a given layer.
   *
   * @param {string} name The name of the layer.
   *
   * @return {SVGElement} The SVG element of the layer.
   */
  Canvas.prototype.showLayer = function (name) {
    if (!name) {
      throw new Error('must specify a name');
    }
    const layer = this._layers[name];
    if (!layer) {
      throw new Error('layer <' + name + '> does not exist');
    }
    const viewport = this._viewport;
    const group = layer.group;
    const index = layer.index;
    if (layer.visible) {
      return group;
    }
    const childIndex = this._getChildIndex(index);
    viewport.insertBefore(group, viewport.childNodes[childIndex] || null);
    layer.visible = true;
    return group;
  };

  /**
   * Hides a given layer.
   *
   * @param {string} name The name of the layer.
   *
   * @return {SVGElement} The SVG element of the layer.
   */
  Canvas.prototype.hideLayer = function (name) {
    if (!name) {
      throw new Error('must specify a name');
    }
    const layer = this._layers[name];
    if (!layer) {
      throw new Error('layer <' + name + '> does not exist');
    }
    const group = layer.group;
    if (!layer.visible) {
      return group;
    }
    remove$3(group);
    layer.visible = false;
    return group;
  };
  Canvas.prototype._removeLayer = function (name) {
    const layer = this._layers[name];
    if (layer) {
      delete this._layers[name];
      remove$3(layer.group);
    }
  };

  /**
   * Returns the currently active layer. Can be null.
   *
   * @return {CanvasLayer|null} The active layer of `null`.
   */
  Canvas.prototype.getActiveLayer = function () {
    const plane = this._findPlaneForRoot(this.getRootElement());
    if (!plane) {
      return null;
    }
    return plane.layer;
  };

  /**
   * Returns the plane which contains the given element(s).
   *
   * If multiple elements are passed, the shared plane is returned
   * (or undefined if no shared plane exists).
   *
   * @param {ElementOrIdentifier|ElementOrIdentifier[]} element
   *
   * @return {RootLike|undefined} The root of the element.
   */
  Canvas.prototype.findRoot = function (element) {
    const elements = this._resolveElements(element);
    let root;
    for (const element of elements) {
      const plane = this._findPlaneForRoot(findRoot(element));
      if (!plane) {
        return;
      }
      if (root && plane.rootElement !== root) {
        // no shared root
        return undefined;
      }
      root = plane.rootElement;
    }
    return root;
  };

  /**
   * Return a list of all root elements on the diagram.
   *
   * @return {(RootLike)[]} The list of root elements.
   */
  Canvas.prototype.getRootElements = function () {
    return this._planes.map(function (plane) {
      return plane.rootElement;
    });
  };
  Canvas.prototype._findPlaneForRoot = function (rootElement) {
    return find$1(this._planes, function (plane) {
      return plane.rootElement === rootElement;
    });
  };

  /**
   * @param {ElementOrIdentifier} element
   *
   * @return {ShapeLike|ConnectionLike|RootLike|undefined}
   */
  Canvas.prototype._resolveElement = function (element) {
    if (typeof element === 'string') {
      return this._elementRegistry.get(element);
    }
    return element;
  };

  /**
   * @param {ElementOrIdentifier|ElementOrIdentifier[]} elements
   *
   * @return {Array<ShapeLike|ConnectionLike|RootLike>}
   */
  Canvas.prototype._resolveElements = function (elements) {
    if (!isArray$2(elements)) {
      elements = [elements];
    }
    return elements.map(element => this._resolveElement(element)).filter(Boolean);
  };

  /**
   * Returns the html element that encloses the
   * drawing canvas.
   *
   * @return {HTMLElement} The HTML element of the container.
   */
  Canvas.prototype.getContainer = function () {
    return this._container;
  };

  // markers //////////////////////

  Canvas.prototype._updateMarker = function (element, marker, add) {
    let container;
    element = this._resolveElement(element);
    element.markers = element.markers || new Set();

    // we need to access all
    container = this._elementRegistry._elements[element.id];
    if (!container) {
      return;
    }
    forEach([container.gfx, container.secondaryGfx], function (gfx) {
      if (gfx) {
        // invoke either addClass or removeClass based on mode
        if (add) {
          element.markers.add(marker);
          classes(gfx).add(marker);
        } else {
          element.markers.delete(marker);
          classes(gfx).remove(marker);
        }
      }
    });

    /**
     * An event indicating that a marker has been updated for an element
     *
     * @event element.marker.update
     * @type {Object}
     * @property {Element} element the shape
     * @property {SVGElement} gfx the graphical representation of the shape
     * @property {string} marker
     * @property {boolean} add true if the marker was added, false if it got removed
     */
    this._eventBus.fire('element.marker.update', {
      element: element,
      gfx: container.gfx,
      marker: marker,
      add: !!add
    });
  };

  /**
   * Adds a marker to an element (basically a css class).
   *
   * Fires the element.marker.update event, making it possible to
   * integrate extension into the marker life-cycle, too.
   *
   * @example
   *
   * ```javascript
   * canvas.addMarker('foo', 'some-marker');
   *
   * const fooGfx = canvas.getGraphics('foo');
   *
   * fooGfx; // <g class="... some-marker"> ... </g>
   * ```
   *
   * @param {ShapeLike|ConnectionLike|string} element The element or its ID.
   * @param {string} marker The marker.
   */
  Canvas.prototype.addMarker = function (element, marker) {
    this._updateMarker(element, marker, true);
  };

  /**
   * Remove a marker from an element.
   *
   * Fires the element.marker.update event, making it possible to
   * integrate extension into the marker life-cycle, too.
   *
   * @param {ShapeLike|ConnectionLike|string} element The element or its ID.
   * @param {string} marker The marker.
   */
  Canvas.prototype.removeMarker = function (element, marker) {
    this._updateMarker(element, marker, false);
  };

  /**
   * Check whether an element has a given marker.
   *
   * @param {ShapeLike|ConnectionLike|string} element The element or its ID.
   * @param {string} marker The marker.
   */
  Canvas.prototype.hasMarker = function (element, marker) {
    element = this._resolveElement(element);
    if (!element.markers) {
      return false;
    }
    return element.markers.has(marker);
  };

  /**
   * Toggles a marker on an element.
   *
   * Fires the element.marker.update event, making it possible to
   * integrate extension into the marker life-cycle, too.
   *
   * @param {ShapeLike|ConnectionLike|string} element The element or its ID.
   * @param {string} marker The marker.
   */
  Canvas.prototype.toggleMarker = function (element, marker) {
    if (this.hasMarker(element, marker)) {
      this.removeMarker(element, marker);
    } else {
      this.addMarker(element, marker);
    }
  };

  /**
   * Returns the current root element.
   *
   * Supports two different modes for handling root elements:
   *
   * 1. if no root element has been added before, an implicit root will be added
   * and returned. This is used in applications that don't require explicit
   * root elements.
   *
   * 2. when root elements have been added before calling `getRootElement`,
   * root elements can be null. This is used for applications that want to manage
   * root elements themselves.
   *
   * @return {RootLike} The current root element.
   */
  Canvas.prototype.getRootElement = function () {
    const rootElement = this._rootElement;

    // can return null if root elements are present but none was set yet
    if (rootElement || this._planes.length) {
      return rootElement;
    }
    return this.setRootElement(this.addRootElement(null));
  };

  /**
   * Adds a given root element and returns it.
   *
   * @param {RootLike} [rootElement] The root element to be added.
   *
   * @return {RootLike} The added root element or an implicit root element.
   */
  Canvas.prototype.addRootElement = function (rootElement) {
    const idx = this._rootsIdx++;
    if (!rootElement) {
      rootElement = {
        id: '__implicitroot_' + idx,
        children: [],
        isImplicit: true
      };
    }
    const layerName = rootElement.layer = 'root-' + idx;
    this._ensureValid('root', rootElement);
    const layer = this.getLayer(layerName, PLANE_LAYER_INDEX);
    this.hideLayer(layerName);
    this._addRoot(rootElement, layer);
    this._planes.push({
      rootElement: rootElement,
      layer: layer
    });
    return rootElement;
  };

  /**
   * Removes a given root element and returns it.
   *
   * @param {RootLike|string} rootElement element or element ID
   *
   * @return {RootLike|undefined} removed element
   */
  Canvas.prototype.removeRootElement = function (rootElement) {
    rootElement = this._resolveElement(rootElement);
    const plane = this._findPlaneForRoot(rootElement);
    if (!plane) {
      return;
    }

    // hook up life-cycle events
    this._removeRoot(rootElement);

    // clean up layer
    this._removeLayer(rootElement.layer);

    // clean up plane
    this._planes = this._planes.filter(function (plane) {
      return plane.rootElement !== rootElement;
    });

    // clean up active root
    if (this._rootElement === rootElement) {
      this._rootElement = null;
    }
    return rootElement;
  };

  /**
   * Sets a given element as the new root element for the canvas
   * and returns the new root element.
   *
   * @param {RootLike} rootElement The root element to be set.
   *
   * @return {RootLike} The set root element.
   */
  Canvas.prototype.setRootElement = function (rootElement) {
    if (rootElement === this._rootElement) {
      return rootElement;
    }
    let plane;
    if (!rootElement) {
      throw new Error('rootElement required');
    }
    plane = this._findPlaneForRoot(rootElement);

    // give set add semantics for backwards compatibility
    if (!plane) {
      rootElement = this.addRootElement(rootElement);
    }
    this._setRoot(rootElement);
    return rootElement;
  };
  Canvas.prototype._removeRoot = function (element) {
    const elementRegistry = this._elementRegistry,
      eventBus = this._eventBus;

    // simulate element remove event sequence
    eventBus.fire('root.remove', {
      element: element
    });
    eventBus.fire('root.removed', {
      element: element
    });
    elementRegistry.remove(element);
  };
  Canvas.prototype._addRoot = function (element, gfx) {
    const elementRegistry = this._elementRegistry,
      eventBus = this._eventBus;

    // resemble element add event sequence
    eventBus.fire('root.add', {
      element: element
    });
    elementRegistry.add(element, gfx);
    eventBus.fire('root.added', {
      element: element,
      gfx: gfx
    });
  };
  Canvas.prototype._setRoot = function (rootElement, layer) {
    const currentRoot = this._rootElement;
    if (currentRoot) {
      // un-associate previous root element <svg>
      this._elementRegistry.updateGraphics(currentRoot, null, true);

      // hide previous layer
      this.hideLayer(currentRoot.layer);
    }
    if (rootElement) {
      if (!layer) {
        layer = this._findPlaneForRoot(rootElement).layer;
      }

      // associate element with <svg>
      this._elementRegistry.updateGraphics(rootElement, this._svg, true);

      // show root layer
      this.showLayer(rootElement.layer);
    }
    this._rootElement = rootElement;
    this._eventBus.fire('root.set', {
      element: rootElement
    });
  };
  Canvas.prototype._ensureValid = function (type, element) {
    if (!element.id) {
      throw new Error('element must have an id');
    }
    if (this._elementRegistry.get(element.id)) {
      throw new Error('element <' + element.id + '> already exists');
    }
    const requiredAttrs = REQUIRED_MODEL_ATTRS[type];
    const valid = every(requiredAttrs, function (attr) {
      return typeof element[attr] !== 'undefined';
    });
    if (!valid) {
      throw new Error('must supply { ' + requiredAttrs.join(', ') + ' } with ' + type);
    }
  };
  Canvas.prototype._setParent = function (element, parent, parentIndex) {
    add$2(parent.children, element, parentIndex);
    element.parent = parent;
  };

  /**
   * Adds an element to the canvas.
   *
   * This wires the parent <-> child relationship between the element and
   * a explicitly specified parent or an implicit root element.
   *
   * During add it emits the events
   *
   *  * <{type}.add> (element, parent)
   *  * <{type}.added> (element, gfx)
   *
   * Extensions may hook into these events to perform their magic.
   *
   * @param {string} type
   * @param {ConnectionLike|ShapeLike} element
   * @param {ShapeLike} [parent]
   * @param {number} [parentIndex]
   *
   * @return {ConnectionLike|ShapeLike} The added element.
   */
  Canvas.prototype._addElement = function (type, element, parent, parentIndex) {
    parent = parent || this.getRootElement();
    const eventBus = this._eventBus,
      graphicsFactory = this._graphicsFactory;
    this._ensureValid(type, element);
    eventBus.fire(type + '.add', {
      element: element,
      parent: parent
    });
    this._setParent(element, parent, parentIndex);

    // create graphics
    const gfx = graphicsFactory.create(type, element, parentIndex);
    this._elementRegistry.add(element, gfx);

    // update its visual
    graphicsFactory.update(type, element, gfx);
    eventBus.fire(type + '.added', {
      element: element,
      gfx: gfx
    });
    return element;
  };

  /**
   * Adds a shape to the canvas.
   *
   * @param {ShapeLike} shape The shape to be added
   * @param {ParentLike} [parent] The shape's parent.
   * @param {number} [parentIndex] The index at which to add the shape to the parent's children.
   *
   * @return {ShapeLike} The added shape.
   */
  Canvas.prototype.addShape = function (shape, parent, parentIndex) {
    return this._addElement('shape', shape, parent, parentIndex);
  };

  /**
   * Adds a connection to the canvas.
   *
   * @param {ConnectionLike} connection The connection to be added.
   * @param {ParentLike} [parent] The connection's parent.
   * @param {number} [parentIndex] The index at which to add the connection to the parent's children.
   *
   * @return {ConnectionLike} The added connection.
   */
  Canvas.prototype.addConnection = function (connection, parent, parentIndex) {
    return this._addElement('connection', connection, parent, parentIndex);
  };

  /**
   * Internal remove element
   */
  Canvas.prototype._removeElement = function (element, type) {
    const elementRegistry = this._elementRegistry,
      graphicsFactory = this._graphicsFactory,
      eventBus = this._eventBus;
    element = elementRegistry.get(element.id || element);
    if (!element) {
      // element was removed already
      return;
    }
    eventBus.fire(type + '.remove', {
      element: element
    });
    graphicsFactory.remove(element);

    // unset parent <-> child relationship
    remove$2(element.parent && element.parent.children, element);
    element.parent = null;
    eventBus.fire(type + '.removed', {
      element: element
    });
    elementRegistry.remove(element);
    return element;
  };

  /**
   * Removes a shape from the canvas.
   *
   * @fires ShapeRemoveEvent
   * @fires ShapeRemovedEvent
   *
   * @param {ShapeLike|string} shape The shape or its ID.
   *
   * @return {ShapeLike} The removed shape.
   */
  Canvas.prototype.removeShape = function (shape) {
    /**
     * An event indicating that a shape is about to be removed from the canvas.
     *
     * @memberOf Canvas
     *
     * @event ShapeRemoveEvent
     * @type {Object}
     * @property {ShapeLike} element The shape.
     * @property {SVGElement} gfx The graphical element.
     */

    /**
     * An event indicating that a shape has been removed from the canvas.
     *
     * @memberOf Canvas
     *
     * @event ShapeRemovedEvent
     * @type {Object}
     * @property {ShapeLike} element The shape.
     * @property {SVGElement} gfx The graphical element.
     */
    return this._removeElement(shape, 'shape');
  };

  /**
   * Removes a connection from the canvas.
   *
   * @fires ConnectionRemoveEvent
   * @fires ConnectionRemovedEvent
   *
   * @param {ConnectionLike|string} connection The connection or its ID.
   *
   * @return {ConnectionLike} The removed connection.
   */
  Canvas.prototype.removeConnection = function (connection) {
    /**
     * An event indicating that a connection is about to be removed from the canvas.
     *
     * @memberOf Canvas
     *
     * @event ConnectionRemoveEvent
     * @type {Object}
     * @property {ConnectionLike} element The connection.
     * @property {SVGElement} gfx The graphical element.
     */

    /**
     * An event indicating that a connection has been removed from the canvas.
     *
     * @memberOf Canvas
     *
     * @event ConnectionRemovedEvent
     * @type {Object}
     * @property {ConnectionLike} element The connection.
     * @property {SVGElement} gfx The graphical element.
     */
    return this._removeElement(connection, 'connection');
  };

  /**
   * Returns the graphical element of an element.
   *
   * @param {ShapeLike|ConnectionLike|string} element The element or its ID.
   * @param {boolean} [secondary=false] Whether to return the secondary graphical element.
   *
   * @return {SVGElement} The graphical element.
   */
  Canvas.prototype.getGraphics = function (element, secondary) {
    return this._elementRegistry.getGraphics(element, secondary);
  };

  /**
   * Perform a viewbox update via a given change function.
   *
   * @param {Function} changeFn
   */
  Canvas.prototype._changeViewbox = function (changeFn) {
    // notify others of the upcoming viewbox change
    this._eventBus.fire('canvas.viewbox.changing');

    // perform actual change
    changeFn.apply(this);

    // reset the cached viewbox so that
    // a new get operation on viewbox or zoom
    // triggers a viewbox re-computation
    this._cachedViewbox = null;

    // notify others of the change; this step
    // may or may not be debounced
    this._viewboxChanged();
  };
  Canvas.prototype._viewboxChanged = function () {
    this._eventBus.fire('canvas.viewbox.changed', {
      viewbox: this.viewbox()
    });
  };

  /**
   * Gets or sets the view box of the canvas, i.e. the
   * area that is currently displayed.
   *
   * The getter may return a cached viewbox (if it is currently
   * changing). To force a recomputation, pass `false` as the first argument.
   *
   * @example
   *
   * ```javascript
   * canvas.viewbox({ x: 100, y: 100, width: 500, height: 500 })
   *
   * // sets the visible area of the diagram to (100|100) -> (600|100)
   * // and and scales it according to the diagram width
   *
   * const viewbox = canvas.viewbox(); // pass `false` to force recomputing the box.
   *
   * console.log(viewbox);
   * // {
   * //   inner: Dimensions,
   * //   outer: Dimensions,
   * //   scale,
   * //   x, y,
   * //   width, height
   * // }
   *
   * // if the current diagram is zoomed and scrolled, you may reset it to the
   * // default zoom via this method, too:
   *
   * const zoomedAndScrolledViewbox = canvas.viewbox();
   *
   * canvas.viewbox({
   *   x: 0,
   *   y: 0,
   *   width: zoomedAndScrolledViewbox.outer.width,
   *   height: zoomedAndScrolledViewbox.outer.height
   * });
   * ```
   *
   * @param {Rect} [box] The viewbox to be set.
   *
   * @return {CanvasViewbox} The set viewbox.
   */
  Canvas.prototype.viewbox = function (box) {
    if (box === undefined && this._cachedViewbox) {
      return structuredClone(this._cachedViewbox);
    }
    const viewport = this._viewport,
      outerBox = this.getSize();
    let innerBox, matrix, activeLayer, transform$1, scale, x, y;
    if (!box) {
      // compute the inner box based on the
      // diagrams active layer. This allows us to exclude
      // external components, such as overlays

      activeLayer = this._rootElement ? this.getActiveLayer() : null;
      innerBox = activeLayer && activeLayer.getBBox() || {};
      transform$1 = transform(viewport);
      matrix = transform$1 ? transform$1.matrix : createMatrix();
      scale = round(matrix.a, 1000);
      x = round(-matrix.e || 0, 1000);
      y = round(-matrix.f || 0, 1000);
      box = this._cachedViewbox = {
        x: x ? x / scale : 0,
        y: y ? y / scale : 0,
        width: outerBox.width / scale,
        height: outerBox.height / scale,
        scale: scale,
        inner: {
          width: innerBox.width || 0,
          height: innerBox.height || 0,
          x: innerBox.x || 0,
          y: innerBox.y || 0
        },
        outer: outerBox
      };
      return box;
    } else {
      this._changeViewbox(function () {
        scale = Math.min(outerBox.width / box.width, outerBox.height / box.height);
        const matrix = this._svg.createSVGMatrix().scale(scale).translate(-box.x, -box.y);
        transform(viewport, matrix);
      });
    }
    return box;
  };

  /**
   * Gets or sets the scroll of the canvas.
   *
   * @param {ScrollDelta} [delta] The scroll to be set.
   *
   * @return {Point}
   */
  Canvas.prototype.scroll = function (delta) {
    const node = this._viewport;
    let matrix = node.getCTM();
    if (delta) {
      this._changeViewbox(function () {
        delta = assign$1({
          dx: 0,
          dy: 0
        }, delta || {});
        matrix = this._svg.createSVGMatrix().translate(delta.dx, delta.dy).multiply(matrix);
        setCTM(node, matrix);
      });
    }
    return {
      x: matrix.e,
      y: matrix.f
    };
  };

  /**
   * Scrolls the viewbox to contain the given element or elements.
   * Optionally specify a padding to be applied to the edges.
   *
   * The canvas navigates to the shared root of the element(s). If no shared
   * root can be found, no navigation is performed.
   *
   * @param {ElementOrIdentifier|ElementOrIdentifier[]} element The element(s) to scroll to or their ID(s).
   * @param {RectTRBL|number} [padding=100] The padding to be applied. Can also specify top, bottom, left and right.
   */
  Canvas.prototype.scrollToElement = function (element, padding) {
    let defaultPadding = 100;
    const elements = this._resolveElements(element);
    if (!elements.length) {
      return;
    }
    const rootElement = this.findRoot(elements);
    if (!rootElement) {
      return;
    }
    if (rootElement !== this.getRootElement()) {
      this.setRootElement(rootElement);
    }
    const visibleElements = elements.filter(e => e != rootElement);
    if (!visibleElements.length) {
      return;
    }
    if (!padding) {
      padding = {};
    }
    if (typeof padding === 'number') {
      defaultPadding = padding;
    }
    padding = {
      top: padding.top || defaultPadding,
      right: padding.right || defaultPadding,
      bottom: padding.bottom || defaultPadding,
      left: padding.left || defaultPadding
    };
    const elementBounds = getBBox(visibleElements),
      elementTrbl = asTRBL(elementBounds),
      viewboxBounds = this.viewbox(),
      zoom = this.zoom();
    let dx, dy;

    // shrink viewboxBounds with padding
    viewboxBounds.y += padding.top / zoom;
    viewboxBounds.x += padding.left / zoom;
    viewboxBounds.width -= (padding.right + padding.left) / zoom;
    viewboxBounds.height -= (padding.bottom + padding.top) / zoom;
    const viewboxTrbl = asTRBL(viewboxBounds);
    const canFit = elementBounds.width < viewboxBounds.width && elementBounds.height < viewboxBounds.height;
    if (!canFit) {
      // top-left when element can't fit
      dx = elementBounds.x - viewboxBounds.x;
      dy = elementBounds.y - viewboxBounds.y;
    } else {
      const dRight = Math.max(0, elementTrbl.right - viewboxTrbl.right),
        dLeft = Math.min(0, elementTrbl.left - viewboxTrbl.left),
        dBottom = Math.max(0, elementTrbl.bottom - viewboxTrbl.bottom),
        dTop = Math.min(0, elementTrbl.top - viewboxTrbl.top);
      dx = dRight || dLeft;
      dy = dBottom || dTop;
    }
    this.scroll({
      dx: -dx * zoom,
      dy: -dy * zoom
    });
  };

  /**
   * Gets or sets the current zoom of the canvas, optionally zooming to the
   * specified position.
   *
   * The getter may return a cached zoom level. Call it with `false` as the first
   * argument to force recomputation of the current level.
   *
   * @param {number|'fit-viewport'} [newScale] The new zoom level, either a number,
   * i.e. 0.9, or `fit-viewport` to adjust the size to fit the current viewport.
   * @param {Point} [center] The reference point { x: ..., y: ...} to zoom to.
   *
   * @return {number} The set zoom level.
   */
  Canvas.prototype.zoom = function (newScale, center) {
    if (!newScale) {
      return this.viewbox(newScale).scale;
    }
    if (newScale === 'fit-viewport') {
      return this._fitViewport(center);
    }
    let outer, matrix;
    this._changeViewbox(function () {
      if (typeof center !== 'object') {
        outer = this.viewbox().outer;
        center = {
          x: outer.width / 2,
          y: outer.height / 2
        };
      }
      matrix = this._setZoom(newScale, center);
    });
    return round(matrix.a, 1000);
  };
  function setCTM(node, m) {
    const mstr = 'matrix(' + m.a + ',' + m.b + ',' + m.c + ',' + m.d + ',' + m.e + ',' + m.f + ')';
    node.setAttribute('transform', mstr);
  }
  Canvas.prototype._fitViewport = function (center) {
    const vbox = this.viewbox(),
      outer = vbox.outer,
      inner = vbox.inner;
    let newScale, newViewbox;

    // display the complete diagram without zooming in.
    // instead of relying on internal zoom, we perform a
    // hard reset on the canvas viewbox to realize this
    //
    // if diagram does not need to be zoomed in, we focus it around
    // the diagram origin instead

    if (inner.x >= 0 && inner.y >= 0 && inner.x + inner.width <= outer.width && inner.y + inner.height <= outer.height && !center) {
      newViewbox = {
        x: 0,
        y: 0,
        width: Math.max(inner.width + inner.x, outer.width),
        height: Math.max(inner.height + inner.y, outer.height)
      };
    } else {
      newScale = Math.min(1, outer.width / inner.width, outer.height / inner.height);
      newViewbox = {
        x: inner.x + (center ? inner.width / 2 - outer.width / newScale / 2 : 0),
        y: inner.y + (center ? inner.height / 2 - outer.height / newScale / 2 : 0),
        width: outer.width / newScale,
        height: outer.height / newScale
      };
    }
    this.viewbox(newViewbox);
    return this.viewbox(false).scale;
  };
  Canvas.prototype._setZoom = function (scale, center) {
    const svg = this._svg,
      viewport = this._viewport;
    const matrix = svg.createSVGMatrix();
    const point = svg.createSVGPoint();
    let centerPoint, originalPoint, currentMatrix, scaleMatrix, newMatrix;
    currentMatrix = viewport.getCTM();
    const currentScale = currentMatrix.a;
    if (center) {
      centerPoint = assign$1(point, center);

      // revert applied viewport transformations
      originalPoint = centerPoint.matrixTransform(currentMatrix.inverse());

      // create scale matrix
      scaleMatrix = matrix.translate(originalPoint.x, originalPoint.y).scale(1 / currentScale * scale).translate(-originalPoint.x, -originalPoint.y);
      newMatrix = currentMatrix.multiply(scaleMatrix);
    } else {
      newMatrix = matrix.scale(scale);
    }
    setCTM(this._viewport, newMatrix);
    return newMatrix;
  };

  /**
   * Returns the size of the canvas.
   *
   * @return {Dimensions} The size of the canvas.
   */
  Canvas.prototype.getSize = function () {
    return {
      width: this._container.clientWidth,
      height: this._container.clientHeight
    };
  };

  /**
   * Returns the absolute bounding box of an element.
   *
   * The absolute bounding box may be used to display overlays in the callers
   * (browser) coordinate system rather than the zoomed in/out canvas coordinates.
   *
   * @param {ShapeLike|ConnectionLike} element The element.
   *
   * @return {Rect} The element's absolute bounding box.
   */
  Canvas.prototype.getAbsoluteBBox = function (element) {
    const vbox = this.viewbox();
    let bbox;

    // connection
    // use svg bbox
    if (element.waypoints) {
      const gfx = this.getGraphics(element);
      bbox = gfx.getBBox();
    }

    // shapes
    // use data
    else {
      bbox = element;
    }
    const x = bbox.x * vbox.scale - vbox.x * vbox.scale;
    const y = bbox.y * vbox.scale - vbox.y * vbox.scale;
    const width = bbox.width * vbox.scale;
    const height = bbox.height * vbox.scale;
    return {
      x: x,
      y: y,
      width: width,
      height: height
    };
  };

  /**
   * Fires an event so other modules can react to the canvas resizing.
   */
  Canvas.prototype.resized = function () {
    // force recomputation of view box
    delete this._cachedViewbox;
    this._eventBus.fire('canvas.resized');
  };

  var ELEMENT_ID = 'data-element-id';

  /**
   * @typedef {import('./Types.js').ElementLike} ElementLike
   *
   * @typedef {import('./EventBus.js').default} EventBus
   *
   * @typedef { (element: ElementLike, gfx: SVGElement) => boolean|any } ElementRegistryFilterCallback
   * @typedef { (element: ElementLike, gfx: SVGElement) => any } ElementRegistryForEachCallback
   */

  /**
   * A registry that keeps track of all shapes in the diagram.
   *
   * @class
   * @constructor
   *
   * @param {EventBus} eventBus
   */
  function ElementRegistry$2(eventBus) {
    /**
     * @type { {
     *   [id: string]: {
     *     element: ElementLike;
     *     gfx?: SVGElement;
     *     secondaryGfx?: SVGElement;
     *   }
     * } }
     */
    this._elements = {};
    this._eventBus = eventBus;
  }
  ElementRegistry$2.$inject = ['eventBus'];

  /**
   * Add an element and its graphical representation(s) to the registry.
   *
   * @param {ElementLike} element The element to be added.
   * @param {SVGElement} gfx The primary graphical representation.
   * @param {SVGElement} [secondaryGfx] The secondary graphical representation.
   */
  ElementRegistry$2.prototype.add = function (element, gfx, secondaryGfx) {
    var id = element.id;
    this._validateId(id);

    // associate dom node with element
    attr(gfx, ELEMENT_ID, id);
    if (secondaryGfx) {
      attr(secondaryGfx, ELEMENT_ID, id);
    }
    this._elements[id] = {
      element: element,
      gfx: gfx,
      secondaryGfx: secondaryGfx
    };
  };

  /**
   * Remove an element from the registry.
   *
   * @param {ElementLike|string} element
   */
  ElementRegistry$2.prototype.remove = function (element) {
    var elements = this._elements,
      id = element.id || element,
      container = id && elements[id];
    if (container) {
      // unset element id on gfx
      attr(container.gfx, ELEMENT_ID, '');
      if (container.secondaryGfx) {
        attr(container.secondaryGfx, ELEMENT_ID, '');
      }
      delete elements[id];
    }
  };

  /**
   * Update an elements ID.
   *
   * @param {ElementLike|string} element The element or its ID.
   * @param {string} newId The new ID.
   */
  ElementRegistry$2.prototype.updateId = function (element, newId) {
    this._validateId(newId);
    if (typeof element === 'string') {
      element = this.get(element);
    }
    this._eventBus.fire('element.updateId', {
      element: element,
      newId: newId
    });
    var gfx = this.getGraphics(element),
      secondaryGfx = this.getGraphics(element, true);
    this.remove(element);
    element.id = newId;
    this.add(element, gfx, secondaryGfx);
  };

  /**
   * Update the graphical representation of an element.
   *
   * @param {ElementLike|string} filter The element or its ID.
   * @param {SVGElement} gfx The new graphical representation.
   * @param {boolean} [secondary=false] Whether to update the secondary graphical representation.
   */
  ElementRegistry$2.prototype.updateGraphics = function (filter, gfx, secondary) {
    var id = filter.id || filter;
    var container = this._elements[id];
    if (secondary) {
      container.secondaryGfx = gfx;
    } else {
      container.gfx = gfx;
    }
    if (gfx) {
      attr(gfx, ELEMENT_ID, id);
    }
    return gfx;
  };

  /**
   * Get the element with the given ID or graphical representation.
   *
   * @example
   *
   * ```javascript
   * elementRegistry.get('SomeElementId_1');
   *
   * elementRegistry.get(gfx);
   * ```
   *
   * @param {string|SVGElement} filter The elements ID or graphical representation.
   *
   * @return {ElementLike|undefined} The element.
   */
  ElementRegistry$2.prototype.get = function (filter) {
    var id;
    if (typeof filter === 'string') {
      id = filter;
    } else {
      id = filter && attr(filter, ELEMENT_ID);
    }
    var container = this._elements[id];
    return container && container.element;
  };

  /**
   * Return all elements that match a given filter function.
   *
   * @param {ElementRegistryFilterCallback} fn The filter function.
   *
   * @return {ElementLike[]} The matching elements.
   */
  ElementRegistry$2.prototype.filter = function (fn) {
    var filtered = [];
    this.forEach(function (element, gfx) {
      if (fn(element, gfx)) {
        filtered.push(element);
      }
    });
    return filtered;
  };

  /**
   * Return the first element that matches the given filter function.
   *
   * @param {ElementRegistryFilterCallback} fn The filter function.
   *
   * @return {ElementLike|undefined} The matching element.
   */
  ElementRegistry$2.prototype.find = function (fn) {
    var map = this._elements,
      keys = Object.keys(map);
    for (var i = 0; i < keys.length; i++) {
      var id = keys[i],
        container = map[id],
        element = container.element,
        gfx = container.gfx;
      if (fn(element, gfx)) {
        return element;
      }
    }
  };

  /**
   * Get all elements.
   *
   * @return {ElementLike[]} All elements.
   */
  ElementRegistry$2.prototype.getAll = function () {
    return this.filter(function (e) {
      return e;
    });
  };

  /**
   * Execute a given function for each element.
   *
   * @param {ElementRegistryForEachCallback} fn The function to execute.
   */
  ElementRegistry$2.prototype.forEach = function (fn) {
    var map = this._elements;
    Object.keys(map).forEach(function (id) {
      var container = map[id],
        element = container.element,
        gfx = container.gfx;
      return fn(element, gfx);
    });
  };

  /**
   * Return the graphical representation of an element.
   *
   * @example
   *
   * ```javascript
   * elementRegistry.getGraphics('SomeElementId_1');
   *
   * elementRegistry.getGraphics(rootElement); // <g ...>
   *
   * elementRegistry.getGraphics(rootElement, true); // <svg ...>
   * ```
   *
   * @param {ElementLike|string} filter The element or its ID.
   * @param {boolean} [secondary=false] Whether to return the secondary graphical representation.
   *
   * @return {SVGElement} The graphical representation.
   */
  ElementRegistry$2.prototype.getGraphics = function (filter, secondary) {
    var id = filter.id || filter;
    var container = this._elements[id];
    return container && (secondary ? container.secondaryGfx : container.gfx);
  };

  /**
   * Validate an ID and throw an error if invalid.
   *
   * @param {string} id
   *
   * @throws {Error} Error indicating that the ID is invalid or already assigned.
   */
  ElementRegistry$2.prototype._validateId = function (id) {
    if (!id) {
      throw new Error('element must have an id');
    }
    if (this._elements[id]) {
      throw new Error('element with id ' + id + ' already added');
    }
  };

  /**
   * Extends a collection with {@link Refs} aware methods
   *
   * @param {Array<Object>} collection
   * @param {Refs} refs instance
   * @param {Object} property represented by the collection
   * @param {Object} target object the collection is attached to
   *
   * @return {RefsCollection<Object>} the extended array
   */
  function extend(collection, refs, property, target) {
    var inverseProperty = property.inverse;

    /**
     * Removes the given element from the array and returns it.
     *
     * @method RefsCollection#remove
     *
     * @param {Object} element the element to remove
     */
    Object.defineProperty(collection, 'remove', {
      value: function (element) {
        var idx = this.indexOf(element);
        if (idx !== -1) {
          this.splice(idx, 1);

          // unset inverse
          refs.unset(element, inverseProperty, target);
        }
        return element;
      }
    });

    /**
     * Returns true if the collection contains the given element
     *
     * @method RefsCollection#contains
     *
     * @param {Object} element the element to check for
     */
    Object.defineProperty(collection, 'contains', {
      value: function (element) {
        return this.indexOf(element) !== -1;
      }
    });

    /**
     * Adds an element to the array, unless it exists already (set semantics).
     *
     * @method RefsCollection#add
     *
     * @param {Object} element the element to add
     * @param {Number} optional index to add element to
     *                 (possibly moving other elements around)
     */
    Object.defineProperty(collection, 'add', {
      value: function (element, idx) {
        var currentIdx = this.indexOf(element);
        if (typeof idx === 'undefined') {
          if (currentIdx !== -1) {
            // element already in collection (!)
            return;
          }

          // add to end of array, as no idx is specified
          idx = this.length;
        }

        // handle already in collection
        if (currentIdx !== -1) {
          // remove element from currentIdx
          this.splice(currentIdx, 1);
        }

        // add element at idx
        this.splice(idx, 0, element);
        if (currentIdx === -1) {
          // set inverse, unless element was
          // in collection already
          refs.set(element, inverseProperty, target);
        }
      }
    });

    // a simple marker, identifying this element
    // as being a refs collection
    Object.defineProperty(collection, '__refs_collection', {
      value: true
    });
    return collection;
  }

  /**
   * Checks if a given collection is extended
   *
   * @param {Array<Object>} collection
   *
   * @return {boolean}
   */
  function isExtended(collection) {
    return collection.__refs_collection === true;
  }
  function hasOwnProperty(e, property) {
    return Object.prototype.hasOwnProperty.call(e, property.name || property);
  }
  function defineCollectionProperty(ref, property, target) {
    var collection = extend(target[property.name] || [], ref, property, target);
    Object.defineProperty(target, property.name, {
      enumerable: property.enumerable,
      value: collection
    });
    if (collection.length) {
      collection.forEach(function (o) {
        ref.set(o, property.inverse, target);
      });
    }
  }
  function defineProperty$1(ref, property, target) {
    var inverseProperty = property.inverse;
    var _value = target[property.name];
    Object.defineProperty(target, property.name, {
      configurable: property.configurable,
      enumerable: property.enumerable,
      get: function () {
        return _value;
      },
      set: function (value) {
        // return if we already performed all changes
        if (value === _value) {
          return;
        }
        var old = _value;

        // temporary set null
        _value = null;
        if (old) {
          ref.unset(old, inverseProperty, target);
        }

        // set new value
        _value = value;

        // set inverse value
        ref.set(_value, inverseProperty, target);
      }
    });
  }

  /**
   * Creates a new references object defining two inversly related
   * attribute descriptors a and b.
   *
   * <p>
   *   When bound to an object using {@link Refs#bind} the references
   *   get activated and ensure that add and remove operations are applied
   *   reversely, too.
   * </p>
   *
   * <p>
   *   For attributes represented as collections {@link Refs} provides the
   *   {@link RefsCollection#add}, {@link RefsCollection#remove} and {@link RefsCollection#contains} extensions
   *   that must be used to properly hook into the inverse change mechanism.
   * </p>
   *
   * @class Refs
   *
   * @classdesc A bi-directional reference between two attributes.
   *
   * @param {Refs.AttributeDescriptor} a property descriptor
   * @param {Refs.AttributeDescriptor} b property descriptor
   *
   * @example
   *
   * var refs = Refs({ name: 'wheels', collection: true, enumerable: true }, { name: 'car' });
   *
   * var car = { name: 'toyota' };
   * var wheels = [{ pos: 'front-left' }, { pos: 'front-right' }];
   *
   * refs.bind(car, 'wheels');
   *
   * car.wheels // []
   * car.wheels.add(wheels[0]);
   * car.wheels.add(wheels[1]);
   *
   * car.wheels // [{ pos: 'front-left' }, { pos: 'front-right' }]
   *
   * wheels[0].car // { name: 'toyota' };
   * car.wheels.remove(wheels[0]);
   *
   * wheels[0].car // undefined
   */
  function Refs(a, b) {
    if (!(this instanceof Refs)) {
      return new Refs(a, b);
    }

    // link
    a.inverse = b;
    b.inverse = a;
    this.props = {};
    this.props[a.name] = a;
    this.props[b.name] = b;
  }

  /**
   * Binds one side of a bi-directional reference to a
   * target object.
   *
   * @memberOf Refs
   *
   * @param  {Object} target
   * @param  {String} property
   */
  Refs.prototype.bind = function (target, property) {
    if (typeof property === 'string') {
      if (!this.props[property]) {
        throw new Error('no property <' + property + '> in ref');
      }
      property = this.props[property];
    }
    if (property.collection) {
      defineCollectionProperty(this, property, target);
    } else {
      defineProperty$1(this, property, target);
    }
  };
  Refs.prototype.ensureRefsCollection = function (target, property) {
    var collection = target[property.name];
    if (!isExtended(collection)) {
      defineCollectionProperty(this, property, target);
    }
    return collection;
  };
  Refs.prototype.ensureBound = function (target, property) {
    if (!hasOwnProperty(target, property)) {
      this.bind(target, property);
    }
  };
  Refs.prototype.unset = function (target, property, value) {
    if (target) {
      this.ensureBound(target, property);
      if (property.collection) {
        this.ensureRefsCollection(target, property).remove(value);
      } else {
        target[property.name] = undefined;
      }
    }
  };
  Refs.prototype.set = function (target, property, value) {
    if (target) {
      this.ensureBound(target, property);
      if (property.collection) {
        this.ensureRefsCollection(target, property).add(value);
      } else {
        target[property.name] = value;
      }
    }
  };

  var parentRefs = new Refs({
      name: 'children',
      enumerable: true,
      collection: true
    }, {
      name: 'parent'
    }),
    labelRefs = new Refs({
      name: 'labels',
      enumerable: true,
      collection: true
    }, {
      name: 'labelTarget'
    }),
    attacherRefs = new Refs({
      name: 'attachers',
      collection: true
    }, {
      name: 'host'
    }),
    outgoingRefs = new Refs({
      name: 'outgoing',
      collection: true
    }, {
      name: 'source'
    }),
    incomingRefs = new Refs({
      name: 'incoming',
      collection: true
    }, {
      name: 'target'
    });

  /**
   * @typedef {import('./Types.js').Element} Element
   * @typedef {import('./Types.js').Shape} Shape
   * @typedef {import('./Types.js').Root} Root
   * @typedef {import('./Types.js').Label} Label
   * @typedef {import('./Types.js').Connection} Connection
   */

  /**
   * The basic graphical representation
   *
   * @class
   * @constructor
   */
  function ElementImpl() {
    /**
     * The object that backs up the shape
     *
     * @name Element#businessObject
     * @type Object
     */
    Object.defineProperty(this, 'businessObject', {
      writable: true
    });

    /**
     * Single label support, will mapped to multi label array
     *
     * @name Element#label
     * @type Object
     */
    Object.defineProperty(this, 'label', {
      get: function () {
        return this.labels[0];
      },
      set: function (newLabel) {
        var label = this.label,
          labels = this.labels;
        if (!newLabel && label) {
          labels.remove(label);
        } else {
          labels.add(newLabel, 0);
        }
      }
    });

    /**
     * The parent shape
     *
     * @name Element#parent
     * @type Shape
     */
    parentRefs.bind(this, 'parent');

    /**
     * The list of labels
     *
     * @name Element#labels
     * @type Label
     */
    labelRefs.bind(this, 'labels');

    /**
     * The list of outgoing connections
     *
     * @name Element#outgoing
     * @type Array<Connection>
     */
    outgoingRefs.bind(this, 'outgoing');

    /**
     * The list of incoming connections
     *
     * @name Element#incoming
     * @type Array<Connection>
     */
    incomingRefs.bind(this, 'incoming');
  }

  /**
   * A graphical object
   *
   * @class
   * @constructor
   *
   * @extends ElementImpl
   */
  function ShapeImpl() {
    ElementImpl.call(this);

    /**
     * Indicates frame shapes
     *
     * @name ShapeImpl#isFrame
     * @type boolean
     */

    /**
     * The list of children
     *
     * @name ShapeImpl#children
     * @type Element[]
     */
    parentRefs.bind(this, 'children');

    /**
     * @name ShapeImpl#host
     * @type Shape
     */
    attacherRefs.bind(this, 'host');

    /**
     * @name ShapeImpl#attachers
     * @type Shape
     */
    attacherRefs.bind(this, 'attachers');
  }
  e(ShapeImpl, ElementImpl);

  /**
   * A root graphical object
   *
   * @class
   * @constructor
   *
   * @extends ElementImpl
   */
  function RootImpl() {
    ElementImpl.call(this);

    /**
     * The list of children
     *
     * @name RootImpl#children
     * @type Element[]
     */
    parentRefs.bind(this, 'children');
  }
  e(RootImpl, ShapeImpl);

  /**
   * A label for an element
   *
   * @class
   * @constructor
   *
   * @extends ShapeImpl
   */
  function LabelImpl() {
    ShapeImpl.call(this);

    /**
     * The labeled element
     *
     * @name LabelImpl#labelTarget
     * @type Element
     */
    labelRefs.bind(this, 'labelTarget');
  }
  e(LabelImpl, ShapeImpl);

  /**
   * A connection between two elements
   *
   * @class
   * @constructor
   *
   * @extends ElementImpl
   */
  function ConnectionImpl() {
    ElementImpl.call(this);

    /**
     * The element this connection originates from
     *
     * @name ConnectionImpl#source
     * @type Element
     */
    outgoingRefs.bind(this, 'source');

    /**
     * The element this connection points to
     *
     * @name ConnectionImpl#target
     * @type Element
     */
    incomingRefs.bind(this, 'target');
  }
  e(ConnectionImpl, ElementImpl);
  var types$1 = {
    connection: ConnectionImpl,
    shape: ShapeImpl,
    label: LabelImpl,
    root: RootImpl
  };

  /**
   * Creates a root element.
   *
   * @overlord
   *
   * @example
   *
   * ```javascript
   * import * as Model from 'diagram-js/lib/model';
   *
   * const root = Model.create('root', {
   *   x: 100,
   *   y: 100,
   *   width: 100,
   *   height: 100
   * });
   * ```
   *
   * @param {'root'} type
   * @param {any} [attrs]
   *
   * @return {Root}
   */

  /**
   * Creates a connection.
   *
   * @overlord
   *
   * @example
   *
   * ```javascript
   * import * as Model from 'diagram-js/lib/model';
   *
   * const connection = Model.create('connection', {
   *   waypoints: [
   *     { x: 100, y: 100 },
   *     { x: 200, y: 100 }
   *   ]
   * });
   * ```
   *
   * @param {'connection'} type
   * @param {any} [attrs]
   *
   * @return {Connection}
   */

  /**
   * Creates a shape.
   *
   * @overlord
   *
   * @example
   *
   * ```javascript
   * import * as Model from 'diagram-js/lib/model';
   *
   * const shape = Model.create('shape', {
   *   x: 100,
   *   y: 100,
   *   width: 100,
   *   height: 100
   * });
   * ```
   *
   * @param {'shape'} type
   * @param {any} [attrs]
   *
   * @return {Shape}
   */

  /**
   * Creates a label.
   *
   * @example
   *
   * ```javascript
   * import * as Model from 'diagram-js/lib/model';
   *
   * const label = Model.create('label', {
   *   x: 100,
   *   y: 100,
   *   width: 100,
   *   height: 100,
   *   labelTarget: shape
   * });
   * ```
   *
   * @param {'label'} type
   * @param {Object} [attrs]
   *
   * @return {Label}
   */
  function create$1(type, attrs) {
    var Type = types$1[type];
    if (!Type) {
      throw new Error('unknown type: <' + type + '>');
    }
    return assign$1(new Type(), attrs);
  }

  /**
   * @typedef {import('../model/Types.js').Element} Element
   * @typedef {import('../model/Types.js').Connection} Connection
   * @typedef {import('../model/Types.js').Label} Label
   * @typedef {import('../model/Types.js').Root} Root
   * @typedef {import('../model/Types.js').Shape} Shape
   */

  /**
   * A factory for model elements.
   *
   * @template {Connection} [T=Connection]
   * @template {Label} [U=Label]
   * @template {Root} [V=Root]
   * @template {Shape} [W=Shape]
   */
  function ElementFactory$1() {
    this._uid = 12;
  }

  /**
   * Create a root element.
   *
   * @param {Partial<Root>} [attrs]
   *
   * @return {V} The created root element.
   */
  ElementFactory$1.prototype.createRoot = function (attrs) {
    return this.create('root', attrs);
  };

  /**
   * Create a label.
   *
   * @param {Partial<Label>} [attrs]
   *
   * @return {U} The created label.
   */
  ElementFactory$1.prototype.createLabel = function (attrs) {
    return this.create('label', attrs);
  };

  /**
   * Create a shape.
   *
   * @param {Partial<Shape>} [attrs]
   *
   * @return {W} The created shape.
   */
  ElementFactory$1.prototype.createShape = function (attrs) {
    return this.create('shape', attrs);
  };

  /**
   * Create a connection.
   *
   * @param {Partial<Connection>} [attrs]
   *
   * @return {T} The created connection.
   */
  ElementFactory$1.prototype.createConnection = function (attrs) {
    return this.create('connection', attrs);
  };

  /**
   * Create a root element.
   *
   * @overlord
   * @param {'root'} type
   * @param {Partial<Root>} [attrs]
   * @return {V}
   */
  /**
   * Create a shape.
   *
   * @overlord
   * @param {'shape'} type
   * @param {Partial<Shape>} [attrs]
   * @return {W}
   */
  /**
   * Create a connection.
   *
   * @overlord
   * @param {'connection'} type
   * @param {Partial<Connection>} [attrs]
   * @return {T}
   */
  /**
   * Create a label.
   *
   * @param {'label'} type
   * @param {Partial<Label>} [attrs]
   * @return {U}
   */
  ElementFactory$1.prototype.create = function (type, attrs) {
    attrs = assign$1({}, attrs || {});
    if (!attrs.id) {
      attrs.id = type + '_' + this._uid++;
    }
    return create$1(type, attrs);
  };

  /**
   * SVGs for elements are generated by the {@link GraphicsFactory}.
   *
   * This utility gives quick access to the important semantic
   * parts of an element.
   */

  /**
   * Returns the visual part of a diagram element.
   *
   * @param {SVGElement} gfx
   *
   * @return {SVGElement}
   */
  function getVisual(gfx) {
    return gfx.childNodes[0];
  }

  /**
   * Returns the children for a given diagram element.
   *
   * @param {SVGElement} gfx
   * @return {SVGElement}
   */
  function getChildren$1(gfx) {
    return gfx.parentNode.childNodes[1];
  }

  /**
   * @param {SVGElement} gfx
   * @param {number} x
   * @param {number} y
   */
  function translate$1(gfx, x, y) {
    var translate = createTransform();
    translate.setTranslate(x, y);
    transform(gfx, translate);
  }

  /**
   * @typedef {import('./Types.js').ConnectionLike} ConnectionLike
   * @typedef {import('./Types.js').ElementLike} ElementLike
   * @typedef {import('./Types.js').ShapeLike} ShapeLike
   *
   * @typedef {import('./ElementRegistry.js').default} ElementRegistry
   * @typedef {import('./EventBus.js').default} EventBus
   */

  /**
   * A factory that creates graphical elements.
   *
   * @param {EventBus} eventBus
   * @param {ElementRegistry} elementRegistry
   */
  function GraphicsFactory(eventBus, elementRegistry) {
    this._eventBus = eventBus;
    this._elementRegistry = elementRegistry;
  }
  GraphicsFactory.$inject = ['eventBus', 'elementRegistry'];

  /**
   * @param { { parent?: any } } element
   * @return {SVGElement}
   */
  GraphicsFactory.prototype._getChildrenContainer = function (element) {
    var gfx = this._elementRegistry.getGraphics(element);
    var childrenGfx;

    // root element
    if (!element.parent) {
      childrenGfx = gfx;
    } else {
      childrenGfx = getChildren$1(gfx);
      if (!childrenGfx) {
        childrenGfx = create$2('g');
        classes(childrenGfx).add('djs-children');
        append(gfx.parentNode, childrenGfx);
      }
    }
    return childrenGfx;
  };

  /**
   * Clears the graphical representation of the element and returns the
   * cleared visual (the <g class="djs-visual" /> element).
   */
  GraphicsFactory.prototype._clear = function (gfx) {
    var visual = getVisual(gfx);
    clear(visual);
    return visual;
  };

  /**
   * Creates a gfx container for shapes and connections
   *
   * The layout is as follows:
   *
   * <g class="djs-group">
   *
   *   <!-- the gfx -->
   *   <g class="djs-element djs-(shape|connection|frame)">
   *     <g class="djs-visual">
   *       <!-- the renderer draws in here -->
   *     </g>
   *
   *     <!-- extensions (overlays, click box, ...) goes here
   *   </g>
   *
   *   <!-- the gfx child nodes -->
   *   <g class="djs-children"></g>
   * </g>
   *
   * @param {string} type the type of the element, i.e. shape | connection
   * @param {SVGElement} childrenGfx
   * @param {number} [parentIndex] position to create container in parent
   * @param {boolean} [isFrame] is frame element
   *
   * @return {SVGElement}
   */
  GraphicsFactory.prototype._createContainer = function (type, childrenGfx, parentIndex, isFrame) {
    var outerGfx = create$2('g');
    classes(outerGfx).add('djs-group');

    // insert node at position
    if (typeof parentIndex !== 'undefined') {
      prependTo(outerGfx, childrenGfx, childrenGfx.childNodes[parentIndex]);
    } else {
      append(childrenGfx, outerGfx);
    }
    var gfx = create$2('g');
    classes(gfx).add('djs-element');
    classes(gfx).add('djs-' + type);
    if (isFrame) {
      classes(gfx).add('djs-frame');
    }
    append(outerGfx, gfx);

    // create visual
    var visual = create$2('g');
    classes(visual).add('djs-visual');
    append(gfx, visual);
    return gfx;
  };

  /**
   * Create a graphical element.
   *
   * @param { 'shape' | 'connection' | 'label' | 'root' } type The type of the element.
   * @param {ElementLike} element The element.
   * @param {number} [parentIndex] The index at which to add the graphical element to its parent's children.
   *
   * @return {SVGElement} The graphical element.
   */
  GraphicsFactory.prototype.create = function (type, element, parentIndex) {
    var childrenGfx = this._getChildrenContainer(element.parent);
    return this._createContainer(type, childrenGfx, parentIndex, isFrameElement(element));
  };

  /**
   * Update the containments of the given elements.
   *
   * @param {ElementLike[]} elements The elements.
   */
  GraphicsFactory.prototype.updateContainments = function (elements) {
    var self = this,
      elementRegistry = this._elementRegistry,
      parents;
    parents = reduce(elements, function (map, e) {
      if (e.parent) {
        map[e.parent.id] = e.parent;
      }
      return map;
    }, {});

    // update all parents of changed and reorganized their children
    // in the correct order (as indicated in our model)
    forEach(parents, function (parent) {
      var children = parent.children;
      if (!children) {
        return;
      }
      var childrenGfx = self._getChildrenContainer(parent);

      // only (re-)insert children that are not already in their expected
      // position; needlessly detaching and re-attaching siblings that did
      // not move breaks in-progress pointer interactions (the browser drops
      // the native `click` when the moused-down node is momentarily removed)
      // and causes unnecessary DOM churn
      var expected = childrenGfx.firstChild;
      forEach(children, function (child) {
        var childGfx = elementRegistry.getGraphics(child).parentNode;
        if (childGfx === expected) {
          expected = expected.nextSibling;
        } else {
          childrenGfx.insertBefore(childGfx, expected);
        }
      });
    });
  };

  /**
   * Draw a shape.
   *
   * @param {SVGElement} visual The graphical element.
   * @param {ShapeLike} element The shape.
   * @param {Object} attrs Optional attributes.
   *
   * @return {SVGElement}
   */
  GraphicsFactory.prototype.drawShape = function (visual, element, attrs = {}) {
    var eventBus = this._eventBus;
    return eventBus.fire('render.shape', {
      gfx: visual,
      element,
      attrs
    });
  };

  /**
   * Get the path of a shape.
   *
   * @param {ShapeLike} element The shape.
   *
   * @return {string} The path of the shape.
   */
  GraphicsFactory.prototype.getShapePath = function (element) {
    var eventBus = this._eventBus;
    return eventBus.fire('render.getShapePath', element);
  };

  /**
   * Draw a connection.
   *
   * @param {SVGElement} visual The graphical element.
   * @param {ConnectionLike} element The connection.
   * @param {Object} attrs Optional attributes.
   *
   * @return {SVGElement}
   */
  GraphicsFactory.prototype.drawConnection = function (visual, element, attrs = {}) {
    var eventBus = this._eventBus;
    return eventBus.fire('render.connection', {
      gfx: visual,
      element,
      attrs
    });
  };

  /**
   * Get the path of a connection.
   *
   * @param {ConnectionLike} connection The connection.
   *
   * @return {string} The path of the connection.
   */
  GraphicsFactory.prototype.getConnectionPath = function (connection) {
    var eventBus = this._eventBus;
    return eventBus.fire('render.getConnectionPath', connection);
  };

  /**
   * Update an elements graphical representation.
   *
   * @param {'shape'|'connection'} type
   * @param {ElementLike} element
   * @param {SVGElement} gfx
   */
  GraphicsFactory.prototype.update = function (type, element, gfx) {
    // do NOT update root element
    if (!element.parent) {
      return;
    }
    var visual = this._clear(gfx);

    // redraw
    if (type === 'shape') {
      this.drawShape(visual, element);

      // update positioning
      translate$1(gfx, element.x, element.y);
    } else if (type === 'connection') {
      this.drawConnection(visual, element);
    } else {
      throw new Error('unknown type: ' + type);
    }
    if (element.hidden) {
      attr(gfx, 'display', 'none');
    } else {
      attr(gfx, 'display', 'block');
    }
  };

  /**
   * Remove a graphical element.
   *
   * @param {ElementLike} element The element.
   */
  GraphicsFactory.prototype.remove = function (element) {
    var gfx = this._elementRegistry.getGraphics(element);

    // remove
    remove$3(gfx.parentNode);
  };

  // helpers //////////

  function prependTo(newNode, parentNode, siblingNode) {
    var node = siblingNode || parentNode.firstChild;

    // do not prepend node to itself to prevent IE from crashing
    // https://github.com/bpmn-io/bpmn-js/issues/746
    if (newNode === node) {
      return;
    }
    parentNode.insertBefore(newNode, node);
  }

  /**
   * @type { import('didi').ModuleDeclaration }
   */
  var CoreModule$2 = {
    __depends__: [DrawModule$1],
    __init__: ['canvas'],
    canvas: ['type', Canvas],
    elementRegistry: ['type', ElementRegistry$2],
    elementFactory: ['type', ElementFactory$1],
    eventBus: ['type', EventBus],
    graphicsFactory: ['type', GraphicsFactory]
  };

  /**
   * @typedef {import('didi').InjectionContext} InjectionContext
   * @typedef {import('didi').LocalsMap} LocalsMap
   * @typedef {import('didi').ModuleDeclaration} ModuleDeclaration
   *
   * @typedef { {
   *   modules?: ModuleDeclaration[];
   * } & Record<string, any> } DiagramOptions
   */

  /**
   * @template T
   * @typedef {import('didi').FactoryFunction<T>} FactoryFunction
   */

  /**
   * @template T
   * @typedef {import('didi').ArrayFunc<T>} ArrayFunc
   */

  /**
   * Bootstrap an injector from a list of modules, instantiating a number of default components
   *
   * @param {ModuleDeclaration[]} modules
   *
   * @return {Injector} a injector to use to access the components
   */
  function bootstrap(modules) {
    var injector = new Injector(modules);
    injector.init();
    return injector;
  }

  /**
   * Creates an injector from passed options.
   *
   * @template ServiceMap
   * @param {DiagramOptions} [options]
   *
   * @return {Injector<ServiceMap>}
   */
  function createInjector$2(options) {
    options = options || {};

    /**
     * @type { ModuleDeclaration }
     */
    var configModule = {
      'config': ['value', options]
    };
    var modules = [configModule, CoreModule$2].concat(options.modules || []);
    return bootstrap(modules);
  }

  /**
   * The main diagram-js entry point that bootstraps the diagram with the given
   * configuration.
   *
   * To register extensions with the diagram, pass them as Array<Module> to the constructor.
   *
   * @class
   * @constructor
   * @template [ServiceMap=null]
   *
   * @example Creating a plug-in that logs whenever a shape is added to the canvas.
   *
   * ```javascript
   * // plug-in implementation
   * function MyLoggingPlugin(eventBus) {
   *   eventBus.on('shape.added', function(event) {
   *     console.log('shape ', event.shape, ' was added to the diagram');
   *   });
   * }
   *
   * // export as module
   * export default {
   *   __init__: [ 'myLoggingPlugin' ],
   *     myLoggingPlugin: [ 'type', MyLoggingPlugin ]
   * };
   * ```
   *
   * Use the plug-in in a Diagram instance:
   *
   * ```javascript
   * import MyLoggingModule from 'path-to-my-logging-plugin';
   *
   * var diagram = new Diagram({
   *   modules: [
   *     MyLoggingModule
   *   ]
   * });
   *
   * diagram.invoke([ 'canvas', function(canvas) {
   *   // add shape to drawing canvas
   *   canvas.addShape({ x: 10, y: 10 });
   * });
   *
   * // 'shape ... was added to the diagram' logged to console
   * ```
   *
   * @param {DiagramOptions} [options]
   * @param {Injector<ServiceMap>} [injector] An (optional) injector to bootstrap the diagram with.
   */
  function Diagram(options, injector) {
    /**
     * @type {Injector<ServiceMap>}
     */
    this._injector = injector || createInjector$2(options);

    // init

    /**
     * An event indicating that all plug-ins are loaded.
     *
     * Use this event to fire other events to interested plug-ins
     *
     * @memberOf Diagram
     *
     * @event diagram.init
     *
     * @example
     *
     * ```javascript
     * eventBus.on('diagram.init', function() {
     *   eventBus.fire('my-custom-event', { foo: 'BAR' });
     * });
     * ```
     *
     * @type {Object}
     */
    this.get('eventBus').fire('diagram.init');
  }

  /**
   * @overlord
   *
   * Resolves a diagram service.
   *
   * @template {keyof ServiceMap} Name
   *
   * @param {Name} name The name of the service to get.
   *
   * @return {ServiceMap[Name]}
   */
  /**
   * @overlord
   *
   * Resolves a diagram service.
   *
   * @template T
   *
   * @param {string} name The name of the service to get.
   * @param {true} strict If false, resolve missing services to null.
   *
   * @return {T}
   */
  /**
   * @overlord
   *
   * Resolves a diagram service.
   *
   * @template T
   *
   * @param {string} name The name of the service to get.
   * @param {boolean} strict If false, resolve missing services to null.
   *
   * @return {T|null}
   */
  /**
   * Resolves a diagram service.
   *
   * @template T
   *
   * @param {string} name The name of the service to get.
   *
   * @return {T}
   */
  Diagram.prototype.get = function (name, strict) {
    return this._injector.get(name, strict);
  };

  /**
   * @overlord
   *
   * Invoke the given function, injecting dependencies. Return the result.
   *
   * @template T
   *
   * @param {FactoryFunction<T>} func
   * @param {InjectionContext} [context]
   * @param {LocalsMap} [locals]
   *
   * @return {T}
   */
  /**
   * Invoke the given function, injecting dependencies provided in
   * array notation. Return the result.
   *
   * @template T
   *
   * @param {ArrayFunc<T>} func function to be invoked
   * @param {InjectionContext} [context] context of the invocation
   * @param {LocalsMap} [locals] locals provided
   *
   * @return {T}
   */
  Diagram.prototype.invoke = function (func, context, locals) {
    return this._injector.invoke(func, context, locals);
  };

  /**
   * Destroys the diagram
   */
  Diagram.prototype.destroy = function () {
    this.get('eventBus').fire('diagram.destroy');
  };

  /**
   * Clear the diagram, removing all contents.
   */
  Diagram.prototype.clear = function () {
    this.get('eventBus').fire('diagram.clear');
  };

  /**
   * Is an element of the given DMN type?
   *
   * @param  {tjs.model.Base|ModdleElement} element
   * @param  {string} type
   *
   * @return {boolean}
   */
  function is(element, type) {
    var bo = getBusinessObject(element);
    return bo && typeof bo.$instanceOf === 'function' && bo.$instanceOf(type);
  }

  /**
   * Return the business object for a given element.
   *
   * @param  {tjs.model.Base|ModdleElement} element
   *
   * @return {ModdleElement}
   */
  function getBusinessObject(element) {
    return element && element.businessObject || element;
  }
  function getName(element) {
    return getBusinessObject(element).name;
  }

  /**
   * Return main boxed expression of a given decision or BKM.
   *
   * @param {ModdleElement} decisionOrBkm - the decision or business knowledge model
   * @returns {ModdleElement|undefined}
   */
  function getBoxedExpression(decisionOrBkm) {
    var bo = getBusinessObject(decisionOrBkm);
    if (is(bo, 'dmn:Decision')) {
      return bo.get('decisionLogic');
    } else if (is(bo, 'dmn:BusinessKnowledgeModel')) {
      var encapsulatedLogic = bo.get('encapsulatedLogic');
      return encapsulatedLogic && encapsulatedLogic.get('body');
    }
  }

  var diRefs = new Refs({
    name: 'dmnElementRef',
    enumerable: true
  }, {
    name: 'di',
    configurable: true
  });
  function DRDTreeWalker(handler, options) {
    // list of elements to handle deferred to ensure
    // prerequisites are drawn
    var deferred = [];
    function visit(element) {
      var gfx = element.gfx;

      // avoid multiple rendering of elements
      if (gfx) {
        throw new Error('already rendered ' + element.id);
      }

      // call handler
      return handler.element(element);
    }
    function visitRoot(element) {
      return handler.root(element);
    }
    function visitIfDi(element) {
      try {
        var gfx = element.di && visit(element);
        return gfx;
      } catch (e) {
        logError(e.message, {
          element: element,
          error: e
        });
      }
    }

    // Semantic handling //////////////////////

    /**
     * Handle definitions and return the rendered diagram (if any)
     *
     * @param {ModdleElement} definitions to walk and import
     * @param {ModdleElement} [diagram] specific diagram to import and display
     *
     * @throws {Error} if no diagram to display could be found
     */
    function handleDefinitions(definitions, diagram) {
      // make sure we walk the correct dmnElement
      var dmnDI = definitions.dmnDI;
      if (!dmnDI) {
        throw new Error('no dmndi:DMNDI');
      }
      var diagrams = dmnDI.diagrams || [];
      if (diagram && diagrams.indexOf(diagram) === -1) {
        throw new Error('diagram not part of dmndi:DMNDI');
      }
      if (!diagram && diagrams && diagrams.length) {
        diagram = diagrams[0];
      }

      // no diagram -> nothing to import
      if (!diagram) {
        throw new Error('no diagram to display');
      }

      // assign current diagram to definitions so that it can accessed later
      definitions.di = diagram;

      // load DI from selected diagram only
      handleDiagram(diagram);
      visitRoot(definitions);
      handleDrgElements(definitions.get('drgElement'));
      handleArtifacts(definitions.get('artifact'));
      handleDeferred();
    }
    function handleDrgElements(elements) {
      forEach(elements, function (element) {
        visitIfDi(element);
        handleRequirements(element);
      });
    }
    function handleArtifacts(elements) {
      forEach(elements, function (element) {
        if (is(element, 'dmn:Association')) {
          handleAssociation(element);
        } else {
          visitIfDi(element);
        }
      });
    }

    /**
     * Defer association visit until all shapes are visited.
     *
     * @param {ModdleElement} element
     */
    function handleAssociation(element) {
      defer(function () {
        visitIfDi(element);
      });
    }

    /**
     * Defer requirements visiting until all shapes are visited.
     *
     * @param {ModdleElement} element
     */
    function handleRequirements(element) {
      forEach(['informationRequirement', 'knowledgeRequirement', 'authorityRequirement'], function (requirements) {
        forEach(element[requirements], function (requirement) {
          defer(function () {
            visitIfDi(requirement);
          });
        });
      });
    }

    // DI handling //////////////////////
    function handleDiagram(diagram) {
      forEach(diagram.diagramElements, handleDiagramElement);
    }
    function handleDiagramElement(diagramElement) {
      registerDi(diagramElement);
    }
    function registerDi(di) {
      var dmnElement = di.dmnElementRef;
      if (dmnElement) {
        if (dmnElement.di) {
          logError('multiple DI elements defined for element', {
            element: dmnElement
          });
        } else {
          diRefs.bind(dmnElement, 'di');
          dmnElement.di = di;
        }
      } else {
        logError('no DMN element referenced in element', {
          element: di
        });
      }
    }
    function defer(fn) {
      deferred.push(fn);
    }
    function handleDeferred() {
      forEach(deferred, function (d) {
        d();
      });
    }
    function logError(message, context) {
      handler.error(message, context);
    }

    // API //////////////////////

    return {
      handleDefinitions: handleDefinitions
    };
  }

  /**
   * Import the definitions into a diagram.
   *
   * Errors and warnings are reported through the specified callback.
   *
   * @param  {Drd} drd
   * @param  {ModdleElement} definitions
   * @param  {Function} done
   *         the callback, invoked with (err, [ warning ]) once the import is done
   */
  function importDRD(drd, definitions, done) {
    var importer = drd.get('drdImporter'),
      eventBus = drd.get('eventBus');
    var error,
      warnings = [];
    function render(definitions) {
      var visitor = {
        root: function (element) {
          return importer.root(element);
        },
        element: function (element, di) {
          return importer.add(element, di);
        },
        error: function (message, context) {
          warnings.push({
            message: message,
            context: context
          });
        }
      };
      var walker = new DRDTreeWalker(visitor);

      // import
      walker.handleDefinitions(definitions);
    }
    eventBus.fire('import.start', {
      definitions: definitions
    });
    try {
      render(definitions);
    } catch (e) {
      error = e;
    }
    eventBus.fire('import.done', {
      error: error,
      warnings: warnings
    });
    done(error, warnings);
  }

  var NO_OP = '$NO_OP';
  var ERROR_MSG = 'a runtime error occured! Use Inferno in development environment to find the error.';
  var isBrowser = !!(typeof window !== 'undefined' && window.document);
  var isArray = Array.isArray;
  function isStringOrNumber(o) {
    var type = typeof o;
    return type === 'string' || type === 'number';
  }
  function isNullOrUndef(o) {
    return isUndefined(o) || isNull(o);
  }
  function isInvalid(o) {
    return isNull(o) || o === false || isTrue(o) || isUndefined(o);
  }
  function isFunction(o) {
    return typeof o === 'function';
  }
  function isString(o) {
    return typeof o === 'string';
  }
  function isNumber(o) {
    return typeof o === 'number';
  }
  function isNull(o) {
    return o === null;
  }
  function isTrue(o) {
    return o === true;
  }
  function isUndefined(o) {
    return o === void 0;
  }
  function isObject(o) {
    return typeof o === 'object';
  }
  function throwError(message) {
    if (!message) {
      message = ERROR_MSG;
    }
    throw new Error("Inferno Error: " + message);
  }
  function warning(message) {
    // tslint:disable-next-line:no-console
    console.error(message);
  }
  function combineFrom(first, second) {
    var out = {};
    if (first) {
      for (var key in first) {
        out[key] = first[key];
      }
    }
    if (second) {
      for (var _key in second) {
        out[_key] = second[_key];
      }
    }
    return out;
  }
  function getTagName(input) {
    var tagName;
    if (isArray(input)) {
      var arrayText = input.length > 3 ? input.slice(0, 3).toString() + ',...' : input.toString();
      tagName = 'Array(' + arrayText + ')';
    } else if (isStringOrNumber(input)) {
      tagName = 'Text(' + input + ')';
    } else if (isInvalid(input)) {
      tagName = 'InvalidVNode(' + input + ')';
    } else {
      var flags = input.flags;
      if (flags & 481 /* VNodeFlags.Element */) {
        tagName = "<" + input.type + (input.className ? ' class="' + input.className + '"' : '') + ">";
      } else if (flags & 16 /* VNodeFlags.Text */) {
        tagName = "Text(" + input.children + ")";
      } else if (flags & 1024 /* VNodeFlags.Portal */) {
        tagName = "Portal*";
      } else {
        var type = input.type;
        // Fallback for IE
        var componentName = type.name || type.displayName || type.constructor.name || (type.toString().match(/^function\s*([^\s(]+)/) || [])[1];
        tagName = "<" + componentName + " />";
      }
    }
    return '>> ' + tagName + '\n';
  }
  function DEV_ValidateKeys(vNodeTree, forceKeyed) {
    var foundKeys = {};
    for (var i = 0, len = vNodeTree.length; i < len; i++) {
      var childNode = vNodeTree[i];
      if (isArray(childNode)) {
        return 'Encountered ARRAY in mount, array must be flattened, or normalize used. Location: \n' + getTagName(childNode);
      }
      if (isInvalid(childNode)) {
        if (forceKeyed) {
          return 'Encountered invalid node when preparing to keyed algorithm. Location: \n' + getTagName(childNode);
        } else if (Object.keys(foundKeys).length !== 0) {
          return 'Encountered invalid node with mixed keys. Location: \n' + getTagName(childNode);
        }
        continue;
      }
      if (typeof childNode === 'object') {
        childNode.isValidated = true;
      }
      // Key can be undefined, null too. But typescript complains for no real reason
      var key = childNode.key;
      if (!isNullOrUndef(key) && !isStringOrNumber(key)) {
        return 'Encountered child vNode where key property is not string or number. Location: \n' + getTagName(childNode);
      }
      var children = childNode.children;
      var childFlags = childNode.childFlags;
      if (!isInvalid(children)) {
        var val = void 0;
        if (childFlags & 12 /* ChildFlags.MultipleChildren */) {
          val = DEV_ValidateKeys(children, childNode.childFlags & 8 /* ChildFlags.HasKeyedChildren */);
        } else if (childFlags === 2 /* ChildFlags.HasVNodeChildren */) {
          val = DEV_ValidateKeys([children], childNode.childFlags & 8 /* ChildFlags.HasKeyedChildren */);
        }
        if (val) {
          val += getTagName(childNode);
          return val;
        }
      }
      if (forceKeyed && isNullOrUndef(key)) {
        return 'Encountered child without key during keyed algorithm. If this error points to Array make sure children is flat list. Location: \n' + getTagName(childNode);
      } else if (!forceKeyed && isNullOrUndef(key)) {
        if (Object.keys(foundKeys).length !== 0) {
          return 'Encountered children with key missing. Location: \n' + getTagName(childNode);
        }
        continue;
      }
      if (foundKeys[key]) {
        return 'Encountered two children with same key: {' + key + '}. Location: \n' + getTagName(childNode);
      }
      foundKeys[key] = true;
    }
  }
  function validateVNodeElementChildren(vNode) {
    {
      if (vNode.childFlags & 1 /* ChildFlags.HasInvalidChildren */) {
        return;
      }
      if (vNode.flags & 64 /* VNodeFlags.InputElement */) {
        throwError("input elements can't have children.");
      }
      if (vNode.flags & 128 /* VNodeFlags.TextareaElement */) {
        throwError("textarea elements can't have children.");
      }
      if (vNode.flags & 481 /* VNodeFlags.Element */) {
        var voidTypes = ['area', 'base', 'br', 'col', 'command', 'embed', 'hr', 'img', 'input', 'keygen', 'link', 'meta', 'param', 'source', 'track', 'wbr'];
        var tag = vNode.type.toLowerCase();
        if (tag === 'media') {
          throwError("media elements can't have children.");
        }
        var idx = voidTypes.indexOf(tag);
        if (idx !== -1) {
          throwError(voidTypes[idx] + " elements can't have children.");
        }
      }
    }
  }
  function validateKeys(vNode) {
    {
      // Checks if there is any key missing or duplicate keys
      if (vNode.isValidated === false && vNode.children && vNode.flags & 481 /* VNodeFlags.Element */) {
        var error = DEV_ValidateKeys(Array.isArray(vNode.children) ? vNode.children : [vNode.children], (vNode.childFlags & 8 /* ChildFlags.HasKeyedChildren */) > 0);
        if (error) {
          throwError(error + getTagName(vNode));
        }
      }
      vNode.isValidated = true;
    }
  }
  var keyPrefix = '$';
  function getVNode(childFlags, children, className, flags, key, props, ref, type) {
    {
      return {
        childFlags: childFlags,
        children: children,
        className: className,
        dom: null,
        flags: flags,
        isValidated: false,
        key: key === void 0 ? null : key,
        parentVNode: null,
        props: props === void 0 ? null : props,
        ref: ref === void 0 ? null : ref,
        type: type
      };
    }
  }
  function createVNode(flags, type, className, children, childFlags, props, key, ref) {
    {
      if (flags & 14 /* VNodeFlags.Component */) {
        throwError('Creating Component vNodes using createVNode is not allowed. Use Inferno.createComponentVNode method.');
      }
    }
    var childFlag = childFlags === void 0 ? 1 /* ChildFlags.HasInvalidChildren */ : childFlags;
    var vNode = getVNode(childFlag, children, className, flags, key, props, ref, type);
    if (childFlag === 0 /* ChildFlags.UnknownChildren */) {
      normalizeChildren(vNode, vNode.children);
    }
    {
      validateVNodeElementChildren(vNode);
    }
    return vNode;
  }
  function createComponentVNode(flags, type, props, key, ref) {
    {
      if (flags & 1 /* VNodeFlags.HtmlElement */) {
        throwError('Creating element vNodes using createComponentVNode is not allowed. Use Inferno.createVNode method.');
      }
    }
    if ((flags & 2 /* VNodeFlags.ComponentUnknown */) > 0) {
      flags = type.prototype && isFunction(type.prototype.render) ? 4 /* VNodeFlags.ComponentClass */ : 8 /* VNodeFlags.ComponentFunction */;
    }
    // set default props
    var defaultProps = type.defaultProps;
    if (!isNullOrUndef(defaultProps)) {
      if (!props) {
        props = {}; // Props can be referenced and modified at application level so always create new object
      }
      for (var prop in defaultProps) {
        if (isUndefined(props[prop])) {
          props[prop] = defaultProps[prop];
        }
      }
    }
    if ((flags & 8 /* VNodeFlags.ComponentFunction */) > 0) {
      var defaultHooks = type.defaultHooks;
      if (!isNullOrUndef(defaultHooks)) {
        if (!ref) {
          // As ref cannot be referenced from application level, we can use the same refs object
          ref = defaultHooks;
        } else {
          for (var _prop in defaultHooks) {
            if (isUndefined(ref[_prop])) {
              ref[_prop] = defaultHooks[_prop];
            }
          }
        }
      }
    }
    var vNode = getVNode(1 /* ChildFlags.HasInvalidChildren */, null, null, flags, key, props, ref, type);
    var optsVNode = options.createVNode;
    if (isFunction(optsVNode)) {
      optsVNode(vNode);
    }
    return vNode;
  }
  function createTextVNode(text, key) {
    return getVNode(1 /* ChildFlags.HasInvalidChildren */, isNullOrUndef(text) ? '' : text, null, 16 /* VNodeFlags.Text */, key, null, null, null);
  }
  function normalizeProps(vNode) {
    var props = vNode.props;
    if (props) {
      var flags = vNode.flags;
      if (flags & 481 /* VNodeFlags.Element */) {
        if (props.children !== void 0 && isNullOrUndef(vNode.children)) {
          normalizeChildren(vNode, props.children);
        }
        if (props.className !== void 0) {
          vNode.className = props.className || null;
          props.className = undefined;
        }
      }
      if (props.key !== void 0) {
        vNode.key = props.key;
        props.key = undefined;
      }
      if (props.ref !== void 0) {
        if (flags & 8 /* VNodeFlags.ComponentFunction */) {
          vNode.ref = combineFrom(vNode.ref, props.ref);
        } else {
          vNode.ref = props.ref;
        }
        props.ref = undefined;
      }
    }
    return vNode;
  }
  function directClone(vNodeToClone) {
    var newVNode;
    var flags = vNodeToClone.flags;
    if (flags & 14 /* VNodeFlags.Component */) {
      var props;
      var propsToClone = vNodeToClone.props;
      if (!isNull(propsToClone)) {
        props = {};
        for (var key in propsToClone) {
          props[key] = propsToClone[key];
        }
      }
      newVNode = createComponentVNode(flags, vNodeToClone.type, props, vNodeToClone.key, vNodeToClone.ref);
    } else if (flags & 481 /* VNodeFlags.Element */) {
      newVNode = createVNode(flags, vNodeToClone.type, vNodeToClone.className, vNodeToClone.children, vNodeToClone.childFlags, vNodeToClone.props, vNodeToClone.key, vNodeToClone.ref);
    } else if (flags & 16 /* VNodeFlags.Text */) {
      newVNode = createTextVNode(vNodeToClone.children, vNodeToClone.key);
    } else if (flags & 1024 /* VNodeFlags.Portal */) {
      newVNode = vNodeToClone;
    }
    return newVNode;
  }
  function createVoidVNode() {
    return createTextVNode('', null);
  }
  function _normalizeVNodes(nodes, result, index, currentKey) {
    for (var len = nodes.length; index < len; index++) {
      var n = nodes[index];
      if (!isInvalid(n)) {
        var newKey = currentKey + keyPrefix + index;
        if (isArray(n)) {
          _normalizeVNodes(n, result, 0, newKey);
        } else {
          if (isStringOrNumber(n)) {
            n = createTextVNode(n, newKey);
          } else {
            var oldKey = n.key;
            var isPrefixedKey = isString(oldKey) && oldKey[0] === keyPrefix;
            if (!isNull(n.dom) || isPrefixedKey) {
              n = directClone(n);
            }
            if (isNull(oldKey) || isPrefixedKey) {
              n.key = newKey;
            } else {
              n.key = currentKey + oldKey;
            }
          }
          result.push(n);
        }
      }
    }
  }
  function normalizeChildren(vNode, children) {
    var newChildren;
    var newChildFlags = 1 /* ChildFlags.HasInvalidChildren */;
    // Don't change children to match strict equal (===) true in patching
    if (isInvalid(children)) {
      newChildren = children;
    } else if (isString(children)) {
      newChildFlags = 2 /* ChildFlags.HasVNodeChildren */;
      newChildren = createTextVNode(children);
    } else if (isNumber(children)) {
      newChildFlags = 2 /* ChildFlags.HasVNodeChildren */;
      newChildren = createTextVNode(children + '');
    } else if (isArray(children)) {
      var len = children.length;
      if (len === 0) {
        newChildren = null;
        newChildFlags = 1 /* ChildFlags.HasInvalidChildren */;
      } else {
        // we assign $ which basically means we've flagged this array for future note
        // if it comes back again, we need to clone it, as people are using it
        // in an immutable way
        // tslint:disable-next-line
        if (Object.isFrozen(children) || children['$'] === true) {
          children = children.slice();
        }
        newChildFlags = 8 /* ChildFlags.HasKeyedChildren */;
        for (var i = 0; i < len; i++) {
          var n = children[i];
          if (isInvalid(n) || isArray(n)) {
            newChildren = newChildren || children.slice(0, i);
            _normalizeVNodes(children, newChildren, i, '');
            break;
          } else if (isStringOrNumber(n)) {
            newChildren = newChildren || children.slice(0, i);
            newChildren.push(createTextVNode(n, keyPrefix + i));
          } else {
            var key = n.key;
            var isNullDom = isNull(n.dom);
            var isNullKey = isNull(key);
            var isPrefixed = !isNullKey && isString(key) && key[0] === keyPrefix;
            if (!isNullDom || isNullKey || isPrefixed) {
              newChildren = newChildren || children.slice(0, i);
              if (!isNullDom || isPrefixed) {
                n = directClone(n);
              }
              if (isNullKey || isPrefixed) {
                n.key = keyPrefix + i;
              }
              newChildren.push(n);
            } else if (newChildren) {
              newChildren.push(n);
            }
          }
        }
        newChildren = newChildren || children;
        newChildren.$ = true;
      }
    } else {
      newChildren = children;
      if (!isNull(children.dom)) {
        newChildren = directClone(children);
      }
      newChildFlags = 2 /* ChildFlags.HasVNodeChildren */;
    }
    vNode.children = newChildren;
    vNode.childFlags = newChildFlags;
    {
      validateVNodeElementChildren(vNode);
    }
    return vNode;
  }
  var options = {
    afterRender: null,
    beforeRender: null,
    createVNode: null,
    renderComplete: null
  };
  var xlinkNS = 'http://www.w3.org/1999/xlink';
  var xmlNS = 'http://www.w3.org/XML/1998/namespace';
  var svgNS = 'http://www.w3.org/2000/svg';
  var namespaces = {
    'xlink:actuate': xlinkNS,
    'xlink:arcrole': xlinkNS,
    'xlink:href': xlinkNS,
    'xlink:role': xlinkNS,
    'xlink:show': xlinkNS,
    'xlink:title': xlinkNS,
    'xlink:type': xlinkNS,
    'xml:base': xmlNS,
    'xml:lang': xmlNS,
    'xml:space': xmlNS
  };

  // We need EMPTY_OBJ defined in one place.
  // Its used for comparison so we cant inline it into shared
  var EMPTY_OBJ = {};
  var LIFECYCLE = [];
  {
    Object.freeze(EMPTY_OBJ);
  }
  function appendChild(parentDom, dom) {
    parentDom.appendChild(dom);
  }
  function insertOrAppend(parentDom, newNode, nextNode) {
    if (isNullOrUndef(nextNode)) {
      appendChild(parentDom, newNode);
    } else {
      parentDom.insertBefore(newNode, nextNode);
    }
  }
  function documentCreateElement(tag, isSVG) {
    if (isSVG) {
      return document.createElementNS(svgNS, tag);
    }
    return document.createElement(tag);
  }
  function replaceChild(parentDom, newDom, lastDom) {
    parentDom.replaceChild(newDom, lastDom);
  }
  function removeChild(parentDom, dom) {
    parentDom.removeChild(dom);
  }
  function callAll(arrayFn) {
    var listener;
    while ((listener = arrayFn.shift()) !== undefined) {
      listener();
    }
  }
  var attachedEventCounts = {};
  var attachedEvents = {};
  function handleEvent(name, nextEvent, dom) {
    var eventsLeft = attachedEventCounts[name];
    var eventsObject = dom.$EV;
    if (nextEvent) {
      if (!eventsLeft) {
        attachedEvents[name] = attachEventToDocument(name);
        attachedEventCounts[name] = 0;
      }
      if (!eventsObject) {
        eventsObject = dom.$EV = {};
      }
      if (!eventsObject[name]) {
        attachedEventCounts[name]++;
      }
      eventsObject[name] = nextEvent;
    } else if (eventsObject && eventsObject[name]) {
      attachedEventCounts[name]--;
      if (eventsLeft === 1) {
        document.removeEventListener(normalizeEventName(name), attachedEvents[name]);
        attachedEvents[name] = null;
      }
      eventsObject[name] = nextEvent;
    }
  }
  // When browsers fully support event.composedPath we could loop it through instead of using parentNode property
  function getTargetNode(event) {
    return isFunction(event.composedPath) ? event.composedPath()[0] : event.target;
  }
  function dispatchEvents(event, isClick, name, eventData) {
    var dom = getTargetNode(event);
    while (!isNull(dom)) {
      // Html Nodes can be nested fe: span inside button in that scenario browser does not handle disabled attribute on parent,
      // because the event listener is on document.body
      // Don't process clicks on disabled elements
      if (isClick && dom.disabled) {
        return;
      }
      var eventsObject = dom.$EV;
      if (eventsObject) {
        var currentEvent = eventsObject[name];
        if (currentEvent) {
          // linkEvent object
          eventData.dom = dom;
          if (currentEvent.event) {
            currentEvent.event(currentEvent.data, event);
          } else {
            currentEvent(event);
          }
          if (event.cancelBubble) {
            return;
          }
        }
      }
      dom = dom.parentNode;
    }
  }
  function normalizeEventName(name) {
    return name.substr(2).toLowerCase();
  }
  function stopPropagation$1() {
    this.cancelBubble = true;
    if (!this.immediatePropagationStopped) {
      this.stopImmediatePropagation();
    }
  }
  function attachEventToDocument(name) {
    var docEvent = function docEvent(event) {
      var type = event.type;
      var isClick = type === 'click' || type === 'dblclick';
      if (isClick && event.button !== 0) {
        // Firefox incorrectly triggers click event for mid/right mouse buttons.
        // This bug has been active for 12 years.
        // https://bugzilla.mozilla.org/show_bug.cgi?id=184051
        event.stopPropagation();
        return false;
      }
      event.stopPropagation = stopPropagation$1;
      // Event data needs to be object to save reference to currentTarget getter
      var eventData = {
        dom: document
      };
      Object.defineProperty(event, 'currentTarget', {
        configurable: true,
        get: function get() {
          return eventData.dom;
        }
      });
      dispatchEvents(event, isClick, name, eventData);
      return;
    };
    document.addEventListener(normalizeEventName(name), docEvent);
    return docEvent;
  }
  function isSameInnerHTML(dom, innerHTML) {
    var tempdom = document.createElement('i');
    tempdom.innerHTML = innerHTML;
    return tempdom.innerHTML === dom.innerHTML;
  }
  function isSamePropsInnerHTML(dom, props) {
    return Boolean(props && props.dangerouslySetInnerHTML && props.dangerouslySetInnerHTML.__html && isSameInnerHTML(dom, props.dangerouslySetInnerHTML.__html));
  }
  function triggerEventListener(props, methodName, e) {
    if (props[methodName]) {
      var listener = props[methodName];
      if (listener.event) {
        listener.event(listener.data, e);
      } else {
        listener(e);
      }
    } else {
      var nativeListenerName = methodName.toLowerCase();
      if (props[nativeListenerName]) {
        props[nativeListenerName](e);
      }
    }
  }
  function createWrappedFunction(methodName, applyValue) {
    var fnMethod = function fnMethod(e) {
      e.stopPropagation();
      var vNode = this.$V;
      // If vNode is gone by the time event fires, no-op
      if (!vNode) {
        return;
      }
      var props = vNode.props || EMPTY_OBJ;
      var dom = vNode.dom;
      if (isString(methodName)) {
        triggerEventListener(props, methodName, e);
      } else {
        for (var i = 0; i < methodName.length; i++) {
          triggerEventListener(props, methodName[i], e);
        }
      }
      if (isFunction(applyValue)) {
        var newVNode = this.$V;
        var newProps = newVNode.props || EMPTY_OBJ;
        applyValue(newProps, dom, false, newVNode);
      }
    };
    Object.defineProperty(fnMethod, 'wrapped', {
      configurable: false,
      enumerable: false,
      value: true,
      writable: false
    });
    return fnMethod;
  }
  function isCheckedType(type) {
    return type === 'checkbox' || type === 'radio';
  }
  var onTextInputChange = createWrappedFunction('onInput', applyValueInput);
  var wrappedOnChange$1 = createWrappedFunction(['onClick', 'onChange'], applyValueInput);
  /* tslint:disable-next-line:no-empty */
  function emptywrapper(event) {
    event.stopPropagation();
  }
  emptywrapper.wrapped = true;
  function inputEvents(dom, nextPropsOrEmpty) {
    if (isCheckedType(nextPropsOrEmpty.type)) {
      dom.onchange = wrappedOnChange$1;
      dom.onclick = emptywrapper;
    } else {
      dom.oninput = onTextInputChange;
    }
  }
  function applyValueInput(nextPropsOrEmpty, dom) {
    var type = nextPropsOrEmpty.type;
    var value = nextPropsOrEmpty.value;
    var checked = nextPropsOrEmpty.checked;
    var multiple = nextPropsOrEmpty.multiple;
    var defaultValue = nextPropsOrEmpty.defaultValue;
    var hasValue = !isNullOrUndef(value);
    if (type && type !== dom.type) {
      dom.setAttribute('type', type);
    }
    if (!isNullOrUndef(multiple) && multiple !== dom.multiple) {
      dom.multiple = multiple;
    }
    if (!isNullOrUndef(defaultValue) && !hasValue) {
      dom.defaultValue = defaultValue + '';
    }
    if (isCheckedType(type)) {
      if (hasValue) {
        dom.value = value;
      }
      if (!isNullOrUndef(checked)) {
        dom.checked = checked;
      }
    } else {
      if (hasValue && dom.value !== value) {
        dom.defaultValue = value;
        dom.value = value;
      } else if (!isNullOrUndef(checked)) {
        dom.checked = checked;
      }
    }
  }
  function updateChildOptionGroup(vNode, value) {
    var type = vNode.type;
    if (type === 'optgroup') {
      var children = vNode.children;
      var childFlags = vNode.childFlags;
      if (childFlags & 12 /* ChildFlags.MultipleChildren */) {
        for (var i = 0, len = children.length; i < len; i++) {
          updateChildOption(children[i], value);
        }
      } else if (childFlags === 2 /* ChildFlags.HasVNodeChildren */) {
        updateChildOption(children, value);
      }
    } else {
      updateChildOption(vNode, value);
    }
  }
  function updateChildOption(vNode, value) {
    var props = vNode.props || EMPTY_OBJ;
    var dom = vNode.dom;
    // we do this as multiple may have changed
    dom.value = props.value;
    if (isArray(value) && value.indexOf(props.value) !== -1 || props.value === value) {
      dom.selected = true;
    } else if (!isNullOrUndef(value) || !isNullOrUndef(props.selected)) {
      dom.selected = props.selected || false;
    }
  }
  var onSelectChange = createWrappedFunction('onChange', applyValueSelect);
  function selectEvents(dom) {
    dom.onchange = onSelectChange;
  }
  function applyValueSelect(nextPropsOrEmpty, dom, mounting, vNode) {
    var multiplePropInBoolean = Boolean(nextPropsOrEmpty.multiple);
    if (!isNullOrUndef(nextPropsOrEmpty.multiple) && multiplePropInBoolean !== dom.multiple) {
      dom.multiple = multiplePropInBoolean;
    }
    var childFlags = vNode.childFlags;
    if ((childFlags & 1 /* ChildFlags.HasInvalidChildren */) === 0) {
      var children = vNode.children;
      var value = nextPropsOrEmpty.value;
      if (mounting && isNullOrUndef(value)) {
        value = nextPropsOrEmpty.defaultValue;
      }
      if (childFlags & 12 /* ChildFlags.MultipleChildren */) {
        for (var i = 0, len = children.length; i < len; i++) {
          updateChildOptionGroup(children[i], value);
        }
      } else if (childFlags === 2 /* ChildFlags.HasVNodeChildren */) {
        updateChildOptionGroup(children, value);
      }
    }
  }
  var onTextareaInputChange = createWrappedFunction('onInput', applyValueTextArea);
  var wrappedOnChange = createWrappedFunction('onChange');
  function textAreaEvents(dom, nextPropsOrEmpty) {
    dom.oninput = onTextareaInputChange;
    if (nextPropsOrEmpty.onChange) {
      dom.onchange = wrappedOnChange;
    }
  }
  function applyValueTextArea(nextPropsOrEmpty, dom, mounting) {
    var value = nextPropsOrEmpty.value;
    var domValue = dom.value;
    if (isNullOrUndef(value)) {
      if (mounting) {
        var defaultValue = nextPropsOrEmpty.defaultValue;
        if (!isNullOrUndef(defaultValue) && defaultValue !== domValue) {
          dom.defaultValue = defaultValue;
          dom.value = defaultValue;
        }
      }
    } else if (domValue !== value) {
      /* There is value so keep it controlled */
      dom.defaultValue = value;
      dom.value = value;
    }
  }

  /**
   * There is currently no support for switching same input between controlled and nonControlled
   * If that ever becomes a real issue, then re design controlled elements
   * Currently user must choose either controlled or non-controlled and stick with that
   */
  function processElement(flags, vNode, dom, nextPropsOrEmpty, mounting, isControlled) {
    if (flags & 64 /* VNodeFlags.InputElement */) {
      applyValueInput(nextPropsOrEmpty, dom);
    } else if (flags & 256 /* VNodeFlags.SelectElement */) {
      applyValueSelect(nextPropsOrEmpty, dom, mounting, vNode);
    } else if (flags & 128 /* VNodeFlags.TextareaElement */) {
      applyValueTextArea(nextPropsOrEmpty, dom, mounting);
    }
    if (isControlled) {
      dom.$V = vNode;
    }
  }
  function addFormElementEventHandlers(flags, dom, nextPropsOrEmpty) {
    if (flags & 64 /* VNodeFlags.InputElement */) {
      inputEvents(dom, nextPropsOrEmpty);
    } else if (flags & 256 /* VNodeFlags.SelectElement */) {
      selectEvents(dom);
    } else if (flags & 128 /* VNodeFlags.TextareaElement */) {
      textAreaEvents(dom, nextPropsOrEmpty);
    }
  }
  function isControlledFormElement(nextPropsOrEmpty) {
    return nextPropsOrEmpty.type && isCheckedType(nextPropsOrEmpty.type) ? !isNullOrUndef(nextPropsOrEmpty.checked) : !isNullOrUndef(nextPropsOrEmpty.value);
  }
  function remove$1(vNode, parentDom) {
    unmount(vNode);
    if (parentDom && vNode.dom) {
      removeChild(parentDom, vNode.dom);
      // Let carbage collector free memory
      vNode.dom = null;
    }
  }
  function unmount(vNode) {
    var flags = vNode.flags;
    if (flags & 481 /* VNodeFlags.Element */) {
      var ref = vNode.ref;
      var props = vNode.props;
      if (isFunction(ref)) {
        ref(null);
      }
      var children = vNode.children;
      var childFlags = vNode.childFlags;
      if (childFlags & 12 /* ChildFlags.MultipleChildren */) {
        unmountAllChildren(children);
      } else if (childFlags === 2 /* ChildFlags.HasVNodeChildren */) {
        unmount(children);
      }
      if (!isNull(props)) {
        for (var name in props) {
          switch (name) {
            case 'onClick':
            case 'onDblClick':
            case 'onFocusIn':
            case 'onFocusOut':
            case 'onKeyDown':
            case 'onKeyPress':
            case 'onKeyUp':
            case 'onMouseDown':
            case 'onMouseMove':
            case 'onMouseUp':
            case 'onSubmit':
            case 'onTouchEnd':
            case 'onTouchMove':
            case 'onTouchStart':
              handleEvent(name, null, vNode.dom);
              break;
          }
        }
      }
    } else {
      var _children = vNode.children;
      // Safe guard for crashed VNode
      if (_children) {
        if (flags & 14 /* VNodeFlags.Component */) {
          var _ref = vNode.ref;
          if (flags & 4 /* VNodeFlags.ComponentClass */) {
            if (isFunction(_children.componentWillUnmount)) {
              _children.componentWillUnmount();
            }
            if (isFunction(_ref)) {
              _ref(null);
            }
            _children.$UN = true;
            if (_children.$LI) {
              unmount(_children.$LI);
            }
          } else {
            if (!isNullOrUndef(_ref) && isFunction(_ref.onComponentWillUnmount)) {
              _ref.onComponentWillUnmount(vNode.dom, vNode.props || EMPTY_OBJ);
            }
            unmount(_children);
          }
        } else if (flags & 1024 /* VNodeFlags.Portal */) {
          remove$1(_children, vNode.type);
        }
      }
    }
  }
  function unmountAllChildren(children) {
    for (var i = 0, len = children.length; i < len; i++) {
      unmount(children[i]);
    }
  }
  function removeAllChildren(dom, children) {
    unmountAllChildren(children);
    dom.textContent = '';
  }
  function createLinkEvent(linkEvent, nextValue) {
    return function (e) {
      linkEvent(nextValue.data, e);
    };
  }
  function patchEvent(name, nextValue, dom) {
    var nameLowerCase = name.toLowerCase();
    if (!isFunction(nextValue) && !isNullOrUndef(nextValue)) {
      var linkEvent = nextValue.event;
      if (linkEvent && isFunction(linkEvent)) {
        dom[nameLowerCase] = createLinkEvent(linkEvent, nextValue);
      } else {
        // Development warning
        {
          throwError("an event on a VNode \"" + name + "\". was not a function or a valid linkEvent.");
        }
      }
    } else {
      var domEvent = dom[nameLowerCase];
      // if the function is wrapped, that means it's been controlled by a wrapper
      if (!domEvent || !domEvent.wrapped) {
        dom[nameLowerCase] = nextValue;
      }
    }
  }
  function getNumberStyleValue(style, value) {
    switch (style) {
      case 'animationIterationCount':
      case 'borderImageOutset':
      case 'borderImageSlice':
      case 'borderImageWidth':
      case 'boxFlex':
      case 'boxFlexGroup':
      case 'boxOrdinalGroup':
      case 'columnCount':
      case 'fillOpacity':
      case 'flex':
      case 'flexGrow':
      case 'flexNegative':
      case 'flexOrder':
      case 'flexPositive':
      case 'flexShrink':
      case 'floodOpacity':
      case 'fontWeight':
      case 'gridColumn':
      case 'gridRow':
      case 'lineClamp':
      case 'lineHeight':
      case 'opacity':
      case 'order':
      case 'orphans':
      case 'stopOpacity':
      case 'strokeDasharray':
      case 'strokeDashoffset':
      case 'strokeMiterlimit':
      case 'strokeOpacity':
      case 'strokeWidth':
      case 'tabSize':
      case 'widows':
      case 'zIndex':
      case 'zoom':
        return value;
      default:
        return value + 'px';
    }
  }
  // We are assuming here that we come from patchProp routine
  // -nextAttrValue cannot be null or undefined
  function patchStyle(lastAttrValue, nextAttrValue, dom) {
    var domStyle = dom.style;
    var style;
    var value;
    if (isString(nextAttrValue)) {
      domStyle.cssText = nextAttrValue;
      return;
    }
    if (!isNullOrUndef(lastAttrValue) && !isString(lastAttrValue)) {
      for (style in nextAttrValue) {
        // do not add a hasOwnProperty check here, it affects performance
        value = nextAttrValue[style];
        if (value !== lastAttrValue[style]) {
          domStyle[style] = isNumber(value) ? getNumberStyleValue(style, value) : value;
        }
      }
      for (style in lastAttrValue) {
        if (isNullOrUndef(nextAttrValue[style])) {
          domStyle[style] = '';
        }
      }
    } else {
      for (style in nextAttrValue) {
        value = nextAttrValue[style];
        domStyle[style] = isNumber(value) ? getNumberStyleValue(style, value) : value;
      }
    }
  }
  function patchProp(prop, lastValue, nextValue, dom, isSVG, hasControlledValue, lastVNode) {
    switch (prop) {
      case 'onClick':
      case 'onDblClick':
      case 'onFocusIn':
      case 'onFocusOut':
      case 'onKeyDown':
      case 'onKeyPress':
      case 'onKeyUp':
      case 'onMouseDown':
      case 'onMouseMove':
      case 'onMouseUp':
      case 'onSubmit':
      case 'onTouchEnd':
      case 'onTouchMove':
      case 'onTouchStart':
        handleEvent(prop, nextValue, dom);
        break;
      case 'children':
      case 'childrenType':
      case 'className':
      case 'defaultValue':
      case 'key':
      case 'multiple':
      case 'ref':
        break;
      case 'autoFocus':
        dom.autofocus = !!nextValue;
        break;
      case 'allowfullscreen':
      case 'autoplay':
      case 'capture':
      case 'checked':
      case 'controls':
      case 'default':
      case 'disabled':
      case 'hidden':
      case 'indeterminate':
      case 'loop':
      case 'muted':
      case 'novalidate':
      case 'open':
      case 'readOnly':
      case 'required':
      case 'reversed':
      case 'scoped':
      case 'seamless':
      case 'selected':
        dom[prop] = !!nextValue;
        break;
      case 'defaultChecked':
      case 'value':
      case 'volume':
        if (hasControlledValue && prop === 'value') {
          return;
        }
        var value = isNullOrUndef(nextValue) ? '' : nextValue;
        if (dom[prop] !== value) {
          dom[prop] = value;
        }
        break;
      case 'dangerouslySetInnerHTML':
        var lastHtml = lastValue && lastValue.__html || '';
        var nextHtml = nextValue && nextValue.__html || '';
        if (lastHtml !== nextHtml) {
          if (!isNullOrUndef(nextHtml) && !isSameInnerHTML(dom, nextHtml)) {
            if (!isNull(lastVNode)) {
              if (lastVNode.childFlags & 12 /* ChildFlags.MultipleChildren */) {
                unmountAllChildren(lastVNode.children);
              } else if (lastVNode.childFlags === 2 /* ChildFlags.HasVNodeChildren */) {
                unmount(lastVNode.children);
              }
              lastVNode.children = null;
              lastVNode.childFlags = 1 /* ChildFlags.HasInvalidChildren */;
            }
            dom.innerHTML = nextHtml;
          }
        }
        break;
      default:
        if (prop[0] === 'o' && prop[1] === 'n') {
          patchEvent(prop, nextValue, dom);
        } else if (isNullOrUndef(nextValue)) {
          dom.removeAttribute(prop);
        } else if (prop === 'style') {
          patchStyle(lastValue, nextValue, dom);
        } else if (isSVG && namespaces[prop]) {
          // We optimize for isSVG being false
          // If we end up in this path we can read property again
          dom.setAttributeNS(namespaces[prop], prop, nextValue);
        } else {
          dom.setAttribute(prop, nextValue);
        }
        break;
    }
  }
  function mountProps(vNode, flags, props, dom, isSVG) {
    var hasControlledValue = false;
    var isFormElement = (flags & 448 /* VNodeFlags.FormElement */) > 0;
    if (isFormElement) {
      hasControlledValue = isControlledFormElement(props);
      if (hasControlledValue) {
        addFormElementEventHandlers(flags, dom, props);
      }
    }
    for (var prop in props) {
      // do not add a hasOwnProperty check here, it affects performance
      patchProp(prop, null, props[prop], dom, isSVG, hasControlledValue, null);
    }
    if (isFormElement) {
      processElement(flags, vNode, dom, props, true, hasControlledValue);
    }
  }
  function createClassComponentInstance(vNode, Component, props, context) {
    var instance = new Component(props, context);
    vNode.children = instance;
    instance.$V = vNode;
    instance.$BS = false;
    instance.context = context;
    if (instance.props === EMPTY_OBJ) {
      instance.props = props;
    }
    instance.$UN = false;
    if (isFunction(instance.componentWillMount)) {
      instance.$BR = true;
      instance.componentWillMount();
      if (instance.$PSS) {
        var state = instance.state;
        var pending = instance.$PS;
        if (isNull(state)) {
          instance.state = pending;
        } else {
          for (var key in pending) {
            state[key] = pending[key];
          }
        }
        instance.$PSS = false;
        instance.$PS = null;
      }
      instance.$BR = false;
    }
    if (isFunction(options.beforeRender)) {
      options.beforeRender(instance);
    }
    var input = handleComponentInput(instance.render(props, instance.state, context), vNode);
    var childContext;
    if (isFunction(instance.getChildContext)) {
      childContext = instance.getChildContext();
    }
    if (isNullOrUndef(childContext)) {
      instance.$CX = context;
    } else {
      instance.$CX = combineFrom(context, childContext);
    }
    if (isFunction(options.afterRender)) {
      options.afterRender(instance);
    }
    instance.$LI = input;
    return instance;
  }
  function handleComponentInput(input, componentVNode) {
    // Development validation
    {
      if (isArray(input)) {
        throwError('a valid Inferno VNode (or null) must be returned from a component render. You may have returned an array or an invalid object.');
      }
    }
    if (isInvalid(input)) {
      input = createVoidVNode();
    } else if (isStringOrNumber(input)) {
      input = createTextVNode(input, null);
    } else {
      if (input.dom) {
        input = directClone(input);
      }
      if (input.flags & 14 /* VNodeFlags.Component */) {
        // if we have an input that is also a component, we run into a tricky situation
        // where the root vNode needs to always have the correct DOM entry
        // we can optimise this in the future, but this gets us out of a lot of issues
        input.parentVNode = componentVNode;
      }
    }
    return input;
  }
  function mount(vNode, parentDom, context, isSVG) {
    var flags = vNode.flags;
    if (flags & 481 /* VNodeFlags.Element */) {
      return mountElement(vNode, parentDom, context, isSVG);
    }
    if (flags & 14 /* VNodeFlags.Component */) {
      return mountComponent(vNode, parentDom, context, isSVG, (flags & 4 /* VNodeFlags.ComponentClass */) > 0);
    }
    if (flags & 512 /* VNodeFlags.Void */ || flags & 16 /* VNodeFlags.Text */) {
      return mountText(vNode, parentDom);
    }
    if (flags & 1024 /* VNodeFlags.Portal */) {
      mount(vNode.children, vNode.type, context, false);
      return vNode.dom = mountText(createVoidVNode(), parentDom);
    }
    // Development validation, in production we don't need to throw because it crashes anyway
    {
      if (typeof vNode === 'object') {
        throwError("mount() received an object that's not a valid VNode, you should stringify it first, fix createVNode flags or call normalizeChildren. Object: \"" + JSON.stringify(vNode) + "\".");
      } else {
        throwError("mount() expects a valid VNode, instead it received an object with the type \"" + typeof vNode + "\".");
      }
    }
  }
  function mountText(vNode, parentDom) {
    var dom = vNode.dom = document.createTextNode(vNode.children);
    if (!isNull(parentDom)) {
      appendChild(parentDom, dom);
    }
    return dom;
  }
  function mountElement(vNode, parentDom, context, isSVG) {
    var flags = vNode.flags;
    var children = vNode.children;
    var props = vNode.props;
    var className = vNode.className;
    var ref = vNode.ref;
    var childFlags = vNode.childFlags;
    isSVG = isSVG || (flags & 32 /* VNodeFlags.SvgElement */) > 0;
    var dom = documentCreateElement(vNode.type, isSVG);
    vNode.dom = dom;
    if (!isNullOrUndef(className) && className !== '') {
      if (isSVG) {
        dom.setAttribute('class', className);
      } else {
        dom.className = className;
      }
    }
    {
      validateKeys(vNode);
    }
    if (!isNull(parentDom)) {
      appendChild(parentDom, dom);
    }
    if ((childFlags & 1 /* ChildFlags.HasInvalidChildren */) === 0) {
      var childrenIsSVG = isSVG === true && vNode.type !== 'foreignObject';
      if (childFlags === 2 /* ChildFlags.HasVNodeChildren */) {
        mount(children, dom, context, childrenIsSVG);
      } else if (childFlags & 12 /* ChildFlags.MultipleChildren */) {
        mountArrayChildren(children, dom, context, childrenIsSVG);
      }
    }
    if (!isNull(props)) {
      mountProps(vNode, flags, props, dom, isSVG);
    }
    {
      if (isString(ref)) {
        throwError('string "refs" are not supported in Inferno 1.0. Use callback "refs" instead.');
      }
    }
    if (isFunction(ref)) {
      mountRef(dom, ref);
    }
    return dom;
  }
  function mountArrayChildren(children, dom, context, isSVG) {
    for (var i = 0, len = children.length; i < len; i++) {
      var child = children[i];
      if (!isNull(child.dom)) {
        children[i] = child = directClone(child);
      }
      mount(child, dom, context, isSVG);
    }
  }
  function mountComponent(vNode, parentDom, context, isSVG, isClass) {
    var dom;
    var type = vNode.type;
    var props = vNode.props || EMPTY_OBJ;
    var ref = vNode.ref;
    if (isClass) {
      var instance = createClassComponentInstance(vNode, type, props, context);
      vNode.dom = dom = mount(instance.$LI, null, instance.$CX, isSVG);
      mountClassComponentCallbacks(vNode, ref, instance);
      instance.$UPD = false;
    } else {
      var input = handleComponentInput(type(props, context), vNode);
      vNode.children = input;
      vNode.dom = dom = mount(input, null, context, isSVG);
      mountFunctionalComponentCallbacks(props, ref, dom);
    }
    if (!isNull(parentDom)) {
      appendChild(parentDom, dom);
    }
    return dom;
  }
  function createClassMountCallback(instance) {
    return function () {
      instance.$UPD = true;
      instance.componentDidMount();
      instance.$UPD = false;
    };
  }
  function mountClassComponentCallbacks(vNode, ref, instance) {
    if (isFunction(ref)) {
      ref(instance);
    } else {
      {
        if (isStringOrNumber(ref)) {
          throwError('string "refs" are not supported in Inferno 1.0. Use callback "refs" instead.');
        } else if (!isNullOrUndef(ref) && isObject(ref) && vNode.flags & 4 /* VNodeFlags.ComponentClass */) {
          throwError('functional component lifecycle events are not supported on ES2015 class components.');
        }
      }
    }
    if (isFunction(instance.componentDidMount)) {
      LIFECYCLE.push(createClassMountCallback(instance));
    }
  }
  function createOnMountCallback(ref, dom, props) {
    return function () {
      return ref.onComponentDidMount(dom, props);
    };
  }
  function mountFunctionalComponentCallbacks(props, ref, dom) {
    if (!isNullOrUndef(ref)) {
      if (isFunction(ref.onComponentWillMount)) {
        ref.onComponentWillMount(props);
      }
      if (isFunction(ref.onComponentDidMount)) {
        LIFECYCLE.push(createOnMountCallback(ref, dom, props));
      }
    }
  }
  function mountRef(dom, value) {
    LIFECYCLE.push(function () {
      return value(dom);
    });
  }
  function hydrateComponent(vNode, dom, context, isSVG, isClass) {
    var type = vNode.type;
    var ref = vNode.ref;
    var props = vNode.props || EMPTY_OBJ;
    if (isClass) {
      var instance = createClassComponentInstance(vNode, type, props, context);
      var input = instance.$LI;
      hydrateVNode(input, dom, instance.$CX, isSVG);
      vNode.dom = input.dom;
      mountClassComponentCallbacks(vNode, ref, instance);
      instance.$UPD = false; // Mount finished allow going sync
    } else {
      var _input = handleComponentInput(type(props, context), vNode);
      hydrateVNode(_input, dom, context, isSVG);
      vNode.children = _input;
      vNode.dom = _input.dom;
      mountFunctionalComponentCallbacks(props, ref, dom);
    }
  }
  function hydrateElement(vNode, dom, context, isSVG) {
    var children = vNode.children;
    var props = vNode.props;
    var className = vNode.className;
    var flags = vNode.flags;
    var ref = vNode.ref;
    isSVG = isSVG || (flags & 32 /* VNodeFlags.SvgElement */) > 0;
    if (dom.nodeType !== 1 || dom.tagName.toLowerCase() !== vNode.type) {
      {
        warning("Inferno hydration: Server-side markup doesn't match client-side markup or Initial render target is not empty");
      }
      var newDom = mountElement(vNode, null, context, isSVG);
      vNode.dom = newDom;
      replaceChild(dom.parentNode, newDom, dom);
    } else {
      vNode.dom = dom;
      var childNode = dom.firstChild;
      var childFlags = vNode.childFlags;
      if ((childFlags & 1 /* ChildFlags.HasInvalidChildren */) === 0) {
        var nextSibling = null;
        while (childNode) {
          nextSibling = childNode.nextSibling;
          if (childNode.nodeType === 8) {
            if (childNode.data === '!') {
              dom.replaceChild(document.createTextNode(''), childNode);
            } else {
              dom.removeChild(childNode);
            }
          }
          childNode = nextSibling;
        }
        childNode = dom.firstChild;
        if (childFlags === 2 /* ChildFlags.HasVNodeChildren */) {
          if (isNull(childNode)) {
            mount(children, dom, context, isSVG);
          } else {
            nextSibling = childNode.nextSibling;
            hydrateVNode(children, childNode, context, isSVG);
            childNode = nextSibling;
          }
        } else if (childFlags & 12 /* ChildFlags.MultipleChildren */) {
          for (var i = 0, len = children.length; i < len; i++) {
            var child = children[i];
            if (isNull(childNode)) {
              mount(child, dom, context, isSVG);
            } else {
              nextSibling = childNode.nextSibling;
              hydrateVNode(child, childNode, context, isSVG);
              childNode = nextSibling;
            }
          }
        }
        // clear any other DOM nodes, there should be only a single entry for the root
        while (childNode) {
          nextSibling = childNode.nextSibling;
          dom.removeChild(childNode);
          childNode = nextSibling;
        }
      } else if (!isNull(dom.firstChild) && !isSamePropsInnerHTML(dom, props)) {
        dom.textContent = ''; // dom has content, but VNode has no children remove everything from DOM
        if (flags & 448 /* VNodeFlags.FormElement */) {
          // If element is form element, we need to clear defaultValue also
          dom.defaultValue = '';
        }
      }
      if (!isNull(props)) {
        mountProps(vNode, flags, props, dom, isSVG);
      }
      if (isNullOrUndef(className)) {
        if (dom.className !== '') {
          dom.removeAttribute('class');
        }
      } else if (isSVG) {
        dom.setAttribute('class', className);
      } else {
        dom.className = className;
      }
      if (isFunction(ref)) {
        mountRef(dom, ref);
      } else {
        {
          if (isString(ref)) {
            throwError('string "refs" are not supported in Inferno 1.0. Use callback "refs" instead.');
          }
        }
      }
    }
  }
  function hydrateText(vNode, dom) {
    if (dom.nodeType !== 3) {
      var newDom = mountText(vNode, null);
      vNode.dom = newDom;
      replaceChild(dom.parentNode, newDom, dom);
    } else {
      var text = vNode.children;
      if (dom.nodeValue !== text) {
        dom.nodeValue = text;
      }
      vNode.dom = dom;
    }
  }
  function hydrateVNode(vNode, dom, context, isSVG) {
    var flags = vNode.flags;
    if (flags & 14 /* VNodeFlags.Component */) {
      hydrateComponent(vNode, dom, context, isSVG, (flags & 4 /* VNodeFlags.ComponentClass */) > 0);
    } else if (flags & 481 /* VNodeFlags.Element */) {
      hydrateElement(vNode, dom, context, isSVG);
    } else if (flags & 16 /* VNodeFlags.Text */) {
      hydrateText(vNode, dom);
    } else if (flags & 512 /* VNodeFlags.Void */) {
      vNode.dom = dom;
    } else {
      {
        throwError("hydrate() expects a valid VNode, instead it received an object with the type \"" + typeof vNode + "\".");
      }
      throwError();
    }
  }
  function hydrate(input, parentDom, callback) {
    var dom = parentDom.firstChild;
    if (!isNull(dom)) {
      if (!isInvalid(input)) {
        hydrateVNode(input, dom, EMPTY_OBJ, false);
      }
      dom = parentDom.firstChild;
      // clear any other DOM nodes, there should be only a single entry for the root
      while (dom = dom.nextSibling) {
        parentDom.removeChild(dom);
      }
    }
    if (LIFECYCLE.length > 0) {
      callAll(LIFECYCLE);
    }
    parentDom.$V = input;
    if (isFunction(callback)) {
      callback();
    }
  }
  function replaceWithNewNode(lastNode, nextNode, parentDom, context, isSVG) {
    unmount(lastNode);
    replaceChild(parentDom, mount(nextNode, null, context, isSVG), lastNode.dom);
  }
  function patch(lastVNode, nextVNode, parentDom, context, isSVG) {
    var nextFlags = nextVNode.flags | 0;
    if (lastVNode.flags !== nextFlags || nextFlags & 2048 /* VNodeFlags.ReCreate */) {
      replaceWithNewNode(lastVNode, nextVNode, parentDom, context, isSVG);
    } else if (nextFlags & 481 /* VNodeFlags.Element */) {
      patchElement(lastVNode, nextVNode, parentDom, context, isSVG, nextFlags);
    } else if (nextFlags & 14 /* VNodeFlags.Component */) {
      patchComponent(lastVNode, nextVNode, parentDom, context, isSVG, (nextFlags & 4 /* VNodeFlags.ComponentClass */) > 0);
    } else if (nextFlags & 16 /* VNodeFlags.Text */) {
      patchText(lastVNode, nextVNode);
    } else if (nextFlags & 512 /* VNodeFlags.Void */) {
      nextVNode.dom = lastVNode.dom;
    } else {
      patchPortal(lastVNode, nextVNode, context);
    }
  }
  function patchContentEditableChildren(dom, nextVNode) {
    if (dom.textContent !== nextVNode.children) {
      dom.textContent = nextVNode.children;
    }
  }
  function patchPortal(lastVNode, nextVNode, context) {
    var lastContainer = lastVNode.type;
    var nextContainer = nextVNode.type;
    var nextChildren = nextVNode.children;
    patchChildren(lastVNode.childFlags, nextVNode.childFlags, lastVNode.children, nextChildren, lastContainer, context, false);
    nextVNode.dom = lastVNode.dom;
    if (lastContainer !== nextContainer && !isInvalid(nextChildren)) {
      var node = nextChildren.dom;
      lastContainer.removeChild(node);
      nextContainer.appendChild(node);
    }
  }
  function patchElement(lastVNode, nextVNode, parentDom, context, isSVG, nextFlags) {
    var nextTag = nextVNode.type;
    if (lastVNode.type !== nextTag) {
      replaceWithNewNode(lastVNode, nextVNode, parentDom, context, isSVG);
    } else {
      var dom = lastVNode.dom;
      var lastProps = lastVNode.props;
      var nextProps = nextVNode.props;
      var isFormElement = false;
      var hasControlledValue = false;
      var nextPropsOrEmpty;
      nextVNode.dom = dom;
      isSVG = isSVG || (nextFlags & 32 /* VNodeFlags.SvgElement */) > 0;
      // inlined patchProps  -- starts --
      if (lastProps !== nextProps) {
        var lastPropsOrEmpty = lastProps || EMPTY_OBJ;
        nextPropsOrEmpty = nextProps || EMPTY_OBJ;
        if (nextPropsOrEmpty !== EMPTY_OBJ) {
          isFormElement = (nextFlags & 448 /* VNodeFlags.FormElement */) > 0;
          if (isFormElement) {
            hasControlledValue = isControlledFormElement(nextPropsOrEmpty);
          }
          for (var prop in nextPropsOrEmpty) {
            var lastValue = lastPropsOrEmpty[prop];
            var nextValue = nextPropsOrEmpty[prop];
            if (lastValue !== nextValue) {
              patchProp(prop, lastValue, nextValue, dom, isSVG, hasControlledValue, lastVNode);
            }
          }
        }
        if (lastPropsOrEmpty !== EMPTY_OBJ) {
          for (var _prop in lastPropsOrEmpty) {
            if (!nextPropsOrEmpty.hasOwnProperty(_prop) && !isNullOrUndef(lastPropsOrEmpty[_prop])) {
              patchProp(_prop, lastPropsOrEmpty[_prop], null, dom, isSVG, hasControlledValue, lastVNode);
            }
          }
        }
      }
      var lastChildren = lastVNode.children;
      var nextChildren = nextVNode.children;
      var nextRef = nextVNode.ref;
      var lastClassName = lastVNode.className;
      var nextClassName = nextVNode.className;
      {
        validateKeys(nextVNode);
      }
      if (nextFlags & 4096 /* VNodeFlags.ContentEditable */) {
        patchContentEditableChildren(dom, nextChildren);
      } else {
        patchChildren(lastVNode.childFlags, nextVNode.childFlags, lastChildren, nextChildren, dom, context, isSVG && nextTag !== 'foreignObject');
      }
      if (isFormElement) {
        processElement(nextFlags, nextVNode, dom, nextPropsOrEmpty, false, hasControlledValue);
      }
      // inlined patchProps  -- ends --
      if (lastClassName !== nextClassName) {
        if (isNullOrUndef(nextClassName)) {
          dom.removeAttribute('class');
        } else if (isSVG) {
          dom.setAttribute('class', nextClassName);
        } else {
          dom.className = nextClassName;
        }
      }
      if (isFunction(nextRef) && lastVNode.ref !== nextRef) {
        mountRef(dom, nextRef);
      } else {
        {
          if (isString(nextRef)) {
            throwError('string "refs" are not supported in Inferno 1.0. Use callback "refs" instead.');
          }
        }
      }
    }
  }
  function patchChildren(lastChildFlags, nextChildFlags, lastChildren, nextChildren, parentDOM, context, isSVG) {
    switch (lastChildFlags) {
      case 2 /* ChildFlags.HasVNodeChildren */:
        switch (nextChildFlags) {
          case 2 /* ChildFlags.HasVNodeChildren */:
            patch(lastChildren, nextChildren, parentDOM, context, isSVG);
            break;
          case 1 /* ChildFlags.HasInvalidChildren */:
            remove$1(lastChildren, parentDOM);
            break;
          default:
            remove$1(lastChildren, parentDOM);
            mountArrayChildren(nextChildren, parentDOM, context, isSVG);
            break;
        }
        break;
      case 1 /* ChildFlags.HasInvalidChildren */:
        switch (nextChildFlags) {
          case 2 /* ChildFlags.HasVNodeChildren */:
            mount(nextChildren, parentDOM, context, isSVG);
            break;
          case 1 /* ChildFlags.HasInvalidChildren */:
            break;
          default:
            mountArrayChildren(nextChildren, parentDOM, context, isSVG);
            break;
        }
        break;
      default:
        if (nextChildFlags & 12 /* ChildFlags.MultipleChildren */) {
          var lastLength = lastChildren.length;
          var nextLength = nextChildren.length;
          // Fast path's for both algorithms
          if (lastLength === 0) {
            if (nextLength > 0) {
              mountArrayChildren(nextChildren, parentDOM, context, isSVG);
            }
          } else if (nextLength === 0) {
            removeAllChildren(parentDOM, lastChildren);
          } else if (nextChildFlags === 8 /* ChildFlags.HasKeyedChildren */ && lastChildFlags === 8 /* ChildFlags.HasKeyedChildren */) {
            patchKeyedChildren(lastChildren, nextChildren, parentDOM, context, isSVG, lastLength, nextLength);
          } else {
            patchNonKeyedChildren(lastChildren, nextChildren, parentDOM, context, isSVG, lastLength, nextLength);
          }
        } else if (nextChildFlags === 1 /* ChildFlags.HasInvalidChildren */) {
          removeAllChildren(parentDOM, lastChildren);
        } else if (nextChildFlags === 2 /* ChildFlags.HasVNodeChildren */) {
          removeAllChildren(parentDOM, lastChildren);
          mount(nextChildren, parentDOM, context, isSVG);
        }
        break;
    }
  }
  function updateClassComponent(instance, nextState, nextVNode, nextProps, parentDom, context, isSVG, force, fromSetState) {
    var lastState = instance.state;
    var lastProps = instance.props;
    nextVNode.children = instance;
    var renderOutput;
    if (instance.$UN) {
      {
        warning('Inferno Error: Can only update a mounted or mounting component. This usually means you called setState() or forceUpdate() on an unmounted component. This is a no-op.');
      }
      return;
    }
    if (lastProps !== nextProps || nextProps === EMPTY_OBJ) {
      if (!fromSetState && isFunction(instance.componentWillReceiveProps)) {
        instance.$BR = true;
        instance.componentWillReceiveProps(nextProps, context);
        // If instance component was removed during its own update do nothing.
        if (instance.$UN) {
          return;
        }
        instance.$BR = false;
      }
      if (instance.$PSS) {
        nextState = combineFrom(nextState, instance.$PS);
        instance.$PSS = false;
        instance.$PS = null;
      }
    }
    /* Update if scu is not defined, or it returns truthy value or force */
    var hasSCU = Boolean(instance.shouldComponentUpdate);
    if (force || !hasSCU || hasSCU && instance.shouldComponentUpdate(nextProps, nextState, context)) {
      if (isFunction(instance.componentWillUpdate)) {
        instance.$BS = true;
        instance.componentWillUpdate(nextProps, nextState, context);
        instance.$BS = false;
      }
      instance.props = nextProps;
      instance.state = nextState;
      instance.context = context;
      if (isFunction(options.beforeRender)) {
        options.beforeRender(instance);
      }
      renderOutput = instance.render(nextProps, nextState, context);
      if (isFunction(options.afterRender)) {
        options.afterRender(instance);
      }
      var didUpdate = renderOutput !== NO_OP;
      var childContext;
      if (isFunction(instance.getChildContext)) {
        childContext = instance.getChildContext();
      }
      if (isNullOrUndef(childContext)) {
        childContext = context;
      } else {
        childContext = combineFrom(context, childContext);
      }
      instance.$CX = childContext;
      if (didUpdate) {
        var lastInput = instance.$LI;
        var nextInput = handleComponentInput(renderOutput, nextVNode);
        patch(lastInput, nextInput, parentDom, childContext, isSVG);
        instance.$LI = nextInput;
        if (isFunction(instance.componentDidUpdate)) {
          instance.componentDidUpdate(lastProps, lastState);
        }
      }
    } else {
      instance.props = nextProps;
      instance.state = nextState;
      instance.context = context;
    }
    nextVNode.dom = instance.$LI.dom;
  }
  function patchComponent(lastVNode, nextVNode, parentDom, context, isSVG, isClass) {
    var nextType = nextVNode.type;
    var lastKey = lastVNode.key;
    var nextKey = nextVNode.key;
    if (lastVNode.type !== nextType || lastKey !== nextKey) {
      replaceWithNewNode(lastVNode, nextVNode, parentDom, context, isSVG);
    } else {
      var nextProps = nextVNode.props || EMPTY_OBJ;
      if (isClass) {
        var instance = lastVNode.children;
        instance.$UPD = true;
        instance.$V = nextVNode;
        updateClassComponent(instance, instance.state, nextVNode, nextProps, parentDom, context, isSVG, false, false);
        instance.$UPD = false;
      } else {
        var shouldUpdate = true;
        var lastProps = lastVNode.props;
        var nextHooks = nextVNode.ref;
        var nextHooksDefined = !isNullOrUndef(nextHooks);
        var lastInput = lastVNode.children;
        nextVNode.dom = lastVNode.dom;
        nextVNode.children = lastInput;
        if (nextHooksDefined && isFunction(nextHooks.onComponentShouldUpdate)) {
          shouldUpdate = nextHooks.onComponentShouldUpdate(lastProps, nextProps);
        }
        if (shouldUpdate !== false) {
          if (nextHooksDefined && isFunction(nextHooks.onComponentWillUpdate)) {
            nextHooks.onComponentWillUpdate(lastProps, nextProps);
          }
          var nextInput = nextType(nextProps, context);
          if (nextInput !== NO_OP) {
            nextInput = handleComponentInput(nextInput, nextVNode);
            patch(lastInput, nextInput, parentDom, context, isSVG);
            nextVNode.children = nextInput;
            nextVNode.dom = nextInput.dom;
            if (nextHooksDefined && isFunction(nextHooks.onComponentDidUpdate)) {
              nextHooks.onComponentDidUpdate(lastProps, nextProps);
            }
          }
        } else if (lastInput.flags & 14 /* VNodeFlags.Component */) {
          lastInput.parentVNode = nextVNode;
        }
      }
    }
  }
  function patchText(lastVNode, nextVNode) {
    var nextText = nextVNode.children;
    var dom = lastVNode.dom;
    if (nextText !== lastVNode.children) {
      dom.nodeValue = nextText;
    }
    nextVNode.dom = dom;
  }
  function patchNonKeyedChildren(lastChildren, nextChildren, dom, context, isSVG, lastChildrenLength, nextChildrenLength) {
    var commonLength = lastChildrenLength > nextChildrenLength ? nextChildrenLength : lastChildrenLength;
    var i = 0;
    var nextChild;
    var lastChild;
    for (; i < commonLength; i++) {
      nextChild = nextChildren[i];
      lastChild = lastChildren[i];
      if (nextChild.dom) {
        nextChild = nextChildren[i] = directClone(nextChild);
      }
      patch(lastChild, nextChild, dom, context, isSVG);
      lastChildren[i] = nextChild;
    }
    if (lastChildrenLength < nextChildrenLength) {
      for (i = commonLength; i < nextChildrenLength; i++) {
        nextChild = nextChildren[i];
        if (nextChild.dom) {
          nextChild = nextChildren[i] = directClone(nextChild);
        }
        mount(nextChild, dom, context, isSVG);
      }
    } else if (lastChildrenLength > nextChildrenLength) {
      for (i = commonLength; i < lastChildrenLength; i++) {
        remove$1(lastChildren[i], dom);
      }
    }
  }
  function patchKeyedChildren(a, b, dom, context, isSVG, aLength, bLength) {
    var aEnd = aLength - 1;
    var bEnd = bLength - 1;
    var i;
    var j = 0;
    var aNode = a[j];
    var bNode = b[j];
    var nextPos;
    // Step 1
    // tslint:disable-next-line
    outer: {
      // Sync nodes with the same key at the beginning.
      while (aNode.key === bNode.key) {
        if (bNode.dom) {
          b[j] = bNode = directClone(bNode);
        }
        patch(aNode, bNode, dom, context, isSVG);
        a[j] = bNode;
        j++;
        if (j > aEnd || j > bEnd) {
          break outer;
        }
        aNode = a[j];
        bNode = b[j];
      }
      aNode = a[aEnd];
      bNode = b[bEnd];
      // Sync nodes with the same key at the end.
      while (aNode.key === bNode.key) {
        if (bNode.dom) {
          b[bEnd] = bNode = directClone(bNode);
        }
        patch(aNode, bNode, dom, context, isSVG);
        a[aEnd] = bNode;
        aEnd--;
        bEnd--;
        if (j > aEnd || j > bEnd) {
          break outer;
        }
        aNode = a[aEnd];
        bNode = b[bEnd];
      }
    }
    if (j > aEnd) {
      if (j <= bEnd) {
        nextPos = bEnd + 1;
        var nextNode = nextPos < bLength ? b[nextPos].dom : null;
        while (j <= bEnd) {
          bNode = b[j];
          if (bNode.dom) {
            b[j] = bNode = directClone(bNode);
          }
          j++;
          insertOrAppend(dom, mount(bNode, null, context, isSVG), nextNode);
        }
      }
    } else if (j > bEnd) {
      while (j <= aEnd) {
        remove$1(a[j++], dom);
      }
    } else {
      var aStart = j;
      var bStart = j;
      var aLeft = aEnd - j + 1;
      var bLeft = bEnd - j + 1;
      var sources = [];
      for (i = 0; i < bLeft; i++) {
        sources.push(0);
      }
      // Keep track if its possible to remove whole DOM using textContent = '';
      var canRemoveWholeContent = aLeft === aLength;
      var moved = false;
      var pos = 0;
      var patched = 0;
      // When sizes are small, just loop them through
      if (bLength < 4 || (aLeft | bLeft) < 32) {
        for (i = aStart; i <= aEnd; i++) {
          aNode = a[i];
          if (patched < bLeft) {
            for (j = bStart; j <= bEnd; j++) {
              bNode = b[j];
              if (aNode.key === bNode.key) {
                sources[j - bStart] = i + 1;
                if (canRemoveWholeContent) {
                  canRemoveWholeContent = false;
                  while (i > aStart) {
                    remove$1(a[aStart++], dom);
                  }
                }
                if (pos > j) {
                  moved = true;
                } else {
                  pos = j;
                }
                if (bNode.dom) {
                  b[j] = bNode = directClone(bNode);
                }
                patch(aNode, bNode, dom, context, isSVG);
                patched++;
                break;
              }
            }
            if (!canRemoveWholeContent && j > bEnd) {
              remove$1(aNode, dom);
            }
          } else if (!canRemoveWholeContent) {
            remove$1(aNode, dom);
          }
        }
      } else {
        var keyIndex = {};
        // Map keys by their index
        for (i = bStart; i <= bEnd; i++) {
          keyIndex[b[i].key] = i;
        }
        // Try to patch same keys
        for (i = aStart; i <= aEnd; i++) {
          aNode = a[i];
          if (patched < bLeft) {
            j = keyIndex[aNode.key];
            if (j !== void 0) {
              if (canRemoveWholeContent) {
                canRemoveWholeContent = false;
                while (i > aStart) {
                  remove$1(a[aStart++], dom);
                }
              }
              bNode = b[j];
              sources[j - bStart] = i + 1;
              if (pos > j) {
                moved = true;
              } else {
                pos = j;
              }
              if (bNode.dom) {
                b[j] = bNode = directClone(bNode);
              }
              patch(aNode, bNode, dom, context, isSVG);
              patched++;
            } else if (!canRemoveWholeContent) {
              remove$1(aNode, dom);
            }
          } else if (!canRemoveWholeContent) {
            remove$1(aNode, dom);
          }
        }
      }
      // fast-path: if nothing patched remove all old and add all new
      if (canRemoveWholeContent) {
        removeAllChildren(dom, a);
        mountArrayChildren(b, dom, context, isSVG);
      } else {
        if (moved) {
          var seq = lis_algorithm(sources);
          j = seq.length - 1;
          for (i = bLeft - 1; i >= 0; i--) {
            if (sources[i] === 0) {
              pos = i + bStart;
              bNode = b[pos];
              if (bNode.dom) {
                b[pos] = bNode = directClone(bNode);
              }
              nextPos = pos + 1;
              insertOrAppend(dom, mount(bNode, null, context, isSVG), nextPos < bLength ? b[nextPos].dom : null);
            } else if (j < 0 || i !== seq[j]) {
              pos = i + bStart;
              bNode = b[pos];
              nextPos = pos + 1;
              insertOrAppend(dom, bNode.dom, nextPos < bLength ? b[nextPos].dom : null);
            } else {
              j--;
            }
          }
        } else if (patched !== bLeft) {
          // when patched count doesn't match b length we need to insert those new ones
          // loop backwards so we can use insertBefore
          for (i = bLeft - 1; i >= 0; i--) {
            if (sources[i] === 0) {
              pos = i + bStart;
              bNode = b[pos];
              if (bNode.dom) {
                b[pos] = bNode = directClone(bNode);
              }
              nextPos = pos + 1;
              insertOrAppend(dom, mount(bNode, null, context, isSVG), nextPos < bLength ? b[nextPos].dom : null);
            }
          }
        }
      }
    }
  }
  // https://en.wikipedia.org/wiki/Longest_increasing_subsequence
  function lis_algorithm(arr) {
    var p = arr.slice();
    var result = [0];
    var i;
    var j;
    var u;
    var v;
    var c;
    var len = arr.length;
    for (i = 0; i < len; i++) {
      var arrI = arr[i];
      if (arrI !== 0) {
        j = result[result.length - 1];
        if (arr[j] < arrI) {
          p[i] = j;
          result.push(i);
          continue;
        }
        u = 0;
        v = result.length - 1;
        while (u < v) {
          c = (u + v) / 2 | 0;
          if (arr[result[c]] < arrI) {
            u = c + 1;
          } else {
            v = c;
          }
        }
        if (arrI < arr[result[u]]) {
          if (u > 0) {
            p[i] = result[u - 1];
          }
          result[u] = i;
        }
      }
    }
    u = result.length;
    v = result[u - 1];
    while (u-- > 0) {
      result[u] = v;
      v = p[v];
    }
    return result;
  }
  {
    if (isBrowser && document.body === null) {
      warning('Inferno warning: you cannot initialize inferno without "document.body". Wait on "DOMContentLoaded" event, add script to bottom of body, or use async/defer attributes on script tag.');
    }
  }
  var documentBody = isBrowser ? document.body : null;
  function render(input, parentDom, callback) {
    // Development warning
    {
      if (documentBody === parentDom) {
        throwError('you cannot render() to the "document.body". Use an empty element as a container instead.');
      }
    }
    if (input === NO_OP) {
      return;
    }
    var rootInput = parentDom.$V;
    if (isNullOrUndef(rootInput)) {
      if (!isInvalid(input)) {
        if (input.dom) {
          input = directClone(input);
        }
        if (isNull(parentDom.firstChild)) {
          mount(input, parentDom, EMPTY_OBJ, false);
          parentDom.$V = input;
        } else {
          hydrate(input, parentDom);
        }
        rootInput = input;
      }
    } else {
      if (isNullOrUndef(input)) {
        remove$1(rootInput, parentDom);
        parentDom.$V = null;
      } else {
        if (input.dom) {
          input = directClone(input);
        }
        patch(rootInput, input, parentDom, EMPTY_OBJ, false);
        rootInput = parentDom.$V = input;
      }
    }
    if (LIFECYCLE.length > 0) {
      callAll(LIFECYCLE);
    }
    if (isFunction(callback)) {
      callback();
    }
    if (isFunction(options.renderComplete)) {
      options.renderComplete(rootInput);
    }
    if (rootInput && rootInput.flags & 14 /* VNodeFlags.Component */) {
      return rootInput.children;
    }
  }
  function createPortal(children, container) {
    return createVNode(1024 /* VNodeFlags.Portal */, container, null, children, 0 /* ChildFlags.UnknownChildren */, null, isInvalid(children) ? null : children.key, null);
  }
  var resolvedPromise = typeof Promise === 'undefined' ? null : Promise.resolve();
  // raf.bind(window) is needed to work around bug in IE10-IE11 strict mode (TypeError: Invalid calling object)
  var fallbackMethod = typeof requestAnimationFrame === 'undefined' ? setTimeout : requestAnimationFrame.bind(window);
  function nextTick(fn) {
    if (resolvedPromise) {
      return resolvedPromise.then(fn);
    }
    return fallbackMethod(fn);
  }
  function queueStateChanges(component, newState, callback, force) {
    if (isFunction(newState)) {
      newState = newState(component.state, component.props, component.context);
    }
    var pending = component.$PS;
    if (isNullOrUndef(pending)) {
      component.$PS = newState;
    } else {
      for (var stateKey in newState) {
        pending[stateKey] = newState[stateKey];
      }
    }
    if (!component.$PSS && !component.$BR) {
      if (!component.$UPD) {
        component.$PSS = true;
        component.$UPD = true;
        applyState(component, force, callback);
        component.$UPD = false;
      } else {
        // Async
        var queue = component.$QU;
        if (isNull(queue)) {
          queue = component.$QU = [];
          nextTick(promiseCallback(component, queue));
        }
        if (isFunction(callback)) {
          queue.push(callback);
        }
      }
    } else {
      component.$PSS = true;
      if (component.$BR && isFunction(callback)) {
        LIFECYCLE.push(callback.bind(component));
      }
    }
  }
  function promiseCallback(component, queue) {
    return function () {
      component.$QU = null;
      component.$UPD = true;
      applyState(component, false, function () {
        for (var i = 0, len = queue.length; i < len; i++) {
          queue[i].call(component);
        }
      });
      component.$UPD = false;
    };
  }
  function applyState(component, force, callback) {
    if (component.$UN) {
      return;
    }
    if (force || !component.$BR) {
      component.$PSS = false;
      var pendingState = component.$PS;
      var prevState = component.state;
      var nextState = combineFrom(prevState, pendingState);
      var props = component.props;
      var context = component.context;
      component.$PS = null;
      var vNode = component.$V;
      var lastInput = component.$LI;
      var parentDom = lastInput.dom && lastInput.dom.parentNode;
      updateClassComponent(component, nextState, vNode, props, parentDom, context, (vNode.flags & 32 /* VNodeFlags.SvgElement */) > 0, force, true);
      if (component.$UN) {
        return;
      }
      if ((component.$LI.flags & 1024 /* VNodeFlags.Portal */) === 0) {
        var dom = component.$LI.dom;
        while (!isNull(vNode = vNode.parentVNode)) {
          if ((vNode.flags & 14 /* VNodeFlags.Component */) > 0) {
            vNode.dom = dom;
          }
        }
      }
      if (LIFECYCLE.length > 0) {
        callAll(LIFECYCLE);
      }
    } else {
      component.state = component.$PS;
      component.$PS = null;
    }
    if (isFunction(callback)) {
      callback.call(component);
    }
  }
  var Component = /*#__PURE__*/function () {
    // QUEUE
    function Component(props, context) {
      this.state = null;
      this.props = void 0;
      this.context = void 0;
      this.refs = void 0;
      // Internal properties
      this.$BR = false;
      // BLOCK RENDER
      this.$BS = true;
      // BLOCK STATE
      this.$PSS = false;
      // PENDING SET STATE
      this.$PS = null;
      // PENDING STATE (PARTIAL or FULL)
      this.$LI = null;
      // LAST INPUT
      this.$V = null;
      // VNODE
      this.$UN = false;
      // UNMOUNTED
      this.$CX = null;
      // CHILDCONTEXT
      this.$UPD = true;
      // UPDATING
      this.$QU = null;
      /** @type {object} */
      this.props = props || EMPTY_OBJ;
      /** @type {object} */
      this.context = context || EMPTY_OBJ; // context should not be mutable
    }
    var _proto = Component.prototype;
    _proto.forceUpdate = function forceUpdate(callback) {
      if (this.$UN) {
        return;
      }
      // Do not allow double render during force update
      queueStateChanges(this, {}, callback, true);
    };
    _proto.setState = function setState(newState, callback) {
      if (this.$UN) {
        return;
      }
      if (!this.$BS) {
        queueStateChanges(this, newState, callback, false);
      } else {
        // Development warning
        {
          throwError('cannot update state via setState() in componentWillUpdate() or constructor.');
        }
        return;
      }
    }
    // tslint:disable-next-line:no-empty
  ;
    _proto.render = function render(_nextProps, _nextState, _nextContext) {};
    return Component;
  }();
  // Public
  Component.defaultProps = void 0;
  {
    /* tslint:disable-next-line:no-empty */
    var testFunc = function testFn() {};
    /* tslint:disable-next-line*/
    console.info('Inferno is in development mode.');
    if ((testFunc.name || testFunc.toString()).indexOf('testFn') === -1) {
      warning("It looks like you're using a minified copy of the development build " + 'of Inferno. When deploying Inferno apps to production, make sure to use ' + 'the production build which skips development warnings and is faster. ' + 'See http://infernojs.org for more details.');
    }
  }

  // inlined ../../../../resources/logo.svg
  var BPMNIO_IMG = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 14.02 5.57" width="53" height="21" style="vertical-align:middle"><path fill="#000000" d="M1.88.92v.14c0 .41-.13.68-.4.8.33.14.46.44.46.86v.33c0 .61-.33.95-.95.95H0V0h.95c.65 0 .93.3.93.92zM.63.57v1.06h.24c.24 0 .38-.1.38-.43V.98c0-.28-.1-.4-.32-.4zm0 1.63v1.22h.36c.2 0 .32-.1.32-.39v-.35c0-.37-.12-.48-.4-.48H.63zM4.18.99v.52c0 .64-.31.98-.94.98h-.3V4h-.62V0h.92c.63 0 .94.35.94.99zM2.94.57v1.35h.3c.2 0 .3-.09.3-.37v-.6c0-.29-.1-.38-.3-.38h-.3zm2.89 2.27L6.25 0h.88v4h-.6V1.12L6.1 3.99h-.6l-.46-2.82v2.82h-.55V0h.87zM8.14 1.1V4h-.56V0h.79L9 2.4V0h.56v4h-.64zm2.49 2.29v.6h-.6v-.6zM12.12 1c0-.63.33-1 .95-1 .61 0 .95.37.95 1v2.04c0 .64-.34 1-.95 1-.62 0-.95-.37-.95-1zm.62 2.08c0 .28.13.39.33.39s.32-.1.32-.4V.98c0-.29-.12-.4-.32-.4s-.33.11-.33.4z"/><path fill="#000000" d="M0 4.53h14.02v1.04H0zM11.08 0h.63v.62h-.63zm.63 4V1h-.63v2.98z"/></svg>';

  /**
   * Adds the project logo to the diagram container as
   * required by the bpmn.io license.
   *
   * @see http://bpmn.io/license
   *
   * @param {Element} container
   */
  function addProjectLogo(container) {
    var linkMarkup = '<a href="http://bpmn.io" ' + 'target="_blank" ' + 'class="bjs-powered-by" ' + 'title="Powered by bpmn.io" ' + 'style="position: absolute; bottom: 15px; right: 15px; z-index: 100;">' + BPMNIO_IMG + '</a>';
    var linkElement = domify(linkMarkup);
    container.appendChild(linkElement);
    event.bind(linkElement, 'click', function (event) {
      open();
      event.preventDefault();
    });
  }
  class PoweredByComponent extends Component {
    constructor(props, context) {
      super(props, context);
      this.node = null;
    }
    componentDidMount() {
      addProjectLogo(this.node);
    }
    render() {
      return createVNode(1, "div", null, null, 1, null, null, node => this.node = node);
    }
  }
  function css(attrs) {
    return attrs.join(';');
  }
  var LIGHTBOX_STYLES = css(['z-index: 1001', 'position: fixed', 'top: 0', 'left: 0', 'right: 0', 'bottom: 0']);
  var BACKDROP_STYLES = css(['width: 100%', 'height: 100%', 'background: rgba(40,40,40,0.2)']);
  var NOTICE_STYLES = css(['position: absolute', 'left: 50%', 'top: 40%', 'transform: translate(-50%)', 'width: 260px', 'padding: 10px', 'background: white', 'box-shadow: 0 1px 4px rgba(0,0,0,0.3)', 'font-family: Helvetica, Arial, sans-serif', 'font-size: 14px', 'display: flex', 'line-height: 1.3']);
  var LIGHTBOX_MARKUP = '<div class="bjs-powered-by-lightbox" style="' + LIGHTBOX_STYLES + '">' + '<div class="backdrop" style="' + BACKDROP_STYLES + '"></div>' + '<div class="notice" style="' + NOTICE_STYLES + '">' + '<a href="https://bpmn.io" target="_blank" rel="noopener" style="margin: 15px 20px 15px 10px; align-self: center;' + '">' + BPMNIO_IMG + '</a>' + '<span>' + 'Web-based tooling for BPMN, DMN and CMMN diagrams ' + 'powered by <a href="https://bpmn.io" target="_blank" rel="noopener">bpmn.io</a>.' + '</span>' + '</div>' + '</div>';
  var lightbox;
  function open() {
    if (!lightbox) {
      lightbox = domify(LIGHTBOX_MARKUP);
      delegate.bind(lightbox, '.backdrop', 'click', function (event) {
        document.body.removeChild(lightbox);
      });
    }
    document.body.appendChild(lightbox);
  }

  function getDefaultExportFromCjs(x) {
    return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
  }
  var hat$1 = {
    exports: {}
  };
  var hasRequiredHat;
  function requireHat() {
    if (hasRequiredHat) return hat$1.exports;
    hasRequiredHat = 1;
    var hat = hat$1.exports = function (bits, base) {
      if (!base) base = 16;
      if (bits === undefined) bits = 128;
      if (bits <= 0) return '0';
      var digits = Math.log(Math.pow(2, bits)) / Math.log(base);
      for (var i = 2; digits === Infinity; i *= 2) {
        digits = Math.log(Math.pow(2, bits / i)) / Math.log(base) * i;
      }
      var rem = digits - Math.floor(digits);
      var res = '';
      for (var i = 0; i < Math.floor(digits); i++) {
        var x = Math.floor(Math.random() * base).toString(base);
        res = x + res;
      }
      if (rem) {
        var b = Math.pow(base, rem);
        var x = Math.floor(Math.random() * b).toString(base);
        res = x + res;
      }
      var parsed = parseInt(res, base);
      if (parsed !== Infinity && parsed >= Math.pow(2, bits)) {
        return hat(bits, base);
      } else return res;
    };
    hat.rack = function (bits, base, expandBy) {
      var fn = function (data) {
        var iters = 0;
        do {
          if (iters++ > 10) {
            if (expandBy) bits += expandBy;else throw new Error('too many ID collisions, use more bits');
          }
          var id = hat(bits, base);
        } while (Object.hasOwnProperty.call(hats, id));
        hats[id] = data;
        return id;
      };
      var hats = fn.hats = {};
      fn.get = function (id) {
        return fn.hats[id];
      };
      fn.set = function (id, value) {
        fn.hats[id] = value;
        return fn;
      };
      fn.bits = bits || 128;
      fn.base = base || 16;
      return fn;
    };
    return hat$1.exports;
  }
  var hatExports = requireHat();
  var hat = /*@__PURE__*/getDefaultExportFromCjs(hatExports);

  /**
   * @typedef { [ number, number ] | [ number, number, number ] } Seed
   */

  /**
   * Create a new id generator / cache instance.
   *
   * You may optionally provide a seed that is used internally.
   *
   * @param {Seed} [seed]
   */
  function Ids(seed) {
    if (!(this instanceof Ids)) {
      return new Ids(seed);
    }
    seed = seed || [128, 36, 1];
    this._seed = seed.length ? hat.rack(seed[0], seed[1], seed[2]) : seed;
  }

  /**
   * Generate a next id.
   *
   * @param {Object} [element] element to bind the id to
   *
   * @return {string} id
   */
  Ids.prototype.next = function (element) {
    return this._seed(element || true);
  };

  /**
   * Generate a next id with a given prefix.
   *
   * @param {Object} [element] element to bind the id to
   *
   * @return {string} id
   */
  Ids.prototype.nextPrefixed = function (prefix, element) {
    var id;
    do {
      id = prefix + this.next(true);
    } while (this.assigned(id));

    // claim {prefix}{random}
    this.claim(id, element);

    // return
    return id;
  };

  /**
   * Manually claim an existing id.
   *
   * @param {string} id
   * @param {any} [element] element the id is claimed by
   */
  Ids.prototype.claim = function (id, element) {
    this._seed.set(id, element || true);
  };

  /**
   * Returns true if the given id has already been assigned.
   *
   * @param  {string} id
   * @return {boolean}
   */
  Ids.prototype.assigned = function (id) {
    return this._seed.get(id) || false;
  };

  /**
   * Unclaim an id.
   *
   * @param  {string} id the id to unclaim
   */
  Ids.prototype.unclaim = function (id) {
    delete this._seed.hats[id];
  };

  /**
   * Clear all claimed ids.
   */
  Ids.prototype.clear = function () {
    var hats = this._seed.hats,
      id;
    for (id in hats) {
      this.unclaim(id);
    }
  };

  var RENDERER_IDS = new Ids();
  var black = 'hsl(225, 10%, 15%)';

  /**
   * Renderer for the DRD view. The default colors are configurable.
   * When default label color is not provided, it will take the default
   * stroke color.
   *
   * @example
   * ```javascript
   * // for simple DRD viewer
   * const viewer = new DrdViewer({
   *   drdRenderer: {
   *     defaultFillColor: '#ffd700',
   *     defaultStrokeColor: '#0057b8',
   *     defaultLabelColor: '#0057b8'
   *   }
   * });
   *
   * // in dmn-js
   * const modeler = new DmnModeler({
   *   drd: {
   *     drdRenderer: {
   *       defaultFillColor: '#ffd700',
   *       defaultStrokeColor: '#0057b8',
   *       defaultLabelColor: '#0057b8'
   *     }
   *   }
   * });
   * ```
   */
  function DrdRenderer(config, eventBus, pathMap, styles, textRenderer, canvas) {
    BaseRenderer.call(this, eventBus);
    var rendererId = RENDERER_IDS.next();
    var computeStyle = styles.computeStyle;
    var markers = {};
    var defaultFillColor = config && config.defaultFillColor || 'white',
      defaultStrokeColor = config && config.defaultStrokeColor || black,
      defaultLabelColor = config && config.defaultLabelColor;
    function marker(type, fill, stroke) {
      var id = type + '-' + colorEscape(fill) + '-' + colorEscape(stroke) + '-' + rendererId;
      if (!markers[id]) {
        createMarker(id, type, fill, stroke);
      }
      return 'url(#' + id + ')';
    }
    function addMarker(id, options) {
      var attrs = assign$1({
        strokeWidth: 1,
        strokeLinecap: 'round',
        strokeDasharray: 'none'
      }, options.attrs);
      var ref = options.ref || {
        x: 0,
        y: 0
      };
      var scale = options.scale || 1;

      // fix for safari / chrome / firefox bug not correctly
      // resetting stroke dash array
      if (attrs.strokeDasharray === 'none') {
        attrs.strokeDasharray = [10000, 1];
      }
      var marker = create$2('marker');
      attr(options.element, attrs);
      append(marker, options.element);
      attr(marker, {
        id: id,
        viewBox: '0 0 20 20',
        refX: ref.x,
        refY: ref.y,
        markerWidth: 20 * scale,
        markerHeight: 20 * scale,
        orient: 'auto'
      });
      var defs = query('defs', canvas._svg);
      if (!defs) {
        defs = create$2('defs');
        append(canvas._svg, defs);
      }
      append(defs, marker);
      markers[id] = marker;
    }
    function createMarker(id, type, fill, stroke) {
      if (type === 'association-start') {
        var associationStart = create$2('path');
        attr(associationStart, {
          d: 'M 11 5 L 1 10 L 11 15'
        });
        addMarker(id, {
          element: associationStart,
          attrs: {
            fill: 'none',
            stroke: stroke,
            strokeWidth: 1.5
          },
          ref: {
            x: 1,
            y: 10
          },
          scale: 0.5
        });
      } else if (type === 'association-end') {
        var associationEnd = create$2('path');
        attr(associationEnd, {
          d: 'M 1 5 L 11 10 L 1 15'
        });
        addMarker(id, {
          element: associationEnd,
          attrs: {
            fill: 'none',
            stroke: stroke,
            strokeWidth: 1.5
          },
          ref: {
            x: 12,
            y: 10
          },
          scale: 0.5
        });
      } else if (type === 'information-requirement-end') {
        var informationRequirementEnd = create$2('path');
        attr(informationRequirementEnd, {
          d: 'M 1 5 L 11 10 L 1 15 Z'
        });
        addMarker(id, {
          element: informationRequirementEnd,
          attrs: {
            fill: stroke,
            stroke: 'none'
          },
          ref: {
            x: 11,
            y: 10
          },
          scale: 1
        });
      } else if (type === 'knowledge-requirement-end') {
        var knowledgeRequirementEnd = create$2('path');
        attr(knowledgeRequirementEnd, {
          d: 'M 1 3 L 11 10 L 1 17'
        });
        addMarker(id, {
          element: knowledgeRequirementEnd,
          attrs: {
            fill: 'none',
            stroke: stroke,
            strokeWidth: 2
          },
          ref: {
            x: 11,
            y: 10
          },
          scale: 0.8
        });
      } else if (type === 'authority-requirement-end') {
        var authorityRequirementEnd = create$2('circle');
        attr(authorityRequirementEnd, {
          cx: 3,
          cy: 3,
          r: 3
        });
        addMarker(id, {
          element: authorityRequirementEnd,
          attrs: {
            fill: stroke,
            stroke: 'none'
          },
          ref: {
            x: 3,
            y: 3
          },
          scale: 0.9
        });
      }
    }
    function drawRect(p, width, height, r, offset, attrs) {
      if (isObject$1(offset)) {
        attrs = offset;
        offset = 0;
      }
      offset = offset || 0;
      attrs = computeStyle(attrs, {
        stroke: black,
        strokeWidth: 2,
        fill: 'white'
      });
      var rect = create$2('rect');
      attr(rect, {
        x: offset,
        y: offset,
        width: width - offset * 2,
        height: height - offset * 2,
        rx: r,
        ry: r
      });
      attr(rect, attrs);
      append(p, rect);
      return rect;
    }
    function renderLabel(p, label, options) {
      var text = textRenderer.createText(label || '', options);
      attr$1(text, 'class', 'djs-label');
      append(p, text);
      return text;
    }
    function renderEmbeddedLabel(p, element, align, options) {
      var name = getName(element);
      options = assign$1({
        box: element,
        align: align,
        padding: 5,
        style: {
          fill: getLabelColor(element, defaultLabelColor, defaultStrokeColor)
        }
      }, options);
      return renderLabel(p, name, options);
    }
    function drawPath(p, d, attrs) {
      attrs = computeStyle(attrs, ['no-fill'], {
        strokeWidth: 2,
        stroke: black
      });
      var path = create$2('path');
      attr(path, {
        d: d
      });
      attr(path, attrs);
      append(p, path);
      return path;
    }
    var handlers = {
      'dmn:Decision': function (p, element) {
        var rect = drawRect(p, element.width, element.height, 0, {
          stroke: getStrokeColor(element, defaultStrokeColor),
          fill: getFillColor(element, defaultFillColor)
        });
        renderEmbeddedLabel(p, element, 'center-middle');
        return rect;
      },
      'dmn:KnowledgeSource': function (p, element) {
        var pathData = pathMap.getScaledPath('KNOWLEDGE_SOURCE', {
          xScaleFactor: 1.021,
          yScaleFactor: 1,
          containerWidth: element.width,
          containerHeight: element.height,
          position: {
            mx: 0.0,
            my: 0.075
          }
        });
        var knowledgeSource = drawPath(p, pathData, {
          strokeWidth: 2,
          fill: getFillColor(element, defaultFillColor),
          stroke: getStrokeColor(element, defaultStrokeColor)
        });
        renderEmbeddedLabel(p, element, 'center-middle');
        return knowledgeSource;
      },
      'dmn:BusinessKnowledgeModel': function (p, element) {
        var pathData = pathMap.getScaledPath('BUSINESS_KNOWLEDGE_MODEL', {
          xScaleFactor: 1,
          yScaleFactor: 1,
          containerWidth: element.width,
          containerHeight: element.height,
          position: {
            mx: 0.0,
            my: 0.3
          }
        });
        var businessKnowledge = drawPath(p, pathData, {
          strokeWidth: 2,
          fill: getFillColor(element, defaultFillColor),
          stroke: getStrokeColor(element, defaultStrokeColor)
        });
        renderEmbeddedLabel(p, element, 'center-middle');
        return businessKnowledge;
      },
      'dmn:InputData': function (p, element) {
        var rect = drawRect(p, element.width, element.height, 22, {
          stroke: getStrokeColor(element, defaultStrokeColor),
          fill: getFillColor(element, defaultFillColor)
        });
        renderEmbeddedLabel(p, element, 'center-middle');
        return rect;
      },
      'dmn:TextAnnotation': function (p, element) {
        var style = {
          'fill': 'none',
          'stroke': 'none'
        };
        var textElement = drawRect(p, element.width, element.height, 0, 0, style);
        var textPathData = pathMap.getScaledPath('TEXT_ANNOTATION', {
          xScaleFactor: 1,
          yScaleFactor: 1,
          containerWidth: element.width,
          containerHeight: element.height,
          position: {
            mx: 0.0,
            my: 0.0
          }
        });
        drawPath(p, textPathData, {
          stroke: getStrokeColor(element, defaultStrokeColor)
        });
        var text = getSemantic(element).text || '';
        renderLabel(p, text, {
          style: {
            fill: getLabelColor(element, defaultLabelColor, defaultStrokeColor)
          },
          box: element,
          align: 'left-top',
          padding: 5
        });
        return textElement;
      },
      'dmn:Association': function (p, element) {
        var semantic = getSemantic(element);
        var fill = getFillColor(element, defaultFillColor),
          stroke = getStrokeColor(element, defaultStrokeColor),
          attrs = {
            stroke: stroke,
            strokeDasharray: '0.5, 5',
            strokeLinecap: 'round',
            strokeLinejoin: 'round',
            fill: 'none'
          };
        if (semantic.associationDirection === 'One' || semantic.associationDirection === 'Both') {
          attrs.markerEnd = marker('association-end', fill, stroke);
        }
        if (semantic.associationDirection === 'Both') {
          attrs.markerStart = marker('association-start', fill, stroke);
        }
        return drawLine(p, element.waypoints, attrs);
      },
      'dmn:InformationRequirement': function (p, element) {
        var fill = getFillColor(element, defaultFillColor),
          stroke = getStrokeColor(element, defaultStrokeColor),
          attrs = {
            stroke: stroke,
            strokeWidth: 1,
            strokeLinecap: 'round',
            strokeLinejoin: 'round',
            markerEnd: marker('information-requirement-end', fill, stroke)
          };
        return drawLine(p, element.waypoints, attrs);
      },
      'dmn:KnowledgeRequirement': function (p, element) {
        var fill = getFillColor(element, defaultFillColor),
          stroke = getStrokeColor(element, defaultStrokeColor);
        var attrs = {
          stroke: stroke,
          strokeWidth: 1,
          strokeDasharray: 5,
          strokeLinecap: 'round',
          strokeLinejoin: 'round',
          markerEnd: marker('knowledge-requirement-end', fill, stroke)
        };
        return drawLine(p, element.waypoints, attrs);
      },
      'dmn:AuthorityRequirement': function (p, element) {
        var fill = getFillColor(element, defaultFillColor),
          stroke = getStrokeColor(element, defaultStrokeColor),
          attrs = {
            stroke: stroke,
            strokeWidth: 1.5,
            strokeDasharray: 5,
            strokeLinecap: 'round',
            strokeLinejoin: 'round',
            markerEnd: marker('authority-requirement-end', fill, stroke)
          };
        return drawLine(p, element.waypoints, attrs);
      }
    };

    // draw shape and connection //////////////////

    function drawShape(parent, element) {
      var h = handlers[element.type];
      if (!h) {
        return BaseRenderer.prototype.drawShape.apply(this, [parent, element]);
      } else {
        return h(parent, element);
      }
    }
    function drawConnection(parent, element) {
      var type = element.type;
      var h = handlers[type];
      if (!h) {
        return BaseRenderer.prototype.drawConnection.apply(this, [parent, element]);
      } else {
        return h(parent, element);
      }
    }
    function drawLine(p, waypoints, attrs) {
      attrs = computeStyle(attrs, ['no-fill'], {
        stroke: black,
        strokeWidth: 2,
        fill: 'none'
      });
      var line = createLine(waypoints, attrs);
      append(p, line);
      return line;
    }
    this.canRender = function (element) {
      return is(element, 'dmn:DMNElement') || is(element, 'dmn:InformationRequirement') || is(element, 'dmn:KnowledgeRequirement') || is(element, 'dmn:AuthorityRequirement');
    };
    this.drawShape = drawShape;
    this.drawConnection = drawConnection;
  }
  e(DrdRenderer, BaseRenderer);
  DrdRenderer.$inject = ['config.drdRenderer', 'eventBus', 'pathMap', 'styles', 'textRenderer', 'canvas'];

  // helper functions //////////////////////

  function getSemantic(element) {
    return element.businessObject;
  }
  function colorEscape(str) {
    // only allow characters and numbers
    return str.replace(/[^0-9a-zA-z]+/g, '_');
  }
  function getStrokeColor(element, defaultColor) {
    return defaultColor;
  }
  function getFillColor(element, defaultColor) {
    return defaultColor;
  }
  function getLabelColor(element, defaultColor, defaultStrokeColor) {
    return defaultColor || getStrokeColor(element, defaultStrokeColor);
  }

  /**
   * @typedef {import('./Types.js').Dimensions} Dimensions
   *
   * @typedef { {
   *   top: number;
   *   left: number;
   *   right: number;
   *   bottom: number;
   * } } Padding
   *
   * @typedef { number | Partial<Padding> } PaddingConfig
   *
   * @typedef { {
   *   horizontal: 'center' | 'left' | 'right';
   *   vertical: 'top' | 'middle';
   * } } Alignment
   *
   *  @typedef { 'center-middle' | 'center-top' } AlignmentConfig
   *
   * @typedef { Partial<{
   *   align: AlignmentConfig;
   *   style: Record<string, number | string>;
   *   padding: PaddingConfig;
   * }> } BaseTextConfig
   *
   * @typedef { BaseTextConfig & Partial<{
   *   size: Dimensions;
   * }> } TextConfig
   *
   * @typedef { BaseTextConfig & Partial<{
   *   box: Dimensions;
   *   fitBox: boolean;
   * }> } TextLayoutConfig
   *
   *  @typedef { Dimensions & {
   *  text: string;
   * } } LineDescriptor
   */

  var DEFAULT_BOX_PADDING = 0;
  var DEFAULT_LABEL_SIZE = {
    width: 150,
    height: 50
  };

  /**
   * @param {AlignmentConfig} align
   * @return {Alignment}
   */
  function parseAlign(align) {
    var parts = align.split('-');
    return {
      horizontal: parts[0] || 'center',
      vertical: parts[1] || 'top'
    };
  }

  /**
   * @param {PaddingConfig} padding
   *
   * @return {Padding}
   */
  function parsePadding(padding) {
    if (isObject$1(padding)) {
      return assign$1({
        top: 0,
        left: 0,
        right: 0,
        bottom: 0
      }, padding);
    } else {
      return {
        top: padding,
        left: padding,
        right: padding,
        bottom: padding
      };
    }
  }

  /** @type {CanvasRenderingContext2D | null} */
  var _canvasContext = null;

  /**
   * @return {CanvasRenderingContext2D | null}
   */
  function getCanvasContext() {
    if (!_canvasContext) {
      _canvasContext = document.createElement('canvas').getContext('2d');
    }
    return _canvasContext;
  }

  /**
   * Build a CSS font string from a style object for use with the canvas
   * measureText API.
   *
   * @param {Record<string, number | string>} style
   *
   * @return {string}
   */
  function buildFont(style) {
    var parts = [];
    if (style.fontStyle) {
      parts.push(style.fontStyle);
    }
    if (style.fontVariant) {
      parts.push(style.fontVariant);
    }
    if (style.fontWeight) {
      parts.push(style.fontWeight);
    }
    if (style.fontStretch) {
      parts.push(style.fontStretch);
    }
    parts.push(buildLength(style.fontSize) || '12px');
    parts.push(style.fontFamily || 'sans-serif');
    return parts.join(' ');
  }

  /**
   * Coerce a CSS length to a string with units, since canvas APIs
   * silently reject unitless lengths and keep the previous value.
   *
   * @param {number | string | undefined} value
   *
   * @return {string | undefined}
   */
  function buildLength(value) {
    if (value == null) {
      return undefined;
    }
    if (typeof value === 'number' || /^-?\d+(\.\d+)?$/.test(value)) {
      return value + 'px';
    }
    return value;
  }

  /**
   * @param {string} text
   * @param {Record<string, number | string>} style
   *
   * @return {import('./Types.js').Dimensions}
   */
  function getTextBBox(text, style) {
    var ctx = getCanvasContext();
    if (!ctx) {
      return {
        width: 0,
        height: 0
      };
    }
    ctx.font = buildFont(style);
    if ('letterSpacing' in ctx) {
      ctx.letterSpacing = buildLength(style.letterSpacing) || '0px';
    }
    var emptyLine = text === '';

    // strip trailing whitespace so measurement matches the browser's
    // native rendering used by direct editing
    var measurable = emptyLine ? 'dummy' : text.replace(/\s+$/, '');
    var metrics = ctx.measureText(measurable);
    return {
      width: emptyLine ? 0 : metrics.width,
      height: 'fontBoundingBoxAscent' in metrics ? metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent : metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent
    };
  }

  /**
   * Layout the next line and return the layouted element.
   *
   * Alters the lines passed.
   *
   * @param {string[]} lines
   * @param {number} maxWidth
   * @param {Record<string, number | string>} style
   *
   * @return {LineDescriptor} the line descriptor
   */
  function layoutNext(lines, maxWidth, style) {
    var originalLine = lines.shift(),
      fitLine = originalLine;
    var textBBox;
    for (;;) {
      textBBox = getTextBBox(fitLine, style);
      textBBox.width = fitLine ? textBBox.width : 0;

      // try to fit
      if (fitLine === ' ' || fitLine === '' || textBBox.width < Math.round(maxWidth) || fitLine.length < 2) {
        return fit(lines, fitLine, originalLine, textBBox);
      }
      fitLine = shortenLine(fitLine, textBBox.width, maxWidth);
    }
  }

  /**
   * @param {string[]} lines
   * @param {string} fitLine
   * @param {string} originalLine
   * @param {Dimensions} textBBox
   *
   * @return {LineDescriptor}
   */
  function fit(lines, fitLine, originalLine, textBBox) {
    if (fitLine.length < originalLine.length) {
      var remainder = originalLine.slice(fitLine.length).trim();
      lines.unshift(remainder);
    }
    return {
      width: textBBox.width,
      height: textBBox.height,
      text: fitLine
    };
  }
  var SOFT_BREAK = '\u00AD';

  /**
   * Shortens a line based on spacing and hyphens.
   * Returns the shortened result on success.
   *
   * @param {string} line
   * @param {number} maxLength the maximum characters of the string
   *
   * @return {string} the shortened string
   */
  function semanticShorten(line, maxLength) {
    var parts = line.split(/(\s|-|\u00AD)/g),
      part,
      shortenedParts = [],
      length = 0;

    // try to shorten via break chars
    if (parts.length > 1) {
      while (part = parts.shift()) {
        if (part.length + length < maxLength) {
          shortenedParts.push(part);
          length += part.length;
        } else {
          // remove previous part, too if hyphen does not fit anymore
          if (part === '-' || part === SOFT_BREAK) {
            shortenedParts.pop();
          }
          break;
        }
      }
    }
    var last = shortenedParts[shortenedParts.length - 1];

    // translate trailing soft break to actual hyphen
    if (last && last === SOFT_BREAK) {
      shortenedParts[shortenedParts.length - 1] = '-';
    }
    return shortenedParts.join('');
  }

  /**
   * @param {string} line
   * @param {number} width
   * @param {number} maxWidth
   *
   * @return {string}
   */
  function shortenLine(line, width, maxWidth) {
    var length = Math.max(line.length * (maxWidth / width), 1);

    // try to shorten semantically (i.e. based on spaces and hyphens)
    var shortenedLine = semanticShorten(line, length);
    if (!shortenedLine) {
      // force shorten by cutting the long word
      shortenedLine = line.slice(0, Math.max(Math.round(length - 1), 1));
    }
    return shortenedLine;
  }

  /**
   * Creates a new label utility
   *
   * @param {TextConfig} [config]
   */
  function Text$1(config) {
    this._config = assign$1({}, {
      size: DEFAULT_LABEL_SIZE,
      padding: DEFAULT_BOX_PADDING,
      style: {},
      align: 'center-top'
    }, config || {});
  }

  /**
   * Returns the layouted text as an SVG element.
   *
   * @param {string} text
   * @param {TextLayoutConfig} options
   *
   * @return {SVGElement}
   */
  Text$1.prototype.createText = function (text, options) {
    return this.layoutText(text, options).element;
  };

  /**
   * Returns a labels layouted dimensions.
   *
   * @param {string} text to layout
   * @param {TextLayoutConfig} options
   *
   * @return {Dimensions}
   */
  Text$1.prototype.getDimensions = function (text, options) {
    return this.layoutText(text, options).dimensions;
  };

  /**
   * Creates and returns a label and its bounding box.
   *
   * @param {string} text the text to render on the label
   * @param {TextLayoutConfig} options
   *
   * @return { {
   *   element: SVGElement,
   *   dimensions: Dimensions
   * } }
   */
  Text$1.prototype.layoutText = function (text, options) {
    var box = assign$1({}, this._config.size, options.box),
      style = assign$1({}, this._config.style, options.style),
      align = parseAlign(options.align || this._config.align),
      padding = parsePadding(options.padding !== undefined ? options.padding : this._config.padding),
      fitBox = options.fitBox || false;
    var lineHeight = getLineHeight(style);

    // we split text by lines and normalize
    // {soft break} + {line break} => { line break }
    var lines = text.split(/\u00AD?\r?\n/),
      layouted = [];
    var maxWidth = box.width - padding.left - padding.right;
    while (lines.length) {
      layouted.push(layoutNext(lines, maxWidth, style));
    }
    if (align.vertical === 'middle') {
      padding.top = padding.bottom = 0;
    }
    var totalHeight = reduce(layouted, function (sum, line, idx) {
      return sum + (lineHeight || line.height);
    }, 0) + padding.top + padding.bottom;
    var maxLineWidth = reduce(layouted, function (sum, line, idx) {
      return line.width > sum ? line.width : sum;
    }, 0);

    // the y position of the next line
    var y = padding.top;
    if (align.vertical === 'middle') {
      y += (box.height - totalHeight) / 2;
    }

    // magic number initial offset
    y -= (lineHeight || layouted[0].height) / 4;
    var textElement = create$2('text');
    attr(textElement, style);

    // layout each line taking into account that parent
    // shape might resize to fit text size
    forEach(layouted, function (line) {
      var x;
      y += lineHeight || line.height;
      switch (align.horizontal) {
        case 'left':
          x = padding.left;
          break;
        case 'right':
          x = (fitBox ? maxLineWidth : maxWidth) - padding.right - line.width;
          break;
        default:
          // aka center
          x = Math.max(((fitBox ? maxLineWidth : maxWidth) - line.width) / 2 + padding.left, 0);
      }
      var tspan = create$2('tspan');
      attr(tspan, {
        x: x,
        y: y
      });
      tspan.textContent = line.text;
      append(textElement, tspan);
    });
    var dimensions = {
      width: maxLineWidth,
      height: totalHeight
    };
    return {
      dimensions: dimensions,
      element: textElement
    };
  };
  function getLineHeight(style) {
    if ('fontSize' in style && 'lineHeight' in style) {
      return style.lineHeight * parseInt(style.fontSize, 10);
    }
  }

  var DEFAULT_FONT_SIZE = 12;
  var LINE_HEIGHT_RATIO = 1.2;
  var MIN_TEXT_ANNOTATION_HEIGHT = 30;
  function TextRenderer(config) {
    var defaultStyle = assign$1({
      fontFamily: 'Arial, sans-serif',
      fontSize: DEFAULT_FONT_SIZE,
      fontWeight: 'normal',
      lineHeight: LINE_HEIGHT_RATIO
    }, config && config.defaultStyle || {});
    var fontSize = parseInt(defaultStyle.fontSize, 10) - 1;
    var externalStyle = assign$1({}, defaultStyle, {
      fontSize: fontSize
    }, config && config.externalStyle || {});
    var textUtil = new Text$1({
      style: defaultStyle
    });

    /**
     * Get the new bounds of an externally rendered,
     * layouted label.
     *
     * @param  {Bounds} bounds
     * @param  {string} text
     *
     * @return {Bounds}
     */
    this.getExternalLabelBounds = function (bounds, text) {
      var layoutedDimensions = textUtil.getDimensions(text, {
        box: {
          width: 90,
          height: 30,
          x: bounds.width / 2 + bounds.x,
          y: bounds.height / 2 + bounds.y
        },
        style: externalStyle
      });

      // resize label shape to fit label text
      return {
        x: Math.round(bounds.x + bounds.width / 2 - layoutedDimensions.width / 2),
        y: Math.round(bounds.y),
        width: Math.ceil(layoutedDimensions.width),
        height: Math.ceil(layoutedDimensions.height)
      };
    };

    /**
     * Get the new bounds of text annotation.
     *
     * @param  {Bounds} bounds
     * @param  {string} text
     *
     * @return {Bounds}
     */
    this.getTextAnnotationBounds = function (bounds, text) {
      var layoutedDimensions = textUtil.getDimensions(text, {
        box: bounds,
        style: defaultStyle,
        align: 'left-top',
        padding: 5
      });
      return {
        x: bounds.x,
        y: bounds.y,
        width: bounds.width,
        height: Math.max(MIN_TEXT_ANNOTATION_HEIGHT, Math.round(layoutedDimensions.height))
      };
    };

    /**
     * Create a layouted text element.
     *
     * @param {string} text
     * @param {Object} [options]
     *
     * @return {SVGElement} rendered text
     */
    this.createText = function (text, options) {
      return textUtil.createText(text, options || {});
    };

    /**
     * Get default text style.
     */
    this.getDefaultStyle = function () {
      return defaultStyle;
    };

    /**
     * Get the external text style.
     */
    this.getExternalStyle = function () {
      return externalStyle;
    };
  }
  TextRenderer.$inject = ['config.textRenderer'];

  /**
   * Map containing SVG paths needed by BpmnRenderer.
   */

  function PathMap() {
    /**
     * Contains a map of path elements
     *
     * <h1>Path definition</h1>
     * A parameterized path is defined like this:
     * <pre>
     * 'GATEWAY_PARALLEL': {
     *   d: 'm {mx},{my} {e.x0},0 0,{e.x1} {e.x1},0 0,{e.y0} -{e.x1},0 0,{e.y1} ' +
            '-{e.x0},0 0,-{e.y1} -{e.x1},0 0,-{e.y0} {e.x1},0 z',
     *   height: 17.5,
     *   width:  17.5,
     *   heightElements: [2.5, 7.5],
     *   widthElements: [2.5, 7.5]
     * }
     * </pre>
     * <p>It's important to specify a correct <b>height and width</b> for the path as the scaling
     * is based on the ratio between the specified height and width in this object and the
     * height and width that is set as scale target (Note x,y coordinates will be scaled with
     * individual ratios).</p>
     * <p>The '<b>heightElements</b>' and '<b>widthElements</b>' array must contain the values that will be scaled.
     * The scaling is based on the computed ratios.
     * Coordinates on the y axis should be in the <b>heightElement</b>'s array, they will be scaled using
     * the computed ratio coefficient.
     * In the parameterized path the scaled values can be accessed through the 'e' object in {} brackets.
     *   <ul>
     *    <li>The values for the y axis can be accessed in the path string using {e.y0}, {e.y1}, ....</li>
     *    <li>The values for the x axis can be accessed in the path string using {e.x0}, {e.x1}, ....</li>
     *   </ul>
     *   The numbers x0, x1 respectively y0, y1, ... map to the corresponding array index.
     * </p>
      m1,1
      l 0,55.3
      c 29.8,19.7 48.4,-4.2 67.2,-6.7
      c 12.2,-2.3 19.8,1.6 30.8,6.2
      l 0,-54.6
      z
      */
    this.pathMap = {
      'KNOWLEDGE_SOURCE': {
        d: 'm {mx},{my} ' + 'l 0,{e.y0} ' + 'c {e.x0},{e.y1} {e.x1},-{e.y2} {e.x2},-{e.y3} ' + 'c {e.x3},-{e.y4} {e.x4},{e.y5} {e.x5},{e.y6} ' + 'l 0,-{e.y7}z',
        width: 100,
        height: 65,
        widthElements: [29.8, 48.4, 67.2, 12.2, 19.8, 30.8],
        heightElements: [55.3, 19.7, 4.2, 6.7, 2.3, 1.6, 6.2, 54.6]
      },
      'BUSINESS_KNOWLEDGE_MODEL': {
        d: 'm {mx},{my} l {e.x0},-{e.y0} l {e.x1},0 l 0,{e.y1} l -{e.x2},{e.y2} l -{e.x3},0z',
        width: 125,
        height: 45,
        widthElements: [13.8, 109.2, 13.8, 109.1],
        heightElements: [13.2, 29.8, 13.2]
      },
      'TEXT_ANNOTATION': {
        d: 'm {mx}, {my} m 10,0 l -10,0 l 0,{e.y0} l 10,0',
        width: 10,
        height: 30,
        widthElements: [10],
        heightElements: [30]
      }
    };
    this.getRawPath = function getRawPath(pathId) {
      return this.pathMap[pathId].d;
    };

    /**
     * Scales the path to the given height and width.
     * <h1>Use case</h1>
     * <p>Use case is to scale the content of elements (event, gateways) based
     * on the element bounding box's size.
     * </p>
     * <h1>Why not transform</h1>
     * <p>Scaling a path with transform() will also scale the stroke and IE does not support
     * the option 'non-scaling-stroke' to prevent this.
     * Also there are use cases where only some parts of a path should be
     * scaled.</p>
     *
     * @param {string} pathId The ID of the path.
     * @param {Object} param <p>
     *   Example param object scales the path to 60% size of the container (data.width, data.height).
     *   <pre>
     *   {
     *     xScaleFactor: 0.6,
     *     yScaleFactor:0.6,
     *     containerWidth: data.width,
     *     containerHeight: data.height,
     *     position: {
     *       mx: 0.46,
     *       my: 0.2,
     *     }
     *   }
     *   </pre>
     *   <ul>
     *    <li>targetpathwidth = xScaleFactor * containerWidth</li>
     *    <li>targetpathheight = yScaleFactor * containerHeight</li>
     *    <li>Position is used to set the starting coordinate of the path. M is computed:
      *    <ul>
      *      <li>position.x * containerWidth</li>
      *      <li>position.y * containerHeight</li>
      *    </ul>
      *    Center of the container <pre> position: {
     *       mx: 0.5,
     *       my: 0.5,
     *     }</pre>
     *     Upper left corner of the container
     *     <pre> position: {
     *       mx: 0.0,
     *       my: 0.0,
     *     }</pre>
     *    </li>
     *   </ul>
     * </p>
     *
     */
    this.getScaledPath = function getScaledPath(pathId, param) {
      var rawPath = this.pathMap[pathId];

      // positioning
      // compute the start point of the path
      var mx, my;
      if (param.abspos) {
        mx = param.abspos.x;
        my = param.abspos.y;
      } else {
        mx = param.containerWidth * param.position.mx;
        my = param.containerHeight * param.position.my;
      }
      var coordinates = {}; // map for the scaled coordinates
      if (param.position) {
        // path
        var heightRatio = param.containerHeight / rawPath.height * param.yScaleFactor;
        var widthRatio = param.containerWidth / rawPath.width * param.xScaleFactor;

        // Apply height ratio
        for (var heightIndex = 0; heightIndex < rawPath.heightElements.length; heightIndex++) {
          coordinates['y' + heightIndex] = rawPath.heightElements[heightIndex] * heightRatio;
        }

        // Apply width ratio
        for (var widthIndex = 0; widthIndex < rawPath.widthElements.length; widthIndex++) {
          coordinates['x' + widthIndex] = rawPath.widthElements[widthIndex] * widthRatio;
        }
      }

      // Apply value to raw path
      var path = format(rawPath.d, {
        mx: mx,
        my: my,
        e: coordinates
      });
      return path;
    };
  }

  // helpers //////////////////////

  // copied and adjusted from https://github.com/adobe-webplatform/Snap.svg/blob/master/src/svg.js
  var tokenRegex = /\{([^{}]+)\}/g,
    objNotationRegex = /(?:(?:^|\.)(.+?)(?=\[|\.|$|\()|\[('|")(.+?)\2\])(\(\))?/g; // matches .xxxxx or ["xxxxx"] to run over object properties

  function replacer(all, key, obj) {
    var res = obj;
    key.replace(objNotationRegex, function (all, name, quote, quotedName, isFunc) {
      name = name || quotedName;
      if (res) {
        if (name in res) {
          res = res[name];
        }
        typeof res == 'function' && isFunc && (res = res());
      }
    });
    res = (res == null || res == obj ? all : res) + '';
    return res;
  }
  function format(str, obj) {
    return String(str).replace(tokenRegex, function (all, key) {
      return replacer(all, key, obj);
    });
  }

  var DrawModule = {
    __init__: ['drdRenderer'],
    drdRenderer: ['type', DrdRenderer],
    textRenderer: ['type', TextRenderer],
    pathMap: ['type', PathMap]
  };

  function DrdImporter(eventBus, canvas, elementFactory, elementRegistry) {
    this._eventBus = eventBus;
    this._canvas = canvas;
    this._elementRegistry = elementRegistry;
    this._elementFactory = elementFactory;
  }
  DrdImporter.$inject = ['eventBus', 'canvas', 'elementFactory', 'elementRegistry'];
  DrdImporter.prototype.root = function (semantic) {
    var element = this._elementFactory.createRoot(elementData$1(semantic));
    this._canvas.setRootElement(element);
    return element;
  };

  /**
   * Add drd element (semantic) to the canvas.
   */
  DrdImporter.prototype.add = function (semantic) {
    var elementFactory = this._elementFactory,
      canvas = this._canvas,
      eventBus = this._eventBus,
      di = semantic.di;
    var element, waypoints, source, target, elementDefinition, bounds;
    if (di.$instanceOf('dmndi:DMNShape')) {
      bounds = di.bounds;
      elementDefinition = elementData$1(semantic, {
        x: Math.round(bounds.x),
        y: Math.round(bounds.y),
        width: Math.round(bounds.width),
        height: Math.round(bounds.height)
      });
      element = elementFactory.createShape(elementDefinition);
      canvas.addShape(element);
      eventBus.fire('drdElement.added', {
        element: element,
        di: di
      });
    } else if (di.$instanceOf('dmndi:DMNEdge')) {
      waypoints = collectWaypoints(di);
      source = this._getSource(semantic);
      target = this._getTarget(semantic);
      if (source && target) {
        elementDefinition = elementData$1(semantic, {
          hidden: false,
          source: source,
          target: target,
          waypoints: waypoints
        });
        element = elementFactory.createConnection(elementDefinition);
        canvas.addConnection(element);
        eventBus.fire('drdElement.added', {
          element: element,
          di: di
        });
      }
    } else {
      throw new Error('unknown di for element ' + semantic.id);
    }
    return element;
  };
  DrdImporter.prototype._getSource = function (semantic) {
    var href, elementReference;
    if (is(semantic, 'dmn:Association')) {
      elementReference = semantic.sourceRef;
    } else if (is(semantic, 'dmn:InformationRequirement')) {
      elementReference = semantic.requiredDecision || semantic.requiredInput;
    } else if (is(semantic, 'dmn:KnowledgeRequirement')) {
      elementReference = semantic.requiredKnowledge;
    } else if (is(semantic, 'dmn:AuthorityRequirement')) {
      elementReference = semantic.requiredDecision || semantic.requiredInput || semantic.requiredAuthority;
    }
    if (elementReference) {
      href = elementReference.href;
    }
    if (href) {
      return this._getShape(getIdFromHref(href));
    }
  };
  DrdImporter.prototype._getTarget = function (semantic) {
    if (is(semantic, 'dmn:Association')) {
      return semantic.targetRef && this._getShape(getIdFromHref(semantic.targetRef.href));
    }
    return this._getShape(semantic.$parent.id);
  };
  DrdImporter.prototype._getShape = function (id) {
    return this._elementRegistry.get(id);
  };

  // helper /////
  function elementData$1(semantic, attrs) {
    return assign$1({
      id: semantic.id,
      type: semantic.$type,
      businessObject: semantic
    }, attrs);
  }
  function collectWaypoints(edge) {
    var waypoints = edge.waypoint;
    if (waypoints) {
      return map(waypoints, function (waypoint) {
        var position = {
          x: waypoint.x,
          y: waypoint.y
        };
        return assign$1({
          original: position
        }, position);
      });
    }
  }
  function getIdFromHref(href) {
    return href.split('#').pop();
  }

  var ImportModule = {
    drdImporter: ['type', DrdImporter]
  };

  var CoreModule$1 = {
    __depends__: [DrawModule, ImportModule]
  };

  /**
   * @typedef { {
   *   [key: string]: string;
   * } } TranslateReplacements
   */

  /**
   * A simple translation stub to be used for multi-language support
   * in diagrams. Can be easily replaced with a more sophisticated
   * solution.
   *
   * @example
   *
   * ```javascript
   * // use it inside any diagram component by injecting `translate`.
   *
   * function MyService(translate) {
   *   alert(translate('HELLO {you}', { you: 'You!' }));
   * }
   * ```
   *
   * @param {string} template to interpolate
   * @param {TranslateReplacements} [replacements] a map with substitutes
   *
   * @return {string} the translated string
   */
  function translate(template, replacements) {
    replacements = replacements || {};
    return template.replace(/{([^}]+)}/g, function (_, key) {
      return replacements[key] || '{' + key + '}';
    });
  }

  /**
   * @type { import('didi').ModuleDeclaration }
   */
  var TranslateModule = {
    translate: ['value', translate]
  };

  /**
   * @typedef {import('./Types.js').Point} Point
   */


  /**
   * @param {import('../core/EventBus.js').Event} event
   *
   * @return {Event}
   */
  function getOriginal(event) {
    return event.originalEvent || event.srcEvent;
  }

  /**
   * @param {MouseEvent} event
   * @param {string} button
   *
   * @return {boolean}
   */
  function isButton(event, button) {
    return (getOriginal(event) || event).button === button;
  }

  /**
   * @param {MouseEvent} event
   *
   * @return {boolean}
   */
  function isPrimaryButton(event) {
    // button === 0 -> left áka primary mouse button
    return isButton(event, 0);
  }

  /**
   * @param {MouseEvent} event
   *
   * @return {boolean}
   */
  function isAuxiliaryButton(event) {
    // button === 1 -> auxiliary áka wheel button
    return isButton(event, 1);
  }

  /**
   * @param {MouseEvent} event
   *
   * @return {boolean}
   */
  function hasSecondaryModifier(event) {
    var originalEvent = getOriginal(event) || event;
    return isPrimaryButton(event) && originalEvent.shiftKey;
  }

  /**
   * @typedef {import('../../model/Types.js').Element} Element
   *
   * @typedef {import('../../core/ElementRegistry.js').default} ElementRegistry
   * @typedef {import('../../core/EventBus.js').default} EventBus
   * @typedef {import('../../draw/Styles.js').default} Styles
   *
   * @typedef {import('../../util/Types.js').Point} Point
   */

  function allowAll(event) {
    return true;
  }
  function allowPrimaryAndAuxiliary(event) {
    return isPrimaryButton(event) || isAuxiliaryButton(event);
  }
  var LOW_PRIORITY$3 = 500;

  /**
   * A plugin that provides interaction events for diagram elements.
   *
   * It emits the following events:
   *
   *   * element.click
   *   * element.contextmenu
   *   * element.dblclick
   *   * element.hover
   *   * element.mousedown
   *   * element.mousemove
   *   * element.mouseup
   *   * element.out
   *
   * Each event is a tuple { element, gfx, originalEvent }.
   *
   * Canceling the event via Event#preventDefault()
   * prevents the original DOM operation.
   *
   * @param {EventBus} eventBus
   * @param {ElementRegistry} elementRegistry
   * @param {Styles} styles
   */
  function InteractionEvents(eventBus, elementRegistry, styles) {
    var self = this;

    /**
     * Fire an interaction event.
     *
     * @param {string} type local event name, e.g. element.click.
     * @param {MouseEvent|TouchEvent} event native event
     * @param {Element} [element] the diagram element to emit the event on;
     *                                   defaults to the event target
     */
    function fire(type, event, element) {
      if (isIgnored(type, event)) {
        return;
      }
      var target, gfx, returnValue;
      if (!element) {
        target = event.delegateTarget || event.target;
        if (target) {
          gfx = target;
          element = elementRegistry.get(gfx);
        }
      } else {
        gfx = elementRegistry.getGraphics(element);
      }
      if (!gfx || !element) {
        return;
      }
      returnValue = eventBus.fire(type, {
        element: element,
        gfx: gfx,
        originalEvent: event
      });
      if (returnValue === false) {
        event.stopPropagation();
        event.preventDefault();
      }
    }

    // TODO(nikku): document this
    var handlers = {};
    function mouseHandler(localEventName) {
      return handlers[localEventName];
    }
    function isIgnored(localEventName, event) {
      var filter = ignoredFilters[localEventName] || isPrimaryButton;

      // only react on left mouse button interactions
      // except for interaction events that are enabled
      // for secundary mouse button
      return !filter(event);
    }
    var bindings = {
      click: 'element.click',
      contextmenu: 'element.contextmenu',
      dblclick: 'element.dblclick',
      mousedown: 'element.mousedown',
      mousemove: 'element.mousemove',
      mouseover: 'element.hover',
      mouseout: 'element.out',
      mouseup: 'element.mouseup'
    };
    var ignoredFilters = {
      'element.contextmenu': allowAll,
      'element.mousedown': allowPrimaryAndAuxiliary,
      'element.mouseup': allowPrimaryAndAuxiliary,
      'element.click': allowPrimaryAndAuxiliary,
      'element.dblclick': allowPrimaryAndAuxiliary
    };

    // manual event trigger //////////

    /**
     * Trigger an interaction event (based on a native dom event)
     * on the target shape or connection.
     *
     * @param {string} eventName the name of the triggered DOM event
     * @param {MouseEvent|TouchEvent} event
     * @param {Element} targetElement
     */
    function triggerMouseEvent(eventName, event, targetElement) {
      // i.e. element.mousedown...
      var localEventName = bindings[eventName];
      if (!localEventName) {
        throw new Error('unmapped DOM event name <' + eventName + '>');
      }
      return fire(localEventName, event, targetElement);
    }
    var ELEMENT_SELECTOR = 'svg, .djs-element';

    // event handling ///////

    function registerEvent(node, event, localEvent, ignoredFilter) {
      var handler = handlers[localEvent] = function (event) {
        fire(localEvent, event);
      };
      if (ignoredFilter) {
        ignoredFilters[localEvent] = ignoredFilter;
      }
      handler.$delegate = delegate.bind(node, ELEMENT_SELECTOR, event, handler);
    }
    function unregisterEvent(node, event, localEvent) {
      var handler = mouseHandler(localEvent);
      if (!handler) {
        return;
      }
      delegate.unbind(node, event, handler.$delegate);
    }
    function registerEvents(svg) {
      forEach(bindings, function (val, key) {
        registerEvent(svg, key, val);
      });
    }
    function unregisterEvents(svg) {
      forEach(bindings, function (val, key) {
        unregisterEvent(svg, key, val);
      });
    }
    eventBus.on('canvas.destroy', function (event) {
      unregisterEvents(event.svg);
    });
    eventBus.on('canvas.init', function (event) {
      registerEvents(event.svg);
    });

    // hit box updating ////////////////

    eventBus.on(['shape.added', 'connection.added'], function (event) {
      var element = event.element,
        gfx = event.gfx;
      eventBus.fire('interactionEvents.createHit', {
        element: element,
        gfx: gfx
      });
    });

    // Update djs-hit on change.
    // A low priortity is necessary, because djs-hit of labels has to be updated
    // after the label bounds have been updated in the renderer.
    eventBus.on(['shape.changed', 'connection.changed'], LOW_PRIORITY$3, function (event) {
      var element = event.element,
        gfx = event.gfx;
      eventBus.fire('interactionEvents.updateHit', {
        element: element,
        gfx: gfx
      });
    });
    eventBus.on('interactionEvents.createHit', LOW_PRIORITY$3, function (event) {
      var element = event.element,
        gfx = event.gfx;
      self.createDefaultHit(element, gfx);
    });
    eventBus.on('interactionEvents.updateHit', function (event) {
      var element = event.element,
        gfx = event.gfx;
      self.updateDefaultHit(element, gfx);
    });

    // hit styles ////////////

    var STROKE_HIT_STYLE = createHitStyle('djs-hit djs-hit-stroke');
    var CLICK_STROKE_HIT_STYLE = createHitStyle('djs-hit djs-hit-click-stroke');
    var ALL_HIT_STYLE = createHitStyle('djs-hit djs-hit-all');
    var NO_MOVE_HIT_STYLE = createHitStyle('djs-hit djs-hit-no-move');
    var HIT_TYPES = {
      'all': ALL_HIT_STYLE,
      'click-stroke': CLICK_STROKE_HIT_STYLE,
      'stroke': STROKE_HIT_STYLE,
      'no-move': NO_MOVE_HIT_STYLE
    };
    function createHitStyle(classNames, attrs) {
      attrs = assign$1({
        stroke: 'white',
        strokeWidth: 15
      }, attrs || {});
      return styles.cls(classNames, ['no-fill', 'no-border'], attrs);
    }

    // style helpers ///////////////

    function applyStyle(hit, type) {
      var attrs = HIT_TYPES[type];
      if (!attrs) {
        throw new Error('invalid hit type <' + type + '>');
      }
      attr(hit, attrs);
      return hit;
    }
    function appendHit(gfx, hit) {
      append(gfx, hit);
    }

    // API

    /**
     * Remove hints on the given graphics.
     *
     * @param {SVGElement} gfx
     */
    this.removeHits = function (gfx) {
      var hits = all('.djs-hit', gfx);
      forEach(hits, remove$3);
    };

    /**
     * Create default hit for the given element.
     *
     * @param {Element} element
     * @param {SVGElement} gfx
     *
     * @return {SVGElement} created hit
     */
    this.createDefaultHit = function (element, gfx) {
      var waypoints = element.waypoints,
        isFrame = element.isFrame,
        boxType;
      if (waypoints) {
        return this.createWaypointsHit(gfx, waypoints);
      } else {
        boxType = isFrame ? 'stroke' : 'all';
        return this.createBoxHit(gfx, boxType, {
          width: element.width,
          height: element.height
        });
      }
    };

    /**
     * Create hits for the given waypoints.
     *
     * @param {SVGElement} gfx
     * @param {Point[]} waypoints
     *
     * @return {SVGElement}
     */
    this.createWaypointsHit = function (gfx, waypoints) {
      var hit = createLine(waypoints);
      applyStyle(hit, 'stroke');
      appendHit(gfx, hit);
      return hit;
    };

    /**
     * Create hits for a box.
     *
     * @param {SVGElement} gfx
     * @param {string} type
     * @param {Object} attrs
     *
     * @return {SVGElement}
     */
    this.createBoxHit = function (gfx, type, attrs) {
      attrs = assign$1({
        x: 0,
        y: 0
      }, attrs);
      var hit = create$2('rect');
      applyStyle(hit, type);
      attr(hit, attrs);
      appendHit(gfx, hit);
      return hit;
    };

    /**
     * Update default hit of the element.
     *
     * @param {Element} element
     * @param {SVGElement} gfx
     *
     * @return {SVGElement} updated hit
     */
    this.updateDefaultHit = function (element, gfx) {
      var hit = query('.djs-hit', gfx);
      if (!hit) {
        return;
      }
      if (element.waypoints) {
        updateLine(hit, element.waypoints);
      } else {
        attr(hit, {
          width: element.width,
          height: element.height
        });
      }
      return hit;
    };
    this.fire = fire;
    this.triggerMouseEvent = triggerMouseEvent;
    this.mouseHandler = mouseHandler;
    this.registerEvent = registerEvent;
    this.unregisterEvent = unregisterEvent;
  }
  InteractionEvents.$inject = ['eventBus', 'elementRegistry', 'styles'];

  /**
   * An event indicating that the mouse hovered over an element
   *
   * @event element.hover
   *
   * @type {Object}
   * @property {Element} element
   * @property {SVGElement} gfx
   * @property {Event} originalEvent
   */

  /**
   * An event indicating that the mouse has left an element
   *
   * @event element.out
   *
   * @type {Object}
   * @property {Element} element
   * @property {SVGElement} gfx
   * @property {Event} originalEvent
   */

  /**
   * An event indicating that the mouse has clicked an element
   *
   * @event element.click
   *
   * @type {Object}
   * @property {Element} element
   * @property {SVGElement} gfx
   * @property {Event} originalEvent
   */

  /**
   * An event indicating that the mouse has double clicked an element
   *
   * @event element.dblclick
   *
   * @type {Object}
   * @property {Element} element
   * @property {SVGElement} gfx
   * @property {Event} originalEvent
   */

  /**
   * An event indicating that the mouse has gone down on an element.
   *
   * @event element.mousedown
   *
   * @type {Object}
   * @property {Element} element
   * @property {SVGElement} gfx
   * @property {Event} originalEvent
   */

  /**
   * An event indicating that the mouse has gone up on an element.
   *
   * @event element.mouseup
   *
   * @type {Object}
   * @property {Element} element
   * @property {SVGElement} gfx
   * @property {Event} originalEvent
   */

  /**
   * An event indicating that the context menu action is triggered
   * via mouse or touch controls.
   *
   * @event element.contextmenu
   *
   * @type {Object}
   * @property {Element} element
   * @property {SVGElement} gfx
   * @property {Event} originalEvent
   */

  /**
   * @type { import('didi').ModuleDeclaration }
   */
  var InteractionEventsModule = {
    __init__: ['interactionEvents'],
    interactionEvents: ['type', InteractionEvents]
  };

  /**
   * @typedef {import('../../core/Canvas.js').default} Canvas
   * @typedef {import('../../core/EventBus.js').default} EventBus
   */

  /**
   * A service that offers the current selection in a diagram.
   * Offers the api to control the selection, too.
   *
   * @param {EventBus} eventBus
   * @param {Canvas} canvas
   */
  function Selection(eventBus, canvas) {
    this._eventBus = eventBus;
    this._canvas = canvas;

    /**
     * @type {Set<Object>}
     */
    this._selectedElements = new Set();
    var self = this;
    eventBus.on(['shape.remove', 'connection.remove'], function (e) {
      var element = e.element;
      self.deselect(element);
    });
    eventBus.on(['diagram.clear', 'root.set'], function (e) {
      self.select(null);
    });
  }
  Selection.$inject = ['eventBus', 'canvas'];

  /**
   * Deselect an element.
   *
   * @param {Object} element The element to deselect.
   */
  Selection.prototype.deselect = function (element) {
    if (!this._selectedElements.has(element)) {
      return;
    }
    var oldSelection = this.get();
    this._selectedElements.delete(element);
    this._eventBus.fire('selection.changed', {
      oldSelection: oldSelection,
      newSelection: this.get()
    });
  };

  /**
   * Get the selected elements.
   *
   * @return {Object[]} The selected elements.
   */
  Selection.prototype.get = function () {
    return Array.from(this._selectedElements);
  };

  /**
   * Check whether an element is selected.
   *
   * @param {Object} element The element.
   *
   * @return {boolean} Whether the element is selected.
   */
  Selection.prototype.isSelected = function (element) {
    return this._selectedElements.has(element);
  };

  /**
   * Select one or many elements.
   *
   * @param {Object|Object[]} elements The element(s) to select.
   * @param {boolean} [add] Whether to add the element(s) to the selected elements.
   * Defaults to `false`.
   */
  Selection.prototype.select = function (elements, add) {
    var oldSelection = this.get();
    if (!isArray$2(elements)) {
      elements = elements ? [elements] : [];
    }
    var canvas = this._canvas;
    var rootElement = canvas.getRootElement();
    elements = elements.filter(function (element) {
      var elementRoot = canvas.findRoot(element);
      return rootElement === elementRoot;
    });

    // selection may be cleared by passing an empty array or null
    // to the method
    if (add) {
      forEach(elements, element => {
        this._selectedElements.add(element);
      });
    } else {
      this._selectedElements = new Set(elements);
    }
    this._eventBus.fire('selection.changed', {
      oldSelection: oldSelection,
      newSelection: this.get()
    });
  };

  /**
   * @typedef {import('../../core/Canvas.js').default} Canvas
   * @typedef {import('../../core/EventBus.js').default} EventBus
   */

  var MARKER_HOVER = 'hover',
    MARKER_SELECTED = 'selected';

  /**
   * A plugin that adds a visible selection UI to shapes and connections
   * by appending the <code>hover</code> and <code>selected</code> classes to them.
   *
   * @class
   *
   * Makes elements selectable, too.
   *
   * @param {Canvas} canvas
   * @param {EventBus} eventBus
   */
  function SelectionVisuals(canvas, eventBus) {
    this._canvas = canvas;
    function addMarker(e, cls) {
      canvas.addMarker(e, cls);
    }
    function removeMarker(e, cls) {
      canvas.removeMarker(e, cls);
    }
    eventBus.on('element.hover', function (event) {
      addMarker(event.element, MARKER_HOVER);
    });
    eventBus.on('element.out', function (event) {
      removeMarker(event.element, MARKER_HOVER);
    });
    eventBus.on('selection.changed', function (event) {
      function deselect(s) {
        removeMarker(s, MARKER_SELECTED);
      }
      function select(s) {
        addMarker(s, MARKER_SELECTED);
      }
      var oldSelection = new Set(event.oldSelection),
        newSelection = new Set(event.newSelection);
      for (let e of oldSelection) {
        if (!newSelection.has(e)) {
          deselect(e);
        }
      }
      for (let e of newSelection) {
        if (!oldSelection.has(e)) {
          select(e);
        }
      }
    });
  }
  SelectionVisuals.$inject = ['canvas', 'eventBus'];

  /**
   * @typedef {import('../../core/Canvas.js').default} Canvas
   * @typedef {import('../../core/ElementRegistry.js').default} ElementRegistry
   * @typedef {import('../../core/EventBus.js').default} EventBus
   * @typedef {import('./Selection.js').default} Selection
   */

  /**
   * @param {EventBus} eventBus
   * @param {Selection} selection
   * @param {Canvas} canvas
   * @param {ElementRegistry} elementRegistry
   */
  function SelectionBehavior(eventBus, selection, canvas, elementRegistry) {
    // Select elements on create
    eventBus.on('create.end', 500, function (event) {
      var context = event.context,
        canExecute = context.canExecute,
        elements = context.elements,
        hints = context.hints || {},
        autoSelect = hints.autoSelect;
      if (canExecute) {
        if (autoSelect === false) {
          // Select no elements
          return;
        }
        if (isArray$2(autoSelect)) {
          selection.select(autoSelect);
        } else {
          // Select all elements by default
          selection.select(elements.filter(isShown));
        }
      }
    });

    // Select connection targets on connect
    eventBus.on('connect.end', 500, function (event) {
      var context = event.context,
        connection = context.connection;
      if (connection) {
        selection.select(connection);
      }
    });

    // Select shapes on move
    eventBus.on('shape.move.end', 500, function (event) {
      var previousSelection = event.previousSelection || [];
      var shape = elementRegistry.get(event.context.shape.id);

      // Always select main shape on move
      var isSelected = find$1(previousSelection, function (selectedShape) {
        return shape.id === selectedShape.id;
      });
      if (!isSelected) {
        selection.select(shape);
      }
    });

    // Select elements on click
    eventBus.on('element.click', function (event) {
      if (!isPrimaryButton(event)) {
        return;
      }
      var element = event.element;
      if (element === canvas.getRootElement()) {
        element = null;
      }
      var isSelected = selection.isSelected(element),
        isMultiSelect = selection.get().length > 1;

      // Add to selection if SHIFT pressed
      var add = hasSecondaryModifier(event);
      if (isSelected && isMultiSelect) {
        if (add) {
          // Deselect element
          return selection.deselect(element);
        } else {
          // Select element only
          return selection.select(element);
        }
      } else if (!isSelected) {
        // Select element
        selection.select(element, add);
      } else {
        // Deselect element
        selection.deselect(element);
      }
    });
  }
  SelectionBehavior.$inject = ['eventBus', 'selection', 'canvas', 'elementRegistry'];
  function isShown(element) {
    return !element.hidden;
  }

  /**
   * @type { import('didi').ModuleDeclaration }
   */
  var SelectionModule = {
    __init__: ['selectionVisuals', 'selectionBehavior'],
    __depends__: [InteractionEventsModule],
    selection: ['type', Selection],
    selectionVisuals: ['type', SelectionVisuals],
    selectionBehavior: ['type', SelectionBehavior]
  };

  /**
   * Util that provides unique IDs.
   *
   * @class
   * @constructor
   *
   * The ids can be customized via a given prefix and contain a random value to avoid collisions.
   *
   * @param {string} [prefix] a prefix to prepend to generated ids (for better readability)
   */
  function IdGenerator(prefix) {
    this._counter = 0;
    this._prefix = (prefix ? prefix + '-' : '') + Math.floor(Math.random() * 1000000000) + '-';
  }

  /**
   * Returns a next unique ID.
   *
   * @return {string} the id
   */
  IdGenerator.prototype.next = function () {
    return this._prefix + ++this._counter;
  };

  // document wide unique overlay ids
  var ids = new IdGenerator('ov');
  var LOW_PRIORITY$2 = 500;

  /**
   * @typedef {import('../../core/Canvas.js').default} Canvas
   * @typedef {import('../../core/ElementRegistry.js').default} ElementRegistry
   * @typedef {import('../../core/EventBus.js').default} EventBus
   *
   * @typedef {import('../../model/Types.js').Element} Element
   *
   * @typedef { {
   *   minZoom?: number,
   *   maxZoom?: number
   * } } OverlaysConfigShow
   *
   * @typedef { {
   *   min?: number,
   *   max?: number
   * } } OverlaysConfigScale
   *
   * @typedef { {
  *   id: string,
  *   type: string | null,
  *   element: Element | string
  * } & OverlayAttrs } Overlay
  *
   * @typedef { {
   *   html: HTMLElement | string,
   *   position: {
   *     top?: number,
   *     right?: number,
   *     bottom?: number,
   *     left?: number
   *   }
   * } & OverlaysConfigDefault } OverlayAttrs
   *
   * @typedef { {
   *   html: HTMLElement,
   *   element: Element,
   *   overlays: Overlay[]
   * } } OverlayContainer
   *
   * @typedef {{
   *   defaults?: OverlaysConfigDefault
   * }} OverlaysConfig
   *
   * @typedef { {
   *  show?: OverlaysConfigShow,
   *  scale?: OverlaysConfigScale | boolean
   * } } OverlaysConfigDefault
   *
   * @typedef { {
   *   id?: string;
   *   element?: Element | string;
   *   type?: string;
   * } | string } OverlaysFilter
   */

  /**
   * A service that allows users to attach overlays to diagram elements.
   *
   * The overlay service will take care of overlay positioning during updates.
   *
   * @example
   *
   * ```javascript
   * // add a pink badge on the top left of the shape
   *
   * overlays.add(someShape, {
   *   position: {
   *     top: -5,
   *     left: -5
   *   },
   *   html: '<div style="width: 10px; background: fuchsia; color: white;">0</div>'
   * });
   *
   * // or add via shape id
   *
   * overlays.add('some-element-id', {
   *   position: {
   *     top: -5,
   *     left: -5
   *   }
   *   html: '<div style="width: 10px; background: fuchsia; color: white;">0</div>'
   * });
   *
   * // or add with optional type
   *
   * overlays.add(someShape, 'badge', {
   *   position: {
   *     top: -5,
   *     left: -5
   *   }
   *   html: '<div style="width: 10px; background: fuchsia; color: white;">0</div>'
   * });
   * ```
   *
   * ```javascript
   * // remove an overlay
   *
   * var id = overlays.add(...);
   * overlays.remove(id);
   *
   *
   * You may configure overlay defaults during tool by providing a `config` module
   * with `overlays.defaults` as an entry:
   *
   * {
   *   overlays: {
   *     defaults: {
   *       show: {
   *         minZoom: 0.7,
   *         maxZoom: 5.0
   *       },
   *       scale: {
   *         min: 1
   *       }
   *     }
   * }
   * ```
   *
   * @param {OverlaysConfig} config
   * @param {EventBus} eventBus
   * @param {Canvas} canvas
   * @param {ElementRegistry} elementRegistry
   */
  function Overlays(config, eventBus, canvas, elementRegistry) {
    this._eventBus = eventBus;
    this._canvas = canvas;
    this._elementRegistry = elementRegistry;
    this._ids = ids;

    /**
     * @type {OverlaysConfigDefault}
     */
    this._overlayDefaults = assign$1({
      // no show constraints
      show: null,
      // always scale
      scale: true
    }, config && config.defaults);

    /**
     * @type {Record<string, Overlay>}
     */
    this._overlays = {};

    /**
     * @type {OverlayContainer[]}
     */
    this._overlayContainers = [];

    /**
     * @type {HTMLElement}
     */
    this._overlayRoot = createRoot(canvas.getContainer());
    this._init();
  }
  Overlays.$inject = ['config.overlays', 'eventBus', 'canvas', 'elementRegistry'];

  /**
   * Returns the overlay with the specified ID or a list of overlays
   * for an element with a given type.
   *
   * @example
   *
   * ```javascript
   * // return the single overlay with the given ID
   * overlays.get('some-id');
   *
   * // return all overlays for the shape
   * overlays.get({ element: someShape });
   *
   * // return all overlays on shape with type 'badge'
   * overlays.get({ element: someShape, type: 'badge' });
   *
   * // shape can also be specified as ID
   * overlays.get({ element: 'element-id', type: 'badge' });
   * ```
   *
   * @param {OverlaysFilter} search The filter to be used to find the overlay(s).
   *
   * @return {Overlay|Overlay[]} The overlay(s).
   */
  Overlays.prototype.get = function (search) {
    if (isString$1(search)) {
      search = {
        id: search
      };
    }
    if (isString$1(search.element)) {
      search.element = this._elementRegistry.get(search.element);
    }
    if (search.element) {
      var container = this._getOverlayContainer(search.element, true);

      // return a list of overlays when searching by element (+type)
      if (container) {
        return search.type ? filter(container.overlays, matchPattern({
          type: search.type
        })) : container.overlays.slice();
      } else {
        return [];
      }
    } else if (search.type) {
      return filter(this._overlays, matchPattern({
        type: search.type
      }));
    } else {
      // return single element when searching by id
      return search.id ? this._overlays[search.id] : null;
    }
  };

  /**
   * Adds an HTML overlay to an element.
   *
   * @param {Element|string} element The element to add the overlay to.
   * @param {string} [type] An optional type that can be used to filter.
   * @param {OverlayAttrs} overlay The overlay.
   *
   * @return {string} The overlay's ID that can be used to get or remove it.
   */
  Overlays.prototype.add = function (element, type, overlay) {
    if (isObject$1(type)) {
      overlay = type;
      type = null;
    }
    if (!element.id) {
      element = this._elementRegistry.get(element);
    }
    if (!overlay.position) {
      throw new Error('must specifiy overlay position');
    }
    if (!overlay.html) {
      throw new Error('must specifiy overlay html');
    }
    if (!element) {
      throw new Error('invalid element specified');
    }
    var id = this._ids.next();
    overlay = assign$1({}, this._overlayDefaults, overlay, {
      id: id,
      type: type,
      element: element,
      html: overlay.html
    });
    this._addOverlay(overlay);
    return id;
  };

  /**
   * Remove an overlay with the given ID or all overlays matching the given filter.
   *
   * @see Overlays#get for filter options.
   *
   * @param {OverlaysFilter} filter The filter to be used to find the overlay.
   */
  Overlays.prototype.remove = function (filter) {
    var overlays = this.get(filter) || [];
    if (!isArray$2(overlays)) {
      overlays = [overlays];
    }
    var self = this;
    forEach(overlays, function (overlay) {
      var container = self._getOverlayContainer(overlay.element, true);
      if (overlay) {
        remove$4(overlay.html);
        remove$4(overlay.htmlContainer);
        delete overlay.htmlContainer;
        delete overlay.element;
        delete self._overlays[overlay.id];
      }
      if (container) {
        var idx = container.overlays.indexOf(overlay);
        if (idx !== -1) {
          container.overlays.splice(idx, 1);
        }
      }
    });
  };

  /**
   * Checks whether overlays are shown.
   *
   * @return {boolean} Whether overlays are shown.
   */
  Overlays.prototype.isShown = function () {
    return this._overlayRoot.style.display !== 'none';
  };

  /**
   * Show all overlays.
   */
  Overlays.prototype.show = function () {
    setVisible(this._overlayRoot);
  };

  /**
   * Hide all overlays.
   */
  Overlays.prototype.hide = function () {
    setVisible(this._overlayRoot, false);
  };

  /**
   * Remove all overlays and their container.
   */
  Overlays.prototype.clear = function () {
    this._overlays = {};
    this._overlayContainers = [];
    clear(this._overlayRoot);
  };
  Overlays.prototype._updateOverlayContainer = function (container) {
    var element = container.element,
      html = container.html;

    // update container left,top according to the elements x,y coordinates
    // this ensures we can attach child elements relative to this container

    var x = element.x,
      y = element.y;
    if (element.waypoints) {
      var bbox = getBBox(element);
      x = bbox.x;
      y = bbox.y;
    }
    setPosition(html, x, y);
    attr$1(container.html, 'data-container-id', element.id);
  };
  Overlays.prototype._updateOverlay = function (overlay) {
    var position = overlay.position,
      htmlContainer = overlay.htmlContainer,
      element = overlay.element;

    // update overlay html relative to shape because
    // it is already positioned on the element

    // update relative
    var left = position.left,
      top = position.top;
    if (position.right !== undefined) {
      var width;
      if (element.waypoints) {
        width = getBBox(element).width;
      } else {
        width = element.width;
      }
      left = position.right * -1 + width;
    }
    if (position.bottom !== undefined) {
      var height;
      if (element.waypoints) {
        height = getBBox(element).height;
      } else {
        height = element.height;
      }
      top = position.bottom * -1 + height;
    }
    setPosition(htmlContainer, left || 0, top || 0);
    this._updateOverlayVisibilty(overlay, this._canvas.viewbox());
  };
  Overlays.prototype._createOverlayContainer = function (element) {
    var html = domify('<div class="djs-overlays" />');
    assign(html, {
      position: 'absolute'
    });
    this._overlayRoot.appendChild(html);
    var container = {
      html: html,
      element: element,
      overlays: []
    };
    this._updateOverlayContainer(container);
    this._overlayContainers.push(container);
    return container;
  };
  Overlays.prototype._updateRoot = function (viewbox) {
    var scale = viewbox.scale || 1;
    var matrix = 'matrix(' + [scale, 0, 0, scale, -1 * viewbox.x * scale, -1 * viewbox.y * scale].join(',') + ')';
    setTransform(this._overlayRoot, matrix);
  };
  Overlays.prototype._getOverlayContainer = function (element, raw) {
    var container = find$1(this._overlayContainers, function (c) {
      return c.element === element;
    });
    if (!container && !raw) {
      return this._createOverlayContainer(element);
    }
    return container;
  };
  Overlays.prototype._addOverlay = function (overlay) {
    var id = overlay.id,
      element = overlay.element,
      html = overlay.html,
      htmlContainer,
      overlayContainer;

    // unwrap jquery (for those who need it)
    if (html.get && html.constructor.prototype.jquery) {
      html = html.get(0);
    }

    // create proper html elements from
    // overlay HTML strings
    if (isString$1(html)) {
      html = domify(html);
    }
    overlayContainer = this._getOverlayContainer(element);
    htmlContainer = domify('<div class="djs-overlay" data-overlay-id="' + id + '">');
    assign(htmlContainer, {
      position: 'absolute'
    });
    htmlContainer.appendChild(html);
    if (overlay.type) {
      classes$1(htmlContainer).add('djs-overlay-' + overlay.type);
    }
    var elementRoot = this._canvas.findRoot(element);
    var activeRoot = this._canvas.getRootElement();
    setVisible(htmlContainer, elementRoot === activeRoot);
    overlay.htmlContainer = htmlContainer;
    overlayContainer.overlays.push(overlay);
    overlayContainer.html.appendChild(htmlContainer);
    this._overlays[id] = overlay;
    this._updateOverlay(overlay);
    this._updateOverlayVisibilty(overlay, this._canvas.viewbox());
  };
  Overlays.prototype._updateOverlayVisibilty = function (overlay, viewbox) {
    var show = overlay.show,
      rootElement = this._canvas.findRoot(overlay.element),
      minZoom = show && show.minZoom,
      maxZoom = show && show.maxZoom,
      htmlContainer = overlay.htmlContainer,
      activeRootElement = this._canvas.getRootElement(),
      visible = true;
    if (rootElement !== activeRootElement) {
      visible = false;
    } else if (show) {
      if (isDefined(minZoom) && minZoom > viewbox.scale || isDefined(maxZoom) && maxZoom < viewbox.scale) {
        visible = false;
      }
    }
    setVisible(htmlContainer, visible);
    this._updateOverlayScale(overlay, viewbox);
  };
  Overlays.prototype._updateOverlayScale = function (overlay, viewbox) {
    var shouldScale = overlay.scale,
      minScale,
      maxScale,
      htmlContainer = overlay.htmlContainer;
    var scale,
      transform = '';
    if (shouldScale !== true) {
      if (shouldScale === false) {
        minScale = 1;
        maxScale = 1;
      } else {
        minScale = shouldScale.min;
        maxScale = shouldScale.max;
      }
      if (isDefined(minScale) && viewbox.scale < minScale) {
        scale = (1 / viewbox.scale || 1) * minScale;
      }
      if (isDefined(maxScale) && viewbox.scale > maxScale) {
        scale = (1 / viewbox.scale || 1) * maxScale;
      }
    }
    if (isDefined(scale)) {
      transform = 'scale(' + scale + ',' + scale + ')';
    }
    setTransform(htmlContainer, transform);
  };
  Overlays.prototype._updateOverlaysVisibilty = function (viewbox) {
    var self = this;
    forEach(this._overlays, function (overlay) {
      self._updateOverlayVisibilty(overlay, viewbox);
    });
  };
  Overlays.prototype._init = function () {
    var eventBus = this._eventBus;
    var self = this;

    // scroll/zoom integration

    function updateViewbox(viewbox) {
      self._updateRoot(viewbox);
      self._updateOverlaysVisibilty(viewbox);
      self.show();
    }
    eventBus.on('canvas.viewbox.changing', function (event) {
      self.hide();
    });
    eventBus.on('canvas.viewbox.changed', function (event) {
      updateViewbox(event.viewbox);
    });

    // remove integration

    eventBus.on(['shape.remove', 'connection.remove'], function (e) {
      var element = e.element;
      var overlays = self.get({
        element: element
      });
      forEach(overlays, function (o) {
        self.remove(o.id);
      });
      var container = self._getOverlayContainer(element);
      if (container) {
        remove$4(container.html);
        var i = self._overlayContainers.indexOf(container);
        if (i !== -1) {
          self._overlayContainers.splice(i, 1);
        }
      }
    });

    // move integration

    eventBus.on('element.changed', LOW_PRIORITY$2, function (e) {
      var element = e.element;
      var container = self._getOverlayContainer(element, true);
      if (container) {
        forEach(container.overlays, function (overlay) {
          self._updateOverlay(overlay);
        });
        self._updateOverlayContainer(container);
      }
    });

    // marker integration, simply add them on the overlays as classes, too.

    eventBus.on('element.marker.update', function (e) {
      var container = self._getOverlayContainer(e.element, true);
      if (container) {
        classes$1(container.html)[e.add ? 'add' : 'remove'](e.marker);
      }
    });
    eventBus.on('root.set', function () {
      self._updateOverlaysVisibilty(self._canvas.viewbox());
    });

    // clear overlays with diagram

    eventBus.on('diagram.clear', this.clear, this);
  };

  // helpers /////////////////////////////

  function createRoot(parentNode) {
    var root = domify('<div class="djs-overlay-container" />');
    assign(root, {
      position: 'absolute',
      width: 0,
      height: 0
    });
    parentNode.insertBefore(root, parentNode.firstChild);
    return root;
  }
  function setPosition(el, x, y) {
    assign(el, {
      left: x + 'px',
      top: y + 'px'
    });
  }

  /**
   * Set element visible
   *
   * @param {DOMElement} el
   * @param {boolean} [visible=true]
   */
  function setVisible(el, visible) {
    el.style.display = visible === false ? 'none' : '';
  }
  function setTransform(el, transform) {
    el.style['transform-origin'] = 'top left';
    ['', '-ms-', '-webkit-'].forEach(function (prefix) {
      el.style[prefix + 'transform'] = transform;
    });
  }

  /**
   * @type { import('didi').ModuleDeclaration }
   */
  var OverlaysModule = {
    __init__: ['overlays'],
    overlays: ['type', Overlays]
  };

  function DefinitionPropertiesView(eventBus, canvas, translate) {
    this._eventBus = eventBus;
    this._canvas = canvas;
    this._translate = translate;
    eventBus.on('diagram.init', function () {
      this._init();
    }, this);
    eventBus.on('import.done', function (event) {
      if (!event.error) {
        this.update();
      }
    }, this);

    /* markup definition */

    this.HTML_MARKUP = '<div class="dmn-definitions">' + '<div class="dmn-definitions-name" title="' + this._translate('Definition name') + '" spellcheck="false">' + '</div>' + '<div class="dmn-definitions-id" title="' + this._translate('Definition ID') + '" spellcheck="false">' + '</div>' + '</div>';
  }
  DefinitionPropertiesView.$inject = ['eventBus', 'canvas', 'translate'];

  /**
   * Initialize
   */
  DefinitionPropertiesView.prototype._init = function () {
    var canvas = this._canvas,
      eventBus = this._eventBus;
    var parent = canvas.getContainer(),
      container = this._container = domify(this.HTML_MARKUP);
    parent.appendChild(container);
    this.nameElement = query('.dmn-definitions-name', this._container);
    this.idElement = query('.dmn-definitions-id', this._container);
    delegate.bind(container, '.dmn-definitions-name, .dmn-definitions-id', 'mousedown', function (event) {
      event.stopPropagation();
    });
    eventBus.fire('definitionIdView.create', {
      html: container
    });
  };
  DefinitionPropertiesView.prototype.update = function () {
    var businessObject = this._canvas.getRootElement().businessObject;
    this.nameElement.textContent = businessObject.name;
    this.idElement.textContent = businessObject.id;
  };

  function PaletteAdapter(eventBus, canvas) {
    function toggleMarker(cls, on) {
      var container = canvas.getContainer();
      classes$1(container).toggle(cls, on);
    }
    eventBus.on('palette.create', function () {
      toggleMarker('with-palette', true);
    });
    eventBus.on('palette.changed', function (event) {
      toggleMarker('with-palette-two-column', event.twoColumn);
    });
  }
  PaletteAdapter.$inject = ['eventBus', 'canvas'];

  var DefinitionPropertiesModule = {
    __depends__: [TranslateModule],
    __init__: ['definitionPropertiesView', 'definitionPropertiesPaletteAdapter'],
    definitionPropertiesView: ['type', DefinitionPropertiesView],
    definitionPropertiesPaletteAdapter: ['type', PaletteAdapter]
  };

  var PROVIDERS = [{
    className: 'dmn-icon-decision-table',
    matches: function (el) {
      var businessObject = getBusinessObject(el);
      return is(businessObject, 'dmn:Decision') && is(businessObject.decisionLogic, 'dmn:DecisionTable');
    },
    title: 'Open decision table'
  }, {
    className: 'dmn-icon-literal-expression',
    matches: function (el) {
      var boxedExpression = getBoxedExpression(el);
      return is(boxedExpression, 'dmn:LiteralExpression');
    },
    title: 'Open literal expression'
  }];

  /**
   * Displays overlays that can be clicked in order to drill
   * down into a DMN element.
   */
  class DrillDown {
    constructor(injector, eventBus, overlays, config, translate) {
      this._injector = injector;
      this._eventBus = eventBus;
      this._overlays = overlays;
      this._translate = translate;
      this._config = config || {
        enabled: true
      };
      eventBus.on(['shape.added'], ({
        element
      }) => {
        for (let i = 0; i < PROVIDERS.length; i++) {
          const {
            matches,
            className,
            title
          } = PROVIDERS[i];
          var editable = matches && matches(element);
          if (editable) {
            this.addOverlay(element, className, title);
          }
        }
      });
    }

    /**
     * Add overlay to an element that enables drill down.
     *
     * @param {Object} element Element to add overlay to.
     * @param {string} className
     *        CSS class that will be added to overlay in order to display icon.
     * @param {string} title added to the button
     */
    addOverlay(element, className, title) {
      const enabled = this._config.enabled !== false;
      const node = this._getOverlayNode(className, title, enabled);
      const overlayId = this._overlays.add(element, {
        position: {
          top: 2,
          left: 2
        },
        html: node
      });

      // TODO(nikku): can we remove renamed to drillDown.enabled
      if (enabled) {
        classes$1(node).add('interactive');
        this.bindEventListener(element, node, overlayId);
      }
    }
    _getOverlayNode(className, title, enabled) {
      const container = document.createElement('div');
      container.className = 'drill-down-overlay';
      if (!enabled) {
        const icon = document.createElement('span');
        icon.className = className;
        container.appendChild(icon);
        return container;
      }
      const button = document.createElement('button');
      button.type = 'button';
      button.className = className;
      button.title = this._translate(title);
      container.appendChild(button);
      return container;
    }

    /**
     * @param {Object} element
     * @param {Object} overlay
     * @param {string} id
     */
    bindEventListener(element, overlay, id) {
      const overlays = this._overlays,
        eventBus = this._eventBus;
      const overlaysRoot = overlays._overlayRoot;
      delegate.bind(overlaysRoot, '[data-overlay-id="' + id + '"]', 'click', () => {
        const triggerDefault = eventBus.fire('drillDown.click', {
          element
        });
        if (triggerDefault === false) {
          return;
        }
        this.drillDown(element);
      });
    }

    /**
     * Drill down into the specific element.
     *
     * @param  {djs.model.Base} element
     *
     * @return {boolean} whether drill down was executed
     */
    drillDown(element) {
      const parent = this._injector.get('_parent', false);

      // no parent; skip drill down
      if (!parent) {
        return false;
      }
      const view = parent.getView(element.businessObject);

      // no view to drill down to
      if (!view) {
        return false;
      }
      parent.open(view);
      return true;
    }
  }
  DrillDown.$inject = ['injector', 'eventBus', 'overlays', 'config.drillDown', 'translate'];

  var DrillDownModule = {
    __depends__: [OverlaysModule, TranslateModule],
    __init__: ['drillDown'],
    drillDown: ['type', DrillDown]
  };

  /**
   * The code in the <project-logo></project-logo> area
   * must not be changed.
   *
   * @see http://bpmn.io/license for more information.
   */


  /**
   * Padding added around the diagram bounds on SVG export.
   *
   * `getBBox` returns the geometry bounds only, excluding element strokes, so
   * without padding strokes at the diagram edges get clipped. Historically this
   * padding was provided implicitly by element outlines, which diagram-js now
   * creates lazily (diagram-js@15.19, bpmn-io/diagram-js#1064).
   */
  const EXPORT_PADDING = 5;

  /**
   * Class set on the canvas container to hide element outlines, which diagram-js
   * excludes from rendering while present. Applied when measuring the export
   * bounds so lazily created outlines do not skew them.
   */
  const OUTLINE_HIDDEN_CLS = 'djs-outline-hidden';

  /**
   * @typedef {import('dmn-js-shared/lib/base/View).OpenResult} OpenResult
   */

  /**
   * @typedef {import('dmn-js-shared/lib/base/View).OpenError} OpenError
   */

  /**
   * A viewer for DMN diagrams.
   *
   * Have a look at {@link NavigatedViewer} or {@link Modeler} for bundles that include
   * additional features.
   *
   *
   * ## Extending the Viewer
   *
   * In order to extend the viewer pass extension modules to bootstrap via the
   * `additionalModules` option. An extension module is an object that exposes
   * named services.
   *
   * The following example depicts the integration of a simple
   * logging component that integrates with interaction events:
   *
   *
   * ```javascript
   *
   * // logging component
   * function InteractionLogger(eventBus) {
   *   eventBus.on('element.hover', function(event) {
   *     console.log()
   *   })
   * }
   *
   * InteractionLogger.$inject = [ 'eventBus' ]; // minification save
   *
   * // extension module
   * var extensionModule = {
   *   __init__: [ 'interactionLogger' ],
   *   interactionLogger: [ 'type', InteractionLogger ]
   * };
   *
   * // extend the viewer
   * var drdViewer = new Viewer({ additionalModules: [ extensionModule ] });
   * drdViewer.importXML(...);
   * ```
   *
   * @param {Object} options configuration options to pass to the viewer
   * @param {DOMElement} [options.container]
   *        the container to render the viewer in, defaults to body
   * @param {Array<didi.Module>} [options.modules]
   *        a list of modules to override the default modules
   * @param {Array<didi.Module>} [options.additionalModules]
   *        a list of modules to use with the default modules
   */
  function Viewer$5(options) {
    this._container = this._createContainer();

    /* <project-logo> */

    addProjectLogo(this._container);

    /* </project-logo> */

    this._init(this._container, options);
  }
  e(Viewer$5, Diagram);

  /**
   * The saveSVG result.
   *
   * @typedef {Object} SaveSVGResult
   *
   * @property {string} svg
   */

  /**
   * Export the currently displayed DMN diagram as
   * an SVG image.
   *
   * @param {Object} [options]
   *
   * @return {Promise<SaveSVGResult>}
   */
  Viewer$5.prototype.saveSVG = wrapForCompatibility(function (options) {
    var self = this;
    return new Promise(function (resolve) {
      var canvas = self.get('canvas');
      var contentNode = canvas.getActiveLayer(),
        defsNode = query('defs', canvas._svg);
      var contents = innerSVG(contentNode),
        defs = defsNode && defsNode.outerHTML || '';

      // hide outlines so they do not skew the measured bounds
      var container = canvas.getContainer();
      classes$1(container).add(OUTLINE_HIDDEN_CLS);
      var bbox;
      try {
        bbox = contentNode.getBBox();
      } finally {
        classes$1(container).remove(OUTLINE_HIDDEN_CLS);
      }
      var x = bbox.x - EXPORT_PADDING,
        y = bbox.y - EXPORT_PADDING,
        width = bbox.width + EXPORT_PADDING * 2,
        height = bbox.height + EXPORT_PADDING * 2;
      var svg = '<?xml version="1.0" encoding="utf-8"?>\n' + '<!-- created with dmn-js / http://bpmn.io -->\n' + '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">\n' + '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" ' + 'width="' + width + '" height="' + height + '" ' + 'viewBox="' + x + ' ' + y + ' ' + width + ' ' + height + '" version="1.1">' + defs + contents + '</svg>';
      resolve({
        svg
      });
    });
  });
  Viewer$5.prototype.getModules = function () {
    return this._modules;
  };

  /**
   * Destroy the viewer instance and remove all its
   * remainders from the document tree.
   */
  Viewer$5.prototype.destroy = function () {
    // diagram destroy
    Diagram.prototype.destroy.call(this);

    // dom detach
    remove$4(this._container);
  };

  /**
   * Register an event listener
   *
   * Remove a previously added listener via {@link #off(event, callback)}.
   *
   * @param {string} event
   * @param {number} [priority]
   * @param {Function} callback
   * @param {Object} [that]
   */
  Viewer$5.prototype.on = function (event, priority, callback, target) {
    return this.get('eventBus').on(event, priority, callback, target);
  };

  /**
   * De-register an event listener
   *
   * @param {string} event
   * @param {Function} callback
   */
  Viewer$5.prototype.off = function (event, callback) {
    this.get('eventBus').off(event, callback);
  };
  Viewer$5.prototype._init = function (container, options) {
    var {
      additionalModules,
      canvas,
      ...additionalOptions
    } = options;
    var baseModules = options.modules || this.getModules(),
      staticModules = [{
        drd: ['value', this]
      }];
    var modules = [...staticModules, ...baseModules, ...(additionalModules || [])];
    var diagramOptions = {
      ...additionalOptions,
      canvas: {
        ...canvas,
        container
      },
      modules
    };

    // invoke diagram constructor
    Diagram.call(this, diagramOptions);
    if (options && options.container) {
      this.attachTo(options.container);
    }
  };

  /**
   * Emit an event on the underlying {@link EventBus}
   *
   * @param  {string} type
   * @param  {Object} event
   *
   * @return {Object} event processing result (if any)
   */
  Viewer$5.prototype._emit = function (type, event) {
    return this.get('eventBus').fire(type, event);
  };
  Viewer$5.prototype._createContainer = function () {
    return domify('<div class="dmn-drd-container"></div>');
  };

  /**
   * Open diagram element.
   *
   * @param  {ModdleElement} definitions
   * @returns {Promise} Resolves with {OpenResult} when successful
   * or rejects with {OpenError}
   */
  Viewer$5.prototype.open = function (definitions) {
    var self = this;
    return new Promise((resolve, reject) => {
      var err;

      // use try/catch to not swallow synchronous exceptions
      // that may be raised during model parsing
      try {
        if (self._definitions) {
          // clear existing rendered diagram
          self.clear();
        }

        // update definitions
        self._definitions = definitions;

        // perform graphical import
        return importDRD(self, definitions, function (err, warnings) {
          if (err) {
            err.warnings = warnings || [];
            reject(err);
          } else {
            resolve({
              warnings: warnings || []
            });
          }
        });
      } catch (e) {
        err = e;
      }
      if (err) {
        err.warnings = err.warnings || [];
        reject(err);
      } else {
        resolve({
          warnings: []
        });
      }
    });
  };

  /**
   * Attach viewer to given parent node.
   *
   * @param  {Element} parentNode
   */
  Viewer$5.prototype.attachTo = function (parentNode) {
    if (!parentNode) {
      throw new Error('parentNode required');
    }

    // ensure we detach from the
    // previous, old parent
    this.detach();
    var container = this._container;
    parentNode.appendChild(container);
    this._emit('attach', {});
    this.get('canvas').resized();
  };

  /**
   * Detach viewer from parent node, if attached.
   */
  Viewer$5.prototype.detach = function () {
    var container = this._container,
      parentNode = container.parentNode;
    if (!parentNode) {
      return;
    }
    this._emit('detach', {});
    parentNode.removeChild(container);
  };
  Viewer$5.prototype._modules = [CoreModule$1, TranslateModule, SelectionModule, OverlaysModule, DefinitionPropertiesModule, DrillDownModule];

  class Base {
    constructor(attrs) {
      assign$1(this, attrs);

      /**
       * The object that backs up the shape
       *
       * @name Base#businessObject
       * @type Object
       */
      defineProperty(this, 'businessObject', {
        writable: true
      });
    }
  }
  class Root extends Base {
    constructor(attrs) {
      super(attrs);

      /**
       * The tables rows
       *
       * @name Root#rows
       * @type Row
       */
      defineProperty(this, 'rows', {
        enumerable: true,
        value: this.rows || []
      });

      /**
       * The tables columns
       *
       * @name Root#cols
       * @type Col
       */
      defineProperty(this, 'cols', {
        enumerable: true,
        value: this.cols || []
      });
    }
  }
  class Row extends Base {
    constructor(attrs) {
      super(attrs);

      /**
       * Reference to the table
       *
       * @name Row#root
       * @type Root
       */
      defineProperty(this, 'root', {
        writable: true
      });

      /**
       * Reference to contained cells
       *
       * @name Row#cells
       * @type Cell
       */
      defineProperty(this, 'cells', {
        enumerable: true,
        value: this.cells || []
      });
    }
  }
  class Col extends Base {
    constructor(attrs) {
      super(attrs);

      /**
       * Reference to the table
       *
       * @name Col#table
       * @type Root
       */
      defineProperty(this, 'root', {
        writable: true
      });

      /**
       * Reference to contained cells
       *
       * @name Row#cells
       * @type Cell
       */
      defineProperty(this, 'cells', {
        enumerable: true,
        value: this.cells || []
      });
    }
  }
  class Cell extends Base {
    constructor(attrs) {
      super(attrs);

      /**
       * Reference to the row
       *
       * @name Cell#row
       * @type Row
       */
      defineProperty(this, 'row', {
        writable: true
      });

      /**
       * Reference to the col
       *
       * @name Cell#col
       * @type Col
       */
      defineProperty(this, 'col', {
        writable: true
      });
    }
  }
  const TYPES = {
    root: Root,
    row: Row,
    col: Col,
    cell: Cell
  };
  function create(type, attrs) {
    const Type = TYPES[type];
    if (!Type) {
      throw new Error('unknown type ' + type);
    }
    return new Type(attrs);
  }

  // helpers /////////////

  function defineProperty(el, prop, options) {
    Object.defineProperty(el, prop, options);
  }

  class ElementFactory {
    constructor() {
      this._uid = 12;
    }
    create(type, attrs = {}) {
      if (!attrs.id) {
        attrs.id = type + '_' + this._uid++;
      }
      return create(type, attrs);
    }
    createRoot(attrs) {
      return this.create('root', attrs);
    }
    createRow(attrs) {
      return this.create('row', attrs);
    }
    createCol(attrs) {
      return this.create('col', attrs);
    }
    createCell(attrs) {
      return this.create('cell', attrs);
    }
  }

  let ElementRegistry$1 = class ElementRegistry {
    constructor(eventBus) {
      this._eventBus = eventBus;
      this._elements = {};
      eventBus.on('table.clear', this.clear.bind(this));
    }
    add(element, type) {
      const {
        id
      } = element;
      this._elements[id] = element;
    }
    remove(element) {
      const id = element.id || element;
      delete this._elements[id];
    }
    get(id) {
      return this._elements[id];
    }
    getAll() {
      return values(this._elements);
    }
    forEach(fn) {
      values(this._elements).forEach(element => fn(element));
    }
    filter(fn) {
      return values(this._elements).filter(element => fn(element));
    }
    clear() {
      this._elements = {};
    }
    updateId(element, newId) {
      this._validateId(newId);
      if (typeof element === 'string') {
        element = this.get(element);
      }
      this._eventBus.fire('element.updateId', {
        element: element,
        newId: newId
      });
      this.remove(element);
      element.id = newId;
      this.add(element);
    }

    /**
    * Validate the suitability of the given id and signals a problem
    * with an exception.
    *
    * @param {String} id
    *
    * @throws {Error} if id is empty or already assigned
    */
    _validateId(id) {
      if (!id) {
        throw new Error('element must have an id');
      }
      if (this._elements[id]) {
        throw new Error('element with id ' + id + ' already added');
      }
    }
  };
  ElementRegistry$1.$inject = ['eventBus'];

  // helpers

  function values(obj) {
    return Object.keys(obj).map(function (k) {
      return obj[k];
    });
  }

  let ChangeSupport$1 = class ChangeSupport {
    constructor(eventBus) {
      this._listeners = {};
      eventBus.on('elements.changed', ({
        elements
      }) => {
        this.elementsChanged(elements);
      });
      eventBus.on('root.remove', context => {
        const oldRootId = context.root.id;
        if (this._listeners[oldRootId]) {
          eventBus.once('root.add', context => {
            const newRootId = context.root.id;
            this.updateId(oldRootId, newRootId);
          });
        }
      });
      eventBus.on('element.updateId', ({
        element,
        newId
      }) => {
        this.updateId(element.id, newId);
      });
    }
    elementsChanged(elements) {
      const invoked = {};
      const elementsLength = elements.length;
      for (let i = 0; i < elementsLength; i++) {
        const {
          id
        } = elements[i];
        if (invoked[id]) {
          return;
        }
        invoked[id] = true;
        const listenersLength = this._listeners[id] && this._listeners[id].length;
        if (listenersLength) {
          for (let j = 0; j < listenersLength; j++) {
            // listeners might remove themselves before they get called
            this._listeners[id][j] && this._listeners[id][j]();
          }
        }
      }
    }
    onElementsChanged(id, listener) {
      if (!this._listeners[id]) {
        this._listeners[id] = [];
      }

      // avoid push for better performance
      this._listeners[id][this._listeners[id].length] = listener;
    }
    offElementsChanged(id, listener) {
      if (!this._listeners[id]) {
        return;
      }
      if (listener) {
        const idx = this._listeners[id].indexOf(listener);
        if (idx !== -1) {
          this._listeners[id].splice(idx, 1);
        }
      } else {
        this._listeners[id].length = 0;
      }
    }
    updateId(oldId, newId) {
      if (this._listeners[oldId]) {
        this._listeners[newId] = this._listeners[oldId];
        delete this._listeners[oldId];
      }
    }
  };
  ChangeSupport$1.$inject = ['eventBus'];

  const DEFAULT_PRIORITY$1 = 1000;
  let Components$1 = class Components {
    constructor() {
      this._listeners = {};
    }
    getComponent(type, context) {
      const listeners = this._listeners[type];
      if (!listeners) {
        return;
      }
      let component;
      for (let i = 0; i < listeners.length; i++) {
        component = listeners[i].callback(context);
        if (component) {
          break;
        }
      }
      return component;
    }
    getComponents(type, context) {
      const listeners = this._listeners[type];
      const components = [];
      if (!listeners) {
        return components;
      }
      for (let i = 0; i < listeners.length; i++) {
        const component = listeners[i].callback(context);
        if (component) {
          components.push(component);
        }
      }
      if (!components.length) {
        return components;
      }
      return components;
    }
    onGetComponent(type, priority, callback) {
      if (isFunction$1(priority)) {
        callback = priority;
        priority = DEFAULT_PRIORITY$1;
      }
      if (!isNumber$1(priority)) {
        throw new Error('priority must be a number');
      }
      const listeners = this._getListeners(type);
      let existingListener, idx;
      const newListener = {
        priority,
        callback
      };
      for (idx = 0; existingListener = listeners[idx]; idx++) {
        if (existingListener.priority < priority) {
          // prepend newListener at before existingListener
          listeners.splice(idx, 0, newListener);
          return;
        }
      }
      listeners.push(newListener);
    }
    offGetComponent(type, callback) {
      const listeners = this._getListeners(type);
      let listener, listenerCallback, idx;
      if (callback) {
        // move through listeners from back to front
        // and remove matching listeners
        for (idx = listeners.length - 1; listener = listeners[idx]; idx--) {
          listenerCallback = listener.callback;
          if (listenerCallback === callback) {
            listeners.splice(idx, 1);
          }
        }
      } else {
        // clear listeners
        listeners.length = 0;
      }
    }
    _getListeners(type) {
      let listeners = this._listeners[type];
      if (!listeners) {
        this._listeners[type] = listeners = [];
      }
      return listeners;
    }
  };

  class TableComponent extends Component {
    constructor(props) {
      super(props);
      const injector = this._injector = props.injector;
      this._sheet = injector.get('sheet');
      this._changeSupport = injector.get('changeSupport');
      this._components = injector.get('components');
      this._eventBus = injector.get('eventBus');
      const throttle = injector.get('throttle');
      this.onElementsChanged = this.onElementsChanged.bind(this);
      this.onScroll = throttle(this.onScroll.bind(this));
    }
    onElementsChanged() {
      this.forceUpdate();
    }
    onScroll() {
      this._eventBus.fire('sheet.scroll');
    }
    getChildContext() {
      return {
        changeSupport: this._changeSupport,
        components: this._components,
        injector: this._injector
      };
    }
    componentWillMount() {
      const {
        id
      } = this._sheet.getRoot();
      this._changeSupport.onElementsChanged(id, this.onElementsChanged);
    }
    componentWillUnmount() {
      const {
        id
      } = this._sheet.getRoot();
      this._changeSupport.offElementsChanged(id, this.onElementsChanged);
    }
    render() {
      const {
        rows,
        cols
      } = this._sheet.getRoot();
      const beforeTableComponents = this._components.getComponents('table.before');
      const afterTableComponents = this._components.getComponents('table.after');
      const Head = this._components.getComponent('table.head');
      const Body = this._components.getComponent('table.body');
      const Foot = this._components.getComponent('table.foot');
      return createVNode(1, "div", "tjs-container", [beforeTableComponents && beforeTableComponents.map((Component, index) => createComponentVNode(2, Component, null, index)), createVNode(1, "div", "tjs-table-container", createVNode(1, "table", "tjs-table", [Head && createComponentVNode(2, Head, {
        "rows": rows,
        "cols": cols
      }), Body && createComponentVNode(2, Body, {
        "rows": rows,
        "cols": cols
      }), Foot && createComponentVNode(2, Foot, {
        "rows": rows,
        "cols": cols
      })], 0), 2, {
        "onScroll": this.onScroll
      }), afterTableComponents && afterTableComponents.map((Component, index) => createComponentVNode(2, Component, null, index))], 0);
    }
  }

  let Renderer$1 = class Renderer {
    constructor(changeSupport, components, config, eventBus, injector) {
      const {
        container
      } = config;
      this._container = container;
      eventBus.on('root.added', () => {
        render(createComponentVNode(2, TableComponent, {
          "injector": injector
        }), container);
      });
      eventBus.on('root.remove', () => {
        render(null, container);
      });
    }
    getContainer() {
      return this._container;
    }
  };
  Renderer$1.$inject = ['changeSupport', 'components', 'config.renderer', 'eventBus', 'injector'];

  var renderModule = {
    __init__: ['changeSupport', 'components', 'renderer'],
    changeSupport: ['type', ChangeSupport$1],
    components: ['type', Components$1],
    renderer: ['type', Renderer$1]
  };

  class Sheet {
    constructor(elementRegistry, eventBus) {
      this._elementRegistry = elementRegistry;
      this._eventBus = eventBus;
      this._root = null;
      eventBus.on('table.clear', () => {
        this.setRoot(null);
      });
    }
    setRoot(root) {
      if (this._root) {
        const oldRoot = this._root;
        this._eventBus.fire('root.remove', {
          root: oldRoot
        });
        this._root = null;
        this._eventBus.fire('root.removed', {
          root: oldRoot
        });
      }
      if (root) {
        this._eventBus.fire('root.add', {
          root
        });
      }
      this._root = root;
      if (root) {
        this._eventBus.fire('root.added', {
          root
        });
      }
    }
    getRoot() {
      if (!this._root) {
        this.setRoot({
          id: '__implicitroot',
          rows: [],
          cols: []
        });
      }
      return this._root;
    }

    /**
     * Add row to sheet.
     *
     * @param {Object} row - Row.
     */
    addRow(row, index) {
      const root = this.getRoot();
      if (root.cols.length != row.cells.length) {
        throw new Error('number of cells is not equal to number of cols');
      }
      if (typeof index === 'undefined') {
        index = root.rows.length;
      }
      addAtIndex(index, root.rows, row);
      row.root = root;
      this._elementRegistry.add(row);
      row.cells.forEach((cell, idx) => {
        this._elementRegistry.add(cell);
        cell.row = row;
        cell.col = root.cols[idx];
        addAtIndex(index, root.cols[idx].cells, cell);
      });
      this._eventBus.fire('row.add', {
        row
      });
      return row;
    }

    /**
     * Remove row from sheet.
     *
     * @param {Object|string} row - Row or row ID.
     */
    removeRow(row) {
      const root = this.getRoot();
      if (typeof row === 'string') {
        row = this._elementRegistry.get(row);
      }
      const index = root.rows.indexOf(row);
      if (index === -1) {
        return;
      }
      removeAtIndex(index, root.rows);
      row.root = undefined;
      this._elementRegistry.remove(row);
      row.cells.forEach((cell, idx) => {
        this._elementRegistry.remove(cell);
        cell.col = undefined;
        removeAtIndex(index, root.cols[idx].cells);
      });
      this._eventBus.fire('row.remove', {
        row
      });
    }

    /**
     * Add col to sheet.
     *
     * @param {Object} col
     * @param {Number} [index]
     */
    addCol(col, index) {
      const root = this.getRoot();
      this._elementRegistry.add(col);
      if (root.rows.length != col.cells.length) {
        throw new Error('number of cells is not equal to number of rows');
      }
      if (typeof index === 'undefined') {
        index = root.cols.length;
      }
      addAtIndex(index, root.cols, col);
      col.root = root;
      col.cells.forEach((cell, idx) => {
        this._elementRegistry.add(cell);
        cell.col = col;
        cell.row = root.rows[idx];
        addAtIndex(index, root.rows[idx].cells, cell);
      });
      this._eventBus.fire('col.add', {
        col
      });
      return col;
    }

    /**
     * Remove col from sheet.
     *
     * @param {Object|string} col - Col or col ID.
     */
    removeCol(col) {
      const root = this.getRoot();
      if (typeof col === 'string') {
        col = this._elementRegistry.get(col);
      }
      const index = root.cols.indexOf(col);
      if (index === -1) {
        return;
      }
      removeAtIndex(index, root.cols);
      col.root = undefined;
      this._elementRegistry.remove(col);
      col.cells.forEach((cell, idx) => {
        this._elementRegistry.remove(cell);
        cell.row = undefined;
        removeAtIndex(index, root.rows[idx].cells);
      });
      this._eventBus.fire('col.remove', {
        col
      });
    }
    resized() {
      this._eventBus.fire('sheet.resized');
    }
  }
  Sheet.$inject = ['elementRegistry', 'eventBus'];

  // helpers /////////////

  /**
   * Insert value
   *
   * @param {number} index - Index to insert value at.
   * @param {Array} array - Array to insert value into.
   * @param {*} value - Value to insert.
   */
  function addAtIndex(index, array, value) {
    return array.splice(index, 0, value);
  }

  /**
   *
   * @param {number} index - Index to remove.
   * @param {Array} array - Array to remove from.
   */
  function removeAtIndex(index, array) {
    return array.splice(index, 1);
  }

  /**
   * A factory to create a configurable throttler.
   *
   * @param {number|boolean} [config=true]
   */
  function ThrottleFactory(config = true) {
    const timeout = typeof config === 'number' ? config : config ? 300 : 0;
    if (timeout) {
      return fn => throttle(fn, timeout);
    } else {
      return fn => fn;
    }
  }
  ThrottleFactory.$inject = ['config.throttle'];

  var core$1 = {
    __depends__: [renderModule],
    __init__: ['elementFactory', 'sheet'],
    elementFactory: ['type', ElementFactory],
    elementRegistry: ['type', ElementRegistry$1],
    eventBus: ['type', EventBus],
    sheet: ['type', Sheet],
    throttle: ['factory', ThrottleFactory]
  };

  class Table {
    constructor(options = {}) {
      let {
        injector
      } = options;
      if (!injector) {
        let {
          modules,
          config
        } = this._init(options);
        injector = createInjector$1(config, modules);
      }
      this.get = injector.get;
      this.invoke = injector.invoke;
      this.get('eventBus').fire('table.init');
      this.get('eventBus').fire('diagram.init');
    }

    /**
     * Intialize table and return modules and config used for creation.
     *
     * @param  {Object} options
     *
     * @return {Object} { modules=[], config }
     */
    _init(options) {
      let {
        modules,
        ...config
      } = options;
      return {
        modules,
        config
      };
    }

    /**
     * Destroys the table. This results in removing the attachment from the container.
     */
    destroy() {
      const eventBus = this.get('eventBus');
      eventBus.fire('table.destroy');
      eventBus.fire('diagram.destroy');
    }

    /**
     * Clears the table. Should be used to reset the state of any stateful services.
     */
    clear() {
      const eventBus = this.get('eventBus');
      eventBus.fire('table.clear');
      eventBus.fire('diagram.clear');
    }
  }
  function createInjector$1(config, modules) {
    const bootstrapModules = [{
      config: ['value', config]
    }, core$1].concat(modules || []);
    const injector = new Injector(bootstrapModules);
    injector.init();
    return injector;
  }

  function elementToString(element) {
    if (!element) {
      return '<null>';
    }
    const id = element.id ? ` id="${element.id}"` : '';
    return `<${element.$type}${id} />`;
  }

  function TableTreeWalker(handler, options) {
    function visit(element, ctx, definitions) {
      var gfx = element.gfx;

      // avoid multiple rendering of elements
      if (gfx) {
        throw new Error(`already rendered ${elementToString(element)}`);
      }

      // call handler
      return handler.element(element, ctx, definitions);
    }
    function visitTable(element) {
      return handler.table(element);
    }

    // Semantic handling //////////////////////

    function handleDecision(decision) {
      if (!decision.id) {
        decision.id = 'decision';
      }
      const table = decision.decisionLogic;
      if (table) {
        if (!table.output) {
          throw new Error(`missing output for ${elementToString(table)}`);
        }
        const ctx = visitTable(table);
        if (table.input) {
          handleClauses(table.input, ctx, table);
        }
        handleClauses(table.output, ctx, table);

        // if any input or output clauses (columns) were added
        // make sure that for each rule the according input/output entry is created
        handleRules(table.rule, ctx, table);
      } else {
        throw new Error(`no table for ${elementToString(decision)}`);
      }
    }
    function handleClauses(clauses, context, definitions) {
      forEach(clauses, function (e) {
        visit(e, context, definitions);
      });
    }
    function handleRules(rules, context, definitions) {
      forEach(rules, function (e) {
        visit(e, context, definitions);
        handleEntry(e.inputEntry, e);
        handleEntry(e.outputEntry, e);
      });
    }
    function handleEntry(entry, context, definitions) {
      forEach(entry, function (e) {
        visit(e, context, definitions);
      });
    }

    // API //////////////////////

    return {
      handleDecision: handleDecision
    };
  }

  /**
   * Import the decision table into a table.
   *
   * Errors and warnings are reported through the specified callback.
   *
   * @param  {decisionTable} decisionTable instance of DecisionTable
   * @param  {ModdleElement} decision moddle element
   * @param  {Function} done
   *         the callback, invoked with (err, [ warning ]) once the import is done
   */
  function importDecision(decisionTable, decision, done) {
    const importer = decisionTable.get('tableImporter'),
      eventBus = decisionTable.get('eventBus'),
      sheet = decisionTable.get('sheet');
    decisionTable.get('modeling', false);
    let error,
      warnings = [];
    function render(decision) {
      const visitor = {
        create(type, parent, clause, rule) {
          return importer.create(type, parent, clause, rule);
        },
        table(element) {
          return importer.add(element);
        },
        element(element, parentShape, definitions) {
          return importer.add(element, parentShape, definitions);
        },
        error(message, context) {
          warnings.push({
            message: message,
            context: context
          });
        }
      };
      const walker = new TableTreeWalker(visitor);

      // import
      walker.handleDecision(decision);
    }
    eventBus.fire('import.render.start', {
      decision: decision
    });
    try {
      render(decision);
    } catch (e) {
      error = e;
    }
    eventBus.fire('import.render.complete', {
      error: error,
      warnings: warnings
    });
    eventBus.fire('elements.changed', {
      elements: [sheet.getRoot()]
    });
    done(error, warnings);
  }

  function newSet() {
    return {
      elements: [],
      index: {}
    };
  }
  function add$1(set, element) {
    const {
      elements,
      index
    } = set;
    if (index[element]) {
      return set;
    } else {
      return {
        elements: [...elements, element],
        index: {
          ...index,
          [element]: true
        }
      };
    }
  }
  function join(set, separator) {
    return set.elements.join(separator);
  }
  function classNames(...args) {
    let set = newSet();
    args.forEach(function (item) {
      const type = typeof item;
      if (type === 'string' && item.length > 0) {
        set = add$1(set, item);
      } else if (type === 'object' && item !== null) {
        Object.keys(item).forEach(function (key) {
          const value = item[key];
          if (value) {
            set = add$1(set, key);
          }
        });
      }
    });
    return join(set, ' ');
  }

  function inject(component) {
    const Type = component.constructor;
    return injectType(Type, component);
  }
  function injectType(Type, component) {
    const annotation = Type.$inject;
    if (!annotation) {
      return;
    }
    const {
      injector
    } = component.context;
    const setupFn = [...annotation, function (...args) {
      for (const idx in args) {
        const name = annotation[idx];
        const value = args[idx];
        component[name] = value;
      }
    }];
    injector.invoke(setupFn);
  }

  /**
   * Composes a number of functions.
   *
   * All receive the the same arguments; the chain is interruped as soon
   * as one function returns a value.
   *
   * @param  {Object}    self
   * @param  {...Function} fns
   *
   * @return {Object}
   */
  function compose(self, ...fns) {
    return function (...args) {
      let result;
      fns.forEach(function (fn) {
        result = fn.call(self, ...args);
        if (typeof result !== 'undefined') {
          return false;
        }
      });
      return result;
    }.bind(self);
  }

  /**
   * A Component and injection aware mixin mechanism.
   *
   * @param {Component} component
   * @param {Object|Function} mixinDef
   */
  function mixin(component, mixinDef) {
    Object.keys(mixinDef).forEach(function (key) {
      if (key === '$inject' || key === '__init') {
        return;
      }
      const mixinFn = mixinDef[key];
      if (key === 'constructor') {
        mixinFn.call(component, component.props, component.context);
      }
      const componentFn = component[key];
      if (typeof componentFn !== 'undefined') {
        if (typeof componentFn !== 'function') {
          throw new Error(`failed to mixin <${key}>: cannot combine with non-fn component value`);
        }
        component[key] = compose(component, componentFn, mixinFn);
      } else {
        component[key] = mixinFn.bind(component);
      }
    });
    if ('$inject' in mixinDef) {
      injectType(mixinDef, component);
    }

    // call initializer
    if ('__init' in mixinDef) {
      mixinDef.__init.call(component, component.props, component.context);
    }
  }

  /**
   * A mixin to make an element _selection aware_.
   */
  const SelectionAware = {
    getSelectionClasses() {
      const {
        selected,
        selectedSecondary,
        focussed
      } = this.state;
      return classNames({
        'selected': selected,
        'selected-secondary': selectedSecondary,
        'focussed': focussed
      });
    },
    selectionChanged(newSelection) {
      // newSelection = { selected, selectedSecondary, focussed }
      this.setState(newSelection);
    },
    componentWillUpdate(newProps) {
      if (newProps.elementId !== this.props.elementId) {
        this.updateSelectionSubscription(false);
      }
    },
    componentDidUpdate(oldProps) {
      if (oldProps.elementId !== this.props.elementId) {
        this.updateSelectionSubscription(true);
      }
    },
    componentDidMount() {
      this.updateSelectionSubscription(true);
    },
    componentWillUnmount() {
      this.updateSelectionSubscription(false);
    },
    updateSelectionSubscription(enable) {
      const {
        elementId
      } = this.props;
      if (!elementId) {
        return;
      }
      if (elementId) {
        this.eventBus[enable ? 'on' : 'off'](`selection.${elementId}.changed`, this.selectionChanged);
      }
    }
  };
  SelectionAware.$inject = ['eventBus'];

  class BaseCell extends Component {
    constructor(props, context) {
      super(props, context);
      mixin(this, SelectionAware);
      inject(this);
    }
    getRenderProps(...cls) {
      const {
        className,
        elementId,
        coords,
        ...props
      } = this.props;
      const baseProps = {
        className: classNames(...cls, this.getSelectionClasses(), className)
      };
      if (elementId) {
        baseProps['data-element-id'] = elementId;
      }
      if (coords) {
        baseProps['data-coords'] = coords;
      }
      return {
        ...baseProps,
        ...props
      };
    }
  }

  class HeaderCell extends BaseCell {
    constructor(props, context) {
      super(props, context);
      this.state = {};
    }
    render() {
      const {
        children
      } = this.props;
      const props = this.getRenderProps('cell');
      return normalizeProps(createVNode(1, "td", null, children, 0, {
        ...props
      }));
    }
  }

  /**
   * A simple slot extension, built upon the components service.
   *
   * @type {Object}
   */
  const ComponentWithSlots = {
    slotFill(slotProps, DefaultFill) {
      const {
        type,
        context,
        ...props
      } = slotProps;
      const Fill = this.components.getComponent(type, context) || DefaultFill;
      if (Fill) {
        return normalizeProps(createComponentVNode(2, Fill, {
          ...context,
          ...props
        }));
      }
      return null;
    },
    slotFills(slotProps) {
      const {
        type,
        context,
        ...props
      } = slotProps;
      const fills = this.components.getComponents(type, context);
      return fills.map(Fill => normalizeProps(createComponentVNode(2, Fill, {
        ...context,
        ...props
      })));
    }
  };
  ComponentWithSlots.$inject = ['components'];

  const MIN_WIDTH = 400;
  class AnnotationHeader extends Component {
    constructor(props, context) {
      super(props, context);
      mixin(this, ComponentWithSlots);
      inject(this);
    }
    componentDidMount() {
      this.changeSupport.onElementsChanged(this.getRoot(), this.onElementsChanged);
    }
    componentWillUnmount() {
      this.changeSupport.offElementsChanged(this.getRoot(), this.onElementsChanged);
    }
    onElementsChanged = () => {
      this.forceUpdate();
    };
    getRoot() {
      return this.sheet.getRoot();
    }
    render() {
      const decisionTable = this.getRoot();
      const annotationsWidth = decisionTable.businessObject.get('annotationsWidth');
      const width = (annotationsWidth || MIN_WIDTH) + 'px';
      return createVNode(1, "th", "annotation header", [this.slotFills({
        type: 'cell-inner',
        context: {
          cellType: 'annotations',
          col: this.sheet.getRoot(),
          minWidth: MIN_WIDTH
        }
      }), this.translate('Annotations')], 0, {
        "style": {
          width
        }
      });
    }
  }
  AnnotationHeader.$inject = ['changeSupport', 'sheet', 'translate'];

  function AnnotationCell(props) {
    const {
      row
    } = props;
    const {
      id,
      description
    } = row.businessObject;
    return createComponentVNode(2, HeaderCell, {
      "className": "annotation",
      "elementId": id,
      children: description || '-'
    });
  }

  function AnnotationsProvider(components) {
    components.onGetComponent('cell', ({
      cellType
    }) => {
      if (cellType === 'after-label-cells') {
        return AnnotationHeader;
      } else if (cellType === 'after-rule-cells') {
        return AnnotationCell;
      }
    });
  }
  AnnotationsProvider.$inject = ['components'];

  var annotationsModule = {
    __init__: ['annotationsProvider'],
    annotationsProvider: ['type', AnnotationsProvider]
  };

  function elementData(semantic, attrs) {
    return assign$1({
      id: semantic.id,
      type: semantic.$type,
      businessObject: semantic
    }, attrs);
  }
  class TableImporter {
    constructor(elementFactory, eventBus, sheet) {
      this._elementFactory = elementFactory;
      this._eventBus = eventBus;
      this._sheet = sheet;
    }

    /**
     * Add DMN element.
     */
    add(semantic) {
      let element;

      // decision table
      if (is(semantic, 'dmn:DecisionTable')) {
        element = this._elementFactory.createRoot(elementData(semantic));
        this._sheet.setRoot(element);
      }

      // input clause
      else if (is(semantic, 'dmn:InputClause')) {
        element = this._elementFactory.createCol(elementData(semantic));
        this._sheet.addCol(element);
      }

      // output clause
      else if (is(semantic, 'dmn:OutputClause')) {
        element = this._elementFactory.createCol(elementData(semantic));
        this._sheet.addCol(element);
      }

      // rule
      else if (is(semantic, 'dmn:DecisionRule')) {
        if (!semantic.inputEntry) {
          semantic.inputEntry = [];
        }
        if (!semantic.outputEntry) {
          semantic.outputEntry = [];
        }
        const cells = [...semantic.inputEntry, ...semantic.outputEntry].map(entry => {
          return this._elementFactory.createCell(elementData(entry));
        });
        element = this._elementFactory.createRow(assign$1(elementData(semantic), {
          cells
        }));
        this._sheet.addRow(element);
      }
      this._eventBus.fire('dmnElement.added', {
        element: element
      });
      return element;
    }
  }
  TableImporter.$inject = ['elementFactory', 'eventBus', 'sheet'];

  var importModule = {
    __depends__: [TranslateModule],
    tableImporter: ['type', TableImporter]
  };

  var coreModule = {
    __depends__: [importModule, renderModule]
  };

  class DecisionTableHead extends Component {
    constructor(props, context) {
      super(props, context);
      mixin(this, ComponentWithSlots);
      this._sheet = context.injector.get('sheet');
      this._changeSupport = context.changeSupport;
    }
    onElementsChanged = () => {
      this.forceUpdate();
    };
    componentWillMount() {
      const root = this._sheet.getRoot();
      this._changeSupport.onElementsChanged(root.id, this.onElementsChanged);
    }
    componentWillUnmount() {
      const root = this._sheet.getRoot();
      this._changeSupport.offElementsChanged(root.id, this.onElementsChanged);
    }
    render() {
      const root = this._sheet.getRoot();
      if (!is(root, 'dmn:DMNElement')) {
        return null;
      }
      const businessObject = getBusinessObject(root);
      const inputs = businessObject.input,
        outputs = businessObject.output;
      return createVNode(1, "thead", null, createVNode(1, "tr", null, [createVNode(1, "th", "index-column"), this.slotFills({
        type: 'cell',
        context: {
          cellType: 'before-label-cells'
        }
      }), inputs && inputs.map((input, index) => {
        const width = input.width || '192px';
        return this.slotFill({
          type: 'cell',
          context: {
            cellType: 'input-header',
            input,
            index,
            inputsLength: inputs.length,
            width
          },
          key: input.id
        }, DefaultInputHeaderCell);
      }), outputs.map((output, index) => {
        return this.slotFill({
          type: 'cell',
          context: {
            cellType: 'output-header',
            output,
            index,
            outputsLength: outputs.length
          },
          key: output.id
        }, DefaultOutputHeaderCell);
      }), this.slotFills({
        type: 'cell',
        context: {
          cellType: 'after-label-cells'
        }
      })], 0), 2);
    }
  }

  // default components ///////////////////////

  function DefaultInputHeaderCell(props, context) {
    const {
      input,
      className,
      index
    } = props;
    const {
      label,
      inputExpression,
      inputValues
    } = input;
    const translate = context.injector.get('translate');
    const actualClassName = (className || '') + ' input-cell';
    return createVNode(1, "th", actualClassName, [createVNode(1, "div", "clause", index === 0 ? translate('When') : translate('And'), 0), label ? createVNode(1, "div", "input-label", label, 0, {
      "title": translate('Input label: ') + label
    }) : createVNode(1, "div", "input-expression", inputExpression.text, 0, {
      "title": translate('Input expression: ') + inputExpression.text
    }), createVNode(1, "div", "input-variable", inputValues && inputValues.text || inputExpression.typeRef, 0, {
      "title": inputValues && inputValues.text ? translate('Input values') : translate('Input type')
    })], 0, {
      "data-col-id": input.id
    }, input.id);
  }
  function DefaultOutputHeaderCell(props, context) {
    const {
      output,
      className,
      index
    } = props;
    const {
      label,
      name,
      outputValues,
      typeRef
    } = output;
    const translate = context.injector.get('translate');
    const actualClassName = (className || '') + ' output-cell';
    return createVNode(1, "th", actualClassName, [createVNode(1, "div", "clause", index === 0 ? translate('Then') : translate('And'), 0), label ? createVNode(1, "div", "output-label", label, 0, {
      "title": translate('Output label')
    }) : createVNode(1, "div", "output-name", name, 0, {
      "title": translate('Output name')
    }), createVNode(1, "div", "output-variable", outputValues && outputValues.text || typeRef, 0, {
      "title": outputValues && outputValues.text ? translate('Output values') : translate('Output type')
    })], 0, null, output.id);
  }

  function DecisionTableHeadProvider(components) {
    components.onGetComponent('table.head', () => DecisionTableHead);
  }
  DecisionTableHeadProvider.$inject = ['components'];

  var decisionTableHeadModule = {
    __init__: ['decisionTableHeadProvider'],
    decisionTableHeadProvider: ['type', DecisionTableHeadProvider]
  };

  class DecisionTablePropertiesComponent extends Component {
    constructor(props, context) {
      super(props, context);
      this._translate = context.injector.get('translate');
      inject(this);
    }
    render() {
      const root = this.sheet.getRoot();
      if (!is(root, 'dmn:DMNElement')) {
        return null;
      }
      const {
        name
      } = root.businessObject.$parent;
      const HitPolicy = this.components.getComponent('hit-policy') || NullComponent;
      return createVNode(1, "div", "decision-table-properties", [createVNode(1, "div", "decision-table-name", name, 0, {
        "title": this._translate('Decision name: ') + name
      }), createVNode(1, "div", "decision-table-header-separator"), createComponentVNode(2, HitPolicy)], 4);
    }
  }
  DecisionTablePropertiesComponent.$inject = ['sheet', 'components'];
  function NullComponent() {
    return null;
  }

  const LOW_PRIORITY$1 = 500;
  class DecisionTableProperties {
    constructor(components) {
      components.onGetComponent('table.before', LOW_PRIORITY$1, () => {
        return DecisionTablePropertiesComponent;
      });
    }
  }
  DecisionTableProperties.$inject = ['components'];

  var decisionTablePropertiesModule = {
    __init__: ['decisionTableProperties'],
    decisionTableProperties: ['type', DecisionTableProperties]
  };

  class DecisionRulesIndexCellComponent extends Component {
    render() {
      const {
        row,
        rowIndex
      } = this.props;
      const {
        components
      } = this.context;
      const innerComponents = components.getComponents('cell-inner', {
        cellType: 'rule-index',
        row,
        rowIndex
      });
      return createVNode(1, "td", "rule-index", [innerComponents && innerComponents.map(InnerComponent => createComponentVNode(2, InnerComponent, {
        "row": row,
        "rowIndex": rowIndex
      })), rowIndex + 1], 0, {
        "data-element-id": row.id,
        "data-row-id": row.id
      });
    }
  }

  class DecisionRuleIndices {
    constructor(components) {
      components.onGetComponent('cell', ({
        cellType
      }) => {
        if (cellType === 'before-rule-cells') {
          return DecisionRulesIndexCellComponent;
        }
      });
    }
  }
  DecisionRuleIndices.$inject = ['components'];

  var decisionRuleIndicesModule = {
    __init__: ['decisionRuleIndices'],
    decisionRuleIndices: ['type', DecisionRuleIndices]
  };

  const EXPRESSION_LANGUAGE_OPTIONS = [{
    label: 'FEEL',
    value: 'feel'
  }];

  /**
   * @typedef ExpressionLanguageDescriptor
   * @property {string} value - value inserted into XML
   * @property {string} label - human-readable label
   */

  /**
   * Provide options and defaults of expression languages via config.
   *
   * @example
   *
   * // there will be two languages available with FEEL as default
   * const editor = new DmnJS({
   *   common: {
   *     expressionLanguages: {
   *       options: [{
   *         value: 'feel',
   *         label: 'FEEL'
   *       }, {
   *         value: 'juel',
   *         label: 'JUEL'
   *       }],
   *       defaults: {
   *         editor: 'feel'
   *       }
   *     }
   *   }
   * })
   */
  class ExpressionLanguages {
    constructor(injector) {
      this._injector = injector;
      const config = injector.get('config.expressionLanguages') || {};
      this._config = {
        options: EXPRESSION_LANGUAGE_OPTIONS,
        defaults: {
          editor: 'feel'
        }
      };

      // first assign the list of languages as it might be required for the legacy defaults
      if (config.options) {
        this._config.options = config.options;
      }
      const legacyDefaults = this._getLegacyDefaults();
      assign$1(this._config.defaults, legacyDefaults, config.defaults);
    }

    /**
     * Get default expression language for a component or the editor if `componentName`
     * is not provided.
     *
     * @param {string} [componentName]
     * @returns {ExpressionLanguageDescriptor}
     */
    getDefault(componentName) {
      const {
        defaults
      } = this._config;
      const defaultFromConfig = defaults[componentName] || defaults.editor;
      return this._getLanguageByValue(defaultFromConfig) || this.getAll()[0];
    }

    /**
     * Get label for provided expression language.
     *
     * @param {string} expressionLanguageValue - value from XML
     * @returns {string}
     */
    getLabel(expressionLanguageValue) {
      const langauge = this._getLanguageByValue(expressionLanguageValue);
      return langauge ? langauge.label : expressionLanguageValue;
    }

    /**
     * Get list of configured expression languages.
     *
     * @returns {ExpressionLanguageDescriptor[]}
     */
    getAll() {
      return this._config.options;
    }
    _getLegacyDefaults() {
      const defaults = {},
        injector = this._injector;
      const inputCellValue = injector.get('config.defaultInputExpressionLanguage');
      const outputCellValue = injector.get('config.defaultOutputExpressionLanguage');
      if (inputCellValue) {
        defaults.inputCell = inputCellValue;
      }
      if (outputCellValue) {
        defaults.outputCell = outputCellValue;
      }
      return defaults;
    }
    _getLanguageByValue(value) {
      return find$1(this.getAll(), language => value === language.value);
    }
  }
  ExpressionLanguages.$inject = ['injector'];

  var ExpressionLanguagesModule = {
    __init__: ['expressionLanguages'],
    expressionLanguages: ['type', ExpressionLanguages]
  };

  /**
   * @typedef {object} FeelLanguageContextConfig
   * @property {string} [parserDialect] - The parser dialect for FEEL, e.g. `camunda`
   * @property {import('@bpmn-io/feel-editor').Variable[]} [builtins] - The built-in functions for FEEL
   */

  class FeelLanguageContext {
    /**
     * Provide parser dialect and built-in functions for FEEL editor.
     *
     * @param {FeelLanguageContextConfig} feelLanguageContext
     */
    constructor(feelLanguageContext) {
      this._feelLanguageContext = feelLanguageContext;
    }
    getConfig() {
      return this._feelLanguageContext;
    }
  }
  FeelLanguageContext.$inject = ['config.feelLanguageContext'];

  var FeelLanguageContextModule = {
    __init__: ['feelLanguageContext'],
    feelLanguageContext: ['type', FeelLanguageContext]
  };

  class DecisionRulesBodyComponent extends Component {
    render({
      rows,
      cols
    }) {
      const {
        components
      } = this.context;
      return createVNode(1, "tbody", null, rows.map((row, rowIndex) => {
        const RowComponent = components.getComponent('row', {
          rowType: 'rule'
        });
        return RowComponent && createComponentVNode(2, RowComponent, {
          "row": row,
          "rowIndex": rowIndex,
          "cols": cols
        }, row.id);
      }), 0);
    }
  }

  class DecisionRulesRowComponent extends Component {
    constructor(props, context) {
      super(props, context);
      mixin(this, ComponentWithSlots);
    }
    render() {
      const {
        row,
        rowIndex,
        cols
      } = this.props;
      const {
        cells
      } = row;
      return createVNode(1, "tr", null, [this.slotFills({
        type: 'cell',
        context: {
          cellType: 'before-rule-cells',
          row,
          rowIndex
        }
      }), cells.map((cell, colIndex) => {
        return this.slotFill({
          type: 'cell',
          context: {
            cellType: 'rule',
            cell,
            rowIndex: rowIndex,
            colIndex: colIndex
          },
          key: cell.id,
          row,
          col: cols[colIndex]
        });
      }), this.slotFills({
        type: 'cell',
        context: {
          cellType: 'after-rule-cells',
          row,
          rowIndex
        }
      })], 0);
    }
  }

  class DecisionRulesCellComponent extends Component {
    render() {
      const {
        cell,
        row,
        col
      } = this.props;
      if (is(cell, 'dmn:UnaryTests')) {
        return createComponentVNode(2, HeaderCell, {
          "className": "input-cell",
          "elementId": cell.id,
          "data-row-id": row.id,
          "data-col-id": col.id,
          children: cell.businessObject.text
        });
      } else {
        return createComponentVNode(2, HeaderCell, {
          "className": "output-cell",
          "elementId": cell.id,
          "data-row-id": row.id,
          "data-col-id": col.id,
          children: cell.businessObject.text
        });
      }
    }
  }

  class Rules {
    constructor(components) {
      components.onGetComponent('table.body', () => DecisionRulesBodyComponent);
      components.onGetComponent('row', ({
        rowType
      }) => {
        if (rowType === 'rule') {
          return DecisionRulesRowComponent;
        }
      });
      components.onGetComponent('cell', ({
        cellType
      }) => {
        if (cellType === 'rule') {
          return DecisionRulesCellComponent;
        }
      });
    }
  }
  Rules.$inject = ['components'];

  var decisionRulesModule = {
    __depends__: [ExpressionLanguagesModule, FeelLanguageContextModule],
    __init__: ['decisionRules'],
    decisionRules: ['type', Rules]
  };

  /* eslint max-len: 0 */
  const HIT_POLICIES = [{
    label: 'Unique',
    value: {
      hitPolicy: 'UNIQUE',
      aggregation: undefined
    },
    explanation: 'No overlap is possible and all rules are disjoint. Only a single rule can be matched'
  }, {
    label: 'First',
    value: {
      hitPolicy: 'FIRST',
      aggregation: undefined
    },
    explanation: 'Rules may overlap. The first matching rule will be chosen'
  }, {
    label: 'Priority',
    value: {
      hitPolicy: 'PRIORITY',
      aggregation: undefined
    },
    explanation: 'Rules may overlap. The one with the highest priority will be chosen'
  }, {
    label: 'Any',
    value: {
      hitPolicy: 'ANY',
      aggregation: undefined
    },
    explanation: 'Rules may overlap. Their output have to match'
  }, {
    label: 'Collect',
    value: {
      hitPolicy: 'COLLECT',
      aggregation: undefined
    },
    explanation: 'Collects the values of all matching rules'
  }, {
    label: 'Collect (Sum)',
    value: {
      hitPolicy: 'COLLECT',
      aggregation: 'SUM'
    },
    explanation: 'Collects the values of all matching rules and sums up to a single value'
  }, {
    label: 'Collect (Min)',
    value: {
      hitPolicy: 'COLLECT',
      aggregation: 'MIN'
    },
    explanation: 'Collects the values of all matching rules and uses the lowest value'
  }, {
    label: 'Collect (Max)',
    value: {
      hitPolicy: 'COLLECT',
      aggregation: 'MAX'
    },
    explanation: 'Collects the values of all matching rules and uses the highest value'
  }, {
    label: 'Collect (Count)',
    value: {
      hitPolicy: 'COLLECT',
      aggregation: 'COUNT'
    },
    explanation: 'Collects the values of all matching rules and counts the number of them'
  }, {
    label: 'Rule order',
    value: {
      hitPolicy: 'RULE ORDER',
      aggregation: undefined
    },
    explanation: 'Collects the values of all matching rules in rule order'
  }, {
    label: 'Output order',
    value: {
      hitPolicy: 'OUTPUT ORDER',
      aggregation: undefined
    },
    explanation: 'Collects the values of all matching rules in decreasing output priority order'
  }];

  class HitPolicy extends Component {
    constructor(props, context) {
      super(props, context);
      this._translate = context.injector.get('translate');
      inject(this);
    }
    getRoot() {
      return this.sheet.getRoot();
    }
    render() {
      const root = this.getRoot(),
        businessObject = root.businessObject;
      const {
        aggregation,
        hitPolicy
      } = businessObject;
      const hitPolicyEntry = find$1(HIT_POLICIES, entry => {
        return isEqualHitPolicy(entry.value, {
          aggregation,
          hitPolicy
        });
      });
      return createVNode(1, "div", "hit-policy header", [createVNode(1, "label", "dms-label", this._translate('Hit policy:'), 0), createVNode(1, "span", "hit-policy-value", this._translate(hitPolicyEntry.label), 0)], 4, {
        "title": this._translate(hitPolicyEntry.explanation)
      });
    }
  }
  HitPolicy.$inject = ['sheet'];

  // helpers //////////////////////
  function isEqualHitPolicy(a, b) {
    return a.hitPolicy === b.hitPolicy && a.aggregation === b.aggregation;
  }

  function HitPolicyProvider(components) {
    components.onGetComponent('hit-policy', () => {
      return HitPolicy;
    });
  }
  HitPolicyProvider.$inject = ['components'];

  var hitPolicyModule = {
    __init__: ['hitPolicyProvider'],
    hitPolicyProvider: ['type', HitPolicyProvider]
  };

  let ViewDrdComponent$2 = class ViewDrdComponent extends Component {
    constructor(props, context) {
      super(props, context);
      const {
        injector
      } = context;
      this._translate = injector.get('translate');
      this._eventBus = injector.get('eventBus');
    }
    onClick = () => {
      this._eventBus.fire('showDrd');
    };
    render() {
      return createVNode(1, "div", "view-drd", createVNode(1, "button", "view-drd-button", this._translate('View DRD'), 0, {
        "type": "button",
        "onClick": this.onClick
      }), 2, null, null, node => this.node = node);
    }
  };

  let ViewDrd$2 = class ViewDrd {
    constructor(components, eventBus, injector, sheet) {
      this._injector = injector;
      this._sheet = sheet;
      components.onGetComponent('table.before', () => {
        if (this.canViewDrd()) {
          return ViewDrdComponent$2;
        }
      });
      eventBus.on('showDrd', () => {
        const parent = injector.get('_parent', false);
        const root = sheet.getRoot();
        const definitions = getDefinitions$1(root);
        if (!definitions) {
          return;
        }

        // open definitions
        const view = parent.getView(definitions);
        parent.open(view);
      });
    }
    canViewDrd() {
      const parent = this._injector.get('_parent', false);
      if (!parent) {
        return false;
      }
      const root = this._sheet.getRoot();
      const definitions = getDefinitions$1(root);
      return !!parent.getView(definitions);
    }
  };
  ViewDrd$2.$inject = ['components', 'eventBus', 'injector', 'sheet'];

  // helpers //////////////////////

  function getDefinitions$1(root) {
    const {
      businessObject
    } = root;

    // root might not have business object
    if (!businessObject) {
      return;
    }
    const decision = businessObject.$parent;
    const definitions = decision.$parent;
    return definitions;
  }

  var viewDrdModule = {
    __init__: ['viewDrd'],
    viewDrd: ['type', ViewDrd$2]
  };

  let PoweredBy$2 = class PoweredBy {
    constructor(components) {
      components.onGetComponent('table.before', () => {
        return PoweredByComponent;
      });
    }
  };
  PoweredBy$2.$inject = ['components'];

  var PoweredByModule$2 = {
    __init__: ['poweredBy'],
    poweredBy: ['type', PoweredBy$2]
  };

  /**
   * @typedef {import('dmn-js-shared/lib/base/View).OpenResult} OpenResult
   */

  /**
   * @typedef {import('dmn-js-shared/lib/base/View).OpenError} OpenError
   */

  let Viewer$4 = class Viewer extends Table {
    constructor(options = {}) {
      const container = Viewer._createContainer();
      super(assign$1(options, {
        renderer: {
          container
        }
      }));
      this._container = container;
    }

    /**
     * Open diagram element.
     *
     * @param  {ModdleElement} decision
     * @returns {Promise} Resolves with {OpenResult} when successful
     * or rejects with {OpenError}
     */
    open(decision) {
      var self = this;
      return new Promise((resolve, reject) => {
        var err;

        // use try/catch to not swallow synchronous exceptions
        // that may be raised during model parsing
        try {
          if (self._decision) {
            // clear existing rendered diagram
            self.clear();
          }

          // update decision
          self._decision = decision;

          // perform import
          return importDecision(self, decision, function (err, warnings) {
            if (err) {
              err.warnings = warnings || [];
              reject(err);
            } else {
              resolve({
                warnings: warnings || []
              });
            }
          });
        } catch (e) {
          err = e;
        }

        // handle synchronously thrown exception
        if (err) {
          err.warnings = err.warnings || [];
          reject(err);
        } else {
          resolve({
            warnings: []
          });
        }
      });
    }

    /**
     * Initialize the table, returning { modules: [], config }.
     *
     * @param  {Object} options
     *
     * @return {Object} init config
     */
    _init(options) {
      let {
        modules,
        additionalModules,
        ...config
      } = options;
      let baseModules = modules || this.getModules();
      let extraModules = additionalModules || [];
      let staticModules = [{
        decisionTable: ['value', this]
      }];
      let allModules = [PoweredByModule$2, ...baseModules, ...extraModules, ...staticModules];
      return {
        modules: allModules,
        config
      };
    }

    /**
     * Register an event listener
     *
     * Remove a previously added listener via {@link #off(event, callback)}.
     *
     * @param {string} event
     * @param {number} [priority]
     * @param {Function} callback
     * @param {Object} [that]
     */
    on(event, priority, callback, target) {
      return this.get('eventBus').on(event, priority, callback, target);
    }

    /**
     * De-register an event listener
     *
     * @param {string} event
     * @param {Function} callback
     */
    off(event, callback) {
      this.get('eventBus').off(event, callback);
    }

    /**
     * Emit an event on the underlying {@link EventBus}
     *
     * @param  {string} type
     * @param  {Object} event
     *
     * @return {Object} event processing result (if any)
     */
    _emit(type, event) {
      return this.get('eventBus').fire(type, event);
    }

    /**
     * Attach viewer to given parent node.
     *
     * @param  {Element} parentNode
     */
    attachTo(parentNode) {
      if (!parentNode) {
        throw new Error('parentNode required');
      }

      // ensure we detach from the
      // previous, old parent
      this.detach();
      const container = this._container;
      parentNode.appendChild(container);
      this._emit('attach', {});
    }

    /**
     * Detach viewer from parent node, if attached.
     */
    detach() {
      const container = this._container,
        parentNode = container.parentNode;
      if (!parentNode) {
        return;
      }
      this._emit('detach', {});
      remove$4(container);
    }
    destroy() {
      super.destroy();
      this.detach();
    }
    getModules() {
      return Viewer._getModules();
    }
    static _getModules() {
      return [annotationsModule, coreModule, TranslateModule, decisionTableHeadModule, decisionTablePropertiesModule, decisionRuleIndicesModule, decisionRulesModule, hitPolicyModule, viewDrdModule];
    }
    static _createContainer() {
      return domify('<div class="dmn-decision-table-container"></div>');
    }
  };

  class ChangeSupport {
    constructor(eventBus) {
      this._listeners = {};
      eventBus.on('elements.changed', ({
        elements
      }) => {
        this.elementsChanged(elements);
      });
      eventBus.on('element.updateId', ({
        element,
        newId
      }) => {
        this.updateId(element.id, newId);
      });
    }
    elementsChanged(elements) {
      const invoked = {};
      const elementsLength = elements.length;
      for (let i = 0; i < elementsLength; i++) {
        const {
          id
        } = elements[i];
        if (invoked[id]) {
          return;
        }
        invoked[id] = true;
        const listenersLength = this._listeners[id] && this._listeners[id].length;
        if (listenersLength) {
          for (let j = 0; j < listenersLength; j++) {
            // listeners might remove themselves before they get called
            this._listeners[id][j] && this._listeners[id][j]();
          }
        }
      }
    }
    onElementsChanged(id, listener) {
      if (!this._listeners[id]) {
        this._listeners[id] = [];
      }

      // avoid push for better performance
      this._listeners[id][this._listeners[id].length] = listener;
    }
    offElementsChanged(id, listener) {
      if (!this._listeners[id]) {
        return;
      }
      if (listener) {
        const idx = this._listeners[id].indexOf(listener);
        if (idx !== -1) {
          this._listeners[id].splice(idx, 1);
        }
      } else {
        this._listeners[id].length = 0;
      }
    }
    updateId(oldId, newId) {
      if (this._listeners[oldId]) {
        this._listeners[newId] = this._listeners[oldId];
        delete this._listeners[oldId];
      }
    }
  }
  ChangeSupport.$inject = ['eventBus'];

  const DEFAULT_PRIORITY = 1000;
  class Components {
    constructor() {
      this._listeners = {};
    }
    getComponent(type, context) {
      const listeners = this._listeners[type];
      if (!listeners) {
        return;
      }
      let component;
      for (let i = 0; i < listeners.length; i++) {
        component = listeners[i].callback(context);
        if (component) {
          break;
        }
      }
      return component;
    }
    getComponents(type, context) {
      const listeners = this._listeners[type];
      if (!listeners) {
        return;
      }
      const components = [];
      for (let i = 0; i < listeners.length; i++) {
        const component = listeners[i].callback(context);
        if (component) {
          components.push(component);
        }
      }
      if (!components.length) {
        return;
      }
      return components;
    }
    onGetComponent(type, priority, callback) {
      if (isFunction$1(priority)) {
        callback = priority;
        priority = DEFAULT_PRIORITY;
      }
      if (!isNumber$1(priority)) {
        throw new Error('priority must be a number');
      }
      const listeners = this._getListeners(type);
      let existingListener, idx;
      const newListener = {
        priority,
        callback
      };
      for (idx = 0; existingListener = listeners[idx]; idx++) {
        if (existingListener.priority < priority) {
          // prepend newListener at before existingListener
          listeners.splice(idx, 0, newListener);
          return;
        }
      }
      listeners.push(newListener);
    }
    offGetComponent(type, callback) {
      const listeners = this._getListeners(type);
      let listener, listenerCallback, idx;
      if (callback) {
        // move through listeners from back to front
        // and remove matching listeners
        for (idx = listeners.length - 1; listener = listeners[idx]; idx--) {
          listenerCallback = listener.callback;
          if (listenerCallback === callback) {
            listeners.splice(idx, 1);
          }
        }
      } else {
        // clear listeners
        listeners.length = 0;
      }
    }
    _getListeners(type) {
      let listeners = this._listeners[type];
      if (!listeners) {
        this._listeners[type] = listeners = [];
      }
      return listeners;
    }
  }

  class ViewerComponent extends Component {
    constructor(props) {
      super(props);
      const injector = this._injector = props.injector;
      this._changeSupport = injector.get('changeSupport');
      this._components = injector.get('components');
      this._renderer = injector.get('renderer');
    }
    getChildContext() {
      return {
        changeSupport: this._changeSupport,
        components: this._components,
        renderer: this._renderer,
        injector: this._injector
      };
    }
    render() {
      const components = this._components.getComponents('viewer');
      return createVNode(1, "div", "viewer-container", components && components.map((Component, index) => createComponentVNode(2, Component, null, index)), 0);
    }
  }

  class Renderer {
    constructor(changeSupport, components, config, eventBus, injector) {
      const {
        container
      } = config;
      this._container = container;
      eventBus.on('renderer.mount', () => {
        render(createComponentVNode(2, ViewerComponent, {
          "injector": injector
        }), container);
      });
      eventBus.on('renderer.unmount', () => {
        render(null, container);
      });
    }
    getContainer() {
      return this._container;
    }
  }
  Renderer.$inject = ['changeSupport', 'components', 'config.renderer', 'eventBus', 'injector'];

  var core = {
    __init__: ['changeSupport', 'components', 'renderer'],
    changeSupport: ['type', ChangeSupport],
    components: ['type', Components],
    eventBus: ['type', EventBus],
    renderer: ['type', Renderer]
  };

  /**
   * A base for React-style viewers.
   */
  let Viewer$3 = class Viewer {
    constructor(options = {}) {
      let {
        injector
      } = options;
      if (!injector) {
        let {
          modules,
          config
        } = this._init(options);
        injector = createInjector(config, modules);
      }
      this.get = injector.get;
      this.invoke = injector.invoke;
      this.get('eventBus').fire('viewer.init');
    }

    /**
     * Intialize and return modules and config used for creation.
     *
     * @param  {Object} options
     *
     * @return {Object} { modules=[], config }
     */
    _init(options) {
      let {
        modules,
        ...config
      } = options;
      return {
        modules,
        config
      };
    }

    /**
     * Destroy. This results in removing the attachment from the container.
     */
    destroy() {
      const eventBus = this.get('eventBus');
      eventBus.fire('viewer.destroy');
    }

    /**
     * Clear. Should be used to reset the state of any stateful services.
     */
    clear() {
      const eventBus = this.get('eventBus');
      eventBus.fire('viewer.clear');
    }
  };

  // helpers //////////////////////

  function createInjector(config, modules) {
    const bootstrapModules = [{
      config: ['value', config]
    }, core].concat(modules || []);
    const injector = new Injector(bootstrapModules);
    injector.init();
    return injector;
  }

  /**
   * A single decision element registry.
   *
   * The sole purpose of this service is to provide the necessary API
   * to serve shared components, i.e. the UpdatePropertiesHandler.
   */
  class ElementRegistry {
    constructor(viewer, eventBus) {
      this._eventBus = eventBus;
      this._viewer = viewer;
    }
    getDecision() {
      return this._viewer.getDecision();
    }
    updateId(element, newId) {
      var decision = this.getDecision();
      if (element !== decision) {
        throw new Error('element !== decision');
      }
      this._eventBus.fire('element.updateId', {
        element: element,
        newId: newId
      });
      element.id = newId;
    }
  }
  ElementRegistry.$inject = ['viewer', 'eventBus'];

  var CoreModule = {
    __init__: ['elementRegistry'],
    elementRegistry: ['type', ElementRegistry]
  };

  class DecisionPropertiesComponent extends Component {
    constructor(props, context) {
      super(props, context);
      this._viewer = context.injector.get('viewer');
    }
    render() {
      // there is only one single element
      const {
        name
      } = this._viewer.getDecision();
      return createVNode(1, "div", "decision-properties", createVNode(1, "h3", "decision-name", name, 0), 2);
    }
  }

  const HIGH_PRIORITY = 1500;
  let DecisionProperties$1 = class DecisionProperties {
    constructor(components) {
      components.onGetComponent('viewer', HIGH_PRIORITY, () => DecisionPropertiesComponent);
    }
  };
  DecisionProperties$1.$inject = ['components'];

  var DecisionPropertiesModule = {
    __init__: ['decisionProperties'],
    decisionProperties: ['type', DecisionProperties$1]
  };

  class LiteralExpressionPropertiesComponent extends Component {
    constructor(props, context) {
      super(props, context);
      this._translate = context.injector.get('translate');
      this._viewer = context.injector.get('viewer');
    }
    render() {
      const decision = this._viewer.getDecision();
      const literalExpression = decision.get('decisionLogic');
      const variable = decision.get('variable');
      return createVNode(1, "div", "literal-expression-properties", createVNode(1, "table", null, [createVNode(1, "tr", null, [createVNode(1, "td", null, this._translate('Variable name:'), 0), createVNode(1, "td", null, createVNode(1, "span", null, variable && variable.get('name') || '-', 0), 2)], 4), createVNode(1, "tr", null, [createVNode(1, "td", null, this._translate('Variable type:'), 0), createVNode(1, "td", null, createVNode(1, "span", null, this._translate(variable && variable.get('typeRef') || '') || '-', 0), 2)], 4), createVNode(1, "tr", null, [createVNode(1, "td", null, this._translate('Expression language:'), 0), createVNode(1, "td", null, createVNode(1, "span", null, literalExpression.expressionLanguage || '-', 0), 2)], 4)], 4), 2);
    }
  }

  const LOW_PRIORITY = 500;
  class DecisionProperties {
    constructor(components) {
      components.onGetComponent('viewer', LOW_PRIORITY, () => {
        return LiteralExpressionPropertiesComponent;
      });
    }
  }
  DecisionProperties.$inject = ['components'];

  var LiteralExpressionPropertiesModule = {
    __depends__: [],
    __init__: ['literalExpressionProperties'],
    literalExpressionProperties: ['type', DecisionProperties]
  };

  const HIGHER_PRIORITY$1 = 2000;
  let PoweredBy$1 = class PoweredBy {
    constructor(components) {
      components.onGetComponent('viewer', HIGHER_PRIORITY$1, () => {
        return PoweredByComponent;
      });
    }
  };
  PoweredBy$1.$inject = ['components'];

  var PoweredByModule$1 = {
    __init__: ['poweredBy'],
    poweredBy: ['type', PoweredBy$1]
  };

  class TextareaComponent extends Component {
    constructor(props, context) {
      super(props, context);
      this._viewer = context.injector.get('viewer');
    }
    render() {
      const {
        text
      } = this._viewer.getDecision().decisionLogic;
      return createVNode(1, "div", "textarea", createVNode(1, "div", "content", text, 0), 2);
    }
  }

  class Textarea {
    constructor(components) {
      components.onGetComponent('viewer', () => TextareaComponent);
    }
  }
  Textarea.$inject = ['components'];

  var TextareaModule = {
    __init__: ['textarea'],
    textarea: ['type', Textarea]
  };

  let ViewDrdComponent$1 = class ViewDrdComponent extends Component {
    constructor(props, context) {
      super(props, context);
      const {
        injector
      } = context;
      this._translate = injector.get('translate');
      this._eventBus = injector.get('eventBus');
    }
    onClick = () => {
      this._eventBus.fire('showDrd');
    };
    render() {
      return createVNode(1, "div", "view-drd", createVNode(1, "button", "view-drd-button", this._translate('View DRD'), 0, {
        "type": "button",
        "onClick": this.onClick
      }), 2, null, null, node => this.node = node);
    }
  };
  ViewDrdComponent$1.$inject = ['translate'];

  const VERY_HIGH_PRIORITY$1 = 2000;
  let ViewDrd$1 = class ViewDrd {
    constructor(components, viewer, eventBus, injector) {
      this._injector = injector;
      this._viewer = viewer;
      components.onGetComponent('viewer', VERY_HIGH_PRIORITY$1, () => {
        if (this.canViewDrd()) {
          return ViewDrdComponent$1;
        }
      });
      eventBus.on('showDrd', () => {
        const parent = injector.get('_parent', false);

        // there is only one single element
        const definitions = this.getDefinitions();

        // open definitions
        const view = parent.getView(definitions);
        parent.open(view);
      });
    }
    canViewDrd() {
      const parent = this._injector.get('_parent', false);
      if (!parent) {
        return;
      }

      // there is only one single element
      const definitions = this.getDefinitions();
      return !!parent.getView(definitions);
    }
    getDefinitions() {
      return getDefinitions(this._viewer.getDecision());
    }
  };
  ViewDrd$1.$inject = ['components', 'viewer', 'eventBus', 'injector'];

  // helpers //////////////////////

  function getDefinitions(decision) {
    const definitions = decision.$parent;
    return definitions;
  }

  var ViewDrdModule$1 = {
    __init__: ['viewDrd'],
    viewDrd: ['type', ViewDrd$1]
  };

  /**
   * @typedef {import('dmn-js-shared/lib/base/View).OpenResult} OpenResult
   */

  /**
   * @typedef {import('dmn-js-shared/lib/base/View).OpenError} OpenError
   */

  let Viewer$2 = class Viewer extends Viewer$3 {
    constructor(options = {}) {
      const container = Viewer._createContainer();
      super(assign$1(options, {
        renderer: {
          container
        }
      }));
      this._container = container;
    }

    /**
     * Open diagram element.
     *
     * @param  {ModdleElement} decision
     * @returns {Promise} Resolves with {OpenResult} when successful
     * or rejects with {OpenError}
     */
    open(decision) {
      var self = this;
      return new Promise(function (resolve, reject) {
        var err;

        // use try/catch to not swallow synchronous exceptions
        // that may be raised during model parsing
        try {
          if (self._decision) {
            // clear existing literal expression
            self.clear();

            // unmount first
            self.get('eventBus').fire('renderer.unmount');
          }

          // update literal expression
          self._decision = decision;

          // let others know about import
          self.get('eventBus').fire('import', decision);
          self.get('eventBus').fire('renderer.mount');
        } catch (e) {
          err = e;
        }

        // handle synchronously thrown exception
        if (err) {
          err.warnings = err.warnings || [];
          reject(err);
        } else {
          resolve({
            warnings: []
          });
        }
      });
    }

    /**
     * Initialize the literal expression, returning { modules: [], config }.
     *
     * @param  {Object} options
     *
     * @return {Object} init config
     */
    _init(options) {
      let {
        modules,
        additionalModules,
        ...config
      } = options;
      let baseModules = modules || this.getModules();
      let extraModules = additionalModules || [];
      let staticModules = [{
        viewer: ['value', this]
      }];
      let allModules = [...baseModules, ...extraModules, ...staticModules];
      return {
        modules: allModules,
        config
      };
    }

    /**
     * Register an event listener
     *
     * Remove a previously added listener via {@link #off(event, callback)}.
     *
     * @param {string} event
     * @param {number} [priority]
     * @param {Function} callback
     * @param {Object} [that]
     */
    on(event, priority, callback, target) {
      return this.get('eventBus').on(event, priority, callback, target);
    }

    /**
     * De-register an event listener
     *
     * @param {string} event
     * @param {Function} callback
     */
    off(event, callback) {
      this.get('eventBus').off(event, callback);
    }

    /**
     * Emit an event on the underlying {@link EventBus}
     *
     * @param  {string} type
     * @param  {Object} event
     *
     * @return {Object} event processing result (if any)
     */
    _emit(type, event) {
      return this.get('eventBus').fire(type, event);
    }

    /**
     * Returns the currently displayed decision.
     *
     * @return {ModdleElement}
     */
    getDecision() {
      return this._decision;
    }

    /**
     * Attach viewer to given parent node.
     *
     * @param  {Element} parentNode
     */
    attachTo(parentNode) {
      if (!parentNode) {
        throw new Error('parentNode required');
      }

      // ensure we detach from the
      // previous, old parent
      this.detach();
      parentNode.appendChild(this._container);
      this._emit('attach', {});
    }

    /**
     * Detach viewer from parent node, if attached.
     */
    detach() {
      const container = this._container,
        parentNode = container.parentNode;
      if (!parentNode) {
        return;
      }
      this._emit('detach', {});
      remove$4(container);
    }
    destroy() {
      super.destroy();
      this.detach();
    }
    getModules() {
      return Viewer._getModules();
    }
    static _getModules() {
      return [CoreModule, TranslateModule, DecisionPropertiesModule, LiteralExpressionPropertiesModule, PoweredByModule$1, TextareaModule, ViewDrdModule$1];
    }
    static _createContainer() {
      return domify('<div class="dmn-literal-expression-container"></div>');
    }
  };

  class ViewRenderer {
    static $inject = ['components'];
    constructor(components) {
      components.onGetComponent('viewer', () => {
        return Header;
      });
      components.onGetComponent('viewer', () => {
        return Body;
      });
      components.onGetComponent('viewer', () => {
        return Footer;
      });
    }
  }
  function Header(_, {
    injector
  }) {
    const components = injector.get('components');
    const headerComponents = components.getComponents('header');
    return createVNode(1, "div", "dmn-boxed-expression-section dmn-boxed-expression-header", headerComponents && headerComponents.map((Component, index) => {
      return createComponentVNode(2, Component, null, index);
    }), 0);
  }
  function Body(_, {
    injector
  }) {
    const components = injector.get('components');
    const bodyComponents = components.getComponents('body');
    return createVNode(1, "div", "dmn-boxed-expression-section dmn-boxed-expression-body", bodyComponents && bodyComponents.map((Component, index) => {
      return createComponentVNode(2, Component, null, index);
    }), 0);
  }
  function Footer(_, {
    injector
  }) {
    const components = injector.get('components');
    const footerComponents = components.getComponents('footer');
    return createVNode(1, "div", "dmn-boxed-expression-section dmn-boxed-expression-footer", footerComponents && footerComponents.map((Component, index) => {
      return createComponentVNode(2, Component, null, index);
    }), 0);
  }

  /**
   * Allows to use modules from `table-js` which depend on `table.*` components.
   * @TODO(barmac): This is a temporary solution until we move context menu out of table-js.
   */
  class TableJsSupport {
    static $inject = ['components'];
    constructor(components) {
      components.onGetComponent('viewer', () => {
        const children = components.getComponents('table.before') || [];
        return () => {
          return createVNode(1, "div", null, children.map((Component, index) => createComponentVNode(2, Component, null, index)), 0);
        };
      });
    }
  }

  var RenderModule = {
    __init__: ['viewRenderer', 'tableJsSupport'],
    'viewRenderer': ['type', ViewRenderer],
    'tableJsSupport': ['type', TableJsSupport]
  };

  const HIGHER_PRIORITY = 2000;
  class PoweredBy {
    constructor(components) {
      components.onGetComponent('viewer', HIGHER_PRIORITY, () => {
        return PoweredByComponent;
      });
    }
  }
  PoweredBy.$inject = ['components'];

  var PoweredByModule = {
    __init__: ['poweredBy'],
    poweredBy: ['type', PoweredBy]
  };

  class LiteralExpressionComponentProvider {
    static $inject = ['components'];
    constructor(components) {
      components.onGetComponent('expression', ({
        expression
      }) => {
        if (is(expression, 'dmn:LiteralExpression')) {
          return LiteralExpressionComponent;
        }
      });
    }
  }
  function LiteralExpressionComponent({
    expression
  }, context) {
    const literalExpression = context.injector.get('literalExpression');
    const text = literalExpression.getText(expression);
    return createVNode(1, "div", "textarea", createVNode(1, "div", "content", text, 0), 2);
  }

  class LiteralExpression {
    getText(literalExpression) {
      return literalExpression.get('text');
    }
  }

  var LiteralExpressionModule = {
    __init__: ['literalExpressionComponent'],
    literalExpressionComponent: ['type', LiteralExpressionComponentProvider],
    literalExpression: ['type', LiteralExpression]
  };

  class FunctionDefinition {
    getParameters(element) {
      return element.get('formalParameter');
    }
    getBody(element) {
      return element.get('body');
    }
    getKind(element) {
      return element.get('kind') || 'FEEL';
    }
  }

  class FunctionDefinitionComponentProvider {
    static $inject = ['components'];
    constructor(components) {
      components.onGetComponent('expression', ({
        expression
      }) => {
        if (is(expression, 'dmn:FunctionDefinition')) {
          return FunctionDefinitionComponent;
        }
      });
    }
  }
  function FunctionDefinitionComponent({
    expression
  }, context) {
    const functionDefinition = context.injector.get('functionDefinition');
    const kind = functionDefinition.getKind(expression);
    const parameters = functionDefinition.getParameters(expression);
    const body = functionDefinition.getBody(expression);
    return createVNode(1, "div", "function-definition", [createComponentVNode(2, Kind, {
      "kind": kind
    }), createComponentVNode(2, FormalParameters, {
      "parameters": parameters
    }), createComponentVNode(2, BodyExpression, {
      "expression": body
    })], 4);
  }
  const KIND_MAP = {
    'FEEL': 'F',
    'Java': 'J',
    'PMML': 'P'
  };
  function Kind({
    kind
  }, context) {
    const translate = context.injector.get('translate');
    return createVNode(1, "div", "function-definition-kind", KIND_MAP[kind], 0, {
      "title": translate('Function kind: {kind}', {
        kind
      })
    });
  }
  function FormalParameters({
    parameters
  }) {
    return createVNode(1, "div", "function-definition-parameters", createVNode(1, "div", null, [createTextVNode("("), parameters.reduce((acc, parameter) => {
      return acc.concat(createComponentVNode(2, Parameter, {
        "parameter": parameter
      }), ', ');
    }, []).slice(0, -1), createTextVNode(")")], 0), 2);
  }
  function Parameter({
    parameter
  }) {
    const {
      name,
      typeRef
    } = parameter;
    const displayedName = name || '<unnamed>';
    return createVNode(1, "span", null, typeRef ? `${displayedName}: ${typeRef}` : displayedName, 0);
  }
  function BodyExpression({
    expression
  }, context) {
    const Expression = context.components.getComponent('expression', {
      expression
    });
    return createVNode(1, "div", "function-definition-body", createComponentVNode(2, Expression, {
      "expression": expression
    }), 2);
  }

  var FunctionDefinitionEditorModule = {
    __init__: ['functionDefinitionComponent'],
    functionDefinition: ['type', FunctionDefinition],
    functionDefinitionComponent: ['type', FunctionDefinitionComponentProvider]
  };

  class ViewDrdComponent extends Component {
    constructor(props, context) {
      super(props, context);
      const {
        injector
      } = context;
      this._translate = injector.get('translate');
      this._eventBus = injector.get('eventBus');
    }
    onClick = () => {
      this._eventBus.fire('showDrd');
    };
    render() {
      return createVNode(1, "div", "view-drd", createVNode(1, "button", "view-drd-button", this._translate('View DRD'), 0, {
        "type": "button",
        "onClick": this.onClick
      }), 2, null, null, node => this.node = node);
    }
  }
  ViewDrdComponent.$inject = ['translate'];

  const VERY_HIGH_PRIORITY = 2000;
  class ViewDrd {
    constructor(components, eventBus, injector) {
      this._injector = injector;
      components.onGetComponent('viewer', VERY_HIGH_PRIORITY, () => {
        if (this.canViewDrd()) {
          return ViewDrdComponent;
        }
      });
      eventBus.on('showDrd', () => {
        const parent = injector.get('_parent', false);

        // there is only one single element
        const definitions = parent.getDefinitions();

        // open definitions
        const view = parent.getView(definitions);
        parent.open(view);
      });
    }
    canViewDrd() {
      const parent = this._injector.get('_parent', false);
      if (!parent) {
        return;
      }

      // there is only one single element
      const definitions = parent.getDefinitions();
      return !!parent.getView(definitions);
    }
  }
  ViewDrd.$inject = ['components', 'eventBus', 'injector'];

  var ViewDrdModule = {
    __init__: ['viewDrd'],
    viewDrd: ['type', ViewDrd]
  };

  function ElementPropertiesComponent(_, context) {
    const viewer = context.injector.get('viewer');

    // there is only one single element
    const {
      name
    } = viewer.getRootElement();
    return createVNode(1, "div", "element-properties", createVNode(1, "h2", "element-name", name, 0), 2);
  }

  class ElementProperties {
    constructor(components) {
      components.onGetComponent('header', () => ElementPropertiesComponent);
    }
  }
  ElementProperties.$inject = ['components'];

  var ElementPropertiesModule = {
    __init__: ['elementProperties'],
    elementProperties: ['type', ElementProperties]
  };

  const FALLBACK_PRIORITY = 100;
  class ElementLogic {
    static $inject = ['components'];
    constructor(components) {
      components.onGetComponent('body', () => {
        return LogicComponent;
      });
      components.onGetComponent('expression', FALLBACK_PRIORITY, () => FallbackExpression);
    }
  }
  function LogicComponent(_, {
    injector
  }) {
    const components = injector.get('components');
    const viewer = injector.get('viewer');
    const rootElement = viewer.getRootElement();
    const expression = getLogic(rootElement);
    const Expression = components.getComponent('expression', {
      expression
    });
    return createComponentVNode(2, Expression, {
      "expression": expression
    });
  }
  function getLogic(element) {
    if (is(element, 'dmn:Decision')) {
      return element.get('decisionLogic');
    } else if (is(element, 'dmn:BusinessKnowledgeModel')) {
      return element.get('encapsulatedLogic');
    }
  }
  function FallbackExpression({
    expression
  }) {
    return createVNode(1, "div", null, createVNode(1, "span", null, [createTextVNode("Expression of type "), expression.$type, createTextVNode(" is not supported.")], 0, {
      "style": "color:red;"
    }), 2);
  }

  var ElementLogicModule = {
    __init__: ['elementLogic'],
    elementLogic: ['type', ElementLogic]
  };

  class ElementVariable {
    static $inject = ['viewer'];
    constructor(viewer) {
      this._viewer = viewer;
    }
    getName() {
      const variable = this.getVariable(),
        element = this._getElement();
      const variableName = variable ? variable.get('name') : null;
      return variableName || element.get('name');
    }
    getType() {
      const variable = this.getVariable();
      return variable ? variable.get('typeRef') : 'Any';
    }
    _getElement() {
      return this._viewer.getRootElement();
    }
    getVariable() {
      return this._getElement().get('variable');
    }
  }

  class ElementVariableComponentProvider {
    static $inject = ['components'];
    constructor(components) {
      components.onGetComponent('footer', () => ElementVariableComponent);
    }
  }
  function ElementVariableComponent(_, context) {
    const elementVariable = context.injector.get('elementVariable');
    const translate = context.injector.get('translate');

    // there is only one single element
    const name = elementVariable.getName();
    const type = elementVariable.getType();
    return createVNode(1, "div", "element-variable", [createVNode(1, "h2", null, createTextVNode("Result"), 2), createVNode(1, "div", "element-variable-name", [createVNode(1, "span", "element-variable-name-label", translate('Variable name'), 0), createVNode(1, "span", null, name, 0)], 4), createVNode(1, "div", "element-variable-type", [createVNode(1, "span", "element-variable-type-label", translate('Variable type'), 0), createVNode(1, "span", null, type, 0)], 4)], 4);
  }

  var ElementVariableModule = {
    __init__: ['elementVariableComponent'],
    elementVariable: ['type', ElementVariable],
    elementVariableComponent: ['type', ElementVariableComponentProvider]
  };

  /**
   * @typedef {import('dmn-js-shared/lib/base/View).OpenResult} OpenResult
   */

  /**
   * @typedef {import('dmn-js-shared/lib/base/View).OpenError} OpenError
   */

  let Viewer$1 = class Viewer extends Viewer$3 {
    constructor(options = {}) {
      const container = Viewer._createContainer();
      super(assign$1(options, {
        renderer: {
          container
        }
      }));
      this._container = container;
    }

    /**
     * Open diagram element.
     *
     * @param  {ModdleElement} element
     * @returns {Promise} Resolves with {OpenResult} when successful
     * or rejects with {OpenError}
     */
    open(element) {
      const eventBus = this.get('eventBus');
      return new Promise((resolve, reject) => {
        let err;

        // use try/catch to not swallow synchronous exceptions
        // that may be raised during model parsing
        try {
          const rootElement = this.getRootElement();
          if (rootElement) {
            // clear existing literal expression
            this.clear();

            // unmount first
            eventBus.fire('renderer.unmount');
          }

          // update literal expression
          this._setRootElement(element);

          // let others know about import
          eventBus.fire('import', element);
          eventBus.fire('renderer.mount');
        } catch (e) {
          err = e;
        }

        // handle synchronously thrown exception
        if (err) {
          err.warnings = err.warnings || [];
          reject(err);
        } else {
          resolve({
            warnings: []
          });
        }
      });
    }

    /**
     * Initialize the viewer, returning { modules: [], config }.
     *
     * @param  {Object} options
     *
     * @return {Object} init config
     */
    _init(options) {
      let {
        modules,
        additionalModules,
        ...config
      } = options;
      let baseModules = modules || this.getModules();
      let extraModules = additionalModules || [];
      let staticModules = [{
        viewer: ['value', this]
      }];
      let allModules = [...baseModules, ...extraModules, ...staticModules];
      return {
        modules: allModules,
        config
      };
    }

    /**
     * Register an event listener
     *
     * Remove a previously added listener via {@link #off(event, callback)}.
     *
     * @param {string} event
     * @param {number} [priority]
     * @param {Function} callback
     * @param {Object} [that]
     */
    on(event, priority, callback, target) {
      return this.get('eventBus').on(event, priority, callback, target);
    }

    /**
     * De-register an event listener
     *
     * @param {string} event
     * @param {Function} callback
     */
    off(event, callback) {
      this.get('eventBus').off(event, callback);
    }

    /**
     * Emit an event on the underlying {@link EventBus}
     *
     * @param  {string} type
     * @param  {Object} event
     *
     * @return {Object} event processing result (if any)
     */
    _emit(type, event) {
      return this.get('eventBus').fire(type, event);
    }

    /**
     * Returns the currently displayed element.
     *
     * @return {ModdleElement}
     */
    getRootElement() {
      return this._root;
    }
    _setRootElement(element) {
      this._root = element;
    }

    /**
     * Attach viewer to given parent node.
     *
     * @param  {Element} parentNode
     */
    attachTo(parentNode) {
      if (!parentNode) {
        throw new Error('parentNode required');
      }

      // ensure we detach from the
      // previous, old parent
      this.detach();
      parentNode.appendChild(this._container);
      this._emit('attach', {});
    }

    /**
     * Detach viewer from parent node, if attached.
     */
    detach() {
      const container = this._container,
        parentNode = container.parentNode;
      if (!parentNode) {
        return;
      }
      this._emit('detach', {});
      remove$4(container);
    }
    destroy() {
      super.destroy();
      this.detach();
    }
    getModules() {
      return [RenderModule, TranslateModule, PoweredByModule, ViewDrdModule, ElementPropertiesModule, ElementLogicModule, FunctionDefinitionEditorModule, LiteralExpressionModule, ElementVariableModule];
    }
    static _createContainer() {
      return domify('<div class="dmn-boxed-expression-container"></div>');
    }
  };

  const ID = 'id';

  /**
   * A generic handler that implements property editing.
   */
  class EditPropertiesHandler {
    constructor(elementRegistry, moddle) {
      this._elementRegistry = elementRegistry;
      this._moddle = moddle;
    }

    /**
     * <do>
     */
    execute(context) {
      const {
        element,
        properties
      } = context;
      const bo = getBusinessObject(element);
      const {
        changed,
        oldProperties
      } = this.updateProperties(bo, properties);
      context.oldProperties = oldProperties;
      return [...changed, element];
    }

    /**
     * <undo>
     */
    revert(context) {
      const {
        element,
        oldProperties
      } = context;
      var bo = getBusinessObject(element);
      var {
        changed
      } = this.updateProperties(bo, oldProperties);
      return [...changed, element];
    }

    /**
     * Update properties of the given business object
     * and return { changed, oldProperties }.
     */
    updateProperties(bo, newProps) {
      const ids = this._moddle.ids;

      // Reduce over all new properties and return
      //
      // {
      //  changed,
      //  oldProperties
      // }
      return reduce(newProps, (result, value, key) => {
        const propertyValue = bo.get(key);

        // handle nested update (plain object), but treat moddle elements
        // as values to be set directly rather than merged
        if (isContainer(value)) {
          if (!isModdleElement(propertyValue) && !isContainer(propertyValue)) {
            throw new Error(`non-existing property <${key}>: cannot update values`);
          }
          let {
            changed,
            oldProperties
          } = this.updateProperties(propertyValue, value);
          return {
            changed: [...result.changed, ...changed, propertyValue],
            oldProperties: {
              ...result.oldProperties,
              [key]: oldProperties
            }
          };
        }

        // handle ID change
        if (key === ID && isIdChange(bo, value)) {
          ids.unclaim(bo[ID]);
          this._elementRegistry.updateId(bo, value);
          ids.claim(value, bo);
        }

        // handle plain update
        bo.set(key, value);
        return {
          changed: result.changed,
          oldProperties: {
            ...result.oldProperties,
            [key]: propertyValue
          }
        };
      }, {
        changed: [],
        oldProperties: {}
      });
    }
  }
  EditPropertiesHandler.$inject = ['elementRegistry', 'moddle'];

  // helpers //////////////////////

  function isIdChange(element, newId) {
    return element[ID] !== newId;
  }
  function isContainer(o) {
    return isDefined(o) && isObject$1(o) && !isModdleElement(o);
  }
  function isModdleElement(o) {
    return !!o?.$type;
  }

  /**
   * Expose `xor`
   */

  var componentXor;
  var hasRequiredComponentXor;
  function requireComponentXor() {
    if (hasRequiredComponentXor) return componentXor;
    hasRequiredComponentXor = 1;
    componentXor = xor;

    /**
     * XOR utility
     *
     * T T F
     * T F T
     * F T T
     * F F F
     *
     * @param {Boolean} a
     * @param {Boolean} b
     * @return {Boolean}
     */

    function xor(a, b) {
      return a ^ b;
    }
    return componentXor;
  }

  /**
   * Global Names
   */

  var componentProps;
  var hasRequiredComponentProps;
  function requireComponentProps() {
    if (hasRequiredComponentProps) return componentProps;
    hasRequiredComponentProps = 1;
    var globals = /\b(Array|Date|Object|Math|JSON)\b/g;

    /**
     * Return immediate identifiers parsed from `str`.
     *
     * @param {String} str
     * @param {String|Function} map function or prefix
     * @return {Array}
     * @api public
     */

    componentProps = function (str, fn) {
      var p = unique(props(str));
      if (fn && 'string' == typeof fn) fn = prefixed(fn);
      if (fn) return map(str, p, fn);
      return p;
    };

    /**
     * Return immediate identifiers in `str`.
     *
     * @param {String} str
     * @return {Array}
     * @api private
     */

    function props(str) {
      return str.replace(/\.\w+|\w+ *\(|"[^"]*"|'[^']*'|\/([^/]+)\//g, '').replace(globals, '').match(/[a-zA-Z_]\w*/g) || [];
    }

    /**
     * Return `str` with `props` mapped with `fn`.
     *
     * @param {String} str
     * @param {Array} props
     * @param {Function} fn
     * @return {String}
     * @api private
     */

    function map(str, props, fn) {
      var re = /\.\w+|\w+ *\(|"[^"]*"|'[^']*'|\/([^/]+)\/|[a-zA-Z_]\w*/g;
      return str.replace(re, function (_) {
        if ('(' == _[_.length - 1]) return fn(_);
        if (!~props.indexOf(_)) return _;
        return fn(_);
      });
    }

    /**
     * Return unique array.
     *
     * @param {Array} arr
     * @return {Array}
     * @api private
     */

    function unique(arr) {
      var ret = [];
      for (var i = 0; i < arr.length; i++) {
        if (~ret.indexOf(arr[i])) continue;
        ret.push(arr[i]);
      }
      return ret;
    }

    /**
     * Map with prefix `str`.
     */

    function prefixed(str) {
      return function (_) {
        return str + _;
      };
    }
    return componentProps;
  }

  /**
   * Module Dependencies
   */

  var domIterator;
  var hasRequiredDomIterator;
  function requireDomIterator() {
    if (hasRequiredDomIterator) return domIterator;
    hasRequiredDomIterator = 1;
    var xor = requireComponentXor();
    var props = requireComponentProps();

    /**
     * Export `Iterator`
     */

    domIterator = Iterator;

    /**
     * Initialize `Iterator`
     *
     * @param {Node} node
     * @param {Node} root
     * @return {Iterator} self
     * @api public
     */

    function Iterator(node, root) {
      if (!(this instanceof Iterator)) return new Iterator(node, root);
      this.node = this.start = this.peeked = node;
      this.root = root;
      this.closingTag = false;
      this._revisit = true;
      this._selects = [];
      this._rejects = [];
      if (node && this.higher(node)) {
        throw new Error('root must be a parent or ancestor to node');
      }
    }

    /**
     * Reset the Iterator
     *
     * @param {Node} node (optional)
     * @return {Iterator} self
     * @api public
     */

    Iterator.prototype.reset = function (node) {
      this.node = node || this.start;
      return this;
    };

    /**
     * Revisit element nodes. Defaults to `true`
     */

    Iterator.prototype.revisit = function (revisit) {
      this._revisit = undefined == revisit ? true : revisit;
      return this;
    };

    /**
     * Jump to the opening tag
     */

    Iterator.prototype.opening = function () {
      if (1 == this.node.nodeType) this.closingTag = false;
      return this;
    };

    /**
     * Jump to the closing tag
     */

    Iterator.prototype.atOpening = function () {
      return !this.closingTag;
    };

    /**
     * Jump to the closing tag
     */

    Iterator.prototype.closing = function () {
      if (1 == this.node.nodeType) this.closingTag = true;
      return this;
    };

    /**
     * Jump to the closing tag
     */

    Iterator.prototype.atClosing = function () {
      return this.closingTag;
    };

    /**
     * Next node
     *
     * @param {Number} type
     * @return {Node|null}
     * @api public
     */

    Iterator.prototype.next = traverse('nextSibling', 'firstChild');

    /**
     * Previous node
     *
     * @param {Number} type
     * @return {Node|null}
     * @api public
     */

    Iterator.prototype.previous = Iterator.prototype.prev = traverse('previousSibling', 'lastChild');

    /**
     * Make traverse function
     *
     * @param {String} dir
     * @param {String} child
     * @return {Function}
     * @api private
     */

    function traverse(dir, child) {
      var next = dir == 'nextSibling';
      return function walk(expr, n, peek) {
        expr = this.compile(expr);
        n = n && n > 0 ? n : 1;
        var node = this.node;
        var closing = this.closingTag;
        var revisit = this._revisit;
        while (node) {
          if (xor(next, closing) && node[child]) {
            // element with children: <em>...</em>
            node = node[child];
            closing = !next;
          } else if (1 == node.nodeType && !node[child] && xor(next, closing)) {
            // empty element tag: <em></em>
            closing = next;
            if (!revisit) continue;
          } else if (node[dir]) {
            // element has a neighbor: ...<em></em>...
            node = node[dir];
            closing = !next;
          } else {
            // done with current layer, move up.
            node = node.parentNode;
            closing = next;
            if (!revisit) continue;
          }
          if (!node || this.higher(node, this.root)) break;
          if (expr(node) && this.selects(node, peek) && this.rejects(node, peek)) {
            if (--n) continue;
            if (!peek) this.node = node;
            this.closingTag = closing;
            return node;
          }
        }
        return null;
      };
    }

    /**
     * Select nodes that cause `expr(node)`
     * to be truthy
     *
     * @param {Number|String|Function} expr
     * @return {Iterator} self
     * @api public
     */

    Iterator.prototype.select = function (expr) {
      expr = this.compile(expr);
      this._selects.push(expr);
      return this;
    };

    /**
     * Run through the selects ORing each
     *
     * @param {Node} node
     * @param {Boolean} peek
     * @return {Boolean}
     * @api private
     */

    Iterator.prototype.selects = function (node, peek) {
      var exprs = this._selects;
      var len = exprs.length;
      if (!len) return true;
      for (var i = 0; i < len; i++) {
        if (exprs[i].call(this, node, peek)) return true;
      }
      return false;
    };

    /**
     * Select nodes that cause `expr(node)`
     * to be falsy
     *
     * @param {Number|String|Function} expr
     * @return {Iterator} self
     * @api public
     */

    Iterator.prototype.reject = function (expr) {
      expr = this.compile(expr);
      this._rejects.push(expr);
      return this;
    };

    /**
     * Run through the reject expressions ANDing each
     *
     * @param {Node} node
     * @param {Boolean} peek
     * @return {Boolean}
     * @api private
     */

    Iterator.prototype.rejects = function (node, peek) {
      var exprs = this._rejects;
      var len = exprs.length;
      if (!len) return true;
      for (var i = 0; i < len; i++) {
        if (exprs[i].call(this, node, peek)) return false;
      }
      return true;
    };

    /**
     * Check if node is higher
     * than root.
     *
     * @param {Node} node
     * @param {Node} root
     * @return {Boolean}
     * @api private
     */

    Iterator.prototype.higher = function (node) {
      var root = this.root;
      if (!root) return false;
      node = node.parentNode;
      while (node && node != root) node = node.parentNode;
      return node != root;
    };

    /**
     * Compile an expression
     *
     * @param {String|Function|Number} expr
     * @return {Function}
     */

    Iterator.prototype.compile = function (expr) {
      switch (typeof expr) {
        case 'number':
          return function (node) {
            return expr == node.nodeType;
          };
        case 'string':
          return new Function('node', 'Object.freeze(node); return ' + props(expr, 'node.'));
        case 'function':
          return expr;
        default:
          return function () {
            return true;
          };
      }
    };

    /**
     * Peek in either direction
     * `n` nodes. Peek backwards
     * using negative numbers.
     *
     * @param {Number} n (optional)
     * @return {Node|null}
     * @api public
     */

    Iterator.prototype.peak = Iterator.prototype.peek = function (expr, n) {
      if (arguments.length == 1) n = expr, expr = true;
      n = undefined == n ? 1 : n;
      if (!n) return this.node;else if (n > 0) return this.next(expr, n, true);else return this.prev(expr, Math.abs(n), true);
    };

    /**
     * Add a plugin
     *
     * @param {Function} fn
     * @return {Iterator}
     * @api public
     */

    Iterator.prototype.use = function (fn) {
      fn(this);
      return this;
    };
    return domIterator;
  }
  requireDomIterator();

  /**
   * Module Dependencies
   */

  window.getSelection();

  // These are filled with ranges (rangeFrom[i] up to but not including
  // rangeTo[i]) of code points that count as extending characters.
  let rangeFrom = [],
    rangeTo = [];
  (() => {
    // Compressed representation of the Grapheme_Cluster_Break=Extend
    // information from
    // http://www.unicode.org/Public/16.0.0/ucd/auxiliary/GraphemeBreakProperty.txt.
    // Each pair of elements represents a range, as an offet from the
    // previous range and a length. Numbers are in base-36, with the empty
    // string being a shorthand for 1.
    let numbers = "lc,34,7n,7,7b,19,,,,2,,2,,,20,b,1c,l,g,,2t,7,2,6,2,2,,4,z,,u,r,2j,b,1m,9,9,,o,4,,9,,3,,5,17,3,3b,f,,w,1j,,,,4,8,4,,3,7,a,2,t,,1m,,,,2,4,8,,9,,a,2,q,,2,2,1l,,4,2,4,2,2,3,3,,u,2,3,,b,2,1l,,4,5,,2,4,,k,2,m,6,,,1m,,,2,,4,8,,7,3,a,2,u,,1n,,,,c,,9,,14,,3,,1l,3,5,3,,4,7,2,b,2,t,,1m,,2,,2,,3,,5,2,7,2,b,2,s,2,1l,2,,,2,4,8,,9,,a,2,t,,20,,4,,2,3,,,8,,29,,2,7,c,8,2q,,2,9,b,6,22,2,r,,,,,,1j,e,,5,,2,5,b,,10,9,,2u,4,,6,,2,2,2,p,2,4,3,g,4,d,,2,2,6,,f,,jj,3,qa,3,t,3,t,2,u,2,1s,2,,7,8,,2,b,9,,19,3,3b,2,y,,3a,3,4,2,9,,6,3,63,2,2,,1m,,,7,,,,,2,8,6,a,2,,1c,h,1r,4,1c,7,,,5,,14,9,c,2,w,4,2,2,,3,1k,,,2,3,,,3,1m,8,2,2,48,3,,d,,7,4,,6,,3,2,5i,1m,,5,ek,,5f,x,2da,3,3x,,2o,w,fe,6,2x,2,n9w,4,,a,w,2,28,2,7k,,3,,4,,p,2,5,,47,2,q,i,d,,12,8,p,b,1a,3,1c,,2,4,2,2,13,,1v,6,2,2,2,2,c,,8,,1b,,1f,,,3,2,2,5,2,,,16,2,8,,6m,,2,,4,,fn4,,kh,g,g,g,a6,2,gt,,6a,,45,5,1ae,3,,2,5,4,14,3,4,,4l,2,fx,4,ar,2,49,b,4w,,1i,f,1k,3,1d,4,2,2,1x,3,10,5,,8,1q,,c,2,1g,9,a,4,2,,2n,3,2,,,2,6,,4g,,3,8,l,2,1l,2,,,,,m,,e,7,3,5,5f,8,2,3,,,n,,29,,2,6,,,2,,,2,,2,6j,,2,4,6,2,,2,r,2,2d,8,2,,,2,2y,,,,2,6,,,2t,3,2,4,,5,77,9,,2,6t,,a,2,,,4,,40,4,2,2,4,,w,a,14,6,2,4,8,,9,6,2,3,1a,d,,2,ba,7,,6,,,2a,m,2,7,,2,,2,3e,6,3,,,2,,7,,,20,2,3,,,,9n,2,f0b,5,1n,7,t4,,1r,4,29,,f5k,2,43q,,,3,4,5,8,8,2,7,u,4,44,3,1iz,1j,4,1e,8,,e,,m,5,,f,11s,7,,h,2,7,,2,,5,79,7,c5,4,15s,7,31,7,240,5,gx7k,2o,3k,6o".split(",").map(s => s ? parseInt(s, 36) : 1);
    for (let i = 0, n = 0; i < numbers.length; i++) (i % 2 ? rangeTo : rangeFrom).push(n = n + numbers[i]);
  })();
  function isExtendingChar(code) {
    if (code < 768) return false;
    for (let from = 0, to = rangeFrom.length;;) {
      let mid = from + to >> 1;
      if (code < rangeFrom[mid]) to = mid;else if (code >= rangeTo[mid]) from = mid + 1;else return true;
      if (from == to) return false;
    }
  }
  function isRegionalIndicator(code) {
    return code >= 0x1F1E6 && code <= 0x1F1FF;
  }
  const ZWJ = 0x200d;
  function findClusterBreak$1(str, pos, forward = true, includeExtending = true) {
    return (forward ? nextClusterBreak : prevClusterBreak)(str, pos, includeExtending);
  }
  function nextClusterBreak(str, pos, includeExtending) {
    if (pos == str.length) return pos;
    // If pos is in the middle of a surrogate pair, move to its start
    if (pos && surrogateLow(str.charCodeAt(pos)) && surrogateHigh(str.charCodeAt(pos - 1))) pos--;
    let prev = codePointAt(str, pos);
    pos += codePointSize(prev);
    while (pos < str.length) {
      let next = codePointAt(str, pos);
      if (prev == ZWJ || next == ZWJ || includeExtending && isExtendingChar(next)) {
        pos += codePointSize(next);
        prev = next;
      } else if (isRegionalIndicator(next)) {
        let countBefore = 0,
          i = pos - 2;
        while (i >= 0 && isRegionalIndicator(codePointAt(str, i))) {
          countBefore++;
          i -= 2;
        }
        if (countBefore % 2 == 0) break;else pos += 2;
      } else {
        break;
      }
    }
    return pos;
  }
  function prevClusterBreak(str, pos, includeExtending) {
    while (pos > 0) {
      let found = nextClusterBreak(str, pos - 2, includeExtending);
      if (found < pos) return found;
      pos--;
    }
    return 0;
  }
  function codePointAt(str, pos) {
    let code0 = str.charCodeAt(pos);
    if (!surrogateHigh(code0) || pos + 1 == str.length) return code0;
    let code1 = str.charCodeAt(pos + 1);
    if (!surrogateLow(code1)) return code0;
    return (code0 - 0xd800 << 10) + (code1 - 0xdc00) + 0x10000;
  }
  function surrogateLow(ch) {
    return ch >= 0xDC00 && ch < 0xE000;
  }
  function surrogateHigh(ch) {
    return ch >= 0xD800 && ch < 0xDC00;
  }
  function codePointSize(code) {
    return code < 0x10000 ? 1 : 2;
  }

  /**
  The data structure for documents. @nonabstract
  */
  class Text {
    /**
    Get the line description around the given position.
    */
    lineAt(pos) {
      if (pos < 0 || pos > this.length) throw new RangeError(`Invalid position ${pos} in document of length ${this.length}`);
      return this.lineInner(pos, false, 1, 0);
    }
    /**
    Get the description for the given (1-based) line number.
    */
    line(n) {
      if (n < 1 || n > this.lines) throw new RangeError(`Invalid line number ${n} in ${this.lines}-line document`);
      return this.lineInner(n, true, 1, 0);
    }
    /**
    Replace a range of the text with the given content.
    */
    replace(from, to, text) {
      [from, to] = clip(this, from, to);
      let parts = [];
      this.decompose(0, from, parts, 2 /* Open.To */);
      if (text.length) text.decompose(0, text.length, parts, 1 /* Open.From */ | 2 /* Open.To */);
      this.decompose(to, this.length, parts, 1 /* Open.From */);
      return TextNode.from(parts, this.length - (to - from) + text.length);
    }
    /**
    Append another document to this one.
    */
    append(other) {
      return this.replace(this.length, this.length, other);
    }
    /**
    Retrieve the text between the given points.
    */
    slice(from, to = this.length) {
      [from, to] = clip(this, from, to);
      let parts = [];
      this.decompose(from, to, parts, 0);
      return TextNode.from(parts, to - from);
    }
    /**
    Test whether this text is equal to another instance.
    */
    eq(other) {
      if (other == this) return true;
      if (other.length != this.length || other.lines != this.lines) return false;
      let start = this.scanIdentical(other, 1),
        end = this.length - this.scanIdentical(other, -1);
      let a = new RawTextCursor(this),
        b = new RawTextCursor(other);
      for (let skip = start, pos = start;;) {
        a.next(skip);
        b.next(skip);
        skip = 0;
        if (a.lineBreak != b.lineBreak || a.done != b.done || a.value != b.value) return false;
        pos += a.value.length;
        if (a.done || pos >= end) return true;
      }
    }
    /**
    Iterate over the text. When `dir` is `-1`, iteration happens
    from end to start. This will return lines and the breaks between
    them as separate strings.
    */
    iter(dir = 1) {
      return new RawTextCursor(this, dir);
    }
    /**
    Iterate over a range of the text. When `from` > `to`, the
    iterator will run in reverse.
    */
    iterRange(from, to = this.length) {
      return new PartialTextCursor(this, from, to);
    }
    /**
    Return a cursor that iterates over the given range of lines,
    _without_ returning the line breaks between, and yielding empty
    strings for empty lines.
    
    When `from` and `to` are given, they should be 1-based line numbers.
    */
    iterLines(from, to) {
      let inner;
      if (from == null) {
        inner = this.iter();
      } else {
        if (to == null) to = this.lines + 1;
        let start = this.line(from).from;
        inner = this.iterRange(start, Math.max(start, to == this.lines + 1 ? this.length : to <= 1 ? 0 : this.line(to - 1).to));
      }
      return new LineCursor(inner);
    }
    /**
    Return the document as a string, using newline characters to
    separate lines.
    */
    toString() {
      return this.sliceString(0);
    }
    /**
    Convert the document to an array of lines (which can be
    deserialized again via [`Text.of`](https://codemirror.net/6/docs/ref/#state.Text^of)).
    */
    toJSON() {
      let lines = [];
      this.flatten(lines);
      return lines;
    }
    /**
    @internal
    */
    constructor() {}
    /**
    Create a `Text` instance for the given array of lines.
    */
    static of(text) {
      if (text.length == 0) throw new RangeError("A document must have at least one line");
      if (text.length == 1 && !text[0]) return Text.empty;
      return text.length <= 32 /* Tree.Branch */ ? new TextLeaf(text) : TextNode.from(TextLeaf.split(text, []));
    }
  }
  // Leaves store an array of line strings. There are always line breaks
  // between these strings. Leaves are limited in size and have to be
  // contained in TextNode instances for bigger documents.
  class TextLeaf extends Text {
    constructor(text, length = textLength(text)) {
      super();
      this.text = text;
      this.length = length;
    }
    get lines() {
      return this.text.length;
    }
    get children() {
      return null;
    }
    lineInner(target, isLine, line, offset) {
      for (let i = 0;; i++) {
        let string = this.text[i],
          end = offset + string.length;
        if ((isLine ? line : end) >= target) return new Line(offset, end, line, string);
        offset = end + 1;
        line++;
      }
    }
    decompose(from, to, target, open) {
      let text = from <= 0 && to >= this.length ? this : new TextLeaf(sliceText(this.text, from, to), Math.min(to, this.length) - Math.max(0, from));
      if (open & 1 /* Open.From */) {
        let prev = target.pop();
        let joined = appendText(text.text, prev.text.slice(), 0, text.length);
        if (joined.length <= 32 /* Tree.Branch */) {
          target.push(new TextLeaf(joined, prev.length + text.length));
        } else {
          let mid = joined.length >> 1;
          target.push(new TextLeaf(joined.slice(0, mid)), new TextLeaf(joined.slice(mid)));
        }
      } else {
        target.push(text);
      }
    }
    replace(from, to, text) {
      if (!(text instanceof TextLeaf)) return super.replace(from, to, text);
      [from, to] = clip(this, from, to);
      let lines = appendText(this.text, appendText(text.text, sliceText(this.text, 0, from)), to);
      let newLen = this.length + text.length - (to - from);
      if (lines.length <= 32 /* Tree.Branch */) return new TextLeaf(lines, newLen);
      return TextNode.from(TextLeaf.split(lines, []), newLen);
    }
    sliceString(from, to = this.length, lineSep = "\n") {
      [from, to] = clip(this, from, to);
      let result = "";
      for (let pos = 0, i = 0; pos <= to && i < this.text.length; i++) {
        let line = this.text[i],
          end = pos + line.length;
        if (pos > from && i) result += lineSep;
        if (from < end && to > pos) result += line.slice(Math.max(0, from - pos), to - pos);
        pos = end + 1;
      }
      return result;
    }
    flatten(target) {
      for (let line of this.text) target.push(line);
    }
    scanIdentical() {
      return 0;
    }
    static split(text, target) {
      let part = [],
        len = -1;
      for (let line of text) {
        part.push(line);
        len += line.length + 1;
        if (part.length == 32 /* Tree.Branch */) {
          target.push(new TextLeaf(part, len));
          part = [];
          len = -1;
        }
      }
      if (len > -1) target.push(new TextLeaf(part, len));
      return target;
    }
  }
  // Nodes provide the tree structure of the `Text` type. They store a
  // number of other nodes or leaves, taking care to balance themselves
  // on changes. There are implied line breaks _between_ the children of
  // a node (but not before the first or after the last child).
  class TextNode extends Text {
    constructor(children, length) {
      super();
      this.children = children;
      this.length = length;
      this.lines = 0;
      for (let child of children) this.lines += child.lines;
    }
    lineInner(target, isLine, line, offset) {
      for (let i = 0;; i++) {
        let child = this.children[i],
          end = offset + child.length,
          endLine = line + child.lines - 1;
        if ((isLine ? endLine : end) >= target) return child.lineInner(target, isLine, line, offset);
        offset = end + 1;
        line = endLine + 1;
      }
    }
    decompose(from, to, target, open) {
      for (let i = 0, pos = 0; pos <= to && i < this.children.length; i++) {
        let child = this.children[i],
          end = pos + child.length;
        if (from <= end && to >= pos) {
          let childOpen = open & ((pos <= from ? 1 /* Open.From */ : 0) | (end >= to ? 2 /* Open.To */ : 0));
          if (pos >= from && end <= to && !childOpen) target.push(child);else child.decompose(from - pos, to - pos, target, childOpen);
        }
        pos = end + 1;
      }
    }
    replace(from, to, text) {
      [from, to] = clip(this, from, to);
      if (text.lines < this.lines) for (let i = 0, pos = 0; i < this.children.length; i++) {
        let child = this.children[i],
          end = pos + child.length;
        // Fast path: if the change only affects one child and the
        // child's size remains in the acceptable range, only update
        // that child
        if (from >= pos && to <= end) {
          let updated = child.replace(from - pos, to - pos, text);
          let totalLines = this.lines - child.lines + updated.lines;
          if (updated.lines < totalLines >> 5 /* Tree.BranchShift */ - 1 && updated.lines > totalLines >> 5 /* Tree.BranchShift */ + 1) {
            let copy = this.children.slice();
            copy[i] = updated;
            return new TextNode(copy, this.length - (to - from) + text.length);
          }
          return super.replace(pos, end, updated);
        }
        pos = end + 1;
      }
      return super.replace(from, to, text);
    }
    sliceString(from, to = this.length, lineSep = "\n") {
      [from, to] = clip(this, from, to);
      let result = "";
      for (let i = 0, pos = 0; i < this.children.length && pos <= to; i++) {
        let child = this.children[i],
          end = pos + child.length;
        if (pos > from && i) result += lineSep;
        if (from < end && to > pos) result += child.sliceString(from - pos, to - pos, lineSep);
        pos = end + 1;
      }
      return result;
    }
    flatten(target) {
      for (let child of this.children) child.flatten(target);
    }
    scanIdentical(other, dir) {
      if (!(other instanceof TextNode)) return 0;
      let length = 0;
      let [iA, iB, eA, eB] = dir > 0 ? [0, 0, this.children.length, other.children.length] : [this.children.length - 1, other.children.length - 1, -1, -1];
      for (;; iA += dir, iB += dir) {
        if (iA == eA || iB == eB) return length;
        let chA = this.children[iA],
          chB = other.children[iB];
        if (chA != chB) return length + chA.scanIdentical(chB, dir);
        length += chA.length + 1;
      }
    }
    static from(children, length = children.reduce((l, ch) => l + ch.length + 1, -1)) {
      let lines = 0;
      for (let ch of children) lines += ch.lines;
      if (lines < 32 /* Tree.Branch */) {
        let flat = [];
        for (let ch of children) ch.flatten(flat);
        return new TextLeaf(flat, length);
      }
      let chunk = Math.max(32 /* Tree.Branch */, lines >> 5 /* Tree.BranchShift */),
        maxChunk = chunk << 1,
        minChunk = chunk >> 1;
      let chunked = [],
        currentLines = 0,
        currentLen = -1,
        currentChunk = [];
      function add(child) {
        let last;
        if (child.lines > maxChunk && child instanceof TextNode) {
          for (let node of child.children) add(node);
        } else if (child.lines > minChunk && (currentLines > minChunk || !currentLines)) {
          flush();
          chunked.push(child);
        } else if (child instanceof TextLeaf && currentLines && (last = currentChunk[currentChunk.length - 1]) instanceof TextLeaf && child.lines + last.lines <= 32 /* Tree.Branch */) {
          currentLines += child.lines;
          currentLen += child.length + 1;
          currentChunk[currentChunk.length - 1] = new TextLeaf(last.text.concat(child.text), last.length + 1 + child.length);
        } else {
          if (currentLines + child.lines > chunk) flush();
          currentLines += child.lines;
          currentLen += child.length + 1;
          currentChunk.push(child);
        }
      }
      function flush() {
        if (currentLines == 0) return;
        chunked.push(currentChunk.length == 1 ? currentChunk[0] : TextNode.from(currentChunk, currentLen));
        currentLen = -1;
        currentLines = currentChunk.length = 0;
      }
      for (let child of children) add(child);
      flush();
      return chunked.length == 1 ? chunked[0] : new TextNode(chunked, length);
    }
  }
  Text.empty = /*@__PURE__*/new TextLeaf([""], 0);
  function textLength(text) {
    let length = -1;
    for (let line of text) length += line.length + 1;
    return length;
  }
  function appendText(text, target, from = 0, to = 1e9) {
    for (let pos = 0, i = 0, first = true; i < text.length && pos <= to; i++) {
      let line = text[i],
        end = pos + line.length;
      if (end >= from) {
        if (end > to) line = line.slice(0, to - pos);
        if (pos < from) line = line.slice(from - pos);
        if (first) {
          target[target.length - 1] += line;
          first = false;
        } else target.push(line);
      }
      pos = end + 1;
    }
    return target;
  }
  function sliceText(text, from, to) {
    return appendText(text, [""], from, to);
  }
  class RawTextCursor {
    constructor(text, dir = 1) {
      this.dir = dir;
      this.done = false;
      this.lineBreak = false;
      this.value = "";
      this.nodes = [text];
      this.offsets = [dir > 0 ? 1 : (text instanceof TextLeaf ? text.text.length : text.children.length) << 1];
    }
    nextInner(skip, dir) {
      this.done = this.lineBreak = false;
      for (;;) {
        let last = this.nodes.length - 1;
        let top = this.nodes[last],
          offsetValue = this.offsets[last],
          offset = offsetValue >> 1;
        let size = top instanceof TextLeaf ? top.text.length : top.children.length;
        if (offset == (dir > 0 ? size : 0)) {
          if (last == 0) {
            this.done = true;
            this.value = "";
            return this;
          }
          if (dir > 0) this.offsets[last - 1]++;
          this.nodes.pop();
          this.offsets.pop();
        } else if ((offsetValue & 1) == (dir > 0 ? 0 : 1)) {
          this.offsets[last] += dir;
          if (skip == 0) {
            this.lineBreak = true;
            this.value = "\n";
            return this;
          }
          skip--;
        } else if (top instanceof TextLeaf) {
          // Move to the next string
          let next = top.text[offset + (dir < 0 ? -1 : 0)];
          this.offsets[last] += dir;
          if (next.length > Math.max(0, skip)) {
            this.value = skip == 0 ? next : dir > 0 ? next.slice(skip) : next.slice(0, next.length - skip);
            return this;
          }
          skip -= next.length;
        } else {
          let next = top.children[offset + (dir < 0 ? -1 : 0)];
          if (skip > next.length) {
            skip -= next.length;
            this.offsets[last] += dir;
          } else {
            if (dir < 0) this.offsets[last]--;
            this.nodes.push(next);
            this.offsets.push(dir > 0 ? 1 : (next instanceof TextLeaf ? next.text.length : next.children.length) << 1);
          }
        }
      }
    }
    next(skip = 0) {
      if (skip < 0) {
        this.nextInner(-skip, -this.dir);
        skip = this.value.length;
      }
      return this.nextInner(skip, this.dir);
    }
  }
  class PartialTextCursor {
    constructor(text, start, end) {
      this.value = "";
      this.done = false;
      this.cursor = new RawTextCursor(text, start > end ? -1 : 1);
      this.pos = start > end ? text.length : 0;
      this.from = Math.min(start, end);
      this.to = Math.max(start, end);
    }
    nextInner(skip, dir) {
      if (dir < 0 ? this.pos <= this.from : this.pos >= this.to) {
        this.value = "";
        this.done = true;
        return this;
      }
      skip += Math.max(0, dir < 0 ? this.pos - this.to : this.from - this.pos);
      let limit = dir < 0 ? this.pos - this.from : this.to - this.pos;
      if (skip > limit) skip = limit;
      limit -= skip;
      let {
        value
      } = this.cursor.next(skip);
      this.pos += (value.length + skip) * dir;
      this.value = value.length <= limit ? value : dir < 0 ? value.slice(value.length - limit) : value.slice(0, limit);
      this.done = !this.value;
      return this;
    }
    next(skip = 0) {
      if (skip < 0) skip = Math.max(skip, this.from - this.pos);else if (skip > 0) skip = Math.min(skip, this.to - this.pos);
      return this.nextInner(skip, this.cursor.dir);
    }
    get lineBreak() {
      return this.cursor.lineBreak && this.value != "";
    }
  }
  class LineCursor {
    constructor(inner) {
      this.inner = inner;
      this.afterBreak = true;
      this.value = "";
      this.done = false;
    }
    next(skip = 0) {
      let {
        done,
        lineBreak,
        value
      } = this.inner.next(skip);
      if (done && this.afterBreak) {
        this.value = "";
        this.afterBreak = false;
      } else if (done) {
        this.done = true;
        this.value = "";
      } else if (lineBreak) {
        if (this.afterBreak) {
          this.value = "";
        } else {
          this.afterBreak = true;
          this.next();
        }
      } else {
        this.value = value;
        this.afterBreak = false;
      }
      return this;
    }
    get lineBreak() {
      return false;
    }
  }
  if (typeof Symbol != "undefined") {
    Text.prototype[Symbol.iterator] = function () {
      return this.iter();
    };
    RawTextCursor.prototype[Symbol.iterator] = PartialTextCursor.prototype[Symbol.iterator] = LineCursor.prototype[Symbol.iterator] = function () {
      return this;
    };
  }
  /**
  This type describes a line in the document. It is created
  on-demand when lines are [queried](https://codemirror.net/6/docs/ref/#state.Text.lineAt).
  */
  class Line {
    /**
    @internal
    */
    constructor(
    /**
    The position of the start of the line.
    */
    from,
    /**
    The position at the end of the line (_before_ the line break,
    or at the end of document for the last line).
    */
    to,
    /**
    This line's line number (1-based).
    */
    number,
    /**
    The line's content.
    */
    text) {
      this.from = from;
      this.to = to;
      this.number = number;
      this.text = text;
    }
    /**
    The length of the line (not including any line break after it).
    */
    get length() {
      return this.to - this.from;
    }
  }
  function clip(text, from, to) {
    from = Math.max(0, Math.min(text.length, from));
    return [from, Math.max(from, Math.min(text.length, to))];
  }

  /**
  Returns a next grapheme cluster break _after_ (not equal to)
  `pos`, if `forward` is true, or before otherwise. Returns `pos`
  itself if no further cluster break is available in the string.
  Moves across surrogate pairs, extending characters (when
  `includeExtending` is true), characters joined with zero-width
  joiners, and flag emoji.
  */
  function findClusterBreak(str, pos, forward = true, includeExtending = true) {
    return findClusterBreak$1(str, pos, forward, includeExtending);
  }
  const DefaultSplit = /\r\n?|\n/;
  /**
  Distinguishes different ways in which positions can be mapped.
  */
  var MapMode = /*@__PURE__*/function (MapMode) {
    /**
    Map a position to a valid new position, even when its context
    was deleted.
    */
    MapMode[MapMode["Simple"] = 0] = "Simple";
    /**
    Return null if deletion happens across the position.
    */
    MapMode[MapMode["TrackDel"] = 1] = "TrackDel";
    /**
    Return null if the character _before_ the position is deleted.
    */
    MapMode[MapMode["TrackBefore"] = 2] = "TrackBefore";
    /**
    Return null if the character _after_ the position is deleted.
    */
    MapMode[MapMode["TrackAfter"] = 3] = "TrackAfter";
    return MapMode;
  }(MapMode || (MapMode = {}));
  /**
  A change description is a variant of [change set](https://codemirror.net/6/docs/ref/#state.ChangeSet)
  that doesn't store the inserted text. As such, it can't be
  applied, but is cheaper to store and manipulate.
  */
  class ChangeDesc {
    // Sections are encoded as pairs of integers. The first is the
    // length in the current document, and the second is -1 for
    // unaffected sections, and the length of the replacement content
    // otherwise. So an insertion would be (0, n>0), a deletion (n>0,
    // 0), and a replacement two positive numbers.
    /**
    @internal
    */
    constructor(
    /**
    @internal
    */
    sections) {
      this.sections = sections;
    }
    /**
    The length of the document before the change.
    */
    get length() {
      let result = 0;
      for (let i = 0; i < this.sections.length; i += 2) result += this.sections[i];
      return result;
    }
    /**
    The length of the document after the change.
    */
    get newLength() {
      let result = 0;
      for (let i = 0; i < this.sections.length; i += 2) {
        let ins = this.sections[i + 1];
        result += ins < 0 ? this.sections[i] : ins;
      }
      return result;
    }
    /**
    False when there are actual changes in this set.
    */
    get empty() {
      return this.sections.length == 0 || this.sections.length == 2 && this.sections[1] < 0;
    }
    /**
    Iterate over the unchanged parts left by these changes. `posA`
    provides the position of the range in the old document, `posB`
    the new position in the changed document.
    */
    iterGaps(f) {
      for (let i = 0, posA = 0, posB = 0; i < this.sections.length;) {
        let len = this.sections[i++],
          ins = this.sections[i++];
        if (ins < 0) {
          f(posA, posB, len);
          posB += len;
        } else {
          posB += ins;
        }
        posA += len;
      }
    }
    /**
    Iterate over the ranges changed by these changes. (See
    [`ChangeSet.iterChanges`](https://codemirror.net/6/docs/ref/#state.ChangeSet.iterChanges) for a
    variant that also provides you with the inserted text.)
    `fromA`/`toA` provides the extent of the change in the starting
    document, `fromB`/`toB` the extent of the replacement in the
    changed document.
    
    When `individual` is true, adjacent changes (which are kept
    separate for [position mapping](https://codemirror.net/6/docs/ref/#state.ChangeDesc.mapPos)) are
    reported separately.
    */
    iterChangedRanges(f, individual = false) {
      iterChanges(this, f, individual);
    }
    /**
    Get a description of the inverted form of these changes.
    */
    get invertedDesc() {
      let sections = [];
      for (let i = 0; i < this.sections.length;) {
        let len = this.sections[i++],
          ins = this.sections[i++];
        if (ins < 0) sections.push(len, ins);else sections.push(ins, len);
      }
      return new ChangeDesc(sections);
    }
    /**
    Compute the combined effect of applying another set of changes
    after this one. The length of the document after this set should
    match the length before `other`.
    */
    composeDesc(other) {
      return this.empty ? other : other.empty ? this : composeSets(this, other);
    }
    /**
    Map this description, which should start with the same document
    as `other`, over another set of changes, so that it can be
    applied after it. When `before` is true, map as if the changes
    in `this` happened before the ones in `other`.
    */
    mapDesc(other, before = false) {
      return other.empty ? this : mapSet(this, other, before);
    }
    mapPos(pos, assoc = -1, mode = MapMode.Simple) {
      let posA = 0,
        posB = 0;
      for (let i = 0; i < this.sections.length;) {
        let len = this.sections[i++],
          ins = this.sections[i++],
          endA = posA + len;
        if (ins < 0) {
          if (endA > pos) return posB + (pos - posA);
          posB += len;
        } else {
          if (mode != MapMode.Simple && endA >= pos && (mode == MapMode.TrackDel && posA < pos && endA > pos || mode == MapMode.TrackBefore && posA < pos || mode == MapMode.TrackAfter && endA > pos)) return null;
          if (endA > pos || endA == pos && assoc < 0 && !len) return pos == posA || assoc < 0 ? posB : posB + ins;
          posB += ins;
        }
        posA = endA;
      }
      if (pos > posA) throw new RangeError(`Position ${pos} is out of range for changeset of length ${posA}`);
      return posB;
    }
    /**
    Check whether these changes touch a given range. When one of the
    changes entirely covers the range, the string `"cover"` is
    returned.
    */
    touchesRange(from, to = from) {
      for (let i = 0, pos = 0; i < this.sections.length && pos <= to;) {
        let len = this.sections[i++],
          ins = this.sections[i++],
          end = pos + len;
        if (ins >= 0 && pos <= to && end >= from) return pos < from && end > to ? "cover" : true;
        pos = end;
      }
      return false;
    }
    /**
    @internal
    */
    toString() {
      let result = "";
      for (let i = 0; i < this.sections.length;) {
        let len = this.sections[i++],
          ins = this.sections[i++];
        result += (result ? " " : "") + len + (ins >= 0 ? ":" + ins : "");
      }
      return result;
    }
    /**
    Serialize this change desc to a JSON-representable value.
    */
    toJSON() {
      return this.sections;
    }
    /**
    Create a change desc from its JSON representation (as produced
    by [`toJSON`](https://codemirror.net/6/docs/ref/#state.ChangeDesc.toJSON).
    */
    static fromJSON(json) {
      if (!Array.isArray(json) || json.length % 2 || json.some(a => typeof a != "number")) throw new RangeError("Invalid JSON representation of ChangeDesc");
      return new ChangeDesc(json);
    }
    /**
    @internal
    */
    static create(sections) {
      return new ChangeDesc(sections);
    }
  }
  /**
  A change set represents a group of modifications to a document. It
  stores the document length, and can only be applied to documents
  with exactly that length.
  */
  class ChangeSet extends ChangeDesc {
    constructor(sections,
    /**
    @internal
    */
    inserted) {
      super(sections);
      this.inserted = inserted;
    }
    /**
    Apply the changes to a document, returning the modified
    document.
    */
    apply(doc) {
      if (this.length != doc.length) throw new RangeError("Applying change set to a document with the wrong length");
      iterChanges(this, (fromA, toA, fromB, _toB, text) => doc = doc.replace(fromB, fromB + (toA - fromA), text), false);
      return doc;
    }
    mapDesc(other, before = false) {
      return mapSet(this, other, before, true);
    }
    /**
    Given the document as it existed _before_ the changes, return a
    change set that represents the inverse of this set, which could
    be used to go from the document created by the changes back to
    the document as it existed before the changes.
    */
    invert(doc) {
      let sections = this.sections.slice(),
        inserted = [];
      for (let i = 0, pos = 0; i < sections.length; i += 2) {
        let len = sections[i],
          ins = sections[i + 1];
        if (ins >= 0) {
          sections[i] = ins;
          sections[i + 1] = len;
          let index = i >> 1;
          while (inserted.length < index) inserted.push(Text.empty);
          inserted.push(len ? doc.slice(pos, pos + len) : Text.empty);
        }
        pos += len;
      }
      return new ChangeSet(sections, inserted);
    }
    /**
    Combine two subsequent change sets into a single set. `other`
    must start in the document produced by `this`. If `this` goes
    `docA` → `docB` and `other` represents `docB` → `docC`, the
    returned value will represent the change `docA` → `docC`.
    */
    compose(other) {
      return this.empty ? other : other.empty ? this : composeSets(this, other, true);
    }
    /**
    Given another change set starting in the same document, maps this
    change set over the other, producing a new change set that can be
    applied to the document produced by applying `other`. When
    `before` is `true`, order changes as if `this` comes before
    `other`, otherwise (the default) treat `other` as coming first.
    
    Given two changes `A` and `B`, `A.compose(B.map(A))` and
    `B.compose(A.map(B, true))` will produce the same document. This
    provides a basic form of [operational
    transformation](https://en.wikipedia.org/wiki/Operational_transformation),
    and can be used for collaborative editing.
    */
    map(other, before = false) {
      return other.empty ? this : mapSet(this, other, before, true);
    }
    /**
    Iterate over the changed ranges in the document, calling `f` for
    each, with the range in the original document (`fromA`-`toA`)
    and the range that replaces it in the new document
    (`fromB`-`toB`).
    
    When `individual` is true, adjacent changes are reported
    separately.
    */
    iterChanges(f, individual = false) {
      iterChanges(this, f, individual);
    }
    /**
    Get a [change description](https://codemirror.net/6/docs/ref/#state.ChangeDesc) for this change
    set.
    */
    get desc() {
      return ChangeDesc.create(this.sections);
    }
    /**
    @internal
    */
    filter(ranges) {
      let resultSections = [],
        resultInserted = [],
        filteredSections = [];
      let iter = new SectionIter(this);
      done: for (let i = 0, pos = 0;;) {
        let next = i == ranges.length ? 1e9 : ranges[i++];
        while (pos < next || pos == next && iter.len == 0) {
          if (iter.done) break done;
          let len = Math.min(iter.len, next - pos);
          addSection(filteredSections, len, -1);
          let ins = iter.ins == -1 ? -1 : iter.off == 0 ? iter.ins : 0;
          addSection(resultSections, len, ins);
          if (ins > 0) addInsert(resultInserted, resultSections, iter.text);
          iter.forward(len);
          pos += len;
        }
        let end = ranges[i++];
        while (pos < end) {
          if (iter.done) break done;
          let len = Math.min(iter.len, end - pos);
          addSection(resultSections, len, -1);
          addSection(filteredSections, len, iter.ins == -1 ? -1 : iter.off == 0 ? iter.ins : 0);
          iter.forward(len);
          pos += len;
        }
      }
      return {
        changes: new ChangeSet(resultSections, resultInserted),
        filtered: ChangeDesc.create(filteredSections)
      };
    }
    /**
    Serialize this change set to a JSON-representable value.
    */
    toJSON() {
      let parts = [];
      for (let i = 0; i < this.sections.length; i += 2) {
        let len = this.sections[i],
          ins = this.sections[i + 1];
        if (ins < 0) parts.push(len);else if (ins == 0) parts.push([len]);else parts.push([len].concat(this.inserted[i >> 1].toJSON()));
      }
      return parts;
    }
    /**
    Create a change set for the given changes, for a document of the
    given length, using `lineSep` as line separator.
    */
    static of(changes, length, lineSep) {
      let sections = [],
        inserted = [],
        pos = 0;
      let total = null;
      function flush(force = false) {
        if (!force && !sections.length) return;
        if (pos < length) addSection(sections, length - pos, -1);
        let set = new ChangeSet(sections, inserted);
        total = total ? total.compose(set.map(total)) : set;
        sections = [];
        inserted = [];
        pos = 0;
      }
      function process(spec) {
        if (Array.isArray(spec)) {
          for (let sub of spec) process(sub);
        } else if (spec instanceof ChangeSet) {
          if (spec.length != length) throw new RangeError(`Mismatched change set length (got ${spec.length}, expected ${length})`);
          flush();
          total = total ? total.compose(spec.map(total)) : spec;
        } else {
          let {
            from,
            to = from,
            insert
          } = spec;
          if (from > to || from < 0 || to > length) throw new RangeError(`Invalid change range ${from} to ${to} (in doc of length ${length})`);
          let insText = !insert ? Text.empty : typeof insert == "string" ? Text.of(insert.split(lineSep || DefaultSplit)) : insert;
          let insLen = insText.length;
          if (from == to && insLen == 0) return;
          if (from < pos) flush();
          if (from > pos) addSection(sections, from - pos, -1);
          addSection(sections, to - from, insLen);
          addInsert(inserted, sections, insText);
          pos = to;
        }
      }
      process(changes);
      flush(!total);
      return total;
    }
    /**
    Create an empty changeset of the given length.
    */
    static empty(length) {
      return new ChangeSet(length ? [length, -1] : [], []);
    }
    /**
    Create a changeset from its JSON representation (as produced by
    [`toJSON`](https://codemirror.net/6/docs/ref/#state.ChangeSet.toJSON).
    */
    static fromJSON(json) {
      if (!Array.isArray(json)) throw new RangeError("Invalid JSON representation of ChangeSet");
      let sections = [],
        inserted = [];
      for (let i = 0; i < json.length; i++) {
        let part = json[i];
        if (typeof part == "number") {
          sections.push(part, -1);
        } else if (!Array.isArray(part) || typeof part[0] != "number" || part.some((e, i) => i && typeof e != "string")) {
          throw new RangeError("Invalid JSON representation of ChangeSet");
        } else if (part.length == 1) {
          sections.push(part[0], 0);
        } else {
          while (inserted.length < i) inserted.push(Text.empty);
          inserted[i] = Text.of(part.slice(1));
          sections.push(part[0], inserted[i].length);
        }
      }
      return new ChangeSet(sections, inserted);
    }
    /**
    @internal
    */
    static createSet(sections, inserted) {
      return new ChangeSet(sections, inserted);
    }
  }
  function addSection(sections, len, ins, forceJoin = false) {
    if (len == 0 && ins <= 0) return;
    let last = sections.length - 2;
    if (last >= 0 && ins <= 0 && ins == sections[last + 1]) sections[last] += len;else if (last >= 0 && len == 0 && sections[last] == 0) sections[last + 1] += ins;else if (forceJoin) {
      sections[last] += len;
      sections[last + 1] += ins;
    } else sections.push(len, ins);
  }
  function addInsert(values, sections, value) {
    if (value.length == 0) return;
    let index = sections.length - 2 >> 1;
    if (index < values.length) {
      values[values.length - 1] = values[values.length - 1].append(value);
    } else {
      while (values.length < index) values.push(Text.empty);
      values.push(value);
    }
  }
  function iterChanges(desc, f, individual) {
    let inserted = desc.inserted;
    for (let posA = 0, posB = 0, i = 0; i < desc.sections.length;) {
      let len = desc.sections[i++],
        ins = desc.sections[i++];
      if (ins < 0) {
        posA += len;
        posB += len;
      } else {
        let endA = posA,
          endB = posB,
          text = Text.empty;
        for (;;) {
          endA += len;
          endB += ins;
          if (ins && inserted) text = text.append(inserted[i - 2 >> 1]);
          if (individual || i == desc.sections.length || desc.sections[i + 1] < 0) break;
          len = desc.sections[i++];
          ins = desc.sections[i++];
        }
        f(posA, endA, posB, endB, text);
        posA = endA;
        posB = endB;
      }
    }
  }
  function mapSet(setA, setB, before, mkSet = false) {
    // Produce a copy of setA that applies to the document after setB
    // has been applied (assuming both start at the same document).
    let sections = [],
      insert = mkSet ? [] : null;
    let a = new SectionIter(setA),
      b = new SectionIter(setB);
    // Iterate over both sets in parallel. inserted tracks, for changes
    // in A that have to be processed piece-by-piece, whether their
    // content has been inserted already, and refers to the section
    // index.
    for (let inserted = -1;;) {
      if (a.done && b.len || b.done && a.len) {
        throw new Error("Mismatched change set lengths");
      } else if (a.ins == -1 && b.ins == -1) {
        // Move across ranges skipped by both sets.
        let len = Math.min(a.len, b.len);
        addSection(sections, len, -1);
        a.forward(len);
        b.forward(len);
      } else if (b.ins >= 0 && (a.ins < 0 || inserted == a.i || a.off == 0 && (b.len < a.len || b.len == a.len && !before))) {
        // If there's a change in B that comes before the next change in
        // A (ordered by start pos, then len, then before flag), skip
        // that (and process any changes in A it covers).
        let len = b.len;
        addSection(sections, b.ins, -1);
        while (len) {
          let piece = Math.min(a.len, len);
          if (a.ins >= 0 && inserted < a.i && a.len <= piece) {
            addSection(sections, 0, a.ins);
            if (insert) addInsert(insert, sections, a.text);
            inserted = a.i;
          }
          a.forward(piece);
          len -= piece;
        }
        b.next();
      } else if (a.ins >= 0) {
        // Process the part of a change in A up to the start of the next
        // non-deletion change in B (if overlapping).
        let len = 0,
          left = a.len;
        while (left) {
          if (b.ins == -1) {
            let piece = Math.min(left, b.len);
            len += piece;
            left -= piece;
            b.forward(piece);
          } else if (b.ins == 0 && b.len < left) {
            left -= b.len;
            b.next();
          } else {
            break;
          }
        }
        addSection(sections, len, inserted < a.i ? a.ins : 0);
        if (insert && inserted < a.i) addInsert(insert, sections, a.text);
        inserted = a.i;
        a.forward(a.len - left);
      } else if (a.done && b.done) {
        return insert ? ChangeSet.createSet(sections, insert) : ChangeDesc.create(sections);
      } else {
        throw new Error("Mismatched change set lengths");
      }
    }
  }
  function composeSets(setA, setB, mkSet = false) {
    let sections = [];
    let insert = mkSet ? [] : null;
    let a = new SectionIter(setA),
      b = new SectionIter(setB);
    for (let open = false;;) {
      if (a.done && b.done) {
        return insert ? ChangeSet.createSet(sections, insert) : ChangeDesc.create(sections);
      } else if (a.ins == 0) {
        // Deletion in A
        addSection(sections, a.len, 0, open);
        a.next();
      } else if (b.len == 0 && !b.done) {
        // Insertion in B
        addSection(sections, 0, b.ins, open);
        if (insert) addInsert(insert, sections, b.text);
        b.next();
      } else if (a.done || b.done) {
        throw new Error("Mismatched change set lengths");
      } else {
        let len = Math.min(a.len2, b.len),
          sectionLen = sections.length;
        if (a.ins == -1) {
          let insB = b.ins == -1 ? -1 : b.off ? 0 : b.ins;
          addSection(sections, len, insB, open);
          if (insert && insB) addInsert(insert, sections, b.text);
        } else if (b.ins == -1) {
          addSection(sections, a.off ? 0 : a.len, len, open);
          if (insert) addInsert(insert, sections, a.textBit(len));
        } else {
          addSection(sections, a.off ? 0 : a.len, b.off ? 0 : b.ins, open);
          if (insert && !b.off) addInsert(insert, sections, b.text);
        }
        open = (a.ins > len || b.ins >= 0 && b.len > len) && (open || sections.length > sectionLen);
        a.forward2(len);
        b.forward(len);
      }
    }
  }
  class SectionIter {
    constructor(set) {
      this.set = set;
      this.i = 0;
      this.next();
    }
    next() {
      let {
        sections
      } = this.set;
      if (this.i < sections.length) {
        this.len = sections[this.i++];
        this.ins = sections[this.i++];
      } else {
        this.len = 0;
        this.ins = -2;
      }
      this.off = 0;
    }
    get done() {
      return this.ins == -2;
    }
    get len2() {
      return this.ins < 0 ? this.len : this.ins;
    }
    get text() {
      let {
          inserted
        } = this.set,
        index = this.i - 2 >> 1;
      return index >= inserted.length ? Text.empty : inserted[index];
    }
    textBit(len) {
      let {
          inserted
        } = this.set,
        index = this.i - 2 >> 1;
      return index >= inserted.length && !len ? Text.empty : inserted[index].slice(this.off, len == null ? undefined : this.off + len);
    }
    forward(len) {
      if (len == this.len) this.next();else {
        this.len -= len;
        this.off += len;
      }
    }
    forward2(len) {
      if (this.ins == -1) this.forward(len);else if (len == this.ins) this.next();else {
        this.ins -= len;
        this.off += len;
      }
    }
  }

  /**
  A single selection range. When
  [`allowMultipleSelections`](https://codemirror.net/6/docs/ref/#state.EditorState^allowMultipleSelections)
  is enabled, a [selection](https://codemirror.net/6/docs/ref/#state.EditorSelection) may hold
  multiple ranges. By default, selections hold exactly one range.
  */
  class SelectionRange {
    constructor(
    /**
    The lower boundary of the range.
    */
    from,
    /**
    The upper boundary of the range.
    */
    to, flags) {
      this.from = from;
      this.to = to;
      this.flags = flags;
    }
    /**
    The anchor of the range—the side that doesn't move when you
    extend it.
    */
    get anchor() {
      return this.flags & 32 /* RangeFlag.Inverted */ ? this.to : this.from;
    }
    /**
    The head of the range, which is moved when the range is
    [extended](https://codemirror.net/6/docs/ref/#state.SelectionRange.extend).
    */
    get head() {
      return this.flags & 32 /* RangeFlag.Inverted */ ? this.from : this.to;
    }
    /**
    True when `anchor` and `head` are at the same position.
    */
    get empty() {
      return this.from == this.to;
    }
    /**
    If this is a cursor that is explicitly associated with the
    character on one of its sides, this returns the side. -1 means
    the character before its position, 1 the character after, and 0
    means no association.
    */
    get assoc() {
      return this.flags & 8 /* RangeFlag.AssocBefore */ ? -1 : this.flags & 16 /* RangeFlag.AssocAfter */ ? 1 : 0;
    }
    /**
    The bidirectional text level associated with this cursor, if
    any.
    */
    get bidiLevel() {
      let level = this.flags & 7 /* RangeFlag.BidiLevelMask */;
      return level == 7 ? null : level;
    }
    /**
    The goal column (stored vertical offset) associated with a
    cursor. This is used to preserve the vertical position when
    [moving](https://codemirror.net/6/docs/ref/#view.EditorView.moveVertically) across
    lines of different length.
    */
    get goalColumn() {
      let value = this.flags >> 6 /* RangeFlag.GoalColumnOffset */;
      return value == 16777215 /* RangeFlag.NoGoalColumn */ ? undefined : value;
    }
    /**
    Map this range through a change, producing a valid range in the
    updated document.
    */
    map(change, assoc = -1) {
      let from, to;
      if (this.empty) {
        from = to = change.mapPos(this.from, assoc);
      } else {
        from = change.mapPos(this.from, 1);
        to = change.mapPos(this.to, -1);
      }
      return from == this.from && to == this.to ? this : new SelectionRange(from, to, this.flags);
    }
    /**
    Extend this range to cover at least `from` to `to`.
    */
    extend(from, to = from, assoc = 0) {
      if (from <= this.anchor && to >= this.anchor) return EditorSelection.range(from, to, undefined, undefined, assoc);
      let head = Math.abs(from - this.anchor) > Math.abs(to - this.anchor) ? from : to;
      return EditorSelection.range(this.anchor, head, undefined, undefined, assoc);
    }
    /**
    Compare this range to another range.
    */
    eq(other, includeAssoc = false) {
      return this.anchor == other.anchor && this.head == other.head && this.goalColumn == other.goalColumn && (!includeAssoc || !this.empty || this.assoc == other.assoc);
    }
    /**
    Return a JSON-serializable object representing the range.
    */
    toJSON() {
      return {
        anchor: this.anchor,
        head: this.head
      };
    }
    /**
    Convert a JSON representation of a range to a `SelectionRange`
    instance.
    */
    static fromJSON(json) {
      if (!json || typeof json.anchor != "number" || typeof json.head != "number") throw new RangeError("Invalid JSON representation for SelectionRange");
      return EditorSelection.range(json.anchor, json.head);
    }
    /**
    @internal
    */
    static create(from, to, flags) {
      return new SelectionRange(from, to, flags);
    }
  }
  /**
  An editor selection holds one or more selection ranges.
  */
  class EditorSelection {
    constructor(
    /**
    The ranges in the selection, sorted by position. Ranges cannot
    overlap (but they may touch, if they aren't empty).
    */
    ranges,
    /**
    The index of the _main_ range in the selection (which is
    usually the range that was added last).
    */
    mainIndex) {
      this.ranges = ranges;
      this.mainIndex = mainIndex;
    }
    /**
    Map a selection through a change. Used to adjust the selection
    position for changes.
    */
    map(change, assoc = -1) {
      if (change.empty) return this;
      return EditorSelection.create(this.ranges.map(r => r.map(change, assoc)), this.mainIndex);
    }
    /**
    Compare this selection to another selection. By default, ranges
    are compared only by position. When `includeAssoc` is true,
    cursor ranges must also have the same
    [`assoc`](https://codemirror.net/6/docs/ref/#state.SelectionRange.assoc) value.
    */
    eq(other, includeAssoc = false) {
      if (this.ranges.length != other.ranges.length || this.mainIndex != other.mainIndex) return false;
      for (let i = 0; i < this.ranges.length; i++) if (!this.ranges[i].eq(other.ranges[i], includeAssoc)) return false;
      return true;
    }
    /**
    Get the primary selection range. Usually, you should make sure
    your code applies to _all_ ranges, by using methods like
    [`changeByRange`](https://codemirror.net/6/docs/ref/#state.EditorState.changeByRange).
    */
    get main() {
      return this.ranges[this.mainIndex];
    }
    /**
    Make sure the selection only has one range. Returns a selection
    holding only the main range from this selection.
    */
    asSingle() {
      return this.ranges.length == 1 ? this : new EditorSelection([this.main], 0);
    }
    /**
    Extend this selection with an extra range.
    */
    addRange(range, main = true) {
      return EditorSelection.create([range].concat(this.ranges), main ? 0 : this.mainIndex + 1);
    }
    /**
    Replace a given range with another range, and then normalize the
    selection to merge and sort ranges if necessary.
    */
    replaceRange(range, which = this.mainIndex) {
      let ranges = this.ranges.slice();
      ranges[which] = range;
      return EditorSelection.create(ranges, this.mainIndex);
    }
    /**
    Convert this selection to an object that can be serialized to
    JSON.
    */
    toJSON() {
      return {
        ranges: this.ranges.map(r => r.toJSON()),
        main: this.mainIndex
      };
    }
    /**
    Create a selection from a JSON representation.
    */
    static fromJSON(json) {
      if (!json || !Array.isArray(json.ranges) || typeof json.main != "number" || json.main >= json.ranges.length) throw new RangeError("Invalid JSON representation for EditorSelection");
      return new EditorSelection(json.ranges.map(r => SelectionRange.fromJSON(r)), json.main);
    }
    /**
    Create a selection holding a single range.
    */
    static single(anchor, head = anchor) {
      return new EditorSelection([EditorSelection.range(anchor, head)], 0);
    }
    /**
    Sort and merge the given set of ranges, creating a valid
    selection.
    */
    static create(ranges, mainIndex = 0) {
      if (ranges.length == 0) throw new RangeError("A selection needs at least one range");
      for (let pos = 0, i = 0; i < ranges.length; i++) {
        let range = ranges[i];
        if (range.empty ? range.from <= pos : range.from < pos) return EditorSelection.normalized(ranges.slice(), mainIndex);
        pos = range.to;
      }
      return new EditorSelection(ranges, mainIndex);
    }
    /**
    Create a cursor selection range at the given position. You can
    safely ignore the optional arguments in most situations.
    */
    static cursor(pos, assoc = 0, bidiLevel, goalColumn) {
      return SelectionRange.create(pos, pos, (assoc == 0 ? 0 : assoc < 0 ? 8 /* RangeFlag.AssocBefore */ : 16 /* RangeFlag.AssocAfter */) | (bidiLevel == null ? 7 : Math.min(6, bidiLevel)) | (goalColumn !== null && goalColumn !== void 0 ? goalColumn : 16777215 /* RangeFlag.NoGoalColumn */) << 6 /* RangeFlag.GoalColumnOffset */);
    }
    /**
    Create a selection range.
    */
    static range(anchor, head, goalColumn, bidiLevel, assoc) {
      let flags = (goalColumn !== null && goalColumn !== void 0 ? goalColumn : 16777215 /* RangeFlag.NoGoalColumn */) << 6 /* RangeFlag.GoalColumnOffset */ | (bidiLevel == null ? 7 : Math.min(6, bidiLevel));
      if (!assoc && anchor != head) assoc = head < anchor ? 1 : -1;
      return head < anchor ? SelectionRange.create(head, anchor, 32 /* RangeFlag.Inverted */ | 16 /* RangeFlag.AssocAfter */ | flags) : SelectionRange.create(anchor, head, (!assoc ? 0 : assoc < 0 ? 8 /* RangeFlag.AssocBefore */ : 16 /* RangeFlag.AssocAfter */) | flags);
    }
    /**
    @internal
    */
    static normalized(ranges, mainIndex = 0) {
      let main = ranges[mainIndex];
      ranges.sort((a, b) => a.from - b.from);
      mainIndex = ranges.indexOf(main);
      for (let i = 1; i < ranges.length; i++) {
        let range = ranges[i],
          prev = ranges[i - 1];
        if (range.empty ? range.from <= prev.to : range.from < prev.to) {
          let from = prev.from,
            to = Math.max(range.to, prev.to);
          if (i <= mainIndex) mainIndex--;
          ranges.splice(--i, 2, range.anchor > range.head ? EditorSelection.range(to, from) : EditorSelection.range(from, to));
        }
      }
      return new EditorSelection(ranges, mainIndex);
    }
  }
  function checkSelection(selection, docLength) {
    for (let range of selection.ranges) if (range.to > docLength) throw new RangeError("Selection points outside of document");
  }
  let nextID = 0;
  /**
  A facet is a labeled value that is associated with an editor
  state. It takes inputs from any number of extensions, and combines
  those into a single output value.

  Examples of uses of facets are the [tab
  size](https://codemirror.net/6/docs/ref/#state.EditorState^tabSize), [editor
  attributes](https://codemirror.net/6/docs/ref/#view.EditorView^editorAttributes), and [update
  listeners](https://codemirror.net/6/docs/ref/#view.EditorView^updateListener).

  Note that `Facet` instances can be used anywhere where
  [`FacetReader`](https://codemirror.net/6/docs/ref/#state.FacetReader) is expected.
  */
  class Facet {
    constructor(
    /**
    @internal
    */
    combine,
    /**
    @internal
    */
    compareInput,
    /**
    @internal
    */
    compare, isStatic, enables) {
      this.combine = combine;
      this.compareInput = compareInput;
      this.compare = compare;
      this.isStatic = isStatic;
      /**
      @internal
      */
      this.id = nextID++;
      this.default = combine([]);
      this.extensions = typeof enables == "function" ? enables(this) : enables;
    }
    /**
    Returns a facet reader for this facet, which can be used to
    [read](https://codemirror.net/6/docs/ref/#state.EditorState.facet) it but not to define values for it.
    */
    get reader() {
      return this;
    }
    /**
    Define a new facet.
    */
    static define(config = {}) {
      return new Facet(config.combine || (a => a), config.compareInput || ((a, b) => a === b), config.compare || (!config.combine ? sameArray$1 : (a, b) => a === b), !!config.static, config.enables);
    }
    /**
    Returns an extension that adds the given value to this facet.
    */
    of(value) {
      return new FacetProvider([], this, 0 /* Provider.Static */, value);
    }
    /**
    Create an extension that computes a value for the facet from a
    state. You must take care to declare the parts of the state that
    this value depends on, since your function is only called again
    for a new state when one of those parts changed.
    
    In cases where your value depends only on a single field, you'll
    want to use the [`from`](https://codemirror.net/6/docs/ref/#state.Facet.from) method instead.
    */
    compute(deps, get) {
      if (this.isStatic) throw new Error("Can't compute a static facet");
      return new FacetProvider(deps, this, 1 /* Provider.Single */, get);
    }
    /**
    Create an extension that computes zero or more values for this
    facet from a state.
    */
    computeN(deps, get) {
      if (this.isStatic) throw new Error("Can't compute a static facet");
      return new FacetProvider(deps, this, 2 /* Provider.Multi */, get);
    }
    from(field, get) {
      if (!get) get = x => x;
      return this.compute([field], state => get(state.field(field)));
    }
  }
  function sameArray$1(a, b) {
    return a == b || a.length == b.length && a.every((e, i) => e === b[i]);
  }
  class FacetProvider {
    constructor(dependencies, facet, type, value) {
      this.dependencies = dependencies;
      this.facet = facet;
      this.type = type;
      this.value = value;
      this.id = nextID++;
    }
    dynamicSlot(addresses) {
      var _a;
      let getter = this.value;
      let compare = this.facet.compareInput;
      let id = this.id,
        idx = addresses[id] >> 1,
        multi = this.type == 2 /* Provider.Multi */;
      let depDoc = false,
        depSel = false,
        depAddrs = [];
      for (let dep of this.dependencies) {
        if (dep == "doc") depDoc = true;else if (dep == "selection") depSel = true;else if ((((_a = addresses[dep.id]) !== null && _a !== void 0 ? _a : 1) & 1) == 0) depAddrs.push(addresses[dep.id]);
      }
      return {
        create(state) {
          state.values[idx] = getter(state);
          return 1 /* SlotStatus.Changed */;
        },
        update(state, tr) {
          if (depDoc && tr.docChanged || depSel && (tr.docChanged || tr.selection) || ensureAll(state, depAddrs)) {
            let newVal = getter(state);
            if (multi ? !compareArray(newVal, state.values[idx], compare) : !compare(newVal, state.values[idx])) {
              state.values[idx] = newVal;
              return 1 /* SlotStatus.Changed */;
            }
          }
          return 0;
        },
        reconfigure: (state, oldState) => {
          let newVal,
            oldAddr = oldState.config.address[id];
          if (oldAddr != null) {
            let oldVal = getAddr(oldState, oldAddr);
            if (this.dependencies.every(dep => {
              return dep instanceof Facet ? oldState.facet(dep) === state.facet(dep) : dep instanceof StateField ? oldState.field(dep, false) == state.field(dep, false) : true;
            }) || (multi ? compareArray(newVal = getter(state), oldVal, compare) : compare(newVal = getter(state), oldVal))) {
              state.values[idx] = oldVal;
              return 0;
            }
          } else {
            newVal = getter(state);
          }
          state.values[idx] = newVal;
          return 1 /* SlotStatus.Changed */;
        }
      };
    }
  }
  function compareArray(a, b, compare) {
    if (a.length != b.length) return false;
    for (let i = 0; i < a.length; i++) if (!compare(a[i], b[i])) return false;
    return true;
  }
  function ensureAll(state, addrs) {
    let changed = false;
    for (let addr of addrs) if (ensureAddr(state, addr) & 1 /* SlotStatus.Changed */) changed = true;
    return changed;
  }
  function dynamicFacetSlot(addresses, facet, providers) {
    let providerAddrs = providers.map(p => addresses[p.id]);
    let providerTypes = providers.map(p => p.type);
    let dynamic = providerAddrs.filter(p => !(p & 1));
    let idx = addresses[facet.id] >> 1;
    function get(state) {
      let values = [];
      for (let i = 0; i < providerAddrs.length; i++) {
        let value = getAddr(state, providerAddrs[i]);
        if (providerTypes[i] == 2 /* Provider.Multi */) for (let val of value) values.push(val);else values.push(value);
      }
      return facet.combine(values);
    }
    return {
      create(state) {
        for (let addr of providerAddrs) ensureAddr(state, addr);
        state.values[idx] = get(state);
        return 1 /* SlotStatus.Changed */;
      },
      update(state, tr) {
        if (!ensureAll(state, dynamic)) return 0;
        let value = get(state);
        if (facet.compare(value, state.values[idx])) return 0;
        state.values[idx] = value;
        return 1 /* SlotStatus.Changed */;
      },
      reconfigure(state, oldState) {
        let depChanged = ensureAll(state, providerAddrs);
        let oldProviders = oldState.config.facets[facet.id],
          oldValue = oldState.facet(facet);
        if (oldProviders && !depChanged && sameArray$1(providers, oldProviders)) {
          state.values[idx] = oldValue;
          return 0;
        }
        let value = get(state);
        if (facet.compare(value, oldValue)) {
          state.values[idx] = oldValue;
          return 0;
        }
        state.values[idx] = value;
        return 1 /* SlotStatus.Changed */;
      }
    };
  }
  const initField = /*@__PURE__*/Facet.define({
    static: true
  });
  /**
  Fields can store additional information in an editor state, and
  keep it in sync with the rest of the state.
  */
  class StateField {
    constructor(
    /**
    @internal
    */
    id, createF, updateF, compareF,
    /**
    @internal
    */
    spec) {
      this.id = id;
      this.createF = createF;
      this.updateF = updateF;
      this.compareF = compareF;
      this.spec = spec;
      /**
      @internal
      */
      this.provides = undefined;
    }
    /**
    Define a state field.
    */
    static define(config) {
      let field = new StateField(nextID++, config.create, config.update, config.compare || ((a, b) => a === b), config);
      if (config.provide) field.provides = config.provide(field);
      return field;
    }
    create(state) {
      let init = state.facet(initField).find(i => i.field == this);
      return ((init === null || init === void 0 ? void 0 : init.create) || this.createF)(state);
    }
    /**
    @internal
    */
    slot(addresses) {
      let idx = addresses[this.id] >> 1;
      return {
        create: state => {
          state.values[idx] = this.create(state);
          return 1 /* SlotStatus.Changed */;
        },
        update: (state, tr) => {
          let oldVal = state.values[idx];
          let value = this.updateF(oldVal, tr);
          if (this.compareF(oldVal, value)) return 0;
          state.values[idx] = value;
          return 1 /* SlotStatus.Changed */;
        },
        reconfigure: (state, oldState) => {
          let init = state.facet(initField),
            oldInit = oldState.facet(initField),
            reInit;
          if ((reInit = init.find(i => i.field == this)) && reInit != oldInit.find(i => i.field == this)) {
            state.values[idx] = reInit.create(state);
            return 1 /* SlotStatus.Changed */;
          }
          if (oldState.config.address[this.id] != null) {
            state.values[idx] = oldState.field(this);
            return 0;
          }
          state.values[idx] = this.create(state);
          return 1 /* SlotStatus.Changed */;
        }
      };
    }
    /**
    Returns an extension that enables this field and overrides the
    way it is initialized. Can be useful when you need to provide a
    non-default starting value for the field.
    */
    init(create) {
      return [this, initField.of({
        field: this,
        create
      })];
    }
    /**
    State field instances can be used as
    [`Extension`](https://codemirror.net/6/docs/ref/#state.Extension) values to enable the field in a
    given state.
    */
    get extension() {
      return this;
    }
  }
  const Prec_ = {
    lowest: 4,
    low: 3,
    default: 2,
    high: 1,
    highest: 0
  };
  function prec(value) {
    return ext => new PrecExtension(ext, value);
  }
  /**
  By default extensions are registered in the order they are found
  in the flattened form of nested array that was provided.
  Individual extension values can be assigned a precedence to
  override this. Extensions that do not have a precedence set get
  the precedence of the nearest parent with a precedence, or
  [`default`](https://codemirror.net/6/docs/ref/#state.Prec.default) if there is no such parent. The
  final ordering of extensions is determined by first sorting by
  precedence and then by order within each precedence.
  */
  const Prec = {
    /**
    The highest precedence level, for extensions that should end up
    near the start of the precedence ordering.
    */
    highest: /*@__PURE__*/prec(Prec_.highest),
    /**
    A higher-than-default precedence, for extensions that should
    come before those with default precedence.
    */
    high: /*@__PURE__*/prec(Prec_.high),
    /**
    The default precedence, which is also used for extensions
    without an explicit precedence.
    */
    default: /*@__PURE__*/prec(Prec_.default),
    /**
    A lower-than-default precedence.
    */
    low: /*@__PURE__*/prec(Prec_.low),
    /**
    The lowest precedence level. Meant for things that should end up
    near the end of the extension order.
    */
    lowest: /*@__PURE__*/prec(Prec_.lowest)
  };
  class PrecExtension {
    constructor(inner, prec) {
      this.inner = inner;
      this.prec = prec;
    }
  }
  /**
  Extension compartments can be used to make a configuration
  dynamic. By [wrapping](https://codemirror.net/6/docs/ref/#state.Compartment.of) part of your
  configuration in a compartment, you can later
  [replace](https://codemirror.net/6/docs/ref/#state.Compartment.reconfigure) that part through a
  transaction.
  */
  class Compartment {
    /**
    Create an instance of this compartment to add to your [state
    configuration](https://codemirror.net/6/docs/ref/#state.EditorStateConfig.extensions).
    */
    of(ext) {
      return new CompartmentInstance(this, ext);
    }
    /**
    Create an [effect](https://codemirror.net/6/docs/ref/#state.TransactionSpec.effects) that
    reconfigures this compartment.
    */
    reconfigure(content) {
      return Compartment.reconfigure.of({
        compartment: this,
        extension: content
      });
    }
    /**
    Get the current content of the compartment in the state, or
    `undefined` if it isn't present.
    */
    get(state) {
      return state.config.compartments.get(this);
    }
  }
  class CompartmentInstance {
    constructor(compartment, inner) {
      this.compartment = compartment;
      this.inner = inner;
    }
  }
  class Configuration {
    constructor(base, compartments, dynamicSlots, address, staticValues, facets) {
      this.base = base;
      this.compartments = compartments;
      this.dynamicSlots = dynamicSlots;
      this.address = address;
      this.staticValues = staticValues;
      this.facets = facets;
      this.statusTemplate = [];
      while (this.statusTemplate.length < dynamicSlots.length) this.statusTemplate.push(0 /* SlotStatus.Unresolved */);
    }
    staticFacet(facet) {
      let addr = this.address[facet.id];
      return addr == null ? facet.default : this.staticValues[addr >> 1];
    }
    static resolve(base, compartments, oldState) {
      let fields = [];
      let facets = Object.create(null);
      let newCompartments = new Map();
      for (let ext of flatten(base, compartments, newCompartments)) {
        if (ext instanceof StateField) fields.push(ext);else (facets[ext.facet.id] || (facets[ext.facet.id] = [])).push(ext);
      }
      let address = Object.create(null);
      let staticValues = [];
      let dynamicSlots = [];
      for (let field of fields) {
        address[field.id] = dynamicSlots.length << 1;
        dynamicSlots.push(a => field.slot(a));
      }
      let oldFacets = oldState === null || oldState === void 0 ? void 0 : oldState.config.facets;
      for (let id in facets) {
        let providers = facets[id],
          facet = providers[0].facet;
        let oldProviders = oldFacets && oldFacets[id] || [];
        if (providers.every(p => p.type == 0 /* Provider.Static */)) {
          address[facet.id] = staticValues.length << 1 | 1;
          if (sameArray$1(oldProviders, providers)) {
            staticValues.push(oldState.facet(facet));
          } else {
            let value = facet.combine(providers.map(p => p.value));
            staticValues.push(oldState && facet.compare(value, oldState.facet(facet)) ? oldState.facet(facet) : value);
          }
        } else {
          for (let p of providers) {
            if (p.type == 0 /* Provider.Static */) {
              address[p.id] = staticValues.length << 1 | 1;
              staticValues.push(p.value);
            } else {
              address[p.id] = dynamicSlots.length << 1;
              dynamicSlots.push(a => p.dynamicSlot(a));
            }
          }
          address[facet.id] = dynamicSlots.length << 1;
          dynamicSlots.push(a => dynamicFacetSlot(a, facet, providers));
        }
      }
      let dynamic = dynamicSlots.map(f => f(address));
      return new Configuration(base, newCompartments, dynamic, address, staticValues, facets);
    }
  }
  function flatten(extension, compartments, newCompartments) {
    let result = [[], [], [], [], []];
    let seen = new Map();
    function inner(ext, prec) {
      let known = seen.get(ext);
      if (known != null) {
        if (known <= prec) return;
        let found = result[known].indexOf(ext);
        if (found > -1) result[known].splice(found, 1);
        if (ext instanceof CompartmentInstance) newCompartments.delete(ext.compartment);
      }
      seen.set(ext, prec);
      if (Array.isArray(ext)) {
        for (let e of ext) inner(e, prec);
      } else if (ext instanceof CompartmentInstance) {
        if (newCompartments.has(ext.compartment)) throw new RangeError(`Duplicate use of compartment in extensions`);
        let content = compartments.get(ext.compartment) || ext.inner;
        newCompartments.set(ext.compartment, content);
        inner(content, prec);
      } else if (ext instanceof PrecExtension) {
        inner(ext.inner, ext.prec);
      } else if (ext instanceof StateField) {
        result[prec].push(ext);
        if (ext.provides) inner(ext.provides, prec);
      } else if (ext instanceof FacetProvider) {
        result[prec].push(ext);
        if (ext.facet.extensions) inner(ext.facet.extensions, Prec_.default);
      } else {
        let content = ext.extension;
        if (!content) throw new Error(`Unrecognized extension value in extension set (${ext}). This sometimes happens because multiple instances of @codemirror/state are loaded, breaking instanceof checks.`);
        inner(content, prec);
      }
    }
    inner(extension, Prec_.default);
    return result.reduce((a, b) => a.concat(b));
  }
  function ensureAddr(state, addr) {
    if (addr & 1) return 2 /* SlotStatus.Computed */;
    let idx = addr >> 1;
    let status = state.status[idx];
    if (status == 4 /* SlotStatus.Computing */) throw new Error("Cyclic dependency between fields and/or facets");
    if (status & 2 /* SlotStatus.Computed */) return status;
    state.status[idx] = 4 /* SlotStatus.Computing */;
    let changed = state.computeSlot(state, state.config.dynamicSlots[idx]);
    return state.status[idx] = 2 /* SlotStatus.Computed */ | changed;
  }
  function getAddr(state, addr) {
    return addr & 1 ? state.config.staticValues[addr >> 1] : state.values[addr >> 1];
  }
  const languageData = /*@__PURE__*/Facet.define();
  const allowMultipleSelections = /*@__PURE__*/Facet.define({
    combine: values => values.some(v => v),
    static: true
  });
  const lineSeparator = /*@__PURE__*/Facet.define({
    combine: values => values.length ? values[0] : undefined,
    static: true
  });
  const changeFilter = /*@__PURE__*/Facet.define();
  const transactionFilter = /*@__PURE__*/Facet.define();
  const transactionExtender = /*@__PURE__*/Facet.define();
  const readOnly = /*@__PURE__*/Facet.define({
    combine: values => values.length ? values[0] : false
  });

  /**
  Annotations are tagged values that are used to add metadata to
  transactions in an extensible way. They should be used to model
  things that effect the entire transaction (such as its [time
  stamp](https://codemirror.net/6/docs/ref/#state.Transaction^time) or information about its
  [origin](https://codemirror.net/6/docs/ref/#state.Transaction^userEvent)). For effects that happen
  _alongside_ the other changes made by the transaction, [state
  effects](https://codemirror.net/6/docs/ref/#state.StateEffect) are more appropriate.
  */
  class Annotation {
    /**
    @internal
    */
    constructor(
    /**
    The annotation type.
    */
    type,
    /**
    The value of this annotation.
    */
    value) {
      this.type = type;
      this.value = value;
    }
    /**
    Define a new type of annotation.
    */
    static define() {
      return new AnnotationType();
    }
  }
  /**
  Marker that identifies a type of [annotation](https://codemirror.net/6/docs/ref/#state.Annotation).
  */
  class AnnotationType {
    /**
    Create an instance of this annotation.
    */
    of(value) {
      return new Annotation(this, value);
    }
  }
  /**
  Representation of a type of state effect. Defined with
  [`StateEffect.define`](https://codemirror.net/6/docs/ref/#state.StateEffect^define).
  */
  class StateEffectType {
    /**
    @internal
    */
    constructor(
    // The `any` types in these function types are there to work
    // around TypeScript issue #37631, where the type guard on
    // `StateEffect.is` mysteriously stops working when these properly
    // have type `Value`.
    /**
    @internal
    */
    map) {
      this.map = map;
    }
    /**
    Create a [state effect](https://codemirror.net/6/docs/ref/#state.StateEffect) instance of this
    type.
    */
    of(value) {
      return new StateEffect(this, value);
    }
  }
  /**
  State effects can be used to represent additional effects
  associated with a [transaction](https://codemirror.net/6/docs/ref/#state.Transaction.effects). They
  are often useful to model changes to custom [state
  fields](https://codemirror.net/6/docs/ref/#state.StateField), when those changes aren't implicit in
  document or selection changes.
  */
  class StateEffect {
    /**
    @internal
    */
    constructor(
    /**
    @internal
    */
    type,
    /**
    The value of this effect.
    */
    value) {
      this.type = type;
      this.value = value;
    }
    /**
    Map this effect through a position mapping. Will return
    `undefined` when that ends up deleting the effect.
    */
    map(mapping) {
      let mapped = this.type.map(this.value, mapping);
      return mapped === undefined ? undefined : mapped == this.value ? this : new StateEffect(this.type, mapped);
    }
    /**
    Tells you whether this effect object is of a given
    [type](https://codemirror.net/6/docs/ref/#state.StateEffectType).
    */
    is(type) {
      return this.type == type;
    }
    /**
    Define a new effect type. The type parameter indicates the type
    of values that his effect holds. It should be a type that
    doesn't include `undefined`, since that is used in
    [mapping](https://codemirror.net/6/docs/ref/#state.StateEffect.map) to indicate that an effect is
    removed.
    */
    static define(spec = {}) {
      return new StateEffectType(spec.map || (v => v));
    }
    /**
    Map an array of effects through a change set.
    */
    static mapEffects(effects, mapping) {
      if (!effects.length) return effects;
      let result = [];
      for (let effect of effects) {
        let mapped = effect.map(mapping);
        if (mapped) result.push(mapped);
      }
      return result;
    }
  }
  /**
  This effect can be used to reconfigure the root extensions of
  the editor. Doing this will discard any extensions
  [appended](https://codemirror.net/6/docs/ref/#state.StateEffect^appendConfig), but does not reset
  the content of [reconfigured](https://codemirror.net/6/docs/ref/#state.Compartment.reconfigure)
  compartments.
  */
  StateEffect.reconfigure = /*@__PURE__*/StateEffect.define();
  /**
  Append extensions to the top-level configuration of the editor.
  */
  StateEffect.appendConfig = /*@__PURE__*/StateEffect.define();
  /**
  Changes to the editor state are grouped into transactions.
  Typically, a user action creates a single transaction, which may
  contain any number of document changes, may change the selection,
  or have other effects. Create a transaction by calling
  [`EditorState.update`](https://codemirror.net/6/docs/ref/#state.EditorState.update), or immediately
  dispatch one by calling
  [`EditorView.dispatch`](https://codemirror.net/6/docs/ref/#view.EditorView.dispatch).
  */
  class Transaction {
    constructor(
    /**
    The state from which the transaction starts.
    */
    startState,
    /**
    The document changes made by this transaction.
    */
    changes,
    /**
    The selection set by this transaction, or undefined if it
    doesn't explicitly set a selection.
    */
    selection,
    /**
    The effects added to the transaction.
    */
    effects,
    /**
    @internal
    */
    annotations,
    /**
    Whether the selection should be scrolled into view after this
    transaction is dispatched.
    */
    scrollIntoView) {
      this.startState = startState;
      this.changes = changes;
      this.selection = selection;
      this.effects = effects;
      this.annotations = annotations;
      this.scrollIntoView = scrollIntoView;
      /**
      @internal
      */
      this._doc = null;
      /**
      @internal
      */
      this._state = null;
      if (selection) checkSelection(selection, changes.newLength);
      if (!annotations.some(a => a.type == Transaction.time)) this.annotations = annotations.concat(Transaction.time.of(Date.now()));
    }
    /**
    @internal
    */
    static create(startState, changes, selection, effects, annotations, scrollIntoView) {
      return new Transaction(startState, changes, selection, effects, annotations, scrollIntoView);
    }
    /**
    The new document produced by the transaction. Contrary to
    [`.state`](https://codemirror.net/6/docs/ref/#state.Transaction.state)`.doc`, accessing this won't
    force the entire new state to be computed right away, so it is
    recommended that [transaction
    filters](https://codemirror.net/6/docs/ref/#state.EditorState^transactionFilter) use this getter
    when they need to look at the new document.
    */
    get newDoc() {
      return this._doc || (this._doc = this.changes.apply(this.startState.doc));
    }
    /**
    The new selection produced by the transaction. If
    [`this.selection`](https://codemirror.net/6/docs/ref/#state.Transaction.selection) is undefined,
    this will [map](https://codemirror.net/6/docs/ref/#state.EditorSelection.map) the start state's
    current selection through the changes made by the transaction.
    */
    get newSelection() {
      return this.selection || this.startState.selection.map(this.changes);
    }
    /**
    The new state created by the transaction. Computed on demand
    (but retained for subsequent access), so it is recommended not to
    access it in [transaction
    filters](https://codemirror.net/6/docs/ref/#state.EditorState^transactionFilter) when possible.
    */
    get state() {
      if (!this._state) this.startState.applyTransaction(this);
      return this._state;
    }
    /**
    Get the value of the given annotation type, if any.
    */
    annotation(type) {
      for (let ann of this.annotations) if (ann.type == type) return ann.value;
      return undefined;
    }
    /**
    Indicates whether the transaction changed the document.
    */
    get docChanged() {
      return !this.changes.empty;
    }
    /**
    Indicates whether this transaction reconfigures the state
    (through a [configuration compartment](https://codemirror.net/6/docs/ref/#state.Compartment) or
    with a top-level configuration
    [effect](https://codemirror.net/6/docs/ref/#state.StateEffect^reconfigure).
    */
    get reconfigured() {
      return this.startState.config != this.state.config;
    }
    /**
    Returns true if the transaction has a [user
    event](https://codemirror.net/6/docs/ref/#state.Transaction^userEvent) annotation that is equal to
    or more specific than `event`. For example, if the transaction
    has `"select.pointer"` as user event, `"select"` and
    `"select.pointer"` will match it.
    */
    isUserEvent(event) {
      let e = this.annotation(Transaction.userEvent);
      return !!(e && (e == event || e.length > event.length && e.slice(0, event.length) == event && e[event.length] == "."));
    }
  }
  /**
  Annotation used to store transaction timestamps. Automatically
  added to every transaction, holding `Date.now()`.
  */
  Transaction.time = /*@__PURE__*/Annotation.define();
  /**
  Annotation used to associate a transaction with a user interface
  event. Holds a string identifying the event, using a
  dot-separated format to support attaching more specific
  information. The events used by the core libraries are:

   - `"input"` when content is entered
     - `"input.type"` for typed input
       - `"input.type.compose"` for composition
     - `"input.paste"` for pasted input
     - `"input.drop"` when adding content with drag-and-drop
     - `"input.complete"` when autocompleting
   - `"delete"` when the user deletes content
     - `"delete.selection"` when deleting the selection
     - `"delete.forward"` when deleting forward from the selection
     - `"delete.backward"` when deleting backward from the selection
     - `"delete.cut"` when cutting to the clipboard
   - `"move"` when content is moved
     - `"move.drop"` when content is moved within the editor through drag-and-drop
   - `"select"` when explicitly changing the selection
     - `"select.pointer"` when selecting with a mouse or other pointing device
   - `"undo"` and `"redo"` for history actions

  Use [`isUserEvent`](https://codemirror.net/6/docs/ref/#state.Transaction.isUserEvent) to check
  whether the annotation matches a given event.
  */
  Transaction.userEvent = /*@__PURE__*/Annotation.define();
  /**
  Annotation indicating whether a transaction should be added to
  the undo history or not.
  */
  Transaction.addToHistory = /*@__PURE__*/Annotation.define();
  /**
  Annotation indicating (when present and true) that a transaction
  represents a change made by some other actor, not the user. This
  is used, for example, to tag other people's changes in
  collaborative editing.
  */
  Transaction.remote = /*@__PURE__*/Annotation.define();
  function joinRanges(a, b) {
    let result = [];
    for (let iA = 0, iB = 0;;) {
      let from, to;
      if (iA < a.length && (iB == b.length || b[iB] >= a[iA])) {
        from = a[iA++];
        to = a[iA++];
      } else if (iB < b.length) {
        from = b[iB++];
        to = b[iB++];
      } else return result;
      if (!result.length || result[result.length - 1] < from) result.push(from, to);else if (result[result.length - 1] < to) result[result.length - 1] = to;
    }
  }
  function mergeTransaction(a, b, sequential) {
    var _a;
    let mapForA, mapForB, changes;
    if (sequential) {
      mapForA = b.changes;
      mapForB = ChangeSet.empty(b.changes.length);
      changes = a.changes.compose(b.changes);
    } else {
      mapForA = b.changes.map(a.changes);
      mapForB = a.changes.mapDesc(b.changes, true);
      changes = a.changes.compose(mapForA);
    }
    return {
      changes,
      selection: b.selection ? b.selection.map(mapForB) : (_a = a.selection) === null || _a === void 0 ? void 0 : _a.map(mapForA),
      effects: StateEffect.mapEffects(a.effects, mapForA).concat(StateEffect.mapEffects(b.effects, mapForB)),
      annotations: a.annotations.length ? a.annotations.concat(b.annotations) : b.annotations,
      scrollIntoView: a.scrollIntoView || b.scrollIntoView
    };
  }
  function resolveTransactionInner(state, spec, docSize) {
    let sel = spec.selection,
      annotations = asArray(spec.annotations);
    if (spec.userEvent) annotations = annotations.concat(Transaction.userEvent.of(spec.userEvent));
    return {
      changes: spec.changes instanceof ChangeSet ? spec.changes : ChangeSet.of(spec.changes || [], docSize, state.facet(lineSeparator)),
      selection: sel && (sel instanceof EditorSelection ? sel : EditorSelection.single(sel.anchor, sel.head)),
      effects: asArray(spec.effects),
      annotations,
      scrollIntoView: !!spec.scrollIntoView
    };
  }
  function resolveTransaction(state, specs, filter) {
    let s = resolveTransactionInner(state, specs.length ? specs[0] : {}, state.doc.length);
    if (specs.length && specs[0].filter === false) filter = false;
    for (let i = 1; i < specs.length; i++) {
      if (specs[i].filter === false) filter = false;
      let seq = !!specs[i].sequential;
      s = mergeTransaction(s, resolveTransactionInner(state, specs[i], seq ? s.changes.newLength : state.doc.length), seq);
    }
    let tr = Transaction.create(state, s.changes, s.selection, s.effects, s.annotations, s.scrollIntoView);
    return extendTransaction(filter ? filterTransaction(tr) : tr);
  }
  // Finish a transaction by applying filters if necessary.
  function filterTransaction(tr) {
    let state = tr.startState;
    // Change filters
    let result = true;
    for (let filter of state.facet(changeFilter)) {
      let value = filter(tr);
      if (value === false) {
        result = false;
        break;
      }
      if (Array.isArray(value)) result = result === true ? value : joinRanges(result, value);
    }
    if (result !== true) {
      let changes, back;
      if (result === false) {
        back = tr.changes.invertedDesc;
        changes = ChangeSet.empty(state.doc.length);
      } else {
        let filtered = tr.changes.filter(result);
        changes = filtered.changes;
        back = filtered.filtered.mapDesc(filtered.changes).invertedDesc;
      }
      tr = Transaction.create(state, changes, tr.selection && tr.selection.map(back), StateEffect.mapEffects(tr.effects, back), tr.annotations, tr.scrollIntoView);
    }
    // Transaction filters
    let filters = state.facet(transactionFilter);
    for (let i = filters.length - 1; i >= 0; i--) {
      let filtered = filters[i](tr);
      if (filtered instanceof Transaction) tr = filtered;else if (Array.isArray(filtered) && filtered.length == 1 && filtered[0] instanceof Transaction) tr = filtered[0];else tr = resolveTransaction(state, asArray(filtered), false);
    }
    return tr;
  }
  function extendTransaction(tr) {
    let state = tr.startState,
      extenders = state.facet(transactionExtender),
      spec = tr;
    for (let i = extenders.length - 1; i >= 0; i--) {
      let extension = extenders[i](tr);
      if (extension && Object.keys(extension).length) spec = mergeTransaction(spec, resolveTransactionInner(state, extension, tr.changes.newLength), true);
    }
    return spec == tr ? tr : Transaction.create(state, tr.changes, tr.selection, spec.effects, spec.annotations, spec.scrollIntoView);
  }
  const none = [];
  function asArray(value) {
    return value == null ? none : Array.isArray(value) ? value : [value];
  }

  /**
  The categories produced by a [character
  categorizer](https://codemirror.net/6/docs/ref/#state.EditorState.charCategorizer). These are used
  do things like selecting by word.
  */
  var CharCategory = /*@__PURE__*/function (CharCategory) {
    /**
    Word characters.
    */
    CharCategory[CharCategory["Word"] = 0] = "Word";
    /**
    Whitespace.
    */
    CharCategory[CharCategory["Space"] = 1] = "Space";
    /**
    Anything else.
    */
    CharCategory[CharCategory["Other"] = 2] = "Other";
    return CharCategory;
  }(CharCategory || (CharCategory = {}));
  const nonASCIISingleCaseWordChar = /[\u00df\u0587\u0590-\u05f4\u0600-\u06ff\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc\uac00-\ud7af]/;
  let wordChar;
  try {
    wordChar = /*@__PURE__*/new RegExp("[\\p{Alphabetic}\\p{Number}_]", "u");
  } catch (_) {}
  function hasWordChar(str) {
    if (wordChar) return wordChar.test(str);
    for (let i = 0; i < str.length; i++) {
      let ch = str[i];
      if (/\w/.test(ch) || ch > "\x80" && (ch.toUpperCase() != ch.toLowerCase() || nonASCIISingleCaseWordChar.test(ch))) return true;
    }
    return false;
  }
  function makeCategorizer(wordChars) {
    return char => {
      if (!/\S/.test(char)) return CharCategory.Space;
      if (hasWordChar(char)) return CharCategory.Word;
      for (let i = 0; i < wordChars.length; i++) if (char.indexOf(wordChars[i]) > -1) return CharCategory.Word;
      return CharCategory.Other;
    };
  }

  /**
  The editor state class is a persistent (immutable) data structure.
  To update a state, you [create](https://codemirror.net/6/docs/ref/#state.EditorState.update) a
  [transaction](https://codemirror.net/6/docs/ref/#state.Transaction), which produces a _new_ state
  instance, without modifying the original object.

  As such, _never_ mutate properties of a state directly. That'll
  just break things.
  */
  class EditorState {
    constructor(
    /**
    @internal
    */
    config,
    /**
    The current document.
    */
    doc,
    /**
    The current selection.
    */
    selection,
    /**
    @internal
    */
    values, computeSlot, tr) {
      this.config = config;
      this.doc = doc;
      this.selection = selection;
      this.values = values;
      this.status = config.statusTemplate.slice();
      this.computeSlot = computeSlot;
      // Fill in the computed state immediately, so that further queries
      // for it made during the update return this state
      if (tr) tr._state = this;
      for (let i = 0; i < this.config.dynamicSlots.length; i++) ensureAddr(this, i << 1);
      this.computeSlot = null;
    }
    field(field, require = true) {
      let addr = this.config.address[field.id];
      if (addr == null) {
        if (require) throw new RangeError("Field is not present in this state");
        return undefined;
      }
      ensureAddr(this, addr);
      return getAddr(this, addr);
    }
    /**
    Create a [transaction](https://codemirror.net/6/docs/ref/#state.Transaction) that updates this
    state. Any number of [transaction specs](https://codemirror.net/6/docs/ref/#state.TransactionSpec)
    can be passed. Unless
    [`sequential`](https://codemirror.net/6/docs/ref/#state.TransactionSpec.sequential) is set, the
    [changes](https://codemirror.net/6/docs/ref/#state.TransactionSpec.changes) (if any) of each spec
    are assumed to start in the _current_ document (not the document
    produced by previous specs), and its
    [selection](https://codemirror.net/6/docs/ref/#state.TransactionSpec.selection) and
    [effects](https://codemirror.net/6/docs/ref/#state.TransactionSpec.effects) are assumed to refer
    to the document created by its _own_ changes. The resulting
    transaction contains the combined effect of all the different
    specs. For [selection](https://codemirror.net/6/docs/ref/#state.TransactionSpec.selection), later
    specs take precedence over earlier ones.
    */
    update(...specs) {
      return resolveTransaction(this, specs, true);
    }
    /**
    @internal
    */
    applyTransaction(tr) {
      let conf = this.config,
        {
          base,
          compartments
        } = conf;
      for (let effect of tr.effects) {
        if (effect.is(Compartment.reconfigure)) {
          if (conf) {
            compartments = new Map();
            conf.compartments.forEach((val, key) => compartments.set(key, val));
            conf = null;
          }
          compartments.set(effect.value.compartment, effect.value.extension);
        } else if (effect.is(StateEffect.reconfigure)) {
          conf = null;
          base = effect.value;
        } else if (effect.is(StateEffect.appendConfig)) {
          conf = null;
          base = asArray(base).concat(effect.value);
        }
      }
      let startValues;
      if (!conf) {
        conf = Configuration.resolve(base, compartments, this);
        let intermediateState = new EditorState(conf, this.doc, this.selection, conf.dynamicSlots.map(() => null), (state, slot) => slot.reconfigure(state, this), null);
        startValues = intermediateState.values;
      } else {
        startValues = tr.startState.values.slice();
      }
      let selection = tr.startState.facet(allowMultipleSelections) ? tr.newSelection : tr.newSelection.asSingle();
      new EditorState(conf, tr.newDoc, selection, startValues, (state, slot) => slot.update(state, tr), tr);
    }
    /**
    Create a [transaction spec](https://codemirror.net/6/docs/ref/#state.TransactionSpec) that
    replaces every selection range with the given content.
    */
    replaceSelection(text) {
      if (typeof text == "string") text = this.toText(text);
      return this.changeByRange(range => ({
        changes: {
          from: range.from,
          to: range.to,
          insert: text
        },
        range: EditorSelection.cursor(range.from + text.length)
      }));
    }
    /**
    Create a set of changes and a new selection by running the given
    function for each range in the active selection. The function
    can return an optional set of changes (in the coordinate space
    of the start document), plus an updated range (in the coordinate
    space of the document produced by the call's own changes). This
    method will merge all the changes and ranges into a single
    changeset and selection, and return it as a [transaction
    spec](https://codemirror.net/6/docs/ref/#state.TransactionSpec), which can be passed to
    [`update`](https://codemirror.net/6/docs/ref/#state.EditorState.update).
    */
    changeByRange(f) {
      let sel = this.selection;
      let result1 = f(sel.ranges[0]);
      let changes = this.changes(result1.changes),
        ranges = [result1.range];
      let effects = asArray(result1.effects);
      for (let i = 1; i < sel.ranges.length; i++) {
        let result = f(sel.ranges[i]);
        let newChanges = this.changes(result.changes),
          newMapped = newChanges.map(changes);
        for (let j = 0; j < i; j++) ranges[j] = ranges[j].map(newMapped);
        let mapBy = changes.mapDesc(newChanges, true);
        ranges.push(result.range.map(mapBy));
        changes = changes.compose(newMapped);
        effects = StateEffect.mapEffects(effects, newMapped).concat(StateEffect.mapEffects(asArray(result.effects), mapBy));
      }
      return {
        changes,
        selection: EditorSelection.create(ranges, sel.mainIndex),
        effects
      };
    }
    /**
    Create a [change set](https://codemirror.net/6/docs/ref/#state.ChangeSet) from the given change
    description, taking the state's document length and line
    separator into account.
    */
    changes(spec = []) {
      if (spec instanceof ChangeSet) return spec;
      return ChangeSet.of(spec, this.doc.length, this.facet(EditorState.lineSeparator));
    }
    /**
    Using the state's [line
    separator](https://codemirror.net/6/docs/ref/#state.EditorState^lineSeparator), create a
    [`Text`](https://codemirror.net/6/docs/ref/#state.Text) instance from the given string.
    */
    toText(string) {
      return Text.of(string.split(this.facet(EditorState.lineSeparator) || DefaultSplit));
    }
    /**
    Return the given range of the document as a string.
    */
    sliceDoc(from = 0, to = this.doc.length) {
      return this.doc.sliceString(from, to, this.lineBreak);
    }
    /**
    Get the value of a state [facet](https://codemirror.net/6/docs/ref/#state.Facet).
    */
    facet(facet) {
      let addr = this.config.address[facet.id];
      if (addr == null) return facet.default;
      ensureAddr(this, addr);
      return getAddr(this, addr);
    }
    /**
    Convert this state to a JSON-serializable object. When custom
    fields should be serialized, you can pass them in as an object
    mapping property names (in the resulting object, which should
    not use `doc` or `selection`) to fields.
    */
    toJSON(fields) {
      let result = {
        doc: this.sliceDoc(),
        selection: this.selection.toJSON()
      };
      if (fields) for (let prop in fields) {
        let value = fields[prop];
        if (value instanceof StateField && this.config.address[value.id] != null) result[prop] = value.spec.toJSON(this.field(fields[prop]), this);
      }
      return result;
    }
    /**
    Deserialize a state from its JSON representation. When custom
    fields should be deserialized, pass the same object you passed
    to [`toJSON`](https://codemirror.net/6/docs/ref/#state.EditorState.toJSON) when serializing as
    third argument.
    */
    static fromJSON(json, config = {}, fields) {
      if (!json || typeof json.doc != "string") throw new RangeError("Invalid JSON representation for EditorState");
      let fieldInit = [];
      if (fields) for (let prop in fields) {
        if (Object.prototype.hasOwnProperty.call(json, prop)) {
          let field = fields[prop],
            value = json[prop];
          fieldInit.push(field.init(state => field.spec.fromJSON(value, state)));
        }
      }
      return EditorState.create({
        doc: json.doc,
        selection: EditorSelection.fromJSON(json.selection),
        extensions: config.extensions ? fieldInit.concat([config.extensions]) : fieldInit
      });
    }
    /**
    Create a new state. You'll usually only need this when
    initializing an editor—updated states are created by applying
    transactions.
    */
    static create(config = {}) {
      let configuration = Configuration.resolve(config.extensions || [], new Map());
      let doc = config.doc instanceof Text ? config.doc : Text.of((config.doc || "").split(configuration.staticFacet(EditorState.lineSeparator) || DefaultSplit));
      let selection = !config.selection ? EditorSelection.single(0) : config.selection instanceof EditorSelection ? config.selection : EditorSelection.single(config.selection.anchor, config.selection.head);
      checkSelection(selection, doc.length);
      if (!configuration.staticFacet(allowMultipleSelections)) selection = selection.asSingle();
      return new EditorState(configuration, doc, selection, configuration.dynamicSlots.map(() => null), (state, slot) => slot.create(state), null);
    }
    /**
    The size (in columns) of a tab in the document, determined by
    the [`tabSize`](https://codemirror.net/6/docs/ref/#state.EditorState^tabSize) facet.
    */
    get tabSize() {
      return this.facet(EditorState.tabSize);
    }
    /**
    Get the proper [line-break](https://codemirror.net/6/docs/ref/#state.EditorState^lineSeparator)
    string for this state.
    */
    get lineBreak() {
      return this.facet(EditorState.lineSeparator) || "\n";
    }
    /**
    Returns true when the editor is
    [configured](https://codemirror.net/6/docs/ref/#state.EditorState^readOnly) to be read-only.
    */
    get readOnly() {
      return this.facet(readOnly);
    }
    /**
    Look up a translation for the given phrase (via the
    [`phrases`](https://codemirror.net/6/docs/ref/#state.EditorState^phrases) facet), or return the
    original string if no translation is found.
    
    If additional arguments are passed, they will be inserted in
    place of markers like `$1` (for the first value) and `$2`, etc.
    A single `$` is equivalent to `$1`, and `$$` will produce a
    literal dollar sign.
    */
    phrase(phrase, ...insert) {
      for (let map of this.facet(EditorState.phrases)) if (Object.prototype.hasOwnProperty.call(map, phrase)) {
        phrase = map[phrase];
        break;
      }
      if (insert.length) phrase = phrase.replace(/\$(\$|\d*)/g, (m, i) => {
        if (i == "$") return "$";
        let n = +(i || 1);
        return !n || n > insert.length ? m : insert[n - 1];
      });
      return phrase;
    }
    /**
    Find the values for a given language data field, provided by the
    the [`languageData`](https://codemirror.net/6/docs/ref/#state.EditorState^languageData) facet.
    
    Examples of language data fields are...
    
    - [`"commentTokens"`](https://codemirror.net/6/docs/ref/#commands.CommentTokens) for specifying
      comment syntax.
    - [`"autocomplete"`](https://codemirror.net/6/docs/ref/#autocomplete.autocompletion^config.override)
      for providing language-specific completion sources.
    - [`"wordChars"`](https://codemirror.net/6/docs/ref/#state.EditorState.charCategorizer) for adding
      characters that should be considered part of words in this
      language.
    - [`"closeBrackets"`](https://codemirror.net/6/docs/ref/#autocomplete.CloseBracketConfig) controls
      bracket closing behavior.
    */
    languageDataAt(name, pos, side = -1) {
      let values = [];
      for (let provider of this.facet(languageData)) {
        for (let result of provider(this, pos, side)) {
          if (Object.prototype.hasOwnProperty.call(result, name)) values.push(result[name]);
        }
      }
      return values;
    }
    /**
    Return a function that can categorize strings (expected to
    represent a single [grapheme cluster](https://codemirror.net/6/docs/ref/#state.findClusterBreak))
    into one of:
    
     - Word (contains an alphanumeric character or a character
       explicitly listed in the local language's `"wordChars"`
       language data, which should be a string)
     - Space (contains only whitespace)
     - Other (anything else)
    */
    charCategorizer(at) {
      let chars = this.languageDataAt("wordChars", at);
      return makeCategorizer(chars.length ? chars[0] : "");
    }
    /**
    Find the word at the given position, meaning the range
    containing all [word](https://codemirror.net/6/docs/ref/#state.CharCategory.Word) characters
    around it. If no word characters are adjacent to the position,
    this returns null.
    */
    wordAt(pos) {
      let {
        text,
        from,
        length
      } = this.doc.lineAt(pos);
      let cat = this.charCategorizer(pos);
      let start = pos - from,
        end = pos - from;
      while (start > 0) {
        let prev = findClusterBreak(text, start, false);
        if (cat(text.slice(prev, start)) != CharCategory.Word) break;
        start = prev;
      }
      while (end < length) {
        let next = findClusterBreak(text, end);
        if (cat(text.slice(end, next)) != CharCategory.Word) break;
        end = next;
      }
      return start == end ? null : EditorSelection.range(start + from, end + from);
    }
  }
  /**
  A facet that, when enabled, causes the editor to allow multiple
  ranges to be selected. Be careful though, because by default the
  editor relies on the native DOM selection, which cannot handle
  multiple selections. An extension like
  [`drawSelection`](https://codemirror.net/6/docs/ref/#view.drawSelection) can be used to make
  secondary selections visible to the user.
  */
  EditorState.allowMultipleSelections = allowMultipleSelections;
  /**
  Configures the tab size to use in this state. The first
  (highest-precedence) value of the facet is used. If no value is
  given, this defaults to 4.
  */
  EditorState.tabSize = /*@__PURE__*/Facet.define({
    combine: values => values.length ? values[0] : 4
  });
  /**
  The line separator to use. By default, any of `"\n"`, `"\r\n"`
  and `"\r"` is treated as a separator when splitting lines, and
  lines are joined with `"\n"`.

  When you configure a value here, only that precise separator
  will be used, allowing you to round-trip documents through the
  editor without normalizing line separators.
  */
  EditorState.lineSeparator = lineSeparator;
  /**
  This facet controls the value of the
  [`readOnly`](https://codemirror.net/6/docs/ref/#state.EditorState.readOnly) getter, which is
  consulted by commands and extensions that implement editing
  functionality to determine whether they should apply. It
  defaults to false, but when its highest-precedence value is
  `true`, such functionality disables itself.

  Not to be confused with
  [`EditorView.editable`](https://codemirror.net/6/docs/ref/#view.EditorView^editable), which
  controls whether the editor's DOM is set to be editable (and
  thus focusable).
  */
  EditorState.readOnly = readOnly;
  /**
  Registers translation phrases. The
  [`phrase`](https://codemirror.net/6/docs/ref/#state.EditorState.phrase) method will look through
  all objects registered with this facet to find translations for
  its argument.
  */
  EditorState.phrases = /*@__PURE__*/Facet.define({
    compare(a, b) {
      let kA = Object.keys(a),
        kB = Object.keys(b);
      return kA.length == kB.length && kA.every(k => a[k] == b[k]);
    }
  });
  /**
  A facet used to register [language
  data](https://codemirror.net/6/docs/ref/#state.EditorState.languageDataAt) providers.
  */
  EditorState.languageData = languageData;
  /**
  Facet used to register change filters, which are called for each
  transaction (unless explicitly
  [disabled](https://codemirror.net/6/docs/ref/#state.TransactionSpec.filter)), and can suppress
  part of the transaction's changes.

  Such a function can return `true` to indicate that it doesn't
  want to do anything, `false` to completely stop the changes in
  the transaction, or a set of ranges in which changes should be
  suppressed. Such ranges are represented as an array of numbers,
  with each pair of two numbers indicating the start and end of a
  range. So for example `[10, 20, 100, 110]` suppresses changes
  between 10 and 20, and between 100 and 110.
  */
  EditorState.changeFilter = changeFilter;
  /**
  Facet used to register a hook that gets a chance to update or
  replace transaction specs before they are applied. This will
  only be applied for transactions that don't have
  [`filter`](https://codemirror.net/6/docs/ref/#state.TransactionSpec.filter) set to `false`. You
  can either return a single transaction spec (possibly the input
  transaction), or an array of specs (which will be combined in
  the same way as the arguments to
  [`EditorState.update`](https://codemirror.net/6/docs/ref/#state.EditorState.update)).

  When possible, it is recommended to avoid accessing
  [`Transaction.state`](https://codemirror.net/6/docs/ref/#state.Transaction.state) in a filter,
  since it will force creation of a state that will then be
  discarded again, if the transaction is actually filtered.

  (This functionality should be used with care. Indiscriminately
  modifying transaction is likely to break something or degrade
  the user experience.)
  */
  EditorState.transactionFilter = transactionFilter;
  /**
  This is a more limited form of
  [`transactionFilter`](https://codemirror.net/6/docs/ref/#state.EditorState^transactionFilter),
  which can only add
  [annotations](https://codemirror.net/6/docs/ref/#state.TransactionSpec.annotations) and
  [effects](https://codemirror.net/6/docs/ref/#state.TransactionSpec.effects). _But_, this type
  of filter runs even if the transaction has disabled regular
  [filtering](https://codemirror.net/6/docs/ref/#state.TransactionSpec.filter), making it suitable
  for effects that don't need to touch the changes or selection,
  but do want to process every transaction.

  Extenders run _after_ filters, when both are present.
  */
  EditorState.transactionExtender = transactionExtender;
  Compartment.reconfigure = /*@__PURE__*/StateEffect.define();

  /**
  Utility function for combining behaviors to fill in a config
  object from an array of provided configs. `defaults` should hold
  default values for all optional fields in `Config`.

  The function will, by default, error
  when a field gets two values that aren't `===`-equal, but you can
  provide combine functions per field to do something else.
  */
  function combineConfig(configs, defaults,
  // Should hold only the optional properties of Config, but I haven't managed to express that
  combine = {}) {
    let result = {};
    for (let config of configs) for (let key of Object.keys(config)) {
      let value = config[key],
        current = result[key];
      if (current === undefined) result[key] = value;else if (current === value || value === undefined) ; // No conflict
      else if (Object.hasOwnProperty.call(combine, key)) result[key] = combine[key](current, value);else throw new Error("Config merge conflict for field " + key);
    }
    for (let key in defaults) if (result[key] === undefined) result[key] = defaults[key];
    return result;
  }

  /**
  Each range is associated with a value, which must inherit from
  this class.
  */
  class RangeValue {
    /**
    Compare this value with another value. Used when comparing
    rangesets. The default implementation compares by identity.
    Unless you are only creating a fixed number of unique instances
    of your value type, it is a good idea to implement this
    properly.
    */
    eq(other) {
      return this == other;
    }
    /**
    Create a [range](https://codemirror.net/6/docs/ref/#state.Range) with this value.
    */
    range(from, to = from) {
      return Range$1.create(from, to, this);
    }
  }
  RangeValue.prototype.startSide = RangeValue.prototype.endSide = 0;
  RangeValue.prototype.point = false;
  RangeValue.prototype.mapMode = MapMode.TrackDel;
  function cmpVal(a, b) {
    return a == b || a.constructor == b.constructor && a.eq(b);
  }
  /**
  A range associates a value with a range of positions.
  */
  let Range$1 = class Range {
    constructor(
    /**
    The range's start position.
    */
    from,
    /**
    Its end position.
    */
    to,
    /**
    The value associated with this range.
    */
    value) {
      this.from = from;
      this.to = to;
      this.value = value;
    }
    /**
    @internal
    */
    static create(from, to, value) {
      return new Range(from, to, value);
    }
  };
  function cmpRange(a, b) {
    return a.from - b.from || a.value.startSide - b.value.startSide;
  }
  class Chunk {
    constructor(from, to, value,
    // Chunks are marked with the largest point that occurs
    // in them (or -1 for no points), so that scans that are
    // only interested in points (such as the
    // heightmap-related logic) can skip range-only chunks.
    maxPoint) {
      this.from = from;
      this.to = to;
      this.value = value;
      this.maxPoint = maxPoint;
    }
    get length() {
      return this.to[this.to.length - 1];
    }
    // Find the index of the given position and side. Use the ranges'
    // `from` pos when `end == false`, `to` when `end == true`.
    findIndex(pos, side, end, startAt = 0) {
      let arr = end ? this.to : this.from;
      for (let lo = startAt, hi = arr.length;;) {
        if (lo == hi) return lo;
        let mid = lo + hi >> 1;
        let diff = arr[mid] - pos || (end ? this.value[mid].endSide : this.value[mid].startSide) - side;
        if (mid == lo) return diff >= 0 ? lo : hi;
        if (diff >= 0) hi = mid;else lo = mid + 1;
      }
    }
    between(offset, from, to, f) {
      for (let i = this.findIndex(from, -1e9 /* C.Far */, true), e = this.findIndex(to, 1000000000 /* C.Far */, false, i); i < e; i++) if (f(this.from[i] + offset, this.to[i] + offset, this.value[i]) === false) return false;
    }
    map(offset, changes) {
      let value = [],
        from = [],
        to = [],
        newPos = -1,
        maxPoint = -1;
      for (let i = 0; i < this.value.length; i++) {
        let val = this.value[i],
          curFrom = this.from[i] + offset,
          curTo = this.to[i] + offset,
          newFrom,
          newTo;
        if (curFrom == curTo) {
          let mapped = changes.mapPos(curFrom, val.startSide, val.mapMode);
          if (mapped == null) continue;
          newFrom = newTo = mapped;
          if (val.startSide != val.endSide) {
            newTo = changes.mapPos(curFrom, val.endSide);
            if (newTo < newFrom) continue;
          }
        } else {
          newFrom = changes.mapPos(curFrom, val.startSide);
          newTo = changes.mapPos(curTo, val.endSide);
          if (newFrom > newTo || newFrom == newTo && val.startSide > 0 && val.endSide <= 0) continue;
        }
        if ((newTo - newFrom || val.endSide - val.startSide) < 0) continue;
        if (newPos < 0) newPos = newFrom;
        if (val.point) maxPoint = Math.max(maxPoint, newTo - newFrom);
        value.push(val);
        from.push(newFrom - newPos);
        to.push(newTo - newPos);
      }
      return {
        mapped: value.length ? new Chunk(from, to, value, maxPoint) : null,
        pos: newPos
      };
    }
  }
  /**
  A range set stores a collection of [ranges](https://codemirror.net/6/docs/ref/#state.Range) in a
  way that makes them efficient to [map](https://codemirror.net/6/docs/ref/#state.RangeSet.map) and
  [update](https://codemirror.net/6/docs/ref/#state.RangeSet.update). This is an immutable data
  structure.
  */
  class RangeSet {
    constructor(
    /**
    @internal
    */
    chunkPos,
    /**
    @internal
    */
    chunk,
    /**
    @internal
    */
    nextLayer,
    /**
    @internal
    */
    maxPoint) {
      this.chunkPos = chunkPos;
      this.chunk = chunk;
      this.nextLayer = nextLayer;
      this.maxPoint = maxPoint;
    }
    /**
    @internal
    */
    static create(chunkPos, chunk, nextLayer, maxPoint) {
      return new RangeSet(chunkPos, chunk, nextLayer, maxPoint);
    }
    /**
    @internal
    */
    get length() {
      let last = this.chunk.length - 1;
      return last < 0 ? 0 : Math.max(this.chunkEnd(last), this.nextLayer.length);
    }
    /**
    The number of ranges in the set.
    */
    get size() {
      if (this.isEmpty) return 0;
      let size = this.nextLayer.size;
      for (let chunk of this.chunk) size += chunk.value.length;
      return size;
    }
    /**
    @internal
    */
    chunkEnd(index) {
      return this.chunkPos[index] + this.chunk[index].length;
    }
    /**
    Update the range set, optionally adding new ranges or filtering
    out existing ones.
    
    (Note: The type parameter is just there as a kludge to work
    around TypeScript variance issues that prevented `RangeSet<X>`
    from being a subtype of `RangeSet<Y>` when `X` is a subtype of
    `Y`.)
    */
    update(updateSpec) {
      let {
        add = [],
        sort = false,
        filterFrom = 0,
        filterTo = this.length
      } = updateSpec;
      let filter = updateSpec.filter;
      if (add.length == 0 && !filter) return this;
      if (sort) add = add.slice().sort(cmpRange);
      if (this.isEmpty) return add.length ? RangeSet.of(add) : this;
      let cur = new LayerCursor(this, null, -1).goto(0),
        i = 0,
        spill = [];
      let builder = new RangeSetBuilder();
      while (cur.value || i < add.length) {
        if (i < add.length && (cur.from - add[i].from || cur.startSide - add[i].value.startSide) >= 0) {
          let range = add[i++];
          if (!builder.addInner(range.from, range.to, range.value)) spill.push(range);
        } else if (cur.rangeIndex == 1 && cur.chunkIndex < this.chunk.length && (i == add.length || this.chunkEnd(cur.chunkIndex) < add[i].from) && (!filter || filterFrom > this.chunkEnd(cur.chunkIndex) || filterTo < this.chunkPos[cur.chunkIndex]) && builder.addChunk(this.chunkPos[cur.chunkIndex], this.chunk[cur.chunkIndex])) {
          cur.nextChunk();
        } else {
          if (!filter || filterFrom > cur.to || filterTo < cur.from || filter(cur.from, cur.to, cur.value)) {
            if (!builder.addInner(cur.from, cur.to, cur.value)) spill.push(Range$1.create(cur.from, cur.to, cur.value));
          }
          cur.next();
        }
      }
      return builder.finishInner(this.nextLayer.isEmpty && !spill.length ? RangeSet.empty : this.nextLayer.update({
        add: spill,
        filter,
        filterFrom,
        filterTo
      }));
    }
    /**
    Map this range set through a set of changes, return the new set.
    */
    map(changes) {
      if (changes.empty || this.isEmpty) return this;
      let chunks = [],
        chunkPos = [],
        maxPoint = -1;
      for (let i = 0; i < this.chunk.length; i++) {
        let start = this.chunkPos[i],
          chunk = this.chunk[i];
        let touch = changes.touchesRange(start, start + chunk.length);
        if (touch === false) {
          maxPoint = Math.max(maxPoint, chunk.maxPoint);
          chunks.push(chunk);
          chunkPos.push(changes.mapPos(start));
        } else if (touch === true) {
          let {
            mapped,
            pos
          } = chunk.map(start, changes);
          if (mapped) {
            maxPoint = Math.max(maxPoint, mapped.maxPoint);
            chunks.push(mapped);
            chunkPos.push(pos);
          }
        }
      }
      let next = this.nextLayer.map(changes);
      return chunks.length == 0 ? next : new RangeSet(chunkPos, chunks, next || RangeSet.empty, maxPoint);
    }
    /**
    Iterate over the ranges that touch the region `from` to `to`,
    calling `f` for each. There is no guarantee that the ranges will
    be reported in any specific order. When the callback returns
    `false`, iteration stops.
    */
    between(from, to, f) {
      if (this.isEmpty) return;
      for (let i = 0; i < this.chunk.length; i++) {
        let start = this.chunkPos[i],
          chunk = this.chunk[i];
        if (to >= start && from <= start + chunk.length && chunk.between(start, from - start, to - start, f) === false) return;
      }
      this.nextLayer.between(from, to, f);
    }
    /**
    Iterate over the ranges in this set, in order, including all
    ranges that end at or after `from`.
    */
    iter(from = 0) {
      return HeapCursor.from([this]).goto(from);
    }
    /**
    @internal
    */
    get isEmpty() {
      return this.nextLayer == this;
    }
    /**
    Iterate over the ranges in a collection of sets, in order,
    starting from `from`.
    */
    static iter(sets, from = 0) {
      return HeapCursor.from(sets).goto(from);
    }
    /**
    Iterate over two groups of sets, calling methods on `comparator`
    to notify it of possible differences.
    */
    static compare(oldSets, newSets,
    /**
    This indicates how the underlying data changed between these
    ranges, and is needed to synchronize the iteration.
    */
    textDiff, comparator,
    /**
    Can be used to ignore all non-point ranges, and points below
    the given size. When -1, all ranges are compared.
    */
    minPointSize = -1) {
      let a = oldSets.filter(set => set.maxPoint > 0 || !set.isEmpty && set.maxPoint >= minPointSize);
      let b = newSets.filter(set => set.maxPoint > 0 || !set.isEmpty && set.maxPoint >= minPointSize);
      let sharedChunks = findSharedChunks(a, b, textDiff);
      let sideA = new SpanCursor(a, sharedChunks, minPointSize);
      let sideB = new SpanCursor(b, sharedChunks, minPointSize);
      textDiff.iterGaps((fromA, fromB, length) => compare(sideA, fromA, sideB, fromB, length, comparator));
      if (textDiff.empty && textDiff.length == 0) compare(sideA, 0, sideB, 0, 0, comparator);
    }
    /**
    Compare the contents of two groups of range sets, returning true
    if they are equivalent in the given range.
    */
    static eq(oldSets, newSets, from = 0, to) {
      if (to == null) to = 1000000000 /* C.Far */ - 1;
      let a = oldSets.filter(set => !set.isEmpty && newSets.indexOf(set) < 0);
      let b = newSets.filter(set => !set.isEmpty && oldSets.indexOf(set) < 0);
      if (a.length != b.length) return false;
      if (!a.length) return true;
      let sharedChunks = findSharedChunks(a, b);
      let sideA = new SpanCursor(a, sharedChunks, 0).goto(from),
        sideB = new SpanCursor(b, sharedChunks, 0).goto(from);
      for (;;) {
        if (sideA.to != sideB.to || !sameValues(sideA.active, sideB.active) || sideA.point && (!sideB.point || !cmpVal(sideA.point, sideB.point))) return false;
        if (sideA.to > to) return true;
        sideA.next();
        sideB.next();
      }
    }
    /**
    Iterate over a group of range sets at the same time, notifying
    the iterator about the ranges covering every given piece of
    content. Returns the open count (see
    [`SpanIterator.span`](https://codemirror.net/6/docs/ref/#state.SpanIterator.span)) at the end
    of the iteration.
    */
    static spans(sets, from, to, iterator,
    /**
    When given and greater than -1, only points of at least this
    size are taken into account.
    */
    minPointSize = -1) {
      let cursor = new SpanCursor(sets, null, minPointSize).goto(from),
        pos = from;
      let openRanges = cursor.openStart;
      for (;;) {
        let curTo = Math.min(cursor.to, to);
        if (cursor.point) {
          let active = cursor.activeForPoint(cursor.to);
          let openCount = cursor.pointFrom < from ? active.length + 1 : cursor.point.startSide < 0 ? active.length : Math.min(active.length, openRanges);
          iterator.point(pos, curTo, cursor.point, active, openCount, cursor.pointRank);
          openRanges = Math.min(cursor.openEnd(curTo), active.length);
        } else if (curTo > pos) {
          iterator.span(pos, curTo, cursor.active, openRanges);
          openRanges = cursor.openEnd(curTo);
        }
        if (cursor.to > to) return openRanges + (cursor.point && cursor.to > to ? 1 : 0);
        pos = cursor.to;
        cursor.next();
      }
    }
    /**
    Create a range set for the given range or array of ranges. By
    default, this expects the ranges to be _sorted_ (by start
    position and, if two start at the same position,
    `value.startSide`). You can pass `true` as second argument to
    cause the method to sort them.
    */
    static of(ranges, sort = false) {
      let build = new RangeSetBuilder();
      for (let range of ranges instanceof Range$1 ? [ranges] : sort ? lazySort(ranges) : ranges) build.add(range.from, range.to, range.value);
      return build.finish();
    }
    /**
    Join an array of range sets into a single set.
    */
    static join(sets) {
      if (!sets.length) return RangeSet.empty;
      let result = sets[sets.length - 1];
      for (let i = sets.length - 2; i >= 0; i--) {
        for (let layer = sets[i]; layer != RangeSet.empty; layer = layer.nextLayer) result = new RangeSet(layer.chunkPos, layer.chunk, result, Math.max(layer.maxPoint, result.maxPoint));
      }
      return result;
    }
  }
  /**
  The empty set of ranges.
  */
  RangeSet.empty = /*@__PURE__*/new RangeSet([], [], null, -1);
  function lazySort(ranges) {
    if (ranges.length > 1) for (let prev = ranges[0], i = 1; i < ranges.length; i++) {
      let cur = ranges[i];
      if (cmpRange(prev, cur) > 0) return ranges.slice().sort(cmpRange);
      prev = cur;
    }
    return ranges;
  }
  RangeSet.empty.nextLayer = RangeSet.empty;
  /**
  A range set builder is a data structure that helps build up a
  [range set](https://codemirror.net/6/docs/ref/#state.RangeSet) directly, without first allocating
  an array of [`Range`](https://codemirror.net/6/docs/ref/#state.Range) objects.
  */
  class RangeSetBuilder {
    finishChunk(newArrays) {
      this.chunks.push(new Chunk(this.from, this.to, this.value, this.maxPoint));
      this.chunkPos.push(this.chunkStart);
      this.chunkStart = -1;
      this.setMaxPoint = Math.max(this.setMaxPoint, this.maxPoint);
      this.maxPoint = -1;
      if (newArrays) {
        this.from = [];
        this.to = [];
        this.value = [];
      }
    }
    /**
    Create an empty builder.
    */
    constructor() {
      this.chunks = [];
      this.chunkPos = [];
      this.chunkStart = -1;
      this.last = null;
      this.lastFrom = -1e9 /* C.Far */;
      this.lastTo = -1e9 /* C.Far */;
      this.from = [];
      this.to = [];
      this.value = [];
      this.maxPoint = -1;
      this.setMaxPoint = -1;
      this.nextLayer = null;
    }
    /**
    Add a range. Ranges should be added in sorted (by `from` and
    `value.startSide`) order.
    */
    add(from, to, value) {
      if (!this.addInner(from, to, value)) (this.nextLayer || (this.nextLayer = new RangeSetBuilder())).add(from, to, value);
    }
    /**
    @internal
    */
    addInner(from, to, value) {
      let diff = from - this.lastTo || value.startSide - this.last.endSide;
      if (diff <= 0 && (from - this.lastFrom || value.startSide - this.last.startSide) < 0) throw new Error("Ranges must be added sorted by `from` position and `startSide`");
      if (diff < 0) return false;
      if (this.from.length == 250 /* C.ChunkSize */) this.finishChunk(true);
      if (this.chunkStart < 0) this.chunkStart = from;
      this.from.push(from - this.chunkStart);
      this.to.push(to - this.chunkStart);
      this.last = value;
      this.lastFrom = from;
      this.lastTo = to;
      this.value.push(value);
      if (value.point) this.maxPoint = Math.max(this.maxPoint, to - from);
      return true;
    }
    /**
    @internal
    */
    addChunk(from, chunk) {
      if ((from - this.lastTo || chunk.value[0].startSide - this.last.endSide) < 0) return false;
      if (this.from.length) this.finishChunk(true);
      this.setMaxPoint = Math.max(this.setMaxPoint, chunk.maxPoint);
      this.chunks.push(chunk);
      this.chunkPos.push(from);
      let last = chunk.value.length - 1;
      this.last = chunk.value[last];
      this.lastFrom = chunk.from[last] + from;
      this.lastTo = chunk.to[last] + from;
      return true;
    }
    /**
    Finish the range set. Returns the new set. The builder can't be
    used anymore after this has been called.
    */
    finish() {
      return this.finishInner(RangeSet.empty);
    }
    /**
    @internal
    */
    finishInner(next) {
      if (this.from.length) this.finishChunk(false);
      if (this.chunks.length == 0) return next;
      let result = RangeSet.create(this.chunkPos, this.chunks, this.nextLayer ? this.nextLayer.finishInner(next) : next, this.setMaxPoint);
      this.from = null; // Make sure further `add` calls produce errors
      return result;
    }
  }
  function findSharedChunks(a, b, textDiff) {
    let inA = new Map();
    for (let set of a) for (let i = 0; i < set.chunk.length; i++) if (set.chunk[i].maxPoint <= 0) inA.set(set.chunk[i], set.chunkPos[i]);
    let shared = new Set();
    for (let set of b) for (let i = 0; i < set.chunk.length; i++) {
      let known = inA.get(set.chunk[i]);
      if (known != null && (textDiff ? textDiff.mapPos(known) : known) == set.chunkPos[i] && !(textDiff === null || textDiff === void 0 ? void 0 : textDiff.touchesRange(known, known + set.chunk[i].length))) shared.add(set.chunk[i]);
    }
    return shared;
  }
  class LayerCursor {
    constructor(layer, skip, minPoint, rank = 0) {
      this.layer = layer;
      this.skip = skip;
      this.minPoint = minPoint;
      this.rank = rank;
    }
    get startSide() {
      return this.value ? this.value.startSide : 0;
    }
    get endSide() {
      return this.value ? this.value.endSide : 0;
    }
    goto(pos, side = -1e9 /* C.Far */) {
      this.chunkIndex = this.rangeIndex = 0;
      this.gotoInner(pos, side, false);
      return this;
    }
    gotoInner(pos, side, forward) {
      while (this.chunkIndex < this.layer.chunk.length) {
        let next = this.layer.chunk[this.chunkIndex];
        if (!(this.skip && this.skip.has(next) || this.layer.chunkEnd(this.chunkIndex) < pos || next.maxPoint < this.minPoint)) break;
        this.chunkIndex++;
        forward = false;
      }
      if (this.chunkIndex < this.layer.chunk.length) {
        let rangeIndex = this.layer.chunk[this.chunkIndex].findIndex(pos - this.layer.chunkPos[this.chunkIndex], side, true);
        if (!forward || this.rangeIndex < rangeIndex) this.setRangeIndex(rangeIndex);
      }
      this.next();
    }
    forward(pos, side) {
      if ((this.to - pos || this.endSide - side) < 0) this.gotoInner(pos, side, true);
    }
    next() {
      for (;;) {
        if (this.chunkIndex == this.layer.chunk.length) {
          this.from = this.to = 1000000000 /* C.Far */;
          this.value = null;
          break;
        } else {
          let chunkPos = this.layer.chunkPos[this.chunkIndex],
            chunk = this.layer.chunk[this.chunkIndex];
          let from = chunkPos + chunk.from[this.rangeIndex];
          this.from = from;
          this.to = chunkPos + chunk.to[this.rangeIndex];
          this.value = chunk.value[this.rangeIndex];
          this.setRangeIndex(this.rangeIndex + 1);
          if (this.minPoint < 0 || this.value.point && this.to - this.from >= this.minPoint) break;
        }
      }
    }
    setRangeIndex(index) {
      if (index == this.layer.chunk[this.chunkIndex].value.length) {
        this.chunkIndex++;
        if (this.skip) {
          while (this.chunkIndex < this.layer.chunk.length && this.skip.has(this.layer.chunk[this.chunkIndex])) this.chunkIndex++;
        }
        this.rangeIndex = 0;
      } else {
        this.rangeIndex = index;
      }
    }
    nextChunk() {
      this.chunkIndex++;
      this.rangeIndex = 0;
      this.next();
    }
    compare(other) {
      return this.from - other.from || this.startSide - other.startSide || this.rank - other.rank || this.to - other.to || this.endSide - other.endSide;
    }
  }
  class HeapCursor {
    constructor(heap) {
      this.heap = heap;
    }
    static from(sets, skip = null, minPoint = -1) {
      let heap = [];
      for (let i = 0; i < sets.length; i++) {
        for (let cur = sets[i]; !cur.isEmpty; cur = cur.nextLayer) {
          if (cur.maxPoint >= minPoint) heap.push(new LayerCursor(cur, skip, minPoint, i));
        }
      }
      return heap.length == 1 ? heap[0] : new HeapCursor(heap);
    }
    get startSide() {
      return this.value ? this.value.startSide : 0;
    }
    goto(pos, side = -1e9 /* C.Far */) {
      for (let cur of this.heap) cur.goto(pos, side);
      for (let i = this.heap.length >> 1; i >= 0; i--) heapBubble(this.heap, i);
      this.next();
      return this;
    }
    forward(pos, side) {
      for (let cur of this.heap) cur.forward(pos, side);
      for (let i = this.heap.length >> 1; i >= 0; i--) heapBubble(this.heap, i);
      if ((this.to - pos || this.value.endSide - side) < 0) this.next();
    }
    next() {
      if (this.heap.length == 0) {
        this.from = this.to = 1000000000 /* C.Far */;
        this.value = null;
        this.rank = -1;
      } else {
        let top = this.heap[0];
        this.from = top.from;
        this.to = top.to;
        this.value = top.value;
        this.rank = top.rank;
        if (top.value) top.next();
        heapBubble(this.heap, 0);
      }
    }
  }
  function heapBubble(heap, index) {
    for (let cur = heap[index];;) {
      let childIndex = (index << 1) + 1;
      if (childIndex >= heap.length) break;
      let child = heap[childIndex];
      if (childIndex + 1 < heap.length && child.compare(heap[childIndex + 1]) >= 0) {
        child = heap[childIndex + 1];
        childIndex++;
      }
      if (cur.compare(child) < 0) break;
      heap[childIndex] = cur;
      heap[index] = child;
      index = childIndex;
    }
  }
  class SpanCursor {
    constructor(sets, skip, minPoint) {
      this.minPoint = minPoint;
      this.active = [];
      this.activeTo = [];
      this.activeRank = [];
      this.minActive = -1;
      // A currently active point range, if any
      this.point = null;
      this.pointFrom = 0;
      this.pointRank = 0;
      this.to = -1e9 /* C.Far */;
      this.endSide = 0;
      // The amount of open active ranges at the start of the iterator.
      // Not including points.
      this.openStart = -1;
      this.cursor = HeapCursor.from(sets, skip, minPoint);
    }
    goto(pos, side = -1e9 /* C.Far */) {
      this.cursor.goto(pos, side);
      this.active.length = this.activeTo.length = this.activeRank.length = 0;
      this.minActive = -1;
      this.to = pos;
      this.endSide = side;
      this.openStart = -1;
      this.next();
      return this;
    }
    forward(pos, side) {
      while (this.minActive > -1 && (this.activeTo[this.minActive] - pos || this.active[this.minActive].endSide - side) < 0) this.removeActive(this.minActive);
      this.cursor.forward(pos, side);
    }
    removeActive(index) {
      remove(this.active, index);
      remove(this.activeTo, index);
      remove(this.activeRank, index);
      this.minActive = findMinIndex(this.active, this.activeTo);
    }
    addActive(trackOpen) {
      let i = 0,
        {
          value,
          to,
          rank
        } = this.cursor;
      // Organize active marks by rank first, then by size
      while (i < this.activeRank.length && (rank - this.activeRank[i] || to - this.activeTo[i]) > 0) i++;
      insert(this.active, i, value);
      insert(this.activeTo, i, to);
      insert(this.activeRank, i, rank);
      if (trackOpen) insert(trackOpen, i, this.cursor.from);
      this.minActive = findMinIndex(this.active, this.activeTo);
    }
    // After calling this, if `this.point` != null, the next range is a
    // point. Otherwise, it's a regular range, covered by `this.active`.
    next() {
      let from = this.to,
        wasPoint = this.point;
      this.point = null;
      let trackOpen = this.openStart < 0 ? [] : null;
      for (;;) {
        let a = this.minActive;
        if (a > -1 && (this.activeTo[a] - this.cursor.from || this.active[a].endSide - this.cursor.startSide) < 0) {
          if (this.activeTo[a] > from) {
            this.to = this.activeTo[a];
            this.endSide = this.active[a].endSide;
            break;
          }
          this.removeActive(a);
          if (trackOpen) remove(trackOpen, a);
        } else if (!this.cursor.value) {
          this.to = this.endSide = 1000000000 /* C.Far */;
          break;
        } else if (this.cursor.from > from) {
          this.to = this.cursor.from;
          this.endSide = this.cursor.startSide;
          break;
        } else {
          let nextVal = this.cursor.value;
          if (!nextVal.point) {
            // Opening a range
            this.addActive(trackOpen);
            this.cursor.next();
          } else if (wasPoint && this.cursor.to == this.to && this.cursor.from < this.cursor.to) {
            // Ignore any non-empty points that end precisely at the end of the prev point
            this.cursor.next();
          } else {
            // New point
            this.point = nextVal;
            this.pointFrom = this.cursor.from;
            this.pointRank = this.cursor.rank;
            this.to = this.cursor.to;
            this.endSide = nextVal.endSide;
            this.cursor.next();
            this.forward(this.to, this.endSide);
            break;
          }
        }
      }
      if (trackOpen) {
        this.openStart = 0;
        for (let i = trackOpen.length - 1; i >= 0 && trackOpen[i] < from; i--) this.openStart++;
      }
    }
    activeForPoint(to) {
      if (!this.active.length) return this.active;
      let active = [];
      for (let i = this.active.length - 1; i >= 0; i--) {
        if (this.activeRank[i] < this.pointRank) break;
        if (this.activeTo[i] > to || this.activeTo[i] == to && this.active[i].endSide >= this.point.endSide) active.push(this.active[i]);
      }
      return active.reverse();
    }
    openEnd(to) {
      let open = 0;
      for (let i = this.activeTo.length - 1; i >= 0 && this.activeTo[i] > to; i--) open++;
      return open;
    }
  }
  function compare(a, startA, b, startB, length, comparator) {
    a.goto(startA);
    b.goto(startB);
    let endB = startB + length;
    let pos = startB,
      dPos = startB - startA;
    let bounds = !!comparator.boundChange;
    for (let boundChange = false;;) {
      let dEnd = a.to + dPos - b.to,
        diff = dEnd || a.endSide - b.endSide;
      let end = diff < 0 ? a.to + dPos : b.to,
        clipEnd = Math.min(end, endB);
      let point = a.point || b.point;
      if (point) {
        if (!(a.point && b.point && cmpVal(a.point, b.point) && sameValues(a.activeForPoint(a.to), b.activeForPoint(b.to)))) comparator.comparePoint(pos, clipEnd, a.point, b.point);
        boundChange = false;
      } else {
        if (boundChange) comparator.boundChange(pos);
        if (clipEnd > pos && !sameValues(a.active, b.active)) comparator.compareRange(pos, clipEnd, a.active, b.active);
        if (bounds && clipEnd < endB && (dEnd || a.openEnd(end) != b.openEnd(end))) boundChange = true;
      }
      if (end > endB) break;
      pos = end;
      if (diff <= 0) a.next();
      if (diff >= 0) b.next();
    }
  }
  function sameValues(a, b) {
    if (a.length != b.length) return false;
    for (let i = 0; i < a.length; i++) if (a[i] != b[i] && !cmpVal(a[i], b[i])) return false;
    return true;
  }
  function remove(array, index) {
    for (let i = index, e = array.length - 1; i < e; i++) array[i] = array[i + 1];
    array.pop();
  }
  function insert(array, index, value) {
    for (let i = array.length - 1; i >= index; i--) array[i + 1] = array[i];
    array[index] = value;
  }
  function findMinIndex(value, array) {
    let found = -1,
      foundPos = 1000000000 /* C.Far */;
    for (let i = 0; i < array.length; i++) if ((array[i] - foundPos || value[i].endSide - value[found].endSide) < 0) {
      found = i;
      foundPos = array[i];
    }
    return found;
  }
  /**
  Find the offset that corresponds to the given column position in a
  string, taking extending characters and tab size into account. By
  default, the string length is returned when it is too short to
  reach the column. Pass `strict` true to make it return -1 in that
  situation.
  */
  function findColumn(string, col, tabSize, strict) {
    for (let i = 0, n = 0;;) {
      if (n >= col) return i;
      if (i == string.length) break;
      n += string.charCodeAt(i) == 9 ? tabSize - n % tabSize : 1;
      i = findClusterBreak(string, i);
    }
    return string.length;
  }

  const C = "\u037c";
  const COUNT = typeof Symbol == "undefined" ? "__" + C : Symbol.for(C);
  const SET = typeof Symbol == "undefined" ? "__styleSet" + Math.floor(Math.random() * 1e8) : Symbol("styleSet");
  const top = typeof globalThis != "undefined" ? globalThis : typeof window != "undefined" ? window : {};

  // :: - Style modules encapsulate a set of CSS rules defined from
  // JavaScript. Their definitions are only available in a given DOM
  // root after it has been _mounted_ there with `StyleModule.mount`.
  //
  // Style modules should be created once and stored somewhere, as
  // opposed to re-creating them every time you need them. The amount of
  // CSS rules generated for a given DOM root is bounded by the amount
  // of style modules that were used. So to avoid leaking rules, don't
  // create these dynamically, but treat them as one-time allocations.
  class StyleModule {
    // :: (Object<Style>, ?{finish: ?(string) → string})
    // Create a style module from the given spec.
    //
    // When `finish` is given, it is called on regular (non-`@`)
    // selectors (after `&` expansion) to compute the final selector.
    constructor(spec, options) {
      this.rules = [];
      let {
        finish
      } = options || {};
      function splitSelector(selector) {
        return /^@/.test(selector) ? [selector] : selector.split(/,\s*/);
      }
      function render(selectors, spec, target, isKeyframes) {
        let local = [],
          isAt = /^@(\w+)\b/.exec(selectors[0]),
          keyframes = isAt && isAt[1] == "keyframes";
        if (isAt && spec == null) return target.push(selectors[0] + ";");
        for (let prop in spec) {
          let value = spec[prop];
          if (/&/.test(prop)) {
            render(prop.split(/,\s*/).map(part => selectors.map(sel => part.replace(/&/, sel))).reduce((a, b) => a.concat(b)), value, target);
          } else if (value && typeof value == "object") {
            if (!isAt) throw new RangeError("The value of a property (" + prop + ") should be a primitive value.");
            render(splitSelector(prop), value, local, keyframes);
          } else if (value != null) {
            local.push(prop.replace(/_.*/, "").replace(/[A-Z]/g, l => "-" + l.toLowerCase()) + ": " + value + ";");
          }
        }
        if (local.length || keyframes) {
          target.push((finish && !isAt && !isKeyframes ? selectors.map(finish) : selectors).join(", ") + " {" + local.join(" ") + "}");
        }
      }
      for (let prop in spec) render(splitSelector(prop), spec[prop], this.rules);
    }

    // :: () → string
    // Returns a string containing the module's CSS rules.
    getRules() {
      return this.rules.join("\n");
    }

    // :: () → string
    // Generate a new unique CSS class name.
    static newName() {
      let id = top[COUNT] || 1;
      top[COUNT] = id + 1;
      return C + id.toString(36);
    }

    // :: (union<Document, ShadowRoot>, union<[StyleModule], StyleModule>, ?{nonce: ?string})
    //
    // Mount the given set of modules in the given DOM root, which ensures
    // that the CSS rules defined by the module are available in that
    // context.
    //
    // Rules are only added to the document once per root.
    //
    // Rule order will follow the order of the modules, so that rules from
    // modules later in the array take precedence of those from earlier
    // modules. If you call this function multiple times for the same root
    // in a way that changes the order of already mounted modules, the old
    // order will be changed.
    //
    // If a Content Security Policy nonce is provided, it is added to
    // the `<style>` tag generated by the library.
    static mount(root, modules, options) {
      let set = root[SET],
        nonce = options && options.nonce;
      if (!set) set = new StyleSet(root, nonce);else if (nonce) set.setNonce(nonce);
      set.mount(Array.isArray(modules) ? modules : [modules], root);
    }
  }
  let adoptedSet = new Map(); //<Document, StyleSet>

  class StyleSet {
    constructor(root, nonce) {
      let doc = root.ownerDocument || root,
        win = doc.defaultView;
      if (!root.head && root.adoptedStyleSheets && win.CSSStyleSheet) {
        let adopted = adoptedSet.get(doc);
        if (adopted) return root[SET] = adopted;
        this.sheet = new win.CSSStyleSheet();
        adoptedSet.set(doc, this);
      } else {
        this.styleTag = doc.createElement("style");
        if (nonce) this.styleTag.setAttribute("nonce", nonce);
      }
      this.modules = [];
      root[SET] = this;
    }
    mount(modules, root) {
      let sheet = this.sheet;
      let pos = 0 /* Current rule offset */,
        j = 0; /* Index into this.modules */
      for (let i = 0; i < modules.length; i++) {
        let mod = modules[i],
          index = this.modules.indexOf(mod);
        if (index < j && index > -1) {
          // Ordering conflict
          this.modules.splice(index, 1);
          j--;
          index = -1;
        }
        if (index == -1) {
          this.modules.splice(j++, 0, mod);
          if (sheet) for (let k = 0; k < mod.rules.length; k++) sheet.insertRule(mod.rules[k], pos++);
        } else {
          while (j < index) pos += this.modules[j++].rules.length;
          pos += mod.rules.length;
          j++;
        }
      }
      if (sheet) {
        if (root.adoptedStyleSheets.indexOf(this.sheet) < 0) root.adoptedStyleSheets = [this.sheet, ...root.adoptedStyleSheets];
      } else {
        let text = "";
        for (let i = 0; i < this.modules.length; i++) text += this.modules[i].getRules() + "\n";
        this.styleTag.textContent = text;
        let target = root.head || root;
        if (this.styleTag.parentNode != target) target.insertBefore(this.styleTag, target.firstChild);
      }
    }
    setNonce(nonce) {
      if (this.styleTag && this.styleTag.getAttribute("nonce") != nonce) this.styleTag.setAttribute("nonce", nonce);
    }
  }

  // Style::Object<union<Style,string>>
  //
  // A style is an object that, in the simple case, maps CSS property
  // names to strings holding their values, as in `{color: "red",
  // fontWeight: "bold"}`. The property names can be given in
  // camel-case—the library will insert a dash before capital letters
  // when converting them to CSS.
  //
  // If you include an underscore in a property name, it and everything
  // after it will be removed from the output, which can be useful when
  // providing a property multiple times, for browser compatibility
  // reasons.
  //
  // A property in a style object can also be a sub-selector, which
  // extends the current context to add a pseudo-selector or a child
  // selector. Such a property should contain a `&` character, which
  // will be replaced by the current selector. For example `{"&:before":
  // {content: '"hi"'}}`. Sub-selectors and regular properties can
  // freely be mixed in a given object. Any property containing a `&` is
  // assumed to be a sub-selector.
  //
  // Finally, a property can specify an @-block to be wrapped around the
  // styles defined inside the object that's the property's value. For
  // example to create a media query you can do `{"@media screen and
  // (min-width: 400px)": {...}}`.

  var base = {
    8: "Backspace",
    9: "Tab",
    10: "Enter",
    12: "NumLock",
    13: "Enter",
    16: "Shift",
    17: "Control",
    18: "Alt",
    20: "CapsLock",
    27: "Escape",
    32: " ",
    33: "PageUp",
    34: "PageDown",
    35: "End",
    36: "Home",
    37: "ArrowLeft",
    38: "ArrowUp",
    39: "ArrowRight",
    40: "ArrowDown",
    44: "PrintScreen",
    45: "Insert",
    46: "Delete",
    59: ";",
    61: "=",
    91: "Meta",
    92: "Meta",
    106: "*",
    107: "+",
    108: ",",
    109: "-",
    110: ".",
    111: "/",
    144: "NumLock",
    145: "ScrollLock",
    160: "Shift",
    161: "Shift",
    162: "Control",
    163: "Control",
    164: "Alt",
    165: "Alt",
    173: "-",
    186: ";",
    187: "=",
    188: ",",
    189: "-",
    190: ".",
    191: "/",
    192: "`",
    219: "[",
    220: "\\",
    221: "]",
    222: "'"
  };
  var shift = {
    48: ")",
    49: "!",
    50: "@",
    51: "#",
    52: "$",
    53: "%",
    54: "^",
    55: "&",
    56: "*",
    57: "(",
    59: ":",
    61: "+",
    173: "_",
    186: ":",
    187: "+",
    188: "<",
    189: "_",
    190: ">",
    191: "?",
    192: "~",
    219: "{",
    220: "|",
    221: "}",
    222: "\""
  };

  // Fill in the digit keys
  for (var i = 0; i < 10; i++) base[48 + i] = base[96 + i] = String(i);

  // The function keys
  for (var i = 1; i <= 24; i++) base[i + 111] = "F" + i;

  // And the alphabetic keys
  for (var i = 65; i <= 90; i++) {
    base[i] = String.fromCharCode(i + 32);
    shift[i] = String.fromCharCode(i);
  }

  // For each code that doesn't have a shift-equivalent, copy the base name
  for (var code in base) if (!shift.hasOwnProperty(code)) shift[code] = base[code];

  function crelt() {
    var elt = arguments[0];
    if (typeof elt == "string") elt = document.createElement(elt);
    var i = 1,
      next = arguments[1];
    if (next && typeof next == "object" && next.nodeType == null && !Array.isArray(next)) {
      for (var name in next) if (Object.prototype.hasOwnProperty.call(next, name)) {
        var value = next[name];
        if (typeof value == "string") elt.setAttribute(name, value);else if (value != null) elt[name] = value;
      }
      i++;
    }
    for (; i < arguments.length; i++) add(elt, arguments[i]);
    return elt;
  }
  function add(elt, child) {
    if (typeof child == "string") {
      elt.appendChild(document.createTextNode(child));
    } else if (child == null) ; else if (child.nodeType != null) {
      elt.appendChild(child);
    } else if (Array.isArray(child)) {
      for (var i = 0; i < child.length; i++) add(elt, child[i]);
    } else {
      throw new RangeError("Unsupported child node: " + child);
    }
  }

  let nav = typeof navigator != "undefined" ? navigator : {
    userAgent: "",
    vendor: "",
    platform: ""
  };
  let doc = typeof document != "undefined" ? document : {
    documentElement: {
      style: {}
    }
  };
  const ie_edge = /*@__PURE__*//Edge\/(\d+)/.exec(nav.userAgent);
  const ie_upto10 = /*@__PURE__*//MSIE \d/.test(nav.userAgent);
  const ie_11up = /*@__PURE__*//Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(nav.userAgent);
  const ie = !!(ie_upto10 || ie_11up || ie_edge);
  const gecko = !ie && /*@__PURE__*//gecko\/(\d+)/i.test(nav.userAgent);
  const chrome = !ie && /*@__PURE__*//Chrome\/(\d+)/.exec(nav.userAgent);
  const webkit = "webkitFontSmoothing" in doc.documentElement.style;
  const safari = !ie && /*@__PURE__*//Apple Computer/.test(nav.vendor);
  const ios = safari && (/*@__PURE__*//Mobile\/\w+/.test(nav.userAgent) || nav.maxTouchPoints > 2);
  var browser = {
    mac: ios || /*@__PURE__*//Mac/.test(nav.platform),
    ie,
    ie_version: ie_upto10 ? doc.documentMode || 6 : ie_11up ? +ie_11up[1] : ie_edge ? +ie_edge[1] : 0,
    gecko,
    gecko_version: gecko ? +(/*@__PURE__*//Firefox\/(\d+)/.exec(nav.userAgent) || [0, 0])[1] : 0,
    chrome: !!chrome,
    chrome_version: chrome ? +chrome[1] : 0,
    ios,
    android: /*@__PURE__*//Android\b/.test(nav.userAgent),
    webkit_version: webkit ? +(/*@__PURE__*//\bAppleWebKit\/(\d+)/.exec(nav.userAgent) || [0, 0])[1] : 0,
    safari,
    safari_version: safari ? +(/*@__PURE__*//\bVersion\/(\d+(\.\d+)?)/.exec(nav.userAgent) || [0, 0])[1] : 0,
    tabSize: doc.documentElement.style.tabSize != null ? "tab-size" : "-moz-tab-size"
  };
  function combineAttrs(source, target) {
    for (let name in source) {
      if (name == "class" && target.class) target.class += " " + source.class;else if (name == "style" && target.style) target.style += ";" + source.style;else target[name] = source[name];
    }
    return target;
  }
  const noAttrs = /*@__PURE__*/Object.create(null);
  function attrsEq(a, b, ignore) {
    if (a == b) return true;
    if (!a) a = noAttrs;
    if (!b) b = noAttrs;
    let keysA = Object.keys(a),
      keysB = Object.keys(b);
    if (keysA.length - (0) != keysB.length - (0)) return false;
    for (let key of keysA) {
      if (key != ignore && (keysB.indexOf(key) == -1 || a[key] !== b[key])) return false;
    }
    return true;
  }
  function setAttrs(dom, attrs) {
    for (let i = dom.attributes.length - 1; i >= 0; i--) {
      let name = dom.attributes[i].name;
      if (attrs[name] == null) dom.removeAttribute(name);
    }
    for (let name in attrs) {
      let value = attrs[name];
      if (name == "style") dom.style.cssText = value;else if (dom.getAttribute(name) != value) dom.setAttribute(name, value);
    }
  }
  function updateAttrs(dom, prev, attrs) {
    let changed = false;
    if (prev) for (let name in prev) if (!(attrs && name in attrs)) {
      changed = true;
      if (name == "style") dom.style.cssText = "";else dom.removeAttribute(name);
    }
    if (attrs) for (let name in attrs) if (!(prev && prev[name] == attrs[name])) {
      changed = true;
      if (name == "style") dom.style.cssText = attrs[name];else dom.setAttribute(name, attrs[name]);
    }
    return changed;
  }
  function getAttrs(dom) {
    let attrs = Object.create(null);
    for (let i = 0; i < dom.attributes.length; i++) {
      let attr = dom.attributes[i];
      attrs[attr.name] = attr.value;
    }
    return attrs;
  }

  /**
  Widgets added to the content are described by subclasses of this
  class. Using a description object like that makes it possible to
  delay creating of the DOM structure for a widget until it is
  needed, and to avoid redrawing widgets even if the decorations
  that define them are recreated.
  */
  class WidgetType {
    /**
    Compare this instance to another instance of the same type.
    (TypeScript can't express this, but only instances of the same
    specific class will be passed to this method.) This is used to
    avoid redrawing widgets when they are replaced by a new
    decoration of the same type. The default implementation just
    returns `false`, which will cause new instances of the widget to
    always be redrawn.
    */
    eq(widget) {
      return false;
    }
    /**
    Update a DOM element created by a widget of the same type (but
    different, non-`eq` content) to reflect this widget. May return
    true to indicate that it could update, false to indicate it
    couldn't (in which case the widget will be redrawn). The default
    implementation just returns false.
    */
    updateDOM(dom, view, from) {
      return false;
    }
    /**
    @internal
    */
    compare(other) {
      return this == other || this.constructor == other.constructor && this.eq(other);
    }
    /**
    The estimated height this widget will have, to be used when
    estimating the height of content that hasn't been drawn. May
    return -1 to indicate you don't know. The default implementation
    returns -1.
    */
    get estimatedHeight() {
      return -1;
    }
    /**
    For inline widgets that are displayed inline (as opposed to
    `inline-block`) and introduce line breaks (through `<br>` tags
    or textual newlines), this must indicate the amount of line
    breaks they introduce. Defaults to 0.
    */
    get lineBreaks() {
      return 0;
    }
    /**
    Can be used to configure which kinds of events inside the widget
    should be ignored by the editor. The default is to ignore all
    events.
    */
    ignoreEvent(event) {
      return true;
    }
    /**
    Override the way screen coordinates for positions at/in the
    widget are found. `pos` will be the offset into the widget, and
    `side` the side of the position that is being queried—less than
    zero for before, greater than zero for after, and zero for
    directly at that position.
    */
    coordsAt(dom, pos, side) {
      return null;
    }
    /**
    @internal
    */
    get isHidden() {
      return false;
    }
    /**
    @internal
    */
    get editable() {
      return false;
    }
    /**
    This is called when the an instance of the widget is removed
    from the editor view.
    */
    destroy(dom) {}
  }
  /**
  The different types of blocks that can occur in an editor view.
  */
  var BlockType = /*@__PURE__*/function (BlockType) {
    /**
    A line of text.
    */
    BlockType[BlockType["Text"] = 0] = "Text";
    /**
    A block widget associated with the position after it.
    */
    BlockType[BlockType["WidgetBefore"] = 1] = "WidgetBefore";
    /**
    A block widget associated with the position before it.
    */
    BlockType[BlockType["WidgetAfter"] = 2] = "WidgetAfter";
    /**
    A block widget [replacing](https://codemirror.net/6/docs/ref/#view.Decoration^replace) a range of content.
    */
    BlockType[BlockType["WidgetRange"] = 3] = "WidgetRange";
    return BlockType;
  }(BlockType || (BlockType = {}));
  /**
  A decoration provides information on how to draw or style a piece
  of content. You'll usually use it wrapped in a
  [`Range`](https://codemirror.net/6/docs/ref/#state.Range), which adds a start and end position.
  @nonabstract
  */
  class Decoration extends RangeValue {
    constructor(
    /**
    @internal
    */
    startSide,
    /**
    @internal
    */
    endSide,
    /**
    @internal
    */
    widget,
    /**
    The config object used to create this decoration. You can
    include additional properties in there to store metadata about
    your decoration.
    */
    spec) {
      super();
      this.startSide = startSide;
      this.endSide = endSide;
      this.widget = widget;
      this.spec = spec;
    }
    /**
    @internal
    */
    get heightRelevant() {
      return false;
    }
    /**
    Create a mark decoration, which influences the styling of the
    content in its range. Nested mark decorations will cause nested
    DOM elements to be created. Nesting order is determined by
    precedence of the [facet](https://codemirror.net/6/docs/ref/#view.EditorView^decorations), with
    the higher-precedence decorations creating the inner DOM nodes.
    Such elements are split on line boundaries and on the boundaries
    of lower-precedence decorations.
    */
    static mark(spec) {
      return new MarkDecoration(spec);
    }
    /**
    Create a widget decoration, which displays a DOM element at the
    given position.
    */
    static widget(spec) {
      let side = Math.max(-1e4, Math.min(10000, spec.side || 0)),
        block = !!spec.block;
      side += block && !spec.inlineOrder ? side > 0 ? 300000000 /* Side.BlockAfter */ : -4e8 /* Side.BlockBefore */ : side > 0 ? 100000000 /* Side.InlineAfter */ : -1e8 /* Side.InlineBefore */;
      return new PointDecoration(spec, side, side, block, spec.widget || null, false);
    }
    /**
    Create a replace decoration which replaces the given range with
    a widget, or simply hides it.
    */
    static replace(spec) {
      let block = !!spec.block,
        startSide,
        endSide;
      if (spec.isBlockGap) {
        startSide = -5e8 /* Side.GapStart */;
        endSide = 400000000 /* Side.GapEnd */;
      } else {
        let {
          start,
          end
        } = getInclusive(spec, block);
        startSide = (start ? block ? -3e8 /* Side.BlockIncStart */ : -1 /* Side.InlineIncStart */ : 500000000 /* Side.NonIncStart */) - 1;
        endSide = (end ? block ? 200000000 /* Side.BlockIncEnd */ : 1 /* Side.InlineIncEnd */ : -6e8 /* Side.NonIncEnd */) + 1;
      }
      return new PointDecoration(spec, startSide, endSide, block, spec.widget || null, true);
    }
    /**
    Create a line decoration, which can add DOM attributes to the
    line starting at the given position.
    */
    static line(spec) {
      return new LineDecoration(spec);
    }
    /**
    Build a [`DecorationSet`](https://codemirror.net/6/docs/ref/#view.DecorationSet) from the given
    decorated range or ranges. If the ranges aren't already sorted,
    pass `true` for `sort` to make the library sort them for you.
    */
    static set(of, sort = false) {
      return RangeSet.of(of, sort);
    }
    /**
    @internal
    */
    hasHeight() {
      return this.widget ? this.widget.estimatedHeight > -1 : false;
    }
  }
  /**
  The empty set of decorations.
  */
  Decoration.none = RangeSet.empty;
  class MarkDecoration extends Decoration {
    constructor(spec) {
      let {
        start,
        end
      } = getInclusive(spec);
      super(start ? -1 /* Side.InlineIncStart */ : 500000000 /* Side.NonIncStart */, end ? 1 /* Side.InlineIncEnd */ : -6e8 /* Side.NonIncEnd */, null, spec);
      this.tagName = spec.tagName || "span";
      this.attrs = spec.class && spec.attributes ? combineAttrs(spec.attributes, {
        class: spec.class
      }) : spec.class ? {
        class: spec.class
      } : spec.attributes || noAttrs;
    }
    eq(other) {
      return this == other || other instanceof MarkDecoration && this.tagName == other.tagName && attrsEq(this.attrs, other.attrs);
    }
    range(from, to = from) {
      if (from >= to) throw new RangeError("Mark decorations may not be empty");
      return super.range(from, to);
    }
  }
  MarkDecoration.prototype.point = false;
  class LineDecoration extends Decoration {
    constructor(spec) {
      super(-2e8 /* Side.Line */, -2e8 /* Side.Line */, null, spec);
    }
    eq(other) {
      return other instanceof LineDecoration && this.spec.class == other.spec.class && attrsEq(this.spec.attributes, other.spec.attributes);
    }
    range(from, to = from) {
      if (to != from) throw new RangeError("Line decoration ranges must be zero-length");
      return super.range(from, to);
    }
  }
  LineDecoration.prototype.mapMode = MapMode.TrackBefore;
  LineDecoration.prototype.point = true;
  class PointDecoration extends Decoration {
    constructor(spec, startSide, endSide, block, widget, isReplace) {
      super(startSide, endSide, widget, spec);
      this.block = block;
      this.isReplace = isReplace;
      this.mapMode = !block ? MapMode.TrackDel : startSide <= 0 ? MapMode.TrackBefore : MapMode.TrackAfter;
    }
    // Only relevant when this.block == true
    get type() {
      return this.startSide != this.endSide ? BlockType.WidgetRange : this.startSide <= 0 ? BlockType.WidgetBefore : BlockType.WidgetAfter;
    }
    get heightRelevant() {
      return this.block || !!this.widget && (this.widget.estimatedHeight >= 5 || this.widget.lineBreaks > 0);
    }
    eq(other) {
      return other instanceof PointDecoration && widgetsEq(this.widget, other.widget) && this.block == other.block && this.startSide == other.startSide && this.endSide == other.endSide;
    }
    range(from, to = from) {
      if (this.isReplace && (from > to || from == to && this.startSide > 0 && this.endSide <= 0)) throw new RangeError("Invalid range for replacement decoration");
      if (!this.isReplace && to != from) throw new RangeError("Widget decorations can only have zero-length ranges");
      return super.range(from, to);
    }
  }
  PointDecoration.prototype.point = true;
  function getInclusive(spec, block = false) {
    let {
      inclusiveStart: start,
      inclusiveEnd: end
    } = spec;
    if (start == null) start = spec.inclusive;
    if (end == null) end = spec.inclusive;
    return {
      start: start !== null && start !== void 0 ? start : block,
      end: end !== null && end !== void 0 ? end : block
    };
  }
  function widgetsEq(a, b) {
    return a == b || !!(a && b && a.compare(b));
  }
  function addRange(from, to, ranges, margin = 0) {
    let last = ranges.length - 1;
    if (last >= 0 && ranges[last] + margin >= from) ranges[last] = Math.max(ranges[last], to);else ranges.push(from, to);
  }
  /**
  A block wrapper defines a DOM node that wraps lines or other block
  wrappers at the top of the document. It affects any line or block
  widget that starts inside its range, including blocks starting
  directly at `from` but not including `to`.
  */
  class BlockWrapper extends RangeValue {
    constructor(
    /**
    @internal
    */
    tagName,
    /**
    @internal
    */
    attributes,
    /**
    @internal
    */
    rank) {
      super();
      this.tagName = tagName;
      this.attributes = attributes;
      this.rank = rank;
    }
    eq(other) {
      return other == this || other instanceof BlockWrapper && this.tagName == other.tagName && attrsEq(this.attributes, other.attributes);
    }
    /**
    Create a block wrapper object with the given tag name and
    attributes.
    */
    static create(spec) {
      return new BlockWrapper(spec.tagName, spec.attributes || noAttrs, spec.rank == null ? 50 : Math.max(0, Math.min(spec.rank, 100)));
    }
    /**
    Create a range set from the given block wrapper ranges.
    */
    static set(of, sort = false) {
      return RangeSet.of(of, sort);
    }
  }
  BlockWrapper.prototype.startSide = BlockWrapper.prototype.endSide = -1;
  function getSelection(root) {
    let target;
    // Browsers differ on whether shadow roots have a getSelection
    // method. If it exists, use that, otherwise, call it on the
    // document.
    if (root.nodeType == 11) {
      // Shadow root
      target = root.getSelection ? root : root.ownerDocument;
    } else {
      target = root;
    }
    return target.getSelection();
  }
  function contains(dom, node) {
    return node ? dom == node || dom.contains(node.nodeType != 1 ? node.parentNode : node) : false;
  }
  function hasSelection(dom, selection) {
    if (!selection.anchorNode) return false;
    try {
      // Firefox will raise 'permission denied' errors when accessing
      // properties of `sel.anchorNode` when it's in a generated CSS
      // element.
      return contains(dom, selection.anchorNode);
    } catch (_) {
      return false;
    }
  }
  function clientRectsFor(dom) {
    if (dom.nodeType == 3) return textRange(dom, 0, dom.nodeValue.length).getClientRects();else if (dom.nodeType == 1) return dom.getClientRects();else return [];
  }
  // Scans forward and backward through DOM positions equivalent to the
  // given one to see if the two are in the same place (i.e. after a
  // text node vs at the end of that text node)
  function isEquivalentPosition(node, off, targetNode, targetOff) {
    return targetNode ? scanFor(node, off, targetNode, targetOff, -1) || scanFor(node, off, targetNode, targetOff, 1) : false;
  }
  function domIndex(node) {
    for (var index = 0;; index++) {
      node = node.previousSibling;
      if (!node) return index;
    }
  }
  function isBlockElement(node) {
    return node.nodeType == 1 && /^(DIV|P|LI|UL|OL|BLOCKQUOTE|DD|DT|H\d|SECTION|PRE)$/.test(node.nodeName);
  }
  function scanFor(node, off, targetNode, targetOff, dir) {
    for (;;) {
      if (node == targetNode && off == targetOff) return true;
      if (off == (dir < 0 ? 0 : maxOffset(node))) {
        if (node.nodeName == "DIV") return false;
        let parent = node.parentNode;
        if (!parent || parent.nodeType != 1) return false;
        off = domIndex(node) + (dir < 0 ? 0 : 1);
        node = parent;
      } else if (node.nodeType == 1) {
        node = node.childNodes[off + (dir < 0 ? -1 : 0)];
        if (node.nodeType == 1 && node.contentEditable == "false") return false;
        off = dir < 0 ? maxOffset(node) : 0;
      } else {
        return false;
      }
    }
  }
  function maxOffset(node) {
    return node.nodeType == 3 ? node.nodeValue.length : node.childNodes.length;
  }
  function flattenRect(rect, left) {
    let x = left ? rect.left : rect.right;
    return {
      left: x,
      right: x,
      top: rect.top,
      bottom: rect.bottom
    };
  }
  function windowRect(win) {
    let vp = win.visualViewport;
    if (vp) return {
      left: 0,
      right: vp.width,
      top: 0,
      bottom: vp.height
    };
    return {
      left: 0,
      right: win.innerWidth,
      top: 0,
      bottom: win.innerHeight
    };
  }
  function getScale(elt, rect) {
    let scaleX = rect.width / elt.offsetWidth;
    let scaleY = rect.height / elt.offsetHeight;
    if (scaleX > 0.995 && scaleX < 1.005 || !isFinite(scaleX) || Math.abs(rect.width - elt.offsetWidth) < 1) scaleX = 1;
    if (scaleY > 0.995 && scaleY < 1.005 || !isFinite(scaleY) || Math.abs(rect.height - elt.offsetHeight) < 1) scaleY = 1;
    return {
      scaleX,
      scaleY
    };
  }
  function scrollRectIntoView(dom, rect, side, x, y, xMargin, yMargin, ltr) {
    let doc = dom.ownerDocument,
      win = doc.defaultView || window;
    for (let cur = dom, stop = false; cur && !stop;) {
      if (cur.nodeType == 1) {
        // Element
        let bounding,
          top = cur == doc.body;
        let scaleX = 1,
          scaleY = 1;
        if (top) {
          bounding = windowRect(win);
        } else {
          if (/^(fixed|sticky)$/.test(getComputedStyle(cur).position)) stop = true;
          if (cur.scrollHeight <= cur.clientHeight && cur.scrollWidth <= cur.clientWidth) {
            cur = cur.assignedSlot || cur.parentNode;
            continue;
          }
          let rect = cur.getBoundingClientRect();
          ({
            scaleX,
            scaleY
          } = getScale(cur, rect));
          // Make sure scrollbar width isn't included in the rectangle
          bounding = {
            left: rect.left,
            right: rect.left + cur.clientWidth * scaleX,
            top: rect.top,
            bottom: rect.top + cur.clientHeight * scaleY
          };
        }
        let moveX = 0,
          moveY = 0;
        if (y == "nearest") {
          if (rect.top < bounding.top + yMargin) {
            moveY = rect.top - (bounding.top + yMargin);
            if (side > 0 && rect.bottom > bounding.bottom + moveY) moveY = rect.bottom - bounding.bottom + yMargin;
          } else if (rect.bottom > bounding.bottom - yMargin) {
            moveY = rect.bottom - bounding.bottom + yMargin;
            if (side < 0 && rect.top - moveY < bounding.top) moveY = rect.top - (bounding.top + yMargin);
          }
        } else {
          let rectHeight = rect.bottom - rect.top,
            boundingHeight = bounding.bottom - bounding.top;
          let targetTop = y == "center" && rectHeight <= boundingHeight ? rect.top + rectHeight / 2 - boundingHeight / 2 : y == "start" || y == "center" && side < 0 ? rect.top - yMargin : rect.bottom - boundingHeight + yMargin;
          moveY = targetTop - bounding.top;
        }
        if (x == "nearest") {
          if (rect.left < bounding.left + xMargin) {
            moveX = rect.left - (bounding.left + xMargin);
            if (side > 0 && rect.right > bounding.right + moveX) moveX = rect.right - bounding.right + xMargin;
          } else if (rect.right > bounding.right - xMargin) {
            moveX = rect.right - bounding.right + xMargin;
            if (side < 0 && rect.left < bounding.left + moveX) moveX = rect.left - (bounding.left + xMargin);
          }
        } else {
          let targetLeft = x == "center" ? rect.left + (rect.right - rect.left) / 2 - (bounding.right - bounding.left) / 2 : x == "start" == ltr ? rect.left - xMargin : rect.right - (bounding.right - bounding.left) + xMargin;
          moveX = targetLeft - bounding.left;
        }
        if (moveX || moveY) {
          if (top) {
            win.scrollBy(moveX, moveY);
          } else {
            let movedX = 0,
              movedY = 0;
            if (moveY) {
              let start = cur.scrollTop;
              cur.scrollTop += moveY / scaleY;
              movedY = (cur.scrollTop - start) * scaleY;
            }
            if (moveX) {
              let start = cur.scrollLeft;
              cur.scrollLeft += moveX / scaleX;
              movedX = (cur.scrollLeft - start) * scaleX;
            }
            rect = {
              left: rect.left - movedX,
              top: rect.top - movedY,
              right: rect.right - movedX,
              bottom: rect.bottom - movedY
            };
            if (movedX && Math.abs(movedX - moveX) < 1) x = "nearest";
            if (movedY && Math.abs(movedY - moveY) < 1) y = "nearest";
          }
        }
        if (top) break;
        if (rect.top < bounding.top || rect.bottom > bounding.bottom || rect.left < bounding.left || rect.right > bounding.right) rect = {
          left: Math.max(rect.left, bounding.left),
          right: Math.min(rect.right, bounding.right),
          top: Math.max(rect.top, bounding.top),
          bottom: Math.min(rect.bottom, bounding.bottom)
        };
        cur = cur.assignedSlot || cur.parentNode;
      } else if (cur.nodeType == 11) {
        // A shadow root
        cur = cur.host;
      } else {
        break;
      }
    }
  }
  function scrollableParents(dom, getX = true) {
    let doc = dom.ownerDocument,
      x = null,
      y = null;
    for (let cur = dom.parentNode; cur;) {
      if (cur == doc.body || (!getX || x) && y) {
        break;
      } else if (cur.nodeType == 1) {
        if (!y && cur.scrollHeight > cur.clientHeight) y = cur;
        if (getX && !x && cur.scrollWidth > cur.clientWidth) x = cur;
        cur = cur.assignedSlot || cur.parentNode;
      } else if (cur.nodeType == 11) {
        cur = cur.host;
      } else {
        break;
      }
    }
    return {
      x,
      y
    };
  }
  class DOMSelectionState {
    constructor() {
      this.anchorNode = null;
      this.anchorOffset = 0;
      this.focusNode = null;
      this.focusOffset = 0;
    }
    eq(domSel) {
      return this.anchorNode == domSel.anchorNode && this.anchorOffset == domSel.anchorOffset && this.focusNode == domSel.focusNode && this.focusOffset == domSel.focusOffset;
    }
    setRange(range) {
      let {
        anchorNode,
        focusNode
      } = range;
      // Clip offsets to node size to avoid crashes when Safari reports bogus offsets (#1152)
      this.set(anchorNode, Math.min(range.anchorOffset, anchorNode ? maxOffset(anchorNode) : 0), focusNode, Math.min(range.focusOffset, focusNode ? maxOffset(focusNode) : 0));
    }
    set(anchorNode, anchorOffset, focusNode, focusOffset) {
      this.anchorNode = anchorNode;
      this.anchorOffset = anchorOffset;
      this.focusNode = focusNode;
      this.focusOffset = focusOffset;
    }
  }
  let preventScrollSupported = null;
  // Safari 26 breaks preventScroll support
  if (browser.safari && browser.safari_version >= 26) preventScrollSupported = false;
  // Feature-detects support for .focus({preventScroll: true}), and uses
  // a fallback kludge when not supported.
  function focusPreventScroll(dom) {
    if (dom.setActive) return dom.setActive(); // in IE
    if (preventScrollSupported) return dom.focus(preventScrollSupported);
    let stack = [];
    for (let cur = dom; cur; cur = cur.parentNode) {
      stack.push(cur, cur.scrollTop, cur.scrollLeft);
      if (cur == cur.ownerDocument) break;
    }
    dom.focus(preventScrollSupported == null ? {
      get preventScroll() {
        preventScrollSupported = {
          preventScroll: true
        };
        return true;
      }
    } : undefined);
    if (!preventScrollSupported) {
      preventScrollSupported = false;
      for (let i = 0; i < stack.length;) {
        let elt = stack[i++],
          top = stack[i++],
          left = stack[i++];
        if (elt.scrollTop != top) elt.scrollTop = top;
        if (elt.scrollLeft != left) elt.scrollLeft = left;
      }
    }
  }
  let scratchRange;
  function textRange(node, from, to = from) {
    let range = scratchRange || (scratchRange = document.createRange());
    range.setEnd(node, to);
    range.setStart(node, from);
    return range;
  }
  function dispatchKey(elt, name, code, mods) {
    let options = {
      key: name,
      code: name,
      keyCode: code,
      which: code,
      cancelable: true
    };
    if (mods) ({
      altKey: options.altKey,
      ctrlKey: options.ctrlKey,
      shiftKey: options.shiftKey,
      metaKey: options.metaKey
    } = mods);
    let down = new KeyboardEvent("keydown", options);
    down.synthetic = true;
    elt.dispatchEvent(down);
    let up = new KeyboardEvent("keyup", options);
    up.synthetic = true;
    elt.dispatchEvent(up);
    return down.defaultPrevented || up.defaultPrevented;
  }
  function getRoot(node) {
    while (node) {
      if (node && (node.nodeType == 9 || node.nodeType == 11 && node.host)) return node;
      node = node.assignedSlot || node.parentNode;
    }
    return null;
  }
  function atElementStart(doc, selection) {
    let node = selection.focusNode,
      offset = selection.focusOffset;
    if (!node || selection.anchorNode != node || selection.anchorOffset != offset) return false;
    // Safari can report bogus offsets (#1152)
    offset = Math.min(offset, maxOffset(node));
    for (;;) {
      if (offset) {
        if (node.nodeType != 1) return false;
        let prev = node.childNodes[offset - 1];
        if (prev.contentEditable == "false") offset--;else {
          node = prev;
          offset = maxOffset(node);
        }
      } else if (node == doc) {
        return true;
      } else {
        offset = domIndex(node);
        node = node.parentNode;
      }
    }
  }
  function isScrolledToBottom(elt) {
    if (elt instanceof Window) return elt.pageYOffset > Math.max(0, elt.document.documentElement.scrollHeight - elt.innerHeight - 4);
    return elt.scrollTop > Math.max(1, elt.scrollHeight - elt.clientHeight - 4);
  }
  function textNodeBefore(startNode, startOffset) {
    for (let node = startNode, offset = startOffset;;) {
      if (node.nodeType == 3 && offset > 0) {
        return {
          node: node,
          offset: offset
        };
      } else if (node.nodeType == 1 && offset > 0) {
        if (node.contentEditable == "false") return null;
        node = node.childNodes[offset - 1];
        offset = maxOffset(node);
      } else if (node.parentNode && !isBlockElement(node)) {
        offset = domIndex(node);
        node = node.parentNode;
      } else {
        return null;
      }
    }
  }
  function textNodeAfter(startNode, startOffset) {
    for (let node = startNode, offset = startOffset;;) {
      if (node.nodeType == 3 && offset < node.nodeValue.length) {
        return {
          node: node,
          offset: offset
        };
      } else if (node.nodeType == 1 && offset < node.childNodes.length) {
        if (node.contentEditable == "false") return null;
        node = node.childNodes[offset];
        offset = 0;
      } else if (node.parentNode && !isBlockElement(node)) {
        offset = domIndex(node) + 1;
        node = node.parentNode;
      } else {
        return null;
      }
    }
  }
  class DOMPos {
    constructor(node, offset, precise = true) {
      this.node = node;
      this.offset = offset;
      this.precise = precise;
    }
    static before(dom, precise) {
      return new DOMPos(dom.parentNode, domIndex(dom), precise);
    }
    static after(dom, precise) {
      return new DOMPos(dom.parentNode, domIndex(dom) + 1, precise);
    }
  }

  /**
  Used to indicate [text direction](https://codemirror.net/6/docs/ref/#view.EditorView.textDirection).
  */
  var Direction = /*@__PURE__*/function (Direction) {
    // (These are chosen to match the base levels, in bidi algorithm
    // terms, of spans in that direction.)
    /**
    Left-to-right.
    */
    Direction[Direction["LTR"] = 0] = "LTR";
    /**
    Right-to-left.
    */
    Direction[Direction["RTL"] = 1] = "RTL";
    return Direction;
  }(Direction || (Direction = {}));
  const LTR = Direction.LTR,
    RTL = Direction.RTL;
  // Decode a string with each type encoded as log2(type)
  function dec(str) {
    let result = [];
    for (let i = 0; i < str.length; i++) result.push(1 << +str[i]);
    return result;
  }
  // Character types for codepoints 0 to 0xf8
  const LowTypes = /*@__PURE__*/dec("88888888888888888888888888888888888666888888787833333333337888888000000000000000000000000008888880000000000000000000000000088888888888888888888888888888888888887866668888088888663380888308888800000000000000000000000800000000000000000000000000000008");
  // Character types for codepoints 0x600 to 0x6f9
  const ArabicTypes = /*@__PURE__*/dec("4444448826627288999999999992222222222222222222222222222222222222222222222229999999999999999999994444444444644222822222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222999999949999999229989999223333333333");
  const Brackets = /*@__PURE__*/Object.create(null),
    BracketStack = [];
  // There's a lot more in
  // https://www.unicode.org/Public/UCD/latest/ucd/BidiBrackets.txt,
  // which are left out to keep code size down.
  for (let p of ["()", "[]", "{}"]) {
    let l = /*@__PURE__*/p.charCodeAt(0),
      r = /*@__PURE__*/p.charCodeAt(1);
    Brackets[l] = r;
    Brackets[r] = -l;
  }
  function charType(ch) {
    return ch <= 0xf7 ? LowTypes[ch] : 0x590 <= ch && ch <= 0x5f4 ? 2 /* T.R */ : 0x600 <= ch && ch <= 0x6f9 ? ArabicTypes[ch - 0x600] : 0x6ee <= ch && ch <= 0x8ac ? 4 /* T.AL */ : 0x2000 <= ch && ch <= 0x200c ? 256 /* T.NI */ : 0xfb50 <= ch && ch <= 0xfdff ? 4 /* T.AL */ : 1 /* T.L */;
  }
  const BidiRE = /[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac\ufb50-\ufdff]/;
  /**
  Represents a contiguous range of text that has a single direction
  (as in left-to-right or right-to-left).
  */
  class BidiSpan {
    /**
    The direction of this span.
    */
    get dir() {
      return this.level % 2 ? RTL : LTR;
    }
    /**
    @internal
    */
    constructor(
    /**
    The start of the span (relative to the start of the line).
    */
    from,
    /**
    The end of the span.
    */
    to,
    /**
    The ["bidi
    level"](https://unicode.org/reports/tr9/#Basic_Display_Algorithm)
    of the span (in this context, 0 means
    left-to-right, 1 means right-to-left, 2 means left-to-right
    number inside right-to-left text).
    */
    level) {
      this.from = from;
      this.to = to;
      this.level = level;
    }
    /**
    @internal
    */
    side(end, dir) {
      return this.dir == dir == end ? this.to : this.from;
    }
    /**
    @internal
    */
    forward(forward, dir) {
      return forward == (this.dir == dir);
    }
    /**
    @internal
    */
    static find(order, index, level, assoc) {
      let maybe = -1;
      for (let i = 0; i < order.length; i++) {
        let span = order[i];
        if (span.from <= index && span.to >= index) {
          if (span.level == level) return i;
          // When multiple spans match, if assoc != 0, take the one that
          // covers that side, otherwise take the one with the minimum
          // level.
          if (maybe < 0 || (assoc != 0 ? assoc < 0 ? span.from < index : span.to > index : order[maybe].level > span.level)) maybe = i;
        }
      }
      if (maybe < 0) throw new RangeError("Index out of range");
      return maybe;
    }
  }
  function isolatesEq(a, b) {
    if (a.length != b.length) return false;
    for (let i = 0; i < a.length; i++) {
      let iA = a[i],
        iB = b[i];
      if (iA.from != iB.from || iA.to != iB.to || iA.direction != iB.direction || !isolatesEq(iA.inner, iB.inner)) return false;
    }
    return true;
  }
  // Reused array of character types
  const types = [];
  // Fill in the character types (in `types`) from `from` to `to` and
  // apply W normalization rules.
  function computeCharTypes(line, rFrom, rTo, isolates, outerType) {
    for (let iI = 0; iI <= isolates.length; iI++) {
      let from = iI ? isolates[iI - 1].to : rFrom,
        to = iI < isolates.length ? isolates[iI].from : rTo;
      let prevType = iI ? 256 /* T.NI */ : outerType;
      // W1. Examine each non-spacing mark (NSM) in the level run, and
      // change the type of the NSM to the type of the previous
      // character. If the NSM is at the start of the level run, it will
      // get the type of sor.
      // W2. Search backwards from each instance of a European number
      // until the first strong type (R, L, AL, or sor) is found. If an
      // AL is found, change the type of the European number to Arabic
      // number.
      // W3. Change all ALs to R.
      // (Left after this: L, R, EN, AN, ET, CS, NI)
      for (let i = from, prev = prevType, prevStrong = prevType; i < to; i++) {
        let type = charType(line.charCodeAt(i));
        if (type == 512 /* T.NSM */) type = prev;else if (type == 8 /* T.EN */ && prevStrong == 4 /* T.AL */) type = 16 /* T.AN */;
        types[i] = type == 4 /* T.AL */ ? 2 /* T.R */ : type;
        if (type & 7 /* T.Strong */) prevStrong = type;
        prev = type;
      }
      // W5. A sequence of European terminators adjacent to European
      // numbers changes to all European numbers.
      // W6. Otherwise, separators and terminators change to Other
      // Neutral.
      // W7. Search backwards from each instance of a European number
      // until the first strong type (R, L, or sor) is found. If an L is
      // found, then change the type of the European number to L.
      // (Left after this: L, R, EN+AN, NI)
      for (let i = from, prev = prevType, prevStrong = prevType; i < to; i++) {
        let type = types[i];
        if (type == 128 /* T.CS */) {
          if (i < to - 1 && prev == types[i + 1] && prev & 24 /* T.Num */) type = types[i] = prev;else types[i] = 256 /* T.NI */;
        } else if (type == 64 /* T.ET */) {
          let end = i + 1;
          while (end < to && types[end] == 64 /* T.ET */) end++;
          let replace = i && prev == 8 /* T.EN */ || end < rTo && types[end] == 8 /* T.EN */ ? prevStrong == 1 /* T.L */ ? 1 /* T.L */ : 8 /* T.EN */ : 256 /* T.NI */;
          for (let j = i; j < end; j++) types[j] = replace;
          i = end - 1;
        } else if (type == 8 /* T.EN */ && prevStrong == 1 /* T.L */) {
          types[i] = 1 /* T.L */;
        }
        prev = type;
        if (type & 7 /* T.Strong */) prevStrong = type;
      }
    }
  }
  // Process brackets throughout a run sequence.
  function processBracketPairs(line, rFrom, rTo, isolates, outerType) {
    let oppositeType = outerType == 1 /* T.L */ ? 2 /* T.R */ : 1 /* T.L */;
    for (let iI = 0, sI = 0, context = 0; iI <= isolates.length; iI++) {
      let from = iI ? isolates[iI - 1].to : rFrom,
        to = iI < isolates.length ? isolates[iI].from : rTo;
      // N0. Process bracket pairs in an isolating run sequence
      // sequentially in the logical order of the text positions of the
      // opening paired brackets using the logic given below. Within this
      // scope, bidirectional types EN and AN are treated as R.
      for (let i = from, ch, br, type; i < to; i++) {
        // Keeps [startIndex, type, strongSeen] triples for each open
        // bracket on BracketStack.
        if (br = Brackets[ch = line.charCodeAt(i)]) {
          if (br < 0) {
            // Closing bracket
            for (let sJ = sI - 3; sJ >= 0; sJ -= 3) {
              if (BracketStack[sJ + 1] == -br) {
                let flags = BracketStack[sJ + 2];
                let type = flags & 2 /* Bracketed.EmbedInside */ ? outerType : !(flags & 4 /* Bracketed.OppositeInside */) ? 0 : flags & 1 /* Bracketed.OppositeBefore */ ? oppositeType : outerType;
                if (type) types[i] = types[BracketStack[sJ]] = type;
                sI = sJ;
                break;
              }
            }
          } else if (BracketStack.length == 189 /* Bracketed.MaxDepth */) {
            break;
          } else {
            BracketStack[sI++] = i;
            BracketStack[sI++] = ch;
            BracketStack[sI++] = context;
          }
        } else if ((type = types[i]) == 2 /* T.R */ || type == 1 /* T.L */) {
          let embed = type == outerType;
          context = embed ? 0 : 1 /* Bracketed.OppositeBefore */;
          for (let sJ = sI - 3; sJ >= 0; sJ -= 3) {
            let cur = BracketStack[sJ + 2];
            if (cur & 2 /* Bracketed.EmbedInside */) break;
            if (embed) {
              BracketStack[sJ + 2] |= 2 /* Bracketed.EmbedInside */;
            } else {
              if (cur & 4 /* Bracketed.OppositeInside */) break;
              BracketStack[sJ + 2] |= 4 /* Bracketed.OppositeInside */;
            }
          }
        }
      }
    }
  }
  function processNeutrals(rFrom, rTo, isolates, outerType) {
    for (let iI = 0, prev = outerType; iI <= isolates.length; iI++) {
      let from = iI ? isolates[iI - 1].to : rFrom,
        to = iI < isolates.length ? isolates[iI].from : rTo;
      // N1. A sequence of neutrals takes the direction of the
      // surrounding strong text if the text on both sides has the same
      // direction. European and Arabic numbers act as if they were R in
      // terms of their influence on neutrals. Start-of-level-run (sor)
      // and end-of-level-run (eor) are used at level run boundaries.
      // N2. Any remaining neutrals take the embedding direction.
      // (Left after this: L, R, EN+AN)
      for (let i = from; i < to;) {
        let type = types[i];
        if (type == 256 /* T.NI */) {
          let end = i + 1;
          for (;;) {
            if (end == to) {
              if (iI == isolates.length) break;
              end = isolates[iI++].to;
              to = iI < isolates.length ? isolates[iI].from : rTo;
            } else if (types[end] == 256 /* T.NI */) {
              end++;
            } else {
              break;
            }
          }
          let beforeL = prev == 1 /* T.L */;
          let afterL = (end < rTo ? types[end] : outerType) == 1 /* T.L */;
          let replace = beforeL == afterL ? beforeL ? 1 /* T.L */ : 2 /* T.R */ : outerType;
          for (let j = end, jI = iI, fromJ = jI ? isolates[jI - 1].to : rFrom; j > i;) {
            if (j == fromJ) {
              j = isolates[--jI].from;
              fromJ = jI ? isolates[jI - 1].to : rFrom;
            }
            types[--j] = replace;
          }
          i = end;
        } else {
          prev = type;
          i++;
        }
      }
    }
  }
  // Find the contiguous ranges of character types in a given range, and
  // emit spans for them. Flip the order of the spans as appropriate
  // based on the level, and call through to compute the spans for
  // isolates at the proper point.
  function emitSpans(line, from, to, level, baseLevel, isolates, order) {
    let ourType = level % 2 ? 2 /* T.R */ : 1 /* T.L */;
    if (level % 2 == baseLevel % 2) {
      // Same dir as base direction, don't flip
      for (let iCh = from, iI = 0; iCh < to;) {
        // Scan a section of characters in direction ourType, unless
        // there's another type of char right after iCh, in which case
        // we scan a section of other characters (which, if ourType ==
        // T.L, may contain both T.R and T.AN chars).
        let sameDir = true,
          isNum = false;
        if (iI == isolates.length || iCh < isolates[iI].from) {
          let next = types[iCh];
          if (next != ourType) {
            sameDir = false;
            isNum = next == 16 /* T.AN */;
          }
        }
        // Holds an array of isolates to pass to a recursive call if we
        // must recurse (to distinguish T.AN inside an RTL section in
        // LTR text), null if we can emit directly
        let recurse = !sameDir && ourType == 1 /* T.L */ ? [] : null;
        let localLevel = sameDir ? level : level + 1;
        let iScan = iCh;
        run: for (;;) {
          if (iI < isolates.length && iScan == isolates[iI].from) {
            if (isNum) break run;
            let iso = isolates[iI];
            // Scan ahead to verify that there is another char in this dir after the isolate(s)
            if (!sameDir) for (let upto = iso.to, jI = iI + 1;;) {
              if (upto == to) break run;
              if (jI < isolates.length && isolates[jI].from == upto) upto = isolates[jI++].to;else if (types[upto] == ourType) break run;else break;
            }
            iI++;
            if (recurse) {
              recurse.push(iso);
            } else {
              if (iso.from > iCh) order.push(new BidiSpan(iCh, iso.from, localLevel));
              let dirSwap = iso.direction == LTR != !(localLevel % 2);
              computeSectionOrder(line, dirSwap ? level + 1 : level, baseLevel, iso.inner, iso.from, iso.to, order);
              iCh = iso.to;
            }
            iScan = iso.to;
          } else if (iScan == to || (sameDir ? types[iScan] != ourType : types[iScan] == ourType)) {
            break;
          } else {
            iScan++;
          }
        }
        if (recurse) emitSpans(line, iCh, iScan, level + 1, baseLevel, recurse, order);else if (iCh < iScan) order.push(new BidiSpan(iCh, iScan, localLevel));
        iCh = iScan;
      }
    } else {
      // Iterate in reverse to flip the span order. Same code again, but
      // going from the back of the section to the front
      for (let iCh = to, iI = isolates.length; iCh > from;) {
        let sameDir = true,
          isNum = false;
        if (!iI || iCh > isolates[iI - 1].to) {
          let next = types[iCh - 1];
          if (next != ourType) {
            sameDir = false;
            isNum = next == 16 /* T.AN */;
          }
        }
        let recurse = !sameDir && ourType == 1 /* T.L */ ? [] : null;
        let localLevel = sameDir ? level : level + 1;
        let iScan = iCh;
        run: for (;;) {
          if (iI && iScan == isolates[iI - 1].to) {
            if (isNum) break run;
            let iso = isolates[--iI];
            // Scan ahead to verify that there is another char in this dir after the isolate(s)
            if (!sameDir) for (let upto = iso.from, jI = iI;;) {
              if (upto == from) break run;
              if (jI && isolates[jI - 1].to == upto) upto = isolates[--jI].from;else if (types[upto - 1] == ourType) break run;else break;
            }
            if (recurse) {
              recurse.push(iso);
            } else {
              if (iso.to < iCh) order.push(new BidiSpan(iso.to, iCh, localLevel));
              let dirSwap = iso.direction == LTR != !(localLevel % 2);
              computeSectionOrder(line, dirSwap ? level + 1 : level, baseLevel, iso.inner, iso.from, iso.to, order);
              iCh = iso.from;
            }
            iScan = iso.from;
          } else if (iScan == from || (sameDir ? types[iScan - 1] != ourType : types[iScan - 1] == ourType)) {
            break;
          } else {
            iScan--;
          }
        }
        if (recurse) emitSpans(line, iScan, iCh, level + 1, baseLevel, recurse, order);else if (iScan < iCh) order.push(new BidiSpan(iScan, iCh, localLevel));
        iCh = iScan;
      }
    }
  }
  function computeSectionOrder(line, level, baseLevel, isolates, from, to, order) {
    let outerType = level % 2 ? 2 /* T.R */ : 1 /* T.L */;
    computeCharTypes(line, from, to, isolates, outerType);
    processBracketPairs(line, from, to, isolates, outerType);
    processNeutrals(from, to, isolates, outerType);
    emitSpans(line, from, to, level, baseLevel, isolates, order);
  }
  function computeOrder(line, direction, isolates) {
    if (!line) return [new BidiSpan(0, 0, direction == RTL ? 1 : 0)];
    if (direction == LTR && !isolates.length && !BidiRE.test(line)) return trivialOrder(line.length);
    if (isolates.length) while (line.length > types.length) types[types.length] = 256 /* T.NI */; // Make sure types array has no gaps
    let order = [],
      level = direction == LTR ? 0 : 1;
    computeSectionOrder(line, level, level, isolates, 0, line.length, order);
    return order;
  }
  function trivialOrder(length) {
    return [new BidiSpan(0, length, 0)];
  }
  let movedOver = "";
  // This implementation moves strictly visually, without concern for a
  // traversal visiting every logical position in the string. It will
  // still do so for simple input, but situations like multiple isolates
  // with the same level next to each other, or text going against the
  // main dir at the end of the line, will make some positions
  // unreachable with this motion. Each visible cursor position will
  // correspond to the lower-level bidi span that touches it.
  //
  // The alternative would be to solve an order globally for a given
  // line, making sure that it includes every position, but that would
  // require associating non-canonical (higher bidi span level)
  // positions with a given visual position, which is likely to confuse
  // people. (And would generally be a lot more complicated.)
  function moveVisually(line, order, dir, start, forward) {
    var _a;
    let startIndex = start.head - line.from;
    let spanI = BidiSpan.find(order, startIndex, (_a = start.bidiLevel) !== null && _a !== void 0 ? _a : -1, start.assoc);
    let span = order[spanI],
      spanEnd = span.side(forward, dir);
    // End of span
    if (startIndex == spanEnd) {
      let nextI = spanI += forward ? 1 : -1;
      if (nextI < 0 || nextI >= order.length) return null;
      span = order[spanI = nextI];
      startIndex = span.side(!forward, dir);
      spanEnd = span.side(forward, dir);
    }
    let nextIndex = findClusterBreak(line.text, startIndex, span.forward(forward, dir));
    if (nextIndex < span.from || nextIndex > span.to) nextIndex = spanEnd;
    movedOver = line.text.slice(Math.min(startIndex, nextIndex), Math.max(startIndex, nextIndex));
    let nextSpan = spanI == (forward ? order.length - 1 : 0) ? null : order[spanI + (forward ? 1 : -1)];
    if (nextSpan && nextIndex == spanEnd && nextSpan.level + (forward ? 0 : 1) < span.level) return EditorSelection.cursor(nextSpan.side(!forward, dir) + line.from, nextSpan.forward(forward, dir) ? 1 : -1, nextSpan.level);
    return EditorSelection.cursor(nextIndex + line.from, span.forward(forward, dir) ? -1 : 1, span.level);
  }
  function autoDirection(text, from, to) {
    for (let i = from; i < to; i++) {
      let type = charType(text.charCodeAt(i));
      if (type == 1 /* T.L */) return LTR;
      if (type == 2 /* T.R */ || type == 4 /* T.AL */) return RTL;
    }
    return LTR;
  }
  const clickAddsSelectionRange = /*@__PURE__*/Facet.define();
  const dragMovesSelection$1 = /*@__PURE__*/Facet.define();
  const mouseSelectionStyle = /*@__PURE__*/Facet.define();
  const exceptionSink = /*@__PURE__*/Facet.define();
  const updateListener = /*@__PURE__*/Facet.define();
  const inputHandler = /*@__PURE__*/Facet.define();
  const focusChangeEffect = /*@__PURE__*/Facet.define();
  const clipboardInputFilter = /*@__PURE__*/Facet.define();
  const clipboardOutputFilter = /*@__PURE__*/Facet.define();
  const perLineTextDirection = /*@__PURE__*/Facet.define({
    combine: values => values.some(x => x)
  });
  const nativeSelectionHidden = /*@__PURE__*/Facet.define({
    combine: values => values.some(x => x)
  });
  const scrollHandler = /*@__PURE__*/Facet.define();
  class ScrollTarget {
    constructor(range, y, x, yMargin, xMargin,
    // This data structure is abused to also store precise scroll
    // snapshots, instead of a `scrollIntoView` request. When this
    // flag is `true`, `range` points at a position in the reference
    // line, `yMargin` holds the difference between the top of that
    // line and the top of the editor, and `xMargin` holds the
    // editor's `scrollLeft`.
    isSnapshot = false) {
      this.range = range;
      this.y = y;
      this.x = x;
      this.yMargin = yMargin;
      this.xMargin = xMargin;
      this.isSnapshot = isSnapshot;
    }
    map(changes) {
      return changes.empty ? this : new ScrollTarget(this.range.map(changes), this.y, this.x, this.yMargin, this.xMargin, this.isSnapshot);
    }
    clip(state) {
      return this.range.to <= state.doc.length ? this : new ScrollTarget(EditorSelection.cursor(state.doc.length), this.y, this.x, this.yMargin, this.xMargin, this.isSnapshot);
    }
  }
  const scrollIntoView = /*@__PURE__*/StateEffect.define({
    map: (t, ch) => t.map(ch)
  });
  const setEditContextFormatting = /*@__PURE__*/StateEffect.define();
  /**
  Log or report an unhandled exception in client code. Should
  probably only be used by extension code that allows client code to
  provide functions, and calls those functions in a context where an
  exception can't be propagated to calling code in a reasonable way
  (for example when in an event handler).

  Either calls a handler registered with
  [`EditorView.exceptionSink`](https://codemirror.net/6/docs/ref/#view.EditorView^exceptionSink),
  `window.onerror`, if defined, or `console.error` (in which case
  it'll pass `context`, when given, as first argument).
  */
  function logException(state, exception, context) {
    let handler = state.facet(exceptionSink);
    if (handler.length) handler[0](exception);else if (window.onerror && window.onerror(String(exception), context, undefined, undefined, exception)) ;else if (context) console.error(context + ":", exception);else console.error(exception);
  }
  const editable = /*@__PURE__*/Facet.define({
    combine: values => values.length ? values[0] : true
  });
  let nextPluginID = 0;
  const viewPlugin = /*@__PURE__*/Facet.define({
    combine(plugins) {
      return plugins.filter((p, i) => {
        for (let j = 0; j < i; j++) if (plugins[j].plugin == p.plugin) return false;
        return true;
      });
    }
  });
  /**
  View plugins associate stateful values with a view. They can
  influence the way the content is drawn, and are notified of things
  that happen in the view. They optionally take an argument, in
  which case you need to call [`of`](https://codemirror.net/6/docs/ref/#view.ViewPlugin.of) to create
  an extension for the plugin. When the argument type is undefined,
  you can use the plugin instance as an extension directly.
  */
  class ViewPlugin {
    constructor(
    /**
    @internal
    */
    id,
    /**
    @internal
    */
    create,
    /**
    @internal
    */
    domEventHandlers,
    /**
    @internal
    */
    domEventObservers, buildExtensions) {
      this.id = id;
      this.create = create;
      this.domEventHandlers = domEventHandlers;
      this.domEventObservers = domEventObservers;
      this.baseExtensions = buildExtensions(this);
      this.extension = this.baseExtensions.concat(viewPlugin.of({
        plugin: this,
        arg: undefined
      }));
    }
    /**
    Create an extension for this plugin with the given argument.
    */
    of(arg) {
      return this.baseExtensions.concat(viewPlugin.of({
        plugin: this,
        arg
      }));
    }
    /**
    Define a plugin from a constructor function that creates the
    plugin's value, given an editor view.
    */
    static define(create, spec) {
      const {
        eventHandlers,
        eventObservers,
        provide,
        decorations: deco
      } = spec || {};
      return new ViewPlugin(nextPluginID++, create, eventHandlers, eventObservers, plugin => {
        let ext = [];
        if (deco) ext.push(decorations.of(view => {
          let pluginInst = view.plugin(plugin);
          return pluginInst ? deco(pluginInst) : Decoration.none;
        }));
        if (provide) ext.push(provide(plugin));
        return ext;
      });
    }
    /**
    Create a plugin for a class whose constructor takes a single
    editor view as argument.
    */
    static fromClass(cls, spec) {
      return ViewPlugin.define((view, arg) => new cls(view, arg), spec);
    }
  }
  class PluginInstance {
    constructor(spec) {
      this.spec = spec;
      // When starting an update, all plugins have this field set to the
      // update object, indicating they need to be updated. When finished
      // updating, it is set to `null`. Retrieving a plugin that needs to
      // be updated with `view.plugin` forces an eager update.
      this.mustUpdate = null;
      // This is null when the plugin is initially created, but
      // initialized on the first update.
      this.value = null;
    }
    get plugin() {
      return this.spec && this.spec.plugin;
    }
    update(view) {
      if (!this.value) {
        if (this.spec) {
          try {
            this.value = this.spec.plugin.create(view, this.spec.arg);
          } catch (e) {
            logException(view.state, e, "CodeMirror plugin crashed");
            this.deactivate();
          }
        }
      } else if (this.mustUpdate) {
        let update = this.mustUpdate;
        this.mustUpdate = null;
        if (this.value.update) {
          try {
            this.value.update(update);
          } catch (e) {
            logException(update.state, e, "CodeMirror plugin crashed");
            if (this.value.destroy) try {
              this.value.destroy();
            } catch (_) {}
            this.deactivate();
          }
        }
      }
      return this;
    }
    destroy(view) {
      var _a;
      if ((_a = this.value) === null || _a === void 0 ? void 0 : _a.destroy) {
        try {
          this.value.destroy();
        } catch (e) {
          logException(view.state, e, "CodeMirror plugin crashed");
        }
      }
    }
    deactivate() {
      this.spec = this.value = null;
    }
  }
  const editorAttributes = /*@__PURE__*/Facet.define();
  const contentAttributes = /*@__PURE__*/Facet.define();
  // Provide decorations
  const decorations = /*@__PURE__*/Facet.define();
  const blockWrappers = /*@__PURE__*/Facet.define();
  const outerDecorations = /*@__PURE__*/Facet.define();
  const atomicRanges = /*@__PURE__*/Facet.define();
  const bidiIsolatedRanges = /*@__PURE__*/Facet.define();
  function getIsolatedRanges(view, line) {
    let isolates = view.state.facet(bidiIsolatedRanges);
    if (!isolates.length) return isolates;
    let sets = isolates.map(i => i instanceof Function ? i(view) : i);
    let result = [];
    RangeSet.spans(sets, line.from, line.to, {
      point() {},
      span(fromDoc, toDoc, active, open) {
        let from = fromDoc - line.from,
          to = toDoc - line.from;
        let level = result;
        for (let i = active.length - 1; i >= 0; i--, open--) {
          let direction = active[i].spec.bidiIsolate,
            update;
          if (direction == null) direction = autoDirection(line.text, from, to);
          if (open > 0 && level.length && (update = level[level.length - 1]).to == from && update.direction == direction) {
            update.to = to;
            level = update.inner;
          } else {
            let add = {
              from,
              to,
              direction,
              inner: []
            };
            level.push(add);
            level = add.inner;
          }
        }
      }
    });
    return result;
  }
  const scrollMargins = /*@__PURE__*/Facet.define();
  function getScrollMargins(view) {
    let left = 0,
      right = 0,
      top = 0,
      bottom = 0;
    for (let source of view.state.facet(scrollMargins)) {
      let m = source(view);
      if (m) {
        if (m.left != null) left = Math.max(left, m.left);
        if (m.right != null) right = Math.max(right, m.right);
        if (m.top != null) top = Math.max(top, m.top);
        if (m.bottom != null) bottom = Math.max(bottom, m.bottom);
      }
    }
    return {
      left,
      right,
      top,
      bottom
    };
  }
  const styleModule = /*@__PURE__*/Facet.define();
  class ChangedRange {
    constructor(fromA, toA, fromB, toB) {
      this.fromA = fromA;
      this.toA = toA;
      this.fromB = fromB;
      this.toB = toB;
    }
    join(other) {
      return new ChangedRange(Math.min(this.fromA, other.fromA), Math.max(this.toA, other.toA), Math.min(this.fromB, other.fromB), Math.max(this.toB, other.toB));
    }
    addToSet(set) {
      let i = set.length,
        me = this;
      for (; i > 0; i--) {
        let range = set[i - 1];
        if (range.fromA > me.toA) continue;
        if (range.toA < me.fromA) break;
        me = me.join(range);
        set.splice(i - 1, 1);
      }
      set.splice(i, 0, me);
      return set;
    }
    // Extend a set to cover all the content in `ranges`, which is a
    // flat array with each pair of numbers representing fromB/toB
    // positions. These pairs are generated in unchanged ranges, so the
    // offset between doc A and doc B is the same for their start and
    // end points.
    static extendWithRanges(diff, ranges) {
      if (ranges.length == 0) return diff;
      let result = [];
      for (let dI = 0, rI = 0, off = 0;;) {
        let nextD = dI < diff.length ? diff[dI].fromB : 1e9;
        let nextR = rI < ranges.length ? ranges[rI] : 1e9;
        let fromB = Math.min(nextD, nextR);
        if (fromB == 1e9) break;
        let fromA = fromB + off,
          toB = fromB,
          toA = fromA;
        for (;;) {
          if (rI < ranges.length && ranges[rI] <= toB) {
            let end = ranges[rI + 1];
            rI += 2;
            toB = Math.max(toB, end);
            for (let i = dI; i < diff.length && diff[i].fromB <= toB; i++) off = diff[i].toA - diff[i].toB;
            toA = Math.max(toA, end + off);
          } else if (dI < diff.length && diff[dI].fromB <= toB) {
            let next = diff[dI++];
            toB = Math.max(toB, next.toB);
            toA = Math.max(toA, next.toA);
            off = next.toA - next.toB;
          } else {
            break;
          }
        }
        result.push(new ChangedRange(fromA, toA, fromB, toB));
      }
      return result;
    }
  }
  /**
  View [plugins](https://codemirror.net/6/docs/ref/#view.ViewPlugin) are given instances of this
  class, which describe what happened, whenever the view is updated.
  */
  class ViewUpdate {
    constructor(
    /**
    The editor view that the update is associated with.
    */
    view,
    /**
    The new editor state.
    */
    state,
    /**
    The transactions involved in the update. May be empty.
    */
    transactions) {
      this.view = view;
      this.state = state;
      this.transactions = transactions;
      /**
      @internal
      */
      this.flags = 0;
      this.startState = view.state;
      this.changes = ChangeSet.empty(this.startState.doc.length);
      for (let tr of transactions) this.changes = this.changes.compose(tr.changes);
      let changedRanges = [];
      this.changes.iterChangedRanges((fromA, toA, fromB, toB) => changedRanges.push(new ChangedRange(fromA, toA, fromB, toB)));
      this.changedRanges = changedRanges;
    }
    /**
    @internal
    */
    static create(view, state, transactions) {
      return new ViewUpdate(view, state, transactions);
    }
    /**
    Tells you whether the [viewport](https://codemirror.net/6/docs/ref/#view.EditorView.viewport) or
    [visible ranges](https://codemirror.net/6/docs/ref/#view.EditorView.visibleRanges) changed in this
    update.
    */
    get viewportChanged() {
      return (this.flags & 4 /* UpdateFlag.Viewport */) > 0;
    }
    /**
    Returns true when
    [`viewportChanged`](https://codemirror.net/6/docs/ref/#view.ViewUpdate.viewportChanged) is true
    and the viewport change is not just the result of mapping it in
    response to document changes.
    */
    get viewportMoved() {
      return (this.flags & 8 /* UpdateFlag.ViewportMoved */) > 0;
    }
    /**
    Indicates whether the height of a block element in the editor
    changed in this update.
    */
    get heightChanged() {
      return (this.flags & 2 /* UpdateFlag.Height */) > 0;
    }
    /**
    Returns true when the document was modified or the size of the
    editor, or elements within the editor, changed.
    */
    get geometryChanged() {
      return this.docChanged || (this.flags & (16 /* UpdateFlag.Geometry */ | 2 /* UpdateFlag.Height */)) > 0;
    }
    /**
    True when this update indicates a focus change.
    */
    get focusChanged() {
      return (this.flags & 1 /* UpdateFlag.Focus */) > 0;
    }
    /**
    Whether the document changed in this update.
    */
    get docChanged() {
      return !this.changes.empty;
    }
    /**
    Whether the selection was explicitly set in this update.
    */
    get selectionSet() {
      return this.transactions.some(tr => tr.selection);
    }
    /**
    @internal
    */
    get empty() {
      return this.flags == 0 && this.transactions.length == 0;
    }
  }
  const noChildren = [];
  class Tile {
    constructor(dom, length, flags = 0) {
      this.dom = dom;
      this.length = length;
      this.flags = flags;
      this.parent = null;
      dom.cmTile = this;
    }
    get breakAfter() {
      return this.flags & 1 /* TileFlag.BreakAfter */;
    }
    get children() {
      return noChildren;
    }
    isWidget() {
      return false;
    }
    get isHidden() {
      return false;
    }
    isComposite() {
      return false;
    }
    isLine() {
      return false;
    }
    isText() {
      return false;
    }
    isBlock() {
      return false;
    }
    get domAttrs() {
      return null;
    }
    sync(track) {
      this.flags |= 2 /* TileFlag.Synced */;
      if (this.flags & 4 /* TileFlag.AttrsDirty */) {
        this.flags &= -5 /* TileFlag.AttrsDirty */;
        let attrs = this.domAttrs;
        if (attrs) setAttrs(this.dom, attrs);
      }
    }
    toString() {
      return this.constructor.name + (this.children.length ? `(${this.children})` : "") + (this.breakAfter ? "#" : "");
    }
    destroy() {
      this.parent = null;
    }
    setDOM(dom) {
      this.dom = dom;
      dom.cmTile = this;
    }
    get posAtStart() {
      return this.parent ? this.parent.posBefore(this) : 0;
    }
    get posAtEnd() {
      return this.posAtStart + this.length;
    }
    posBefore(tile, start = this.posAtStart) {
      let pos = start;
      for (let child of this.children) {
        if (child == tile) return pos;
        pos += child.length + child.breakAfter;
      }
      throw new RangeError("Invalid child in posBefore");
    }
    posAfter(tile) {
      return this.posBefore(tile) + tile.length;
    }
    covers(side) {
      return true;
    }
    coordsIn(pos, side) {
      return null;
    }
    domPosFor(off, side) {
      let index = domIndex(this.dom);
      let after = this.length ? off > 0 : side > 0;
      return new DOMPos(this.parent.dom, index + (after ? 1 : 0), off == 0 || off == this.length);
    }
    markDirty(attrs) {
      this.flags &= -3 /* TileFlag.Synced */;
      if (attrs) this.flags |= 4 /* TileFlag.AttrsDirty */;
      if (this.parent && this.parent.flags & 2 /* TileFlag.Synced */) this.parent.markDirty(false);
    }
    get overrideDOMText() {
      return null;
    }
    get root() {
      for (let t = this; t; t = t.parent) if (t instanceof DocTile) return t;
      return null;
    }
    static get(dom) {
      return dom.cmTile;
    }
  }
  class CompositeTile extends Tile {
    constructor(dom) {
      super(dom, 0);
      this._children = [];
    }
    isComposite() {
      return true;
    }
    get children() {
      return this._children;
    }
    get lastChild() {
      return this.children.length ? this.children[this.children.length - 1] : null;
    }
    append(child) {
      this.children.push(child);
      child.parent = this;
    }
    sync(track) {
      if (this.flags & 2 /* TileFlag.Synced */) return;
      super.sync(track);
      let parent = this.dom,
        prev = null,
        next;
      let tracking = (track === null || track === void 0 ? void 0 : track.node) == parent ? track : null;
      let length = 0;
      for (let child of this.children) {
        child.sync(track);
        length += child.length + child.breakAfter;
        next = prev ? prev.nextSibling : parent.firstChild;
        if (tracking && next != child.dom) tracking.written = true;
        if (child.dom.parentNode == parent) {
          while (next && next != child.dom) next = rm$1(next);
        } else {
          parent.insertBefore(child.dom, next);
        }
        prev = child.dom;
      }
      next = prev ? prev.nextSibling : parent.firstChild;
      if (tracking && next) tracking.written = true;
      while (next) next = rm$1(next);
      this.length = length;
    }
  }
  // Remove a DOM node and return its next sibling.
  function rm$1(dom) {
    let next = dom.nextSibling;
    dom.parentNode.removeChild(dom);
    return next;
  }
  // The top-level tile. Its dom property equals view.contentDOM.
  class DocTile extends CompositeTile {
    constructor(view, dom) {
      super(dom);
      this.view = view;
    }
    owns(tile) {
      for (; tile; tile = tile.parent) if (tile == this) return true;
      return false;
    }
    isBlock() {
      return true;
    }
    nearest(dom) {
      for (;;) {
        if (!dom) return null;
        let tile = Tile.get(dom);
        if (tile && this.owns(tile)) return tile;
        dom = dom.parentNode;
      }
    }
    blockTiles(f) {
      for (let stack = [], cur = this, i = 0, pos = 0;;) {
        if (i == cur.children.length) {
          if (!stack.length) return;
          cur = cur.parent;
          if (cur.breakAfter) pos++;
          i = stack.pop();
        } else {
          let next = cur.children[i++];
          if (next instanceof BlockWrapperTile) {
            stack.push(i);
            cur = next;
            i = 0;
          } else {
            let end = pos + next.length;
            let result = f(next, pos);
            if (result !== undefined) return result;
            pos = end + next.breakAfter;
          }
        }
      }
    }
    // Find the block at the given position. If side < -1, make sure to
    // stay before block widgets at that position, if side > 1, after
    // such widgets (used for selection drawing, which needs to be able
    // to get coordinates for positions that aren't valid cursor positions).
    resolveBlock(pos, side) {
      let before,
        beforeOff = -1,
        after,
        afterOff = -1;
      this.blockTiles((tile, off) => {
        let end = off + tile.length;
        if (pos >= off && pos <= end) {
          if (tile.isWidget() && side >= -1 && side <= 1) {
            if (tile.flags & 32 /* TileFlag.After */) return true;
            if (tile.flags & 16 /* TileFlag.Before */) before = undefined;
          }
          if ((off < pos || pos == end && (side < -1 ? tile.length : tile.covers(1))) && (!before || !tile.isWidget() && before.isWidget())) {
            before = tile;
            beforeOff = pos - off;
          }
          if ((end > pos || pos == off && (side > 1 ? tile.length : tile.covers(-1))) && (!after || !tile.isWidget() && after.isWidget())) {
            after = tile;
            afterOff = pos - off;
          }
        }
      });
      if (!before && !after) throw new Error("No tile at position " + pos);
      return before && side < 0 || !after ? {
        tile: before,
        offset: beforeOff
      } : {
        tile: after,
        offset: afterOff
      };
    }
  }
  class BlockWrapperTile extends CompositeTile {
    constructor(dom, wrapper) {
      super(dom);
      this.wrapper = wrapper;
    }
    isBlock() {
      return true;
    }
    covers(side) {
      if (!this.children.length) return false;
      return side < 0 ? this.children[0].covers(-1) : this.lastChild.covers(1);
    }
    get domAttrs() {
      return this.wrapper.attributes;
    }
    static of(wrapper, dom) {
      let tile = new BlockWrapperTile(dom || document.createElement(wrapper.tagName), wrapper);
      if (!dom) tile.flags |= 4 /* TileFlag.AttrsDirty */;
      return tile;
    }
  }
  class LineTile extends CompositeTile {
    constructor(dom, attrs) {
      super(dom);
      this.attrs = attrs;
    }
    isLine() {
      return true;
    }
    static start(attrs, dom, keepAttrs) {
      let line = new LineTile(dom || document.createElement("div"), attrs);
      if (!dom || !keepAttrs) line.flags |= 4 /* TileFlag.AttrsDirty */;
      return line;
    }
    get domAttrs() {
      return this.attrs;
    }
    // Find the tile associated with a given position in this line.
    resolveInline(pos, side, forCoords) {
      let before = null,
        beforeOff = -1,
        after = null,
        afterOff = -1;
      function scan(tile, pos) {
        for (let i = 0, off = 0; i < tile.children.length && off <= pos; i++) {
          let child = tile.children[i],
            end = off + child.length;
          if (end >= pos) {
            if (child.isComposite()) {
              scan(child, pos - off);
            } else if ((!after || after.isHidden && (side > 0 || forCoords && onSameLine(after, child))) && (end > pos || child.flags & 32 /* TileFlag.After */)) {
              after = child;
              afterOff = pos - off;
            } else if (off < pos || child.flags & 16 /* TileFlag.Before */ && !child.isHidden) {
              before = child;
              beforeOff = pos - off;
            }
          }
          off = end;
        }
      }
      scan(this, pos);
      let target = (side < 0 ? before : after) || before || after;
      return target ? {
        tile: target,
        offset: target == before ? beforeOff : afterOff
      } : null;
    }
    coordsIn(pos, side) {
      let found = this.resolveInline(pos, side, true);
      if (!found) return fallbackRect(this);
      return found.tile.coordsIn(Math.max(0, found.offset), side);
    }
    domIn(pos, side) {
      let found = this.resolveInline(pos, side);
      if (found) {
        let {
          tile,
          offset
        } = found;
        if (this.dom.contains(tile.dom)) {
          if (tile.isText()) return new DOMPos(tile.dom, Math.min(tile.dom.nodeValue.length, offset));
          return tile.domPosFor(offset, tile.flags & 16 /* TileFlag.Before */ ? 1 : tile.flags & 32 /* TileFlag.After */ ? -1 : side);
        }
        let parent = found.tile.parent,
          saw = false;
        for (let ch of parent.children) {
          if (saw) return new DOMPos(ch.dom, 0);
          if (ch == found.tile) {
            saw = true;
          }
        }
      }
      return new DOMPos(this.dom, 0);
    }
  }
  function fallbackRect(tile) {
    let last = tile.dom.lastChild;
    if (!last) return tile.dom.getBoundingClientRect();
    let rects = clientRectsFor(last);
    return rects[rects.length - 1] || null;
  }
  function onSameLine(a, b) {
    let posA = a.coordsIn(0, 1),
      posB = b.coordsIn(0, 1);
    return posA && posB && posB.top < posA.bottom;
  }
  class MarkTile extends CompositeTile {
    constructor(dom, mark) {
      super(dom);
      this.mark = mark;
    }
    get domAttrs() {
      return this.mark.attrs;
    }
    static of(mark, dom) {
      let tile = new MarkTile(dom || document.createElement(mark.tagName), mark);
      if (!dom) tile.flags |= 4 /* TileFlag.AttrsDirty */;
      return tile;
    }
  }
  class TextTile extends Tile {
    constructor(dom, text) {
      super(dom, text.length);
      this.text = text;
    }
    sync(track) {
      if (this.flags & 2 /* TileFlag.Synced */) return;
      super.sync(track);
      if (this.dom.nodeValue != this.text) {
        if (track && track.node == this.dom) track.written = true;
        this.dom.nodeValue = this.text;
      }
    }
    isText() {
      return true;
    }
    toString() {
      return JSON.stringify(this.text);
    }
    coordsIn(pos, side) {
      let length = this.dom.nodeValue.length;
      if (pos > length) pos = length;
      let from = pos,
        to = pos,
        flatten = 0;
      if (pos == 0 && side < 0 || pos == length && side >= 0) {
        if (!(browser.chrome || browser.gecko)) {
          // These browsers reliably return valid rectangles for empty ranges
          if (pos) {
            from--;
            flatten = 1;
          } // FIXME this is wrong in RTL text
          else if (to < length) {
            to++;
            flatten = -1;
          }
        }
      } else {
        if (side < 0) from--;else if (to < length) to++;
      }
      let rects = textRange(this.dom, from, to).getClientRects();
      if (!rects.length) return null;
      let rect = rects[(flatten ? flatten < 0 : side >= 0) ? 0 : rects.length - 1];
      if (browser.safari && !flatten && rect.width == 0) rect = Array.prototype.find.call(rects, r => r.width) || rect;
      return flatten ? flattenRect(rect, flatten < 0) : rect || null;
    }
    static of(text, dom) {
      let tile = new TextTile(dom || document.createTextNode(text), text);
      if (!dom) tile.flags |= 2 /* TileFlag.Synced */;
      return tile;
    }
  }
  class WidgetTile extends Tile {
    constructor(dom, length, widget, flags) {
      super(dom, length, flags);
      this.widget = widget;
    }
    isWidget() {
      return true;
    }
    get isHidden() {
      return this.widget.isHidden;
    }
    covers(side) {
      if (this.flags & 48 /* TileFlag.PointWidget */) return false;
      return (this.flags & (side < 0 ? 64 /* TileFlag.IncStart */ : 128 /* TileFlag.IncEnd */)) > 0;
    }
    coordsIn(pos, side) {
      return this.coordsInWidget(pos, side, false);
    }
    coordsInWidget(pos, side, block) {
      let custom = this.widget.coordsAt(this.dom, pos, side);
      if (custom) return custom;
      if (block) {
        return flattenRect(this.dom.getBoundingClientRect(), this.length ? pos == 0 : side <= 0);
      } else {
        let rects = this.dom.getClientRects(),
          rect = null;
        if (!rects.length) return null;
        let fromBack = this.flags & 16 /* TileFlag.Before */ ? true : this.flags & 32 /* TileFlag.After */ ? false : pos > 0;
        for (let i = fromBack ? rects.length - 1 : 0;; i += fromBack ? -1 : 1) {
          rect = rects[i];
          if (pos > 0 ? i == 0 : i == rects.length - 1 || rect.top < rect.bottom) break;
        }
        return flattenRect(rect, !fromBack);
      }
    }
    get overrideDOMText() {
      if (!this.length) return Text.empty;
      let {
        root
      } = this;
      if (!root) return Text.empty;
      let start = this.posAtStart;
      return root.view.state.doc.slice(start, start + this.length);
    }
    destroy() {
      super.destroy();
      this.widget.destroy(this.dom);
    }
    static of(widget, view, length, flags, dom) {
      if (!dom) {
        dom = widget.toDOM(view);
        if (!widget.editable) dom.contentEditable = "false";
      }
      return new WidgetTile(dom, length, widget, flags);
    }
  }
  // These are drawn around uneditable widgets to avoid a number of
  // browser bugs that show up when the cursor is directly next to
  // uneditable inline content.
  class WidgetBufferTile extends Tile {
    constructor(flags) {
      let img = document.createElement("img");
      img.className = "cm-widgetBuffer";
      img.setAttribute("aria-hidden", "true");
      super(img, 0, flags);
    }
    get isHidden() {
      return true;
    }
    get overrideDOMText() {
      return Text.empty;
    }
    coordsIn(pos) {
      return this.dom.getBoundingClientRect();
    }
  }
  // Represents a position in the tile tree.
  class TilePointer {
    constructor(top) {
      this.index = 0;
      this.beforeBreak = false;
      this.parents = [];
      this.tile = top;
    }
    // Advance by the given distance. If side is -1, stop leaving or
    // entering tiles, or skipping zero-length tiles, once the distance
    // has been traversed. When side is 1, leave, enter, or skip
    // everything at the end position.
    advance(dist, side, walker) {
      let {
        tile,
        index,
        beforeBreak,
        parents
      } = this;
      while (dist || side > 0) {
        if (!tile.isComposite()) {
          if (index == tile.length) {
            beforeBreak = !!tile.breakAfter;
            ({
              tile,
              index
            } = parents.pop());
            index++;
          } else if (!dist) {
            break;
          } else {
            let take = Math.min(dist, tile.length - index);
            if (walker) walker.skip(tile, index, index + take);
            dist -= take;
            index += take;
          }
        } else if (beforeBreak) {
          if (!dist) break;
          if (walker) walker.break();
          dist--;
          beforeBreak = false;
        } else if (index == tile.children.length) {
          if (!dist && !parents.length) break;
          if (walker) walker.leave(tile);
          beforeBreak = !!tile.breakAfter;
          ({
            tile,
            index
          } = parents.pop());
          index++;
        } else {
          let next = tile.children[index],
            brk = next.breakAfter;
          if ((side > 0 ? next.length <= dist : next.length < dist) && (!walker || walker.skip(next, 0, next.length) !== false || !next.isComposite)) {
            beforeBreak = !!brk;
            index++;
            dist -= next.length;
          } else {
            parents.push({
              tile,
              index
            });
            tile = next;
            index = 0;
            if (walker && next.isComposite()) walker.enter(next);
          }
        }
      }
      this.tile = tile;
      this.index = index;
      this.beforeBreak = beforeBreak;
      return this;
    }
    get root() {
      return this.parents.length ? this.parents[0].tile : this.tile;
    }
  }

  // Used to track open block wrappers
  class OpenWrapper {
    constructor(from, to, wrapper, rank) {
      this.from = from;
      this.to = to;
      this.wrapper = wrapper;
      this.rank = rank;
    }
  }
  // This class builds up a new document tile using input from either
  // iteration over the old tree or iteration over the document +
  // decorations. The add* methods emit elements into the tile
  // structure. To avoid awkward synchronization issues, marks and block
  // wrappers are treated as belonging to to their content, rather than
  // opened/closed independently.
  //
  // All composite tiles that are touched by changes are rebuilt,
  // reusing as much of the old tree (either whole nodes or just DOM
  // elements) as possible. The new tree is built without the Synced
  // flag, and then synced (during which DOM parent/child relations are
  // fixed up, text nodes filled in, and attributes added) in a second
  // phase.
  class TileBuilder {
    constructor(cache, root, blockWrappers) {
      this.cache = cache;
      this.root = root;
      this.blockWrappers = blockWrappers;
      this.curLine = null;
      this.lastBlock = null;
      this.afterWidget = null;
      this.pos = 0;
      this.wrappers = [];
      this.wrapperPos = 0;
    }
    addText(text, marks, openStart, tile) {
      var _a;
      this.flushBuffer();
      let parent = this.ensureMarks(marks, openStart);
      let prev = parent.lastChild;
      if (prev && prev.isText() && !(prev.flags & 8 /* TileFlag.Composition */) && prev.length + text.length < 512 /* C.Chunk */) {
        this.cache.reused.set(prev, 2 /* Reused.DOM */);
        let tile = parent.children[parent.children.length - 1] = new TextTile(prev.dom, prev.text + text);
        tile.parent = parent;
      } else {
        parent.append(tile || TextTile.of(text, (_a = this.cache.find(TextTile)) === null || _a === void 0 ? void 0 : _a.dom));
      }
      this.pos += text.length;
      this.afterWidget = null;
    }
    addComposition(composition, context) {
      let line = this.curLine;
      if (line.dom != context.line.dom) {
        line.setDOM(this.cache.reused.has(context.line) ? freeNode(context.line.dom) : context.line.dom);
        this.cache.reused.set(context.line, 2 /* Reused.DOM */);
      }
      let head = line;
      for (let i = context.marks.length - 1; i >= 0; i--) {
        let mark = context.marks[i];
        let last = head.lastChild;
        if (last instanceof MarkTile && last.mark.eq(mark.mark)) {
          if (last.dom != mark.dom) last.setDOM(freeNode(mark.dom));
          head = last;
        } else {
          if (this.cache.reused.get(mark)) {
            let tile = Tile.get(mark.dom);
            if (tile) tile.setDOM(freeNode(mark.dom));
          }
          let nw = MarkTile.of(mark.mark, mark.dom);
          head.append(nw);
          head = nw;
        }
        this.cache.reused.set(mark, 2 /* Reused.DOM */);
      }
      let oldTile = Tile.get(composition.text);
      if (oldTile) this.cache.reused.set(oldTile, 2 /* Reused.DOM */);
      let text = new TextTile(composition.text, composition.text.nodeValue);
      text.flags |= 8 /* TileFlag.Composition */;
      this.pos = composition.range.toB;
      head.append(text);
    }
    addInlineWidget(widget, marks, openStart) {
      // Adjacent same-side-facing non-replacing widgets don't need buffers between them
      let noSpace = this.afterWidget && widget.flags & 48 /* TileFlag.PointWidget */ && (this.afterWidget.flags & 48 /* TileFlag.PointWidget */) == (widget.flags & 48 /* TileFlag.PointWidget */);
      if (!noSpace) this.flushBuffer();
      let parent = this.ensureMarks(marks, openStart);
      if (!noSpace && !(widget.flags & 16 /* TileFlag.Before */)) parent.append(this.getBuffer(1));
      parent.append(widget);
      this.pos += widget.length;
      this.afterWidget = widget;
    }
    addMark(tile, marks, openStart) {
      this.flushBuffer();
      let parent = this.ensureMarks(marks, openStart);
      parent.append(tile);
      this.pos += tile.length;
      this.afterWidget = null;
    }
    addBlockWidget(widget) {
      this.getBlockPos().append(widget);
      this.pos += widget.length;
      this.lastBlock = widget;
      this.endLine();
    }
    continueWidget(length) {
      let widget = this.afterWidget || this.lastBlock;
      widget.length += length;
      this.pos += length;
    }
    addLineStart(attrs, dom) {
      var _a;
      if (!attrs) attrs = lineBaseAttrs;
      let tile = LineTile.start(attrs, dom || ((_a = this.cache.find(LineTile)) === null || _a === void 0 ? void 0 : _a.dom), !!dom);
      this.getBlockPos().append(this.lastBlock = this.curLine = tile);
    }
    addLine(tile) {
      this.getBlockPos().append(tile);
      this.pos += tile.length;
      this.lastBlock = tile;
      this.endLine();
    }
    addBreak() {
      this.lastBlock.flags |= 1 /* TileFlag.BreakAfter */;
      this.endLine();
      this.pos++;
    }
    addLineStartIfNotCovered(attrs) {
      if (!this.blockPosCovered()) this.addLineStart(attrs);
    }
    ensureLine(attrs) {
      if (!this.curLine) this.addLineStart(attrs);
    }
    ensureMarks(marks, openStart) {
      var _a;
      let parent = this.curLine;
      for (let i = marks.length - 1; i >= 0; i--) {
        let mark = marks[i],
          last;
        if (openStart > 0 && (last = parent.lastChild) && last instanceof MarkTile && last.mark.eq(mark)) {
          parent = last;
          openStart--;
        } else {
          let tile = MarkTile.of(mark, (_a = this.cache.find(MarkTile, m => m.mark.eq(mark))) === null || _a === void 0 ? void 0 : _a.dom);
          parent.append(tile);
          parent = tile;
          openStart = 0;
        }
      }
      return parent;
    }
    endLine() {
      if (this.curLine) {
        this.flushBuffer();
        let last = this.curLine.lastChild;
        if (!last || !hasContent(this.curLine, false) || last.dom.nodeName != "BR" && last.isWidget() && !(browser.ios && hasContent(this.curLine, true))) this.curLine.append(this.cache.findWidget(BreakWidget, 0, 32 /* TileFlag.After */) || new WidgetTile(BreakWidget.toDOM(), 0, BreakWidget, 32 /* TileFlag.After */));
        this.curLine = this.afterWidget = null;
      }
    }
    updateBlockWrappers() {
      if (this.wrapperPos > this.pos + 10000 /* C.WrapperReset */) {
        this.blockWrappers.goto(this.pos);
        this.wrappers.length = 0;
      }
      for (let i = this.wrappers.length - 1; i >= 0; i--) if (this.wrappers[i].to < this.pos) this.wrappers.splice(i, 1);
      for (let cur = this.blockWrappers; cur.value && cur.from <= this.pos; cur.next()) if (cur.to >= this.pos) {
        let rank = cur.rank * 102 + cur.value.rank;
        let wrap = new OpenWrapper(cur.from, cur.to, cur.value, rank),
          i = this.wrappers.length;
        while (i > 0 && (this.wrappers[i - 1].rank - wrap.rank || this.wrappers[i - 1].to - wrap.to) < 0) i--;
        this.wrappers.splice(i, 0, wrap);
      }
      this.wrapperPos = this.pos;
    }
    getBlockPos() {
      var _a;
      this.updateBlockWrappers();
      let parent = this.root;
      for (let wrap of this.wrappers) {
        let last = parent.lastChild;
        if (wrap.from < this.pos && last instanceof BlockWrapperTile && last.wrapper.eq(wrap.wrapper)) {
          parent = last;
        } else {
          let tile = BlockWrapperTile.of(wrap.wrapper, (_a = this.cache.find(BlockWrapperTile, t => t.wrapper.eq(wrap.wrapper))) === null || _a === void 0 ? void 0 : _a.dom);
          parent.append(tile);
          parent = tile;
        }
      }
      return parent;
    }
    blockPosCovered() {
      let last = this.lastBlock;
      return last != null && !last.breakAfter && (!last.isWidget() || (last.flags & (32 /* TileFlag.After */ | 128 /* TileFlag.IncEnd */)) > 0);
    }
    getBuffer(side) {
      let flags = 2 /* TileFlag.Synced */ | (side < 0 ? 16 /* TileFlag.Before */ : 32 /* TileFlag.After */);
      let found = this.cache.find(WidgetBufferTile, undefined, 1 /* Reused.Full */);
      if (found) found.flags = flags;
      return found || new WidgetBufferTile(flags);
    }
    flushBuffer() {
      if (this.afterWidget && !(this.afterWidget.flags & 32 /* TileFlag.After */)) {
        this.afterWidget.parent.append(this.getBuffer(-1));
        this.afterWidget = null;
      }
    }
  }
  // Helps getting efficient access to the document text.
  class TextStream {
    constructor(doc) {
      this.skipCount = 0;
      this.text = "";
      this.textOff = 0;
      this.cursor = doc.iter();
    }
    skip(len) {
      // Advance the iterator past the replaced content
      if (this.textOff + len <= this.text.length) {
        this.textOff += len;
      } else {
        this.skipCount += len - (this.text.length - this.textOff);
        this.text = "";
        this.textOff = 0;
      }
    }
    next(maxLen) {
      if (this.textOff == this.text.length) {
        let {
          value,
          lineBreak,
          done
        } = this.cursor.next(this.skipCount);
        this.skipCount = 0;
        if (done) throw new Error("Ran out of text content when drawing inline views");
        this.text = value;
        let len = this.textOff = Math.min(maxLen, value.length);
        return lineBreak ? null : value.slice(0, len);
      }
      let end = Math.min(this.text.length, this.textOff + maxLen);
      let chars = this.text.slice(this.textOff, end);
      this.textOff = end;
      return chars;
    }
  }
  // Assign the tile classes bucket numbers for caching.
  const buckets = [WidgetTile, LineTile, TextTile, MarkTile, WidgetBufferTile, BlockWrapperTile, DocTile];
  for (let i = 0; i < buckets.length; i++) buckets[i].bucket = i;
  // Leaf tiles and line tiles may be reused in their entirety. All
  // others will get new tiles allocated, using the old DOM when
  // possible.
  class TileCache {
    constructor(view) {
      this.view = view;
      // Buckets are circular buffers, using `index` as the current
      // position.
      this.buckets = buckets.map(() => []);
      this.index = buckets.map(() => 0);
      this.reused = new Map();
    }
    // Put a tile in the cache.
    add(tile) {
      let i = tile.constructor.bucket,
        bucket = this.buckets[i];
      if (bucket.length < 6 /* C.Bucket */) bucket.push(tile);else bucket[this.index[i] = (this.index[i] + 1) % 6 /* C.Bucket */] = tile;
    }
    find(cls, test, type = 2 /* Reused.DOM */) {
      let i = cls.bucket;
      let bucket = this.buckets[i],
        off = this.index[i];
      for (let j = bucket.length - 1; j >= 0; j--) {
        // Look at the most recently added items first (last-in, first-out)
        let index = (j + off) % bucket.length,
          tile = bucket[index];
        if ((!test || test(tile)) && !this.reused.has(tile)) {
          bucket.splice(index, 1);
          if (index < off) this.index[i]--;
          this.reused.set(tile, type);
          return tile;
        }
      }
      return null;
    }
    findWidget(widget, length, flags) {
      let widgets = this.buckets[0];
      if (widgets.length) for (let i = 0, pass = 0;; i++) {
        if (i == widgets.length) {
          if (pass) return null;
          pass = 1;
          i = 0;
        }
        let tile = widgets[i];
        if (!this.reused.has(tile) && (pass == 0 ? tile.widget.compare(widget) : tile.widget.constructor == widget.constructor && widget.updateDOM(tile.dom, this.view, tile.widget))) {
          widgets.splice(i, 1);
          if (i < this.index[0]) this.index[0]--;
          if (tile.widget == widget && tile.length == length && (tile.flags & (496 /* TileFlag.Widget */ | 1 /* TileFlag.BreakAfter */)) == flags) {
            this.reused.set(tile, 1 /* Reused.Full */);
            return tile;
          } else {
            this.reused.set(tile, 2 /* Reused.DOM */);
            return new WidgetTile(tile.dom, length, widget, tile.flags & -498 | flags);
          }
        }
      }
    }
    reuse(tile) {
      this.reused.set(tile, 1 /* Reused.Full */);
      return tile;
    }
    maybeReuse(tile, type = 2 /* Reused.DOM */) {
      if (this.reused.has(tile)) return undefined;
      this.reused.set(tile, type);
      return tile.dom;
    }
    clear() {
      for (let i = 0; i < this.buckets.length; i++) this.buckets[i].length = this.index[i] = 0;
    }
  }
  // This class organizes a pass over the document, guided by the array
  // of replaced ranges. For ranges that haven't changed, it iterates
  // the old tree and copies its content into the new document. For
  // changed ranges, it runs a decoration iterator to guide generation
  // of content.
  class TileUpdate {
    constructor(view, old, blockWrappers, decorations, disallowBlockEffectsFor) {
      this.view = view;
      this.decorations = decorations;
      this.disallowBlockEffectsFor = disallowBlockEffectsFor;
      this.openWidget = false;
      this.openMarks = 0;
      this.cache = new TileCache(view);
      this.text = new TextStream(view.state.doc);
      this.builder = new TileBuilder(this.cache, new DocTile(view, view.contentDOM), RangeSet.iter(blockWrappers));
      this.cache.reused.set(old, 2 /* Reused.DOM */);
      this.old = new TilePointer(old);
      this.reuseWalker = {
        skip: (tile, from, to) => {
          this.cache.add(tile);
          if (tile.isComposite()) return false;
        },
        enter: tile => this.cache.add(tile),
        leave: () => {},
        break: () => {}
      };
    }
    run(changes, composition) {
      let compositionContext = composition && this.getCompositionContext(composition.text);
      for (let posA = 0, posB = 0, i = 0;;) {
        let next = i < changes.length ? changes[i++] : null;
        let skipA = next ? next.fromA : this.old.root.length;
        if (skipA > posA) {
          let len = skipA - posA;
          this.preserve(len, !i, !next);
          posA = skipA;
          posB += len;
        }
        if (!next) break;
        // Compositions need to be handled specially, forcing the
        // focused text node and its parent nodes to remain stable at
        // that point in the document.
        if (composition && next.fromA <= composition.range.fromA && next.toA >= composition.range.toA) {
          this.forward(next.fromA, composition.range.fromA, composition.range.fromA < composition.range.toA ? 1 : -1);
          this.emit(posB, composition.range.fromB);
          this.builder.flushBuffer();
          this.cache.clear(); // Must not reuse DOM across composition
          this.builder.addComposition(composition, compositionContext);
          this.text.skip(composition.range.toB - composition.range.fromB);
          this.forward(composition.range.fromA, next.toA);
          this.emit(composition.range.toB, next.toB);
        } else {
          this.forward(next.fromA, next.toA);
          this.emit(posB, next.toB);
        }
        posB = next.toB;
        posA = next.toA;
      }
      if (this.builder.curLine) this.builder.endLine();
      return this.builder.root;
    }
    preserve(length, incStart, incEnd) {
      let activeMarks = getMarks(this.old),
        openMarks = this.openMarks;
      this.old.advance(length, incEnd ? 1 : -1, {
        skip: (tile, from, to) => {
          if (tile.isWidget()) {
            if (this.openWidget) {
              this.builder.continueWidget(to - from);
            } else {
              let widget = to > 0 || from < tile.length ? WidgetTile.of(tile.widget, this.view, to - from, tile.flags & 496 /* TileFlag.Widget */, this.cache.maybeReuse(tile)) : this.cache.reuse(tile);
              if (widget.flags & 256 /* TileFlag.Block */) {
                widget.flags &= -2 /* TileFlag.BreakAfter */;
                this.builder.addBlockWidget(widget);
              } else {
                this.builder.ensureLine(null);
                this.builder.addInlineWidget(widget, activeMarks, openMarks);
                openMarks = activeMarks.length;
              }
            }
          } else if (tile.isText()) {
            this.builder.ensureLine(null);
            if (!from && to == tile.length && !this.cache.reused.has(tile)) {
              this.builder.addText(tile.text, activeMarks, openMarks, this.cache.reuse(tile));
            } else {
              this.cache.add(tile);
              this.builder.addText(tile.text.slice(from, to), activeMarks, openMarks);
            }
            openMarks = activeMarks.length;
          } else if (tile.isLine()) {
            tile.flags &= -2 /* TileFlag.BreakAfter */;
            this.cache.reused.set(tile, 1 /* Reused.Full */);
            this.builder.addLine(tile);
          } else if (tile instanceof WidgetBufferTile) {
            this.cache.add(tile);
          } else if (tile instanceof MarkTile) {
            this.builder.ensureLine(null);
            this.builder.addMark(tile, activeMarks, openMarks);
            this.cache.reused.set(tile, 1 /* Reused.Full */);
            openMarks = activeMarks.length;
          } else {
            return false;
          }
          this.openWidget = false;
        },
        enter: tile => {
          if (tile.isLine()) {
            this.builder.addLineStart(tile.attrs, this.cache.maybeReuse(tile));
          } else {
            this.cache.add(tile);
            if (tile instanceof MarkTile) activeMarks.unshift(tile.mark);
          }
          this.openWidget = false;
        },
        leave: tile => {
          if (tile.isLine()) {
            if (activeMarks.length) activeMarks.length = openMarks = 0;
          } else if (tile instanceof MarkTile) {
            activeMarks.shift();
            openMarks = Math.min(openMarks, activeMarks.length);
          }
        },
        break: () => {
          this.builder.addBreak();
          this.openWidget = false;
        }
      });
      this.text.skip(length);
    }
    emit(from, to) {
      let pendingLineAttrs = null;
      let b = this.builder,
        markCount = 0;
      let openEnd = RangeSet.spans(this.decorations, from, to, {
        point: (from, to, deco, active, openStart, index) => {
          if (deco instanceof PointDecoration) {
            if (this.disallowBlockEffectsFor[index]) {
              if (deco.block) throw new RangeError("Block decorations may not be specified via plugins");
              if (to > this.view.state.doc.lineAt(from).to) throw new RangeError("Decorations that replace line breaks may not be specified via plugins");
            }
            markCount = active.length;
            if (openStart > active.length) {
              b.continueWidget(to - from);
            } else {
              let widget = deco.widget || (deco.block ? NullWidget.block : NullWidget.inline);
              let flags = widgetFlags(deco);
              let tile = this.cache.findWidget(widget, to - from, flags) || WidgetTile.of(widget, this.view, to - from, flags);
              if (deco.block) {
                if (deco.startSide > 0) b.addLineStartIfNotCovered(pendingLineAttrs);
                b.addBlockWidget(tile);
              } else {
                b.ensureLine(pendingLineAttrs);
                b.addInlineWidget(tile, active, openStart);
              }
            }
            pendingLineAttrs = null;
          } else {
            pendingLineAttrs = addLineDeco(pendingLineAttrs, deco);
          }
          if (to > from) this.text.skip(to - from);
        },
        span: (from, to, active, openStart) => {
          for (let pos = from; pos < to;) {
            let chars = this.text.next(Math.min(512 /* C.Chunk */, to - pos));
            if (chars == null) {
              // Line break
              b.addLineStartIfNotCovered(pendingLineAttrs);
              b.addBreak();
              pos++;
            } else {
              b.ensureLine(pendingLineAttrs);
              b.addText(chars, active, pos == from ? openStart : active.length);
              pos += chars.length;
            }
            pendingLineAttrs = null;
          }
        }
      });
      b.addLineStartIfNotCovered(pendingLineAttrs);
      this.openWidget = openEnd > markCount;
      this.openMarks = openEnd;
    }
    forward(from, to, side = 1) {
      if (to - from <= 10) {
        this.old.advance(to - from, side, this.reuseWalker);
      } else {
        this.old.advance(5, -1, this.reuseWalker);
        this.old.advance(to - from - 10, -1);
        this.old.advance(5, side, this.reuseWalker);
      }
    }
    getCompositionContext(text) {
      let marks = [],
        line = null;
      for (let parent = text.parentNode;; parent = parent.parentNode) {
        let tile = Tile.get(parent);
        if (parent == this.view.contentDOM) break;
        if (tile instanceof MarkTile) marks.push(tile);else if (tile === null || tile === void 0 ? void 0 : tile.isLine()) line = tile;else if (tile instanceof BlockWrapperTile) ; // Ignore
        else if (parent.nodeName == "DIV" && !line && parent != this.view.contentDOM) line = new LineTile(parent, lineBaseAttrs);else if (!line) marks.push(MarkTile.of(new MarkDecoration({
          tagName: parent.nodeName.toLowerCase(),
          attributes: getAttrs(parent)
        }), parent));
      }
      return {
        line: line,
        marks
      };
    }
  }
  function hasContent(tile, requireText) {
    let scan = tile => {
      for (let ch of tile.children) if ((requireText ? ch.isText() : ch.length) || scan(ch)) return true;
      return false;
    };
    return scan(tile);
  }
  function widgetFlags(deco) {
    let flags = deco.isReplace ? (deco.startSide < 0 ? 64 /* TileFlag.IncStart */ : 0) | (deco.endSide > 0 ? 128 /* TileFlag.IncEnd */ : 0) : deco.startSide > 0 ? 32 /* TileFlag.After */ : 16 /* TileFlag.Before */;
    if (deco.block) flags |= 256 /* TileFlag.Block */;
    return flags;
  }
  const lineBaseAttrs = {
    class: "cm-line"
  };
  function addLineDeco(value, deco) {
    let attrs = deco.spec.attributes,
      cls = deco.spec.class;
    if (!attrs && !cls) return value;
    if (!value) value = {
      class: "cm-line"
    };
    if (attrs) combineAttrs(attrs, value);
    if (cls) value.class += " " + cls;
    return value;
  }
  function getMarks(ptr) {
    let found = [];
    for (let i = ptr.parents.length; i > 1; i--) {
      let tile = i == ptr.parents.length ? ptr.tile : ptr.parents[i].tile;
      if (tile instanceof MarkTile) found.push(tile.mark);
    }
    return found;
  }
  function freeNode(node) {
    let tile = Tile.get(node);
    if (tile) tile.setDOM(node.cloneNode());
    return node;
  }
  class NullWidget extends WidgetType {
    constructor(tag) {
      super();
      this.tag = tag;
    }
    eq(other) {
      return other.tag == this.tag;
    }
    toDOM() {
      return document.createElement(this.tag);
    }
    updateDOM(elt) {
      return elt.nodeName.toLowerCase() == this.tag;
    }
    get isHidden() {
      return true;
    }
  }
  NullWidget.inline = /*@__PURE__*/new NullWidget("span");
  NullWidget.block = /*@__PURE__*/new NullWidget("div");
  const BreakWidget = /*@__PURE__*/new class extends WidgetType {
    toDOM() {
      return document.createElement("br");
    }
    get isHidden() {
      return true;
    }
    get editable() {
      return true;
    }
  }();
  class DocView {
    constructor(view) {
      this.view = view;
      this.decorations = [];
      this.blockWrappers = [];
      this.dynamicDecorationMap = [false];
      this.domChanged = null;
      this.hasComposition = null;
      this.editContextFormatting = Decoration.none;
      this.lastCompositionAfterCursor = false;
      // Track a minimum width for the editor. When measuring sizes in
      // measureVisibleLineHeights, this is updated to point at the width
      // of a given element and its extent in the document. When a change
      // happens in that range, these are reset. That way, once we've seen
      // a line/element of a given length, we keep the editor wide enough
      // to fit at least that element, until it is changed, at which point
      // we forget it again.
      this.minWidth = 0;
      this.minWidthFrom = 0;
      this.minWidthTo = 0;
      // Track whether the DOM selection was set in a lossy way, so that
      // we don't mess it up when reading it back it
      this.impreciseAnchor = null;
      this.impreciseHead = null;
      this.forceSelection = false;
      // Used by the resize observer to ignore resizes that we caused
      // ourselves
      this.lastUpdate = Date.now();
      this.updateDeco();
      this.tile = new DocTile(view, view.contentDOM);
      this.updateInner([new ChangedRange(0, 0, 0, view.state.doc.length)], null);
    }
    // Update the document view to a given state.
    update(update) {
      var _a;
      let changedRanges = update.changedRanges;
      if (this.minWidth > 0 && changedRanges.length) {
        if (!changedRanges.every(({
          fromA,
          toA
        }) => toA < this.minWidthFrom || fromA > this.minWidthTo)) {
          this.minWidth = this.minWidthFrom = this.minWidthTo = 0;
        } else {
          this.minWidthFrom = update.changes.mapPos(this.minWidthFrom, 1);
          this.minWidthTo = update.changes.mapPos(this.minWidthTo, 1);
        }
      }
      this.updateEditContextFormatting(update);
      let readCompositionAt = -1;
      if (this.view.inputState.composing >= 0 && !this.view.observer.editContext) {
        if ((_a = this.domChanged) === null || _a === void 0 ? void 0 : _a.newSel) readCompositionAt = this.domChanged.newSel.head;else if (!touchesComposition(update.changes, this.hasComposition) && !update.selectionSet) readCompositionAt = update.state.selection.main.head;
      }
      let composition = readCompositionAt > -1 ? findCompositionRange(this.view, update.changes, readCompositionAt) : null;
      this.domChanged = null;
      if (this.hasComposition) {
        let {
          from,
          to
        } = this.hasComposition;
        changedRanges = new ChangedRange(from, to, update.changes.mapPos(from, -1), update.changes.mapPos(to, 1)).addToSet(changedRanges.slice());
      }
      this.hasComposition = composition ? {
        from: composition.range.fromB,
        to: composition.range.toB
      } : null;
      // When the DOM nodes around the selection are moved to another
      // parent, Chrome sometimes reports a different selection through
      // getSelection than the one that it actually shows to the user.
      // This forces a selection update when lines are joined to work
      // around that. Issue #54
      if ((browser.ie || browser.chrome) && !composition && update && update.state.doc.lines != update.startState.doc.lines) this.forceSelection = true;
      let prevDeco = this.decorations,
        prevWrappers = this.blockWrappers;
      this.updateDeco();
      let decoDiff = findChangedDeco(prevDeco, this.decorations, update.changes);
      if (decoDiff.length) changedRanges = ChangedRange.extendWithRanges(changedRanges, decoDiff);
      let blockDiff = findChangedWrappers(prevWrappers, this.blockWrappers, update.changes);
      if (blockDiff.length) changedRanges = ChangedRange.extendWithRanges(changedRanges, blockDiff);
      if (composition && !changedRanges.some(r => r.fromA <= composition.range.fromA && r.toA >= composition.range.toA)) changedRanges = composition.range.addToSet(changedRanges.slice());
      if (this.tile.flags & 2 /* TileFlag.Synced */ && changedRanges.length == 0) {
        return false;
      } else {
        this.updateInner(changedRanges, composition);
        if (update.transactions.length) this.lastUpdate = Date.now();
        return true;
      }
    }
    // Used by update and the constructor do perform the actual DOM
    // update
    updateInner(changes, composition) {
      this.view.viewState.mustMeasureContent = true;
      let {
        observer
      } = this.view;
      observer.ignore(() => {
        if (composition || changes.length) {
          let oldTile = this.tile;
          let builder = new TileUpdate(this.view, oldTile, this.blockWrappers, this.decorations, this.dynamicDecorationMap);
          if (composition && Tile.get(composition.text)) builder.cache.reused.set(Tile.get(composition.text), 2 /* Reused.DOM */);
          this.tile = builder.run(changes, composition);
          destroyDropped(oldTile, builder.cache.reused);
        }
        // Lock the height during redrawing, since Chrome sometimes
        // messes with the scroll position during DOM mutation (though
        // no relayout is triggered and I cannot imagine how it can
        // recompute the scroll position without a layout)
        this.tile.dom.style.height = this.view.viewState.contentHeight / this.view.scaleY + "px";
        this.tile.dom.style.flexBasis = this.minWidth ? this.minWidth + "px" : "";
        // Chrome will sometimes, when DOM mutations occur directly
        // around the selection, get confused and report a different
        // selection from the one it displays (issue #218). This tries
        // to detect that situation.
        let track = browser.chrome || browser.ios ? {
          node: observer.selectionRange.focusNode,
          written: false
        } : undefined;
        this.tile.sync(track);
        if (track && (track.written || observer.selectionRange.focusNode != track.node || !this.tile.dom.contains(track.node))) this.forceSelection = true;
        this.tile.dom.style.height = "";
      });
      let gaps = [];
      if (this.view.viewport.from || this.view.viewport.to < this.view.state.doc.length) for (let child of this.tile.children) if (child.isWidget() && child.widget instanceof BlockGapWidget) gaps.push(child.dom);
      observer.updateGaps(gaps);
    }
    updateEditContextFormatting(update) {
      this.editContextFormatting = this.editContextFormatting.map(update.changes);
      for (let tr of update.transactions) for (let effect of tr.effects) if (effect.is(setEditContextFormatting)) {
        this.editContextFormatting = effect.value;
      }
    }
    // Sync the DOM selection to this.state.selection
    updateSelection(mustRead = false, fromPointer = false) {
      if (mustRead || !this.view.observer.selectionRange.focusNode) this.view.observer.readSelectionRange();
      let {
        dom
      } = this.tile;
      let activeElt = this.view.root.activeElement,
        focused = activeElt == dom;
      let selectionNotFocus = !focused && !(this.view.state.facet(editable) || dom.tabIndex > -1) && hasSelection(dom, this.view.observer.selectionRange) && !(activeElt && dom.contains(activeElt));
      if (!(focused || fromPointer || selectionNotFocus)) return;
      let force = this.forceSelection;
      this.forceSelection = false;
      let main = this.view.state.selection.main,
        anchor,
        head;
      if (main.empty) {
        head = anchor = this.inlineDOMNearPos(main.anchor, main.assoc || 1);
      } else {
        head = this.inlineDOMNearPos(main.head, main.head == main.from ? 1 : -1);
        anchor = this.inlineDOMNearPos(main.anchor, main.anchor == main.from ? 1 : -1);
      }
      // Always reset on Firefox when next to an uneditable node to
      // avoid invisible cursor bugs (#111)
      if (browser.gecko && main.empty && !this.hasComposition && betweenUneditable(anchor)) {
        let dummy = document.createTextNode("");
        this.view.observer.ignore(() => anchor.node.insertBefore(dummy, anchor.node.childNodes[anchor.offset] || null));
        anchor = head = new DOMPos(dummy, 0);
        force = true;
      }
      let domSel = this.view.observer.selectionRange;
      // If the selection is already here, or in an equivalent position, don't touch it
      if (force || !domSel.focusNode || (!isEquivalentPosition(anchor.node, anchor.offset, domSel.anchorNode, domSel.anchorOffset) || !isEquivalentPosition(head.node, head.offset, domSel.focusNode, domSel.focusOffset)) && !this.suppressWidgetCursorChange(domSel, main)) {
        this.view.observer.ignore(() => {
          // Chrome Android will hide the virtual keyboard when tapping
          // inside an uneditable node, and not bring it back when we
          // move the cursor to its proper position. This tries to
          // restore the keyboard by cycling focus.
          if (browser.android && browser.chrome && dom.contains(domSel.focusNode) && inUneditable(domSel.focusNode, dom)) {
            dom.blur();
            dom.focus({
              preventScroll: true
            });
          }
          let rawSel = getSelection(this.view.root);
          if (!rawSel) ;else if (main.empty) {
            // Work around https://bugzilla.mozilla.org/show_bug.cgi?id=1612076
            if (browser.gecko) {
              let nextTo = nextToUneditable(anchor.node, anchor.offset);
              if (nextTo && nextTo != (1 /* NextTo.Before */ | 2 /* NextTo.After */)) {
                let text = (nextTo == 1 /* NextTo.Before */ ? textNodeBefore : textNodeAfter)(anchor.node, anchor.offset);
                if (text) anchor = new DOMPos(text.node, text.offset);
              }
            }
            rawSel.collapse(anchor.node, anchor.offset);
            if (main.bidiLevel != null && rawSel.caretBidiLevel !== undefined) rawSel.caretBidiLevel = main.bidiLevel;
          } else if (rawSel.extend) {
            // Selection.extend can be used to create an 'inverted' selection
            // (one where the focus is before the anchor), but not all
            // browsers support it yet.
            rawSel.collapse(anchor.node, anchor.offset);
            // Safari will ignore the call above when the editor is
            // hidden, and then raise an error on the call to extend
            // (#940).
            try {
              rawSel.extend(head.node, head.offset);
            } catch (_) {}
          } else {
            // Primitive (IE) way
            let range = document.createRange();
            if (main.anchor > main.head) [anchor, head] = [head, anchor];
            range.setEnd(head.node, head.offset);
            range.setStart(anchor.node, anchor.offset);
            rawSel.removeAllRanges();
            rawSel.addRange(range);
          }
          if (selectionNotFocus && this.view.root.activeElement == dom) {
            dom.blur();
            if (activeElt) activeElt.focus();
          }
        });
        this.view.observer.setSelectionRange(anchor, head);
      }
      this.impreciseAnchor = anchor.precise ? null : new DOMPos(domSel.anchorNode, domSel.anchorOffset);
      this.impreciseHead = head.precise ? null : new DOMPos(domSel.focusNode, domSel.focusOffset);
    }
    // If a zero-length widget is inserted next to the cursor during
    // composition, avoid moving it across it and disrupting the
    // composition.
    suppressWidgetCursorChange(sel, cursor) {
      return this.hasComposition && cursor.empty && isEquivalentPosition(sel.focusNode, sel.focusOffset, sel.anchorNode, sel.anchorOffset) && this.posFromDOM(sel.focusNode, sel.focusOffset) == cursor.head;
    }
    enforceCursorAssoc() {
      if (this.hasComposition) return;
      let {
          view
        } = this,
        cursor = view.state.selection.main;
      let sel = getSelection(view.root);
      let {
        anchorNode,
        anchorOffset
      } = view.observer.selectionRange;
      if (!sel || !cursor.empty || !cursor.assoc || !sel.modify) return;
      let line = this.lineAt(cursor.head, cursor.assoc);
      if (!line) return;
      let lineStart = line.posAtStart;
      if (cursor.head == lineStart || cursor.head == lineStart + line.length) return;
      let before = this.coordsAt(cursor.head, -1),
        after = this.coordsAt(cursor.head, 1);
      if (!before || !after || before.bottom > after.top) return;
      let dom = this.domAtPos(cursor.head + cursor.assoc, cursor.assoc);
      sel.collapse(dom.node, dom.offset);
      sel.modify("move", cursor.assoc < 0 ? "forward" : "backward", "lineboundary");
      // This can go wrong in corner cases like single-character lines,
      // so check and reset if necessary.
      view.observer.readSelectionRange();
      let newRange = view.observer.selectionRange;
      if (view.docView.posFromDOM(newRange.anchorNode, newRange.anchorOffset) != cursor.from) sel.collapse(anchorNode, anchorOffset);
    }
    posFromDOM(node, offset) {
      let tile = this.tile.nearest(node);
      if (!tile) return this.tile.dom.compareDocumentPosition(node) & 2 /* PRECEDING */ ? 0 : this.view.state.doc.length;
      let start = tile.posAtStart;
      if (tile.isComposite()) {
        let after;
        if (node == tile.dom) {
          after = tile.dom.childNodes[offset];
        } else {
          let bias = maxOffset(node) == 0 ? 0 : offset == 0 ? -1 : 1;
          for (;;) {
            let parent = node.parentNode;
            if (parent == tile.dom) break;
            if (bias == 0 && parent.firstChild != parent.lastChild) {
              if (node == parent.firstChild) bias = -1;else bias = 1;
            }
            node = parent;
          }
          if (bias < 0) after = node;else after = node.nextSibling;
        }
        if (after == tile.dom.firstChild) return start;
        while (after && !Tile.get(after)) after = after.nextSibling;
        if (!after) return start + tile.length;
        for (let i = 0, pos = start;; i++) {
          let child = tile.children[i];
          if (child.dom == after) return pos;
          pos += child.length + child.breakAfter;
        }
      } else if (tile.isText()) {
        return node == tile.dom ? start + offset : start + (offset ? tile.length : 0);
      } else {
        return start;
      }
    }
    domAtPos(pos, side) {
      let {
        tile,
        offset
      } = this.tile.resolveBlock(pos, side);
      if (tile.isWidget()) return tile.domPosFor(pos, side);
      return tile.domIn(offset, side);
    }
    inlineDOMNearPos(pos, side) {
      let before,
        beforeOff = -1,
        beforeBad = false;
      let after,
        afterOff = -1,
        afterBad = false;
      this.tile.blockTiles((tile, off) => {
        if (tile.isWidget()) {
          if (tile.flags & 32 /* TileFlag.After */ && off >= pos) return true;
          if (tile.flags & 16 /* TileFlag.Before */) beforeBad = true;
        } else {
          let end = off + tile.length;
          if (off <= pos) {
            before = tile;
            beforeOff = pos - off;
            beforeBad = end < pos;
          }
          if (end >= pos && !after) {
            after = tile;
            afterOff = pos - off;
            afterBad = off > pos;
          }
          if (off > pos && after) return true;
        }
      });
      if (!before && !after) return this.domAtPos(pos, side);
      if (beforeBad && after) before = null;else if (afterBad && before) after = null;
      return before && side < 0 || !after ? before.domIn(beforeOff, side) : after.domIn(afterOff, side);
    }
    coordsAt(pos, side) {
      let {
        tile,
        offset
      } = this.tile.resolveBlock(pos, side);
      if (tile.isWidget()) {
        if (tile.widget instanceof BlockGapWidget) return null;
        return tile.coordsInWidget(offset, side, true);
      }
      return tile.coordsIn(offset, side);
    }
    lineAt(pos, side) {
      let {
        tile
      } = this.tile.resolveBlock(pos, side);
      return tile.isLine() ? tile : null;
    }
    coordsForChar(pos) {
      let {
        tile,
        offset
      } = this.tile.resolveBlock(pos, 1);
      if (!tile.isLine()) return null;
      function scan(tile, offset) {
        if (tile.isComposite()) {
          for (let ch of tile.children) {
            if (ch.length >= offset) {
              let found = scan(ch, offset);
              if (found) return found;
            }
            offset -= ch.length;
            if (offset < 0) break;
          }
        } else if (tile.isText() && offset < tile.length) {
          let end = findClusterBreak(tile.text, offset);
          if (end == offset) return null;
          let rects = textRange(tile.dom, offset, end).getClientRects();
          for (let i = 0; i < rects.length; i++) {
            let rect = rects[i];
            if (i == rects.length - 1 || rect.top < rect.bottom && rect.left < rect.right) return rect;
          }
        }
        return null;
      }
      return scan(tile, offset);
    }
    measureVisibleLineHeights(viewport) {
      let result = [],
        {
          from,
          to
        } = viewport;
      let contentWidth = this.view.contentDOM.clientWidth;
      let isWider = contentWidth > Math.max(this.view.scrollDOM.clientWidth, this.minWidth) + 1;
      let widest = -1,
        ltr = this.view.textDirection == Direction.LTR;
      let spaceAbove = 0;
      let scan = (tile, pos, measureBounds) => {
        for (let i = 0; i < tile.children.length; i++) {
          if (pos > to) break;
          let child = tile.children[i],
            end = pos + child.length;
          let childRect = child.dom.getBoundingClientRect(),
            {
              height
            } = childRect;
          if (measureBounds && !i) spaceAbove += childRect.top - measureBounds.top;
          if (child instanceof BlockWrapperTile) {
            if (end > from) scan(child, pos, childRect);
          } else if (pos >= from) {
            if (spaceAbove > 0) result.push(-spaceAbove);
            result.push(height + spaceAbove);
            spaceAbove = 0;
            if (isWider) {
              let last = child.dom.lastChild;
              let rects = last ? clientRectsFor(last) : [];
              if (rects.length) {
                let rect = rects[rects.length - 1];
                let width = ltr ? rect.right - childRect.left : childRect.right - rect.left;
                if (width > widest) {
                  widest = width;
                  this.minWidth = contentWidth;
                  this.minWidthFrom = pos;
                  this.minWidthTo = end;
                }
              }
            }
          }
          if (measureBounds && i == tile.children.length - 1) spaceAbove += measureBounds.bottom - childRect.bottom;
          pos = end + child.breakAfter;
        }
      };
      scan(this.tile, 0, null);
      return result;
    }
    textDirectionAt(pos) {
      let {
        tile
      } = this.tile.resolveBlock(pos, 1);
      return getComputedStyle(tile.dom).direction == "rtl" ? Direction.RTL : Direction.LTR;
    }
    measureTextSize() {
      let lineMeasure = this.tile.blockTiles(tile => {
        if (tile.isLine() && tile.children.length && tile.length <= 20) {
          let totalWidth = 0,
            textHeight;
          for (let child of tile.children) {
            if (!child.isText() || /[^ -~]/.test(child.text)) return undefined;
            let rects = clientRectsFor(child.dom);
            if (rects.length != 1) return undefined;
            totalWidth += rects[0].width;
            textHeight = rects[0].height;
          }
          if (totalWidth) return {
            lineHeight: tile.dom.getBoundingClientRect().height,
            charWidth: totalWidth / tile.length,
            textHeight
          };
        }
      });
      if (lineMeasure) return lineMeasure;
      // If no workable line exists, force a layout of a measurable element
      let dummy = document.createElement("div"),
        lineHeight,
        charWidth,
        textHeight;
      dummy.className = "cm-line";
      dummy.style.width = "99999px";
      dummy.style.position = "absolute";
      dummy.textContent = "abc def ghi jkl mno pqr stu";
      this.view.observer.ignore(() => {
        this.tile.dom.appendChild(dummy);
        let rect = clientRectsFor(dummy.firstChild)[0];
        lineHeight = dummy.getBoundingClientRect().height;
        charWidth = rect && rect.width ? rect.width / 27 : 7;
        textHeight = rect && rect.height ? rect.height : lineHeight;
        dummy.remove();
      });
      return {
        lineHeight,
        charWidth,
        textHeight
      };
    }
    computeBlockGapDeco() {
      let deco = [],
        vs = this.view.viewState;
      for (let pos = 0, i = 0;; i++) {
        let next = i == vs.viewports.length ? null : vs.viewports[i];
        let end = next ? next.from - 1 : this.view.state.doc.length;
        if (end > pos) {
          let height = (vs.lineBlockAt(end).bottom - vs.lineBlockAt(pos).top) / this.view.scaleY;
          deco.push(Decoration.replace({
            widget: new BlockGapWidget(height),
            block: true,
            inclusive: true,
            isBlockGap: true
          }).range(pos, end));
        }
        if (!next) break;
        pos = next.to + 1;
      }
      return Decoration.set(deco);
    }
    updateDeco() {
      let i = 1;
      let allDeco = this.view.state.facet(decorations).map(d => {
        let dynamic = this.dynamicDecorationMap[i++] = typeof d == "function";
        return dynamic ? d(this.view) : d;
      });
      let dynamicOuter = false,
        outerDeco = this.view.state.facet(outerDecorations).map((d, i) => {
          let dynamic = typeof d == "function";
          if (dynamic) dynamicOuter = true;
          return dynamic ? d(this.view) : d;
        });
      if (outerDeco.length) {
        this.dynamicDecorationMap[i++] = dynamicOuter;
        allDeco.push(RangeSet.join(outerDeco));
      }
      this.decorations = [this.editContextFormatting, ...allDeco, this.computeBlockGapDeco(), this.view.viewState.lineGapDeco];
      while (i < this.decorations.length) this.dynamicDecorationMap[i++] = false;
      this.blockWrappers = this.view.state.facet(blockWrappers).map(v => typeof v == "function" ? v(this.view) : v);
    }
    scrollIntoView(target) {
      var _a;
      if (target.isSnapshot) {
        let ref = this.view.viewState.lineBlockAt(target.range.head);
        this.view.scrollDOM.scrollTop = ref.top - target.yMargin;
        this.view.scrollDOM.scrollLeft = target.xMargin;
        return;
      }
      for (let handler of this.view.state.facet(scrollHandler)) {
        try {
          if (handler(this.view, target.range, target)) return true;
        } catch (e) {
          logException(this.view.state, e, "scroll handler");
        }
      }
      let {
        range
      } = target;
      let rect = this.coordsAt(range.head, (_a = range.assoc) !== null && _a !== void 0 ? _a : range.empty ? 0 : range.head > range.anchor ? -1 : 1),
        other;
      if (!rect) return;
      if (!range.empty && (other = this.coordsAt(range.anchor, range.anchor > range.head ? -1 : 1))) rect = {
        left: Math.min(rect.left, other.left),
        top: Math.min(rect.top, other.top),
        right: Math.max(rect.right, other.right),
        bottom: Math.max(rect.bottom, other.bottom)
      };
      let margins = getScrollMargins(this.view);
      let targetRect = {
        left: rect.left - margins.left,
        top: rect.top - margins.top,
        right: rect.right + margins.right,
        bottom: rect.bottom + margins.bottom
      };
      let {
        offsetWidth,
        offsetHeight
      } = this.view.scrollDOM;
      scrollRectIntoView(this.view.scrollDOM, targetRect, range.head < range.anchor ? -1 : 1, target.x, target.y, Math.max(Math.min(target.xMargin, offsetWidth), -offsetWidth), Math.max(Math.min(target.yMargin, offsetHeight), -offsetHeight), this.view.textDirection == Direction.LTR);
      // On mobile browsers, the visual viewport may be smaller than the
      // actual reported viewport, causing scrollRectIntoView to fail to
      // scroll properly. Unfortunately, this visual viewport cannot be
      // updated directly, and scrollIntoView is the only way a script
      // can affect it. So this tries to kludge around the problem by
      // calling scrollIntoView on the scroll target's line.
      if (window.visualViewport && window.innerHeight - window.visualViewport.height > 1 && (rect.top > window.pageYOffset + window.visualViewport.offsetTop + window.visualViewport.height || rect.bottom < window.pageYOffset + window.visualViewport.offsetTop)) {
        let line = this.view.docView.lineAt(range.head, 1);
        if (line) line.dom.scrollIntoView({
          block: "nearest"
        });
      }
    }
    lineHasWidget(pos) {
      let scan = child => child.isWidget() || child.children.some(scan);
      return scan(this.tile.resolveBlock(pos, 1).tile);
    }
    destroy() {
      destroyDropped(this.tile);
    }
  }
  function destroyDropped(tile, reused) {
    let r = reused === null || reused === void 0 ? void 0 : reused.get(tile);
    if (r != 1 /* Reused.Full */) {
      if (r == null) tile.destroy();
      for (let ch of tile.children) destroyDropped(ch, reused);
    }
  }
  function betweenUneditable(pos) {
    return pos.node.nodeType == 1 && pos.node.firstChild && (pos.offset == 0 || pos.node.childNodes[pos.offset - 1].contentEditable == "false") && (pos.offset == pos.node.childNodes.length || pos.node.childNodes[pos.offset].contentEditable == "false");
  }
  function findCompositionNode(view, headPos) {
    let sel = view.observer.selectionRange;
    if (!sel.focusNode) return null;
    let textBefore = textNodeBefore(sel.focusNode, sel.focusOffset);
    let textAfter = textNodeAfter(sel.focusNode, sel.focusOffset);
    let textNode = textBefore || textAfter;
    if (textAfter && textBefore && textAfter.node != textBefore.node) {
      let tileAfter = Tile.get(textAfter.node);
      if (!tileAfter || tileAfter.isText() && tileAfter.text != textAfter.node.nodeValue) {
        textNode = textAfter;
      } else if (view.docView.lastCompositionAfterCursor) {
        let tileBefore = Tile.get(textBefore.node);
        if (!(!tileBefore || tileBefore.isText() && tileBefore.text != textBefore.node.nodeValue)) textNode = textAfter;
      }
    }
    view.docView.lastCompositionAfterCursor = textNode != textBefore;
    if (!textNode) return null;
    let from = headPos - textNode.offset;
    return {
      from,
      to: from + textNode.node.nodeValue.length,
      node: textNode.node
    };
  }
  function findCompositionRange(view, changes, headPos) {
    let found = findCompositionNode(view, headPos);
    if (!found) return null;
    let {
        node: textNode,
        from,
        to
      } = found,
      text = textNode.nodeValue;
    // Don't try to preserve multi-line compositions
    if (/[\n\r]/.test(text)) return null;
    if (view.state.doc.sliceString(found.from, found.to) != text) return null;
    let inv = changes.invertedDesc;
    return {
      range: new ChangedRange(inv.mapPos(from), inv.mapPos(to), from, to),
      text: textNode
    };
  }
  function nextToUneditable(node, offset) {
    if (node.nodeType != 1) return 0;
    return (offset && node.childNodes[offset - 1].contentEditable == "false" ? 1 /* NextTo.Before */ : 0) | (offset < node.childNodes.length && node.childNodes[offset].contentEditable == "false" ? 2 /* NextTo.After */ : 0);
  }
  let DecorationComparator$1 = class DecorationComparator {
    constructor() {
      this.changes = [];
    }
    compareRange(from, to) {
      addRange(from, to, this.changes);
    }
    comparePoint(from, to) {
      addRange(from, to, this.changes);
    }
    boundChange(pos) {
      addRange(pos, pos, this.changes);
    }
  };
  function findChangedDeco(a, b, diff) {
    let comp = new DecorationComparator$1();
    RangeSet.compare(a, b, diff, comp);
    return comp.changes;
  }
  class WrapperComparator {
    constructor() {
      this.changes = [];
    }
    compareRange(from, to) {
      addRange(from, to, this.changes);
    }
    comparePoint() {}
    boundChange(pos) {
      addRange(pos, pos, this.changes);
    }
  }
  function findChangedWrappers(a, b, diff) {
    let comp = new WrapperComparator();
    RangeSet.compare(a, b, diff, comp);
    return comp.changes;
  }
  function inUneditable(node, inside) {
    for (let cur = node; cur && cur != inside; cur = cur.assignedSlot || cur.parentNode) {
      if (cur.nodeType == 1 && cur.contentEditable == 'false') {
        return true;
      }
    }
    return false;
  }
  function touchesComposition(changes, composition) {
    let touched = false;
    if (composition) changes.iterChangedRanges((from, to) => {
      if (from < composition.to && to > composition.from) touched = true;
    });
    return touched;
  }
  class BlockGapWidget extends WidgetType {
    constructor(height) {
      super();
      this.height = height;
    }
    toDOM() {
      let elt = document.createElement("div");
      elt.className = "cm-gap";
      this.updateDOM(elt);
      return elt;
    }
    eq(other) {
      return other.height == this.height;
    }
    updateDOM(elt) {
      elt.style.height = this.height + "px";
      return true;
    }
    get editable() {
      return true;
    }
    get estimatedHeight() {
      return this.height;
    }
    ignoreEvent() {
      return false;
    }
  }
  function groupAt(state, pos, bias = 1) {
    let categorize = state.charCategorizer(pos);
    let line = state.doc.lineAt(pos),
      linePos = pos - line.from;
    if (line.length == 0) return EditorSelection.cursor(pos);
    if (linePos == 0) bias = 1;else if (linePos == line.length) bias = -1;
    let from = linePos,
      to = linePos;
    if (bias < 0) from = findClusterBreak(line.text, linePos, false);else to = findClusterBreak(line.text, linePos);
    let cat = categorize(line.text.slice(from, to));
    while (from > 0) {
      let prev = findClusterBreak(line.text, from, false);
      if (categorize(line.text.slice(prev, from)) != cat) break;
      from = prev;
    }
    while (to < line.length) {
      let next = findClusterBreak(line.text, to);
      if (categorize(line.text.slice(to, next)) != cat) break;
      to = next;
    }
    return EditorSelection.range(from + line.from, to + line.from);
  }
  function posAtCoordsImprecise(view, contentRect, block, x, y) {
    let into = Math.round((x - contentRect.left) * view.defaultCharacterWidth);
    if (view.lineWrapping && block.height > view.defaultLineHeight * 1.5) {
      let textHeight = view.viewState.heightOracle.textHeight;
      let line = Math.floor((y - block.top - (view.defaultLineHeight - textHeight) * 0.5) / textHeight);
      into += line * view.viewState.heightOracle.lineLength;
    }
    let content = view.state.sliceDoc(block.from, block.to);
    return block.from + findColumn(content, into, view.state.tabSize);
  }
  function blockAt(view, pos, side) {
    let line = view.lineBlockAt(pos);
    if (Array.isArray(line.type)) {
      let best;
      for (let l of line.type) {
        if (l.from > pos) break;
        if (l.to < pos) continue;
        if (l.from < pos && l.to > pos) return l;
        if (!best || l.type == BlockType.Text && (best.type != l.type || (side < 0 ? l.from < pos : l.to > pos))) best = l;
      }
      return best || line;
    }
    return line;
  }
  function moveToLineBoundary(view, start, forward, includeWrap) {
    let line = blockAt(view, start.head, start.assoc || -1);
    let coords = !includeWrap || line.type != BlockType.Text || !(view.lineWrapping || line.widgetLineBreaks) ? null : view.coordsAtPos(start.assoc < 0 && start.head > line.from ? start.head - 1 : start.head);
    if (coords) {
      let editorRect = view.dom.getBoundingClientRect();
      let direction = view.textDirectionAt(line.from);
      let pos = view.posAtCoords({
        x: forward == (direction == Direction.LTR) ? editorRect.right - 1 : editorRect.left + 1,
        y: (coords.top + coords.bottom) / 2
      });
      if (pos != null) return EditorSelection.cursor(pos, forward ? -1 : 1);
    }
    return EditorSelection.cursor(forward ? line.to : line.from, forward ? -1 : 1);
  }
  function moveByChar(view, start, forward, by) {
    let line = view.state.doc.lineAt(start.head),
      spans = view.bidiSpans(line);
    let direction = view.textDirectionAt(line.from);
    for (let cur = start, check = null;;) {
      let next = moveVisually(line, spans, direction, cur, forward),
        char = movedOver;
      if (!next) {
        if (line.number == (forward ? view.state.doc.lines : 1)) return cur;
        char = "\n";
        line = view.state.doc.line(line.number + (forward ? 1 : -1));
        spans = view.bidiSpans(line);
        next = view.visualLineSide(line, !forward);
      }
      if (!check) {
        if (!by) return next;
        check = by(char);
      } else if (!check(char)) {
        return cur;
      }
      cur = next;
    }
  }
  function byGroup(view, pos, start) {
    let categorize = view.state.charCategorizer(pos);
    let cat = categorize(start);
    return next => {
      let nextCat = categorize(next);
      if (cat == CharCategory.Space) cat = nextCat;
      return cat == nextCat;
    };
  }
  function moveVertically(view, start, forward, distance) {
    let startPos = start.head,
      dir = forward ? 1 : -1;
    if (startPos == (forward ? view.state.doc.length : 0)) return EditorSelection.cursor(startPos, start.assoc);
    let goal = start.goalColumn,
      startY;
    let rect = view.contentDOM.getBoundingClientRect();
    let startCoords = view.coordsAtPos(startPos, start.assoc || ((start.empty ? forward : start.head == start.from) ? 1 : -1));
    let docTop = view.documentTop;
    if (startCoords) {
      if (goal == null) goal = startCoords.left - rect.left;
      startY = dir < 0 ? startCoords.top : startCoords.bottom;
    } else {
      let line = view.viewState.lineBlockAt(startPos);
      if (goal == null) goal = Math.min(rect.right - rect.left, view.defaultCharacterWidth * (startPos - line.from));
      startY = (dir < 0 ? line.top : line.bottom) + docTop;
    }
    let resolvedGoal = rect.left + goal;
    let halfText = view.viewState.heightOracle.textHeight >> 1,
      dist = distance !== null && distance !== void 0 ? distance : halfText;
    for (let scan = 0;; scan += halfText) {
      let y = startY + (dist + scan) * dir;
      let pos = posAtCoords(view, {
        x: resolvedGoal,
        y
      }, false, dir);
      if (forward ? y > rect.bottom : y < rect.top) return EditorSelection.cursor(pos.pos, pos.assoc);
      let posCoords = view.coordsAtPos(pos.pos, pos.assoc),
        mid = posCoords ? (posCoords.top + posCoords.bottom) / 2 : 0;
      if (!posCoords || (forward ? mid > startY : mid < startY)) return EditorSelection.cursor(pos.pos, pos.assoc, undefined, goal);
    }
  }
  function skipAtomicRanges(atoms, pos, bias) {
    for (;;) {
      let moved = 0;
      for (let set of atoms) {
        set.between(pos - 1, pos + 1, (from, to, value) => {
          if (pos > from && pos < to) {
            let side = moved || bias || (pos - from < to - pos ? -1 : 1);
            pos = side < 0 ? from : to;
            moved = side;
          }
        });
      }
      if (!moved) return pos;
    }
  }
  function skipAtomsForSelection(atoms, sel) {
    let ranges = null;
    for (let i = 0; i < sel.ranges.length; i++) {
      let range = sel.ranges[i],
        updated = null;
      if (range.empty) {
        let pos = skipAtomicRanges(atoms, range.from, 0);
        if (pos != range.from) updated = EditorSelection.cursor(pos, -1);
      } else {
        let from = skipAtomicRanges(atoms, range.from, -1);
        let to = skipAtomicRanges(atoms, range.to, 1);
        if (from != range.from || to != range.to) updated = EditorSelection.range(range.from == range.anchor ? from : to, range.from == range.head ? from : to);
      }
      if (updated) {
        if (!ranges) ranges = sel.ranges.slice();
        ranges[i] = updated;
      }
    }
    return ranges ? EditorSelection.create(ranges, sel.mainIndex) : sel;
  }
  function skipAtoms(view, oldPos, pos) {
    let newPos = skipAtomicRanges(view.state.facet(atomicRanges).map(f => f(view)), pos.from, oldPos.head > pos.from ? -1 : 1);
    return newPos == pos.from ? pos : EditorSelection.cursor(newPos, newPos < pos.from ? 1 : -1);
  }
  class PosAssoc {
    constructor(pos, assoc) {
      this.pos = pos;
      this.assoc = assoc;
    }
  }
  function posAtCoords(view, coords, precise, scanY) {
    let content = view.contentDOM.getBoundingClientRect(),
      docTop = content.top + view.viewState.paddingTop;
    let {
        x,
        y
      } = coords,
      yOffset = y - docTop,
      block;
    // First find the block at the given Y position, if any. If scanY is
    // given (used for vertical cursor motion), try to skip widgets and
    // line padding.
    for (;;) {
      if (yOffset < 0) return new PosAssoc(0, 1);
      if (yOffset > view.viewState.docHeight) return new PosAssoc(view.state.doc.length, -1);
      block = view.elementAtHeight(yOffset);
      if (scanY == null) break;
      if (block.type == BlockType.Text) {
        if (scanY < 0 ? block.to < view.viewport.from : block.from > view.viewport.to) break;
        // Check whether we aren't landing on the top/bottom padding of the line
        let rect = view.docView.coordsAt(scanY < 0 ? block.from : block.to, scanY > 0 ? -1 : 1);
        if (rect && (scanY < 0 ? rect.top <= yOffset + docTop : rect.bottom >= yOffset + docTop)) break;
      }
      let halfLine = view.viewState.heightOracle.textHeight / 2;
      yOffset = scanY > 0 ? block.bottom + halfLine : block.top - halfLine;
    }
    // If outside the viewport, return null if precise==true, an
    // estimate otherwise.
    if (view.viewport.from >= block.to || view.viewport.to <= block.from) {
      if (precise) return null;
      if (block.type == BlockType.Text) {
        let pos = posAtCoordsImprecise(view, content, block, x, y);
        return new PosAssoc(pos, pos == block.from ? 1 : -1);
      }
    }
    if (block.type != BlockType.Text) return yOffset < (block.top + block.bottom) / 2 ? new PosAssoc(block.from, 1) : new PosAssoc(block.to, -1);
    // Here we know we're in a line, so run the logic for inline layout
    let line = view.docView.lineAt(block.from, 2);
    if (!line || line.length != block.length) line = view.docView.lineAt(block.from, -2);
    return new InlineCoordsScan(view, x, y, view.textDirectionAt(block.from)).scanTile(line, block.from);
  }
  class InlineCoordsScan {
    constructor(view, x, y, baseDir) {
      this.view = view;
      this.x = x;
      this.y = y;
      this.baseDir = baseDir;
      // Cached bidi info
      this.line = null;
      this.spans = null;
    }
    bidiSpansAt(pos) {
      if (!this.line || this.line.from > pos || this.line.to < pos) {
        this.line = this.view.state.doc.lineAt(pos);
        this.spans = this.view.bidiSpans(this.line);
      }
      return this;
    }
    baseDirAt(pos, side) {
      let {
        line,
        spans
      } = this.bidiSpansAt(pos);
      let level = spans[BidiSpan.find(spans, pos - line.from, -1, side)].level;
      return level == this.baseDir;
    }
    dirAt(pos, side) {
      let {
        line,
        spans
      } = this.bidiSpansAt(pos);
      return spans[BidiSpan.find(spans, pos - line.from, -1, side)].dir;
    }
    // Used to short-circuit bidi tests for content with a uniform direction
    bidiIn(from, to) {
      let {
        spans,
        line
      } = this.bidiSpansAt(from);
      return spans.length > 1 || spans.length && (spans[0].level != this.baseDir || spans[0].to + line.from < to);
    }
    // Scan through the rectangles for the content of a tile with inline
    // content, looking for one that overlaps the queried position
    // vertically and is closest horizontally. The caller is responsible
    // for dividing its content into N pieces, and pass an array with
    // N+1 positions (including the position after the last piece). For
    // a text tile, these will be character clusters, for a composite
    // tile, these will be child tiles.
    scan(positions, getRects, recursed = false) {
      let lo = 0,
        hi = positions.length - 1,
        seen = new Set();
      let bidi = this.bidiIn(positions[0], positions[hi]);
      let above, below;
      let closestI = -1,
        closestDx = 1e9,
        closestRect;
      // Because, when the content is bidirectional, a regular binary
      // search is hard to perform (the content order does not
      // correspond to visual order), this loop does something between a
      // regular binary search and a full scan, depending on what it can
      // get away with. The outer hi/lo bounds are only adjusted for
      // elements that are part of the base order.
      //
      // To make sure all elements inside those bounds are visited,
      // eventually, we keep a set of seen indices, and if the midpoint
      // has already been handled, we start in a random index within the
      // current bounds and scan forward until we find an index that
      // hasn't been seen yet.
      search: while (lo < hi) {
        let dist = hi - lo,
          mid = lo + hi >> 1;
        adjust: if (seen.has(mid)) {
          let scan = lo + Math.floor(Math.random() * dist);
          for (let i = 0; i < dist; i++) {
            if (!seen.has(scan)) {
              mid = scan;
              break adjust;
            }
            scan++;
            if (scan == hi) scan = lo; // Wrap around
          }
          break search; // No index found, we're done
        }
        seen.add(mid);
        let rects = getRects(mid);
        if (rects) for (let i = 0; i < rects.length; i++) {
          let rect = rects[i],
            side = 0;
          // Ignore empty rectangles when there are other rectangles
          if (rect.width == 0 && rects.length > 1) continue;
          if (rect.bottom < this.y) {
            if (!above || above.bottom < rect.bottom) above = rect;
            side = 1;
          } else if (rect.top > this.y) {
            if (!below || below.top > rect.top) below = rect;
            side = -1;
          } else {
            let off = rect.left > this.x ? this.x - rect.left : rect.right < this.x ? this.x - rect.right : 0;
            let dx = Math.abs(off);
            if (dx < closestDx) {
              closestI = mid;
              closestDx = dx;
              closestRect = rect;
            }
            if (off) side = off < 0 == (this.baseDir == Direction.LTR) ? -1 : 1;
          }
          // Narrow binary search when it is safe to do so
          if (side == -1 && (!bidi || this.baseDirAt(positions[mid], 1))) hi = mid;else if (side == 1 && (!bidi || this.baseDirAt(positions[mid + 1], -1))) lo = mid + 1;
        }
      }
      // If no element with y overlap is found, find the nearest element
      // on the y axis, move this.y into it, and retry the scan.
      if (!closestRect) {
        if (!below && !above) return {
          i: positions[0],
          after: false
        };
        let side = above && (!below || this.y - above.bottom < below.top - this.y) ? above : below;
        this.y = (side.top + side.bottom) / 2;
        return this.scan(positions, getRects, true);
      }
      // Handle the case where closest matched a higher element on the
      // same line as an element below/above the coords
      if (closestDx && !recursed) {
        let {
          top,
          bottom
        } = closestRect;
        if (above && above.bottom > (top + top + bottom) / 3) {
          this.y = above.bottom - 1;
          return this.scan(positions, getRects, true);
        }
        if (below && below.top < (top + bottom + bottom) / 3) {
          this.y = below.top + 1;
          return this.scan(positions, getRects, true);
        }
      }
      let ltr = (bidi ? this.dirAt(positions[closestI], 1) : this.baseDir) == Direction.LTR;
      return {
        i: closestI,
        // Test whether x is closes to the start or end of this element
        after: this.x > (closestRect.left + closestRect.right) / 2 == ltr
      };
    }
    scanText(tile, offset) {
      let positions = [];
      for (let i = 0; i < tile.length; i = findClusterBreak(tile.text, i)) positions.push(offset + i);
      positions.push(offset + tile.length);
      let scan = this.scan(positions, i => {
        let off = positions[i] - offset,
          end = positions[i + 1] - offset;
        return textRange(tile.dom, off, end).getClientRects();
      });
      return scan.after ? new PosAssoc(positions[scan.i + 1], -1) : new PosAssoc(positions[scan.i], 1);
    }
    scanTile(tile, offset) {
      if (!tile.length) return new PosAssoc(offset, 1);
      if (tile.children.length == 1) {
        // Short-circuit single-child tiles
        let child = tile.children[0];
        if (child.isText()) return this.scanText(child, offset);else if (child.isComposite()) return this.scanTile(child, offset);
      }
      let positions = [offset];
      for (let i = 0, pos = offset; i < tile.children.length; i++) positions.push(pos += tile.children[i].length);
      let scan = this.scan(positions, i => {
        let child = tile.children[i];
        if (child.flags & 48 /* TileFlag.PointWidget */) return null;
        return (child.dom.nodeType == 1 ? child.dom : textRange(child.dom, 0, child.length)).getClientRects();
      });
      let child = tile.children[scan.i],
        pos = positions[scan.i];
      if (child.isText()) return this.scanText(child, pos);
      if (child.isComposite()) return this.scanTile(child, pos);
      return scan.after ? new PosAssoc(positions[scan.i + 1], -1) : new PosAssoc(pos, 1);
    }
  }
  const LineBreakPlaceholder = "\uffff";
  class DOMReader {
    constructor(points, view) {
      this.points = points;
      this.view = view;
      this.text = "";
      this.lineSeparator = view.state.facet(EditorState.lineSeparator);
    }
    append(text) {
      this.text += text;
    }
    lineBreak() {
      this.text += LineBreakPlaceholder;
    }
    readRange(start, end) {
      if (!start) return this;
      let parent = start.parentNode;
      for (let cur = start;;) {
        this.findPointBefore(parent, cur);
        let oldLen = this.text.length;
        this.readNode(cur);
        let tile = Tile.get(cur),
          next = cur.nextSibling;
        if (next == end) {
          if ((tile === null || tile === void 0 ? void 0 : tile.breakAfter) && !next && parent != this.view.contentDOM) this.lineBreak();
          break;
        }
        let nextTile = Tile.get(next);
        if ((tile && nextTile ? tile.breakAfter : (tile ? tile.breakAfter : isBlockElement(cur)) || isBlockElement(next) && (cur.nodeName != "BR" || (tile === null || tile === void 0 ? void 0 : tile.isWidget())) && this.text.length > oldLen) && !isEmptyToEnd(next, end)) this.lineBreak();
        cur = next;
      }
      this.findPointBefore(parent, end);
      return this;
    }
    readTextNode(node) {
      let text = node.nodeValue;
      for (let point of this.points) if (point.node == node) point.pos = this.text.length + Math.min(point.offset, text.length);
      for (let off = 0, re = this.lineSeparator ? null : /\r\n?|\n/g;;) {
        let nextBreak = -1,
          breakSize = 1,
          m;
        if (this.lineSeparator) {
          nextBreak = text.indexOf(this.lineSeparator, off);
          breakSize = this.lineSeparator.length;
        } else if (m = re.exec(text)) {
          nextBreak = m.index;
          breakSize = m[0].length;
        }
        this.append(text.slice(off, nextBreak < 0 ? text.length : nextBreak));
        if (nextBreak < 0) break;
        this.lineBreak();
        if (breakSize > 1) for (let point of this.points) if (point.node == node && point.pos > this.text.length) point.pos -= breakSize - 1;
        off = nextBreak + breakSize;
      }
    }
    readNode(node) {
      let tile = Tile.get(node);
      let fromView = tile && tile.overrideDOMText;
      if (fromView != null) {
        this.findPointInside(node, fromView.length);
        for (let i = fromView.iter(); !i.next().done;) {
          if (i.lineBreak) this.lineBreak();else this.append(i.value);
        }
      } else if (node.nodeType == 3) {
        this.readTextNode(node);
      } else if (node.nodeName == "BR") {
        if (node.nextSibling) this.lineBreak();
      } else if (node.nodeType == 1) {
        this.readRange(node.firstChild, null);
      }
    }
    findPointBefore(node, next) {
      for (let point of this.points) if (point.node == node && node.childNodes[point.offset] == next) point.pos = this.text.length;
    }
    findPointInside(node, length) {
      for (let point of this.points) if (node.nodeType == 3 ? point.node == node : node.contains(point.node)) point.pos = this.text.length + (isAtEnd(node, point.node, point.offset) ? length : 0);
    }
  }
  function isAtEnd(parent, node, offset) {
    for (;;) {
      if (!node || offset < maxOffset(node)) return false;
      if (node == parent) return true;
      offset = domIndex(node) + 1;
      node = node.parentNode;
    }
  }
  function isEmptyToEnd(node, end) {
    let widgets;
    for (;; node = node.nextSibling) {
      if (node == end || !node) break;
      let view = Tile.get(node);
      if (!(view === null || view === void 0 ? void 0 : view.isWidget())) return false;
      if (view) (widgets || (widgets = [])).push(view);
    }
    if (widgets) for (let w of widgets) {
      let override = w.overrideDOMText;
      if (override === null || override === void 0 ? void 0 : override.length) return false;
    }
    return true;
  }
  class DOMPoint {
    constructor(node, offset) {
      this.node = node;
      this.offset = offset;
      this.pos = -1;
    }
  }
  class DOMChange {
    constructor(view, start, end, typeOver) {
      this.typeOver = typeOver;
      this.bounds = null;
      this.text = "";
      this.domChanged = start > -1;
      let {
          impreciseHead: iHead,
          impreciseAnchor: iAnchor
        } = view.docView,
        curSel = view.state.selection;
      if (view.state.readOnly && start > -1) {
        // Ignore changes when the editor is read-only
        this.newSel = null;
      } else if (start > -1 && (this.bounds = domBoundsAround(view.docView.tile, start, end, 0))) {
        let selPoints = iHead || iAnchor ? [] : selectionPoints(view);
        let reader = new DOMReader(selPoints, view);
        reader.readRange(this.bounds.startDOM, this.bounds.endDOM);
        this.text = reader.text;
        this.newSel = selectionFromPoints(selPoints, this.bounds.from);
      } else {
        let domSel = view.observer.selectionRange;
        let head = iHead && iHead.node == domSel.focusNode && iHead.offset == domSel.focusOffset || !contains(view.contentDOM, domSel.focusNode) ? curSel.main.head : view.docView.posFromDOM(domSel.focusNode, domSel.focusOffset);
        let anchor = iAnchor && iAnchor.node == domSel.anchorNode && iAnchor.offset == domSel.anchorOffset || !contains(view.contentDOM, domSel.anchorNode) ? curSel.main.anchor : view.docView.posFromDOM(domSel.anchorNode, domSel.anchorOffset);
        // iOS will refuse to select the block gaps when doing
        // select-all.
        // Chrome will put the selection *inside* them, confusing
        // posFromDOM
        let vp = view.viewport;
        if ((browser.ios || browser.chrome) && curSel.main.empty && head != anchor && (vp.from > 0 || vp.to < view.state.doc.length)) {
          let from = Math.min(head, anchor),
            to = Math.max(head, anchor);
          let offFrom = vp.from - from,
            offTo = vp.to - to;
          if ((offFrom == 0 || offFrom == 1 || from == 0) && (offTo == 0 || offTo == -1 || to == view.state.doc.length)) {
            head = 0;
            anchor = view.state.doc.length;
          }
        }
        if (view.inputState.composing > -1 && curSel.ranges.length > 1) {
          this.newSel = curSel.replaceRange(EditorSelection.range(anchor, head));
        } else if (view.lineWrapping && anchor == head && !(curSel.main.empty && curSel.main.head == head) && view.inputState.lastTouchTime > Date.now() - 100) {
          // If this is a cursor selection change in a line-wrapping
          // editor that may have been a touch, use the last touch
          // position to assign a side to the cursor.
          let before = view.coordsAtPos(head, -1),
            assoc = 0;
          if (before) assoc = view.inputState.lastTouchY <= before.bottom ? -1 : 1;
          this.newSel = EditorSelection.create([EditorSelection.cursor(head, assoc)]);
        } else {
          this.newSel = EditorSelection.single(anchor, head);
        }
      }
    }
  }
  function domBoundsAround(tile, from, to, offset) {
    if (tile.isComposite()) {
      let fromI = -1,
        fromStart = -1,
        toI = -1,
        toEnd = -1;
      for (let i = 0, pos = offset, prevEnd = offset; i < tile.children.length; i++) {
        let child = tile.children[i],
          end = pos + child.length;
        if (pos < from && end > to) return domBoundsAround(child, from, to, pos);
        if (end >= from && fromI == -1) {
          fromI = i;
          fromStart = pos;
        }
        if (pos > to && child.dom.parentNode == tile.dom) {
          toI = i;
          toEnd = prevEnd;
          break;
        }
        prevEnd = end;
        pos = end + child.breakAfter;
      }
      return {
        from: fromStart,
        to: toEnd < 0 ? offset + tile.length : toEnd,
        startDOM: (fromI ? tile.children[fromI - 1].dom.nextSibling : null) || tile.dom.firstChild,
        endDOM: toI < tile.children.length && toI >= 0 ? tile.children[toI].dom : null
      };
    } else if (tile.isText()) {
      return {
        from: offset,
        to: offset + tile.length,
        startDOM: tile.dom,
        endDOM: tile.dom.nextSibling
      };
    } else {
      return null;
    }
  }
  function applyDOMChange(view, domChange) {
    let change;
    let {
        newSel
      } = domChange,
      {
        state
      } = view,
      sel = state.selection.main;
    let lastKey = view.inputState.lastKeyTime > Date.now() - 100 ? view.inputState.lastKeyCode : -1;
    if (domChange.bounds) {
      let {
        from,
        to
      } = domChange.bounds;
      let preferredPos = sel.from,
        preferredSide = null;
      // Prefer anchoring to end when Backspace is pressed (or, on
      // Android, when something was deleted)
      if (lastKey === 8 || browser.android && domChange.text.length < to - from) {
        preferredPos = sel.to;
        preferredSide = "end";
      }
      let cmp = state.doc.sliceString(from, to, LineBreakPlaceholder),
        selEnd,
        diff;
      if (!sel.empty && sel.from >= from && sel.to <= to && (domChange.typeOver || cmp != domChange.text) && cmp.slice(0, sel.from - from) == domChange.text.slice(0, sel.from - from) && cmp.slice(sel.to - from) == domChange.text.slice(selEnd = domChange.text.length - (cmp.length - (sel.to - from)))) {
        // This looks like a selection replacement
        change = {
          from: sel.from,
          to: sel.to,
          insert: Text.of(domChange.text.slice(sel.from - from, selEnd).split(LineBreakPlaceholder))
        };
      } else if (diff = findDiff(cmp, domChange.text, preferredPos - from, preferredSide)) {
        // Chrome inserts two newlines when pressing shift-enter at the
        // end of a line. DomChange drops one of those.
        if (browser.chrome && lastKey == 13 && diff.toB == diff.from + 2 && domChange.text.slice(diff.from, diff.toB) == LineBreakPlaceholder + LineBreakPlaceholder) diff.toB--;
        change = {
          from: from + diff.from,
          to: from + diff.toA,
          insert: Text.of(domChange.text.slice(diff.from, diff.toB).split(LineBreakPlaceholder))
        };
      }
    } else if (newSel && (!view.hasFocus && state.facet(editable) || sameSelPos(newSel, sel))) {
      newSel = null;
    }
    if (!change && !newSel) return false;
    if ((browser.mac || browser.android) && change && change.from == change.to && change.from == sel.head - 1 && /^\. ?$/.test(change.insert.toString()) && view.contentDOM.getAttribute("autocorrect") == "off") {
      // Detect insert-period-on-double-space Mac and Android behavior,
      // and transform it into a regular space insert.
      if (newSel && change.insert.length == 2) newSel = EditorSelection.single(newSel.main.anchor - 1, newSel.main.head - 1);
      change = {
        from: change.from,
        to: change.to,
        insert: Text.of([change.insert.toString().replace(".", " ")])
      };
    } else if (state.doc.lineAt(sel.from).to < sel.to && view.docView.lineHasWidget(sel.to) && view.inputState.insertingTextAt > Date.now() - 50) {
      // For a cross-line insertion, Chrome and Safari will crudely take
      // the text of the line after the selection, flattening any
      // widgets, and move it into the joined line. This tries to detect
      // such a situation, and replaces the change with a selection
      // replace of the text provided by the beforeinput event.
      change = {
        from: sel.from,
        to: sel.to,
        insert: state.toText(view.inputState.insertingText)
      };
    } else if (browser.chrome && change && change.from == change.to && change.from == sel.head && change.insert.toString() == "\n " && view.lineWrapping) {
      // In Chrome, if you insert a space at the start of a wrapped
      // line, it will actually insert a newline and a space, causing a
      // bogus new line to be created in CodeMirror (#968)
      if (newSel) newSel = EditorSelection.single(newSel.main.anchor - 1, newSel.main.head - 1);
      change = {
        from: sel.from,
        to: sel.to,
        insert: Text.of([" "])
      };
    }
    if (change) {
      return applyDOMChangeInner(view, change, newSel, lastKey);
    } else if (newSel && !sameSelPos(newSel, sel)) {
      let scrollIntoView = false,
        userEvent = "select";
      if (view.inputState.lastSelectionTime > Date.now() - 50) {
        if (view.inputState.lastSelectionOrigin == "select") scrollIntoView = true;
        userEvent = view.inputState.lastSelectionOrigin;
        if (userEvent == "select.pointer") newSel = skipAtomsForSelection(state.facet(atomicRanges).map(f => f(view)), newSel);
      }
      view.dispatch({
        selection: newSel,
        scrollIntoView,
        userEvent
      });
      return true;
    } else {
      return false;
    }
  }
  function applyDOMChangeInner(view, change, newSel, lastKey = -1) {
    if (browser.ios && view.inputState.flushIOSKey(change)) return true;
    let sel = view.state.selection.main;
    // Android browsers don't fire reasonable key events for enter,
    // backspace, or delete. So this detects changes that look like
    // they're caused by those keys, and reinterprets them as key
    // events. (Some of these keys are also handled by beforeinput
    // events and the pendingAndroidKey mechanism, but that's not
    // reliable in all situations.)
    if (browser.android && (change.to == sel.to && (
    // GBoard will sometimes remove a space it just inserted
    // after a completion when you press enter
    change.from == sel.from || change.from == sel.from - 1 && view.state.sliceDoc(change.from, sel.from) == " ") && change.insert.length == 1 && change.insert.lines == 2 && dispatchKey(view.contentDOM, "Enter", 13) || (change.from == sel.from - 1 && change.to == sel.to && change.insert.length == 0 || lastKey == 8 && change.insert.length < change.to - change.from && change.to > sel.head) && dispatchKey(view.contentDOM, "Backspace", 8) || change.from == sel.from && change.to == sel.to + 1 && change.insert.length == 0 && dispatchKey(view.contentDOM, "Delete", 46))) return true;
    let text = change.insert.toString();
    if (view.inputState.composing >= 0) view.inputState.composing++;
    let defaultTr;
    let defaultInsert = () => defaultTr || (defaultTr = applyDefaultInsert(view, change, newSel));
    if (!view.state.facet(inputHandler).some(h => h(view, change.from, change.to, text, defaultInsert))) view.dispatch(defaultInsert());
    return true;
  }
  function applyDefaultInsert(view, change, newSel) {
    let tr,
      startState = view.state,
      sel = startState.selection.main,
      inAtomic = -1;
    if (change.from == change.to && change.from < sel.from || change.from > sel.to) {
      let side = change.from < sel.from ? -1 : 1,
        pos = side < 0 ? sel.from : sel.to;
      let moved = skipAtomicRanges(startState.facet(atomicRanges).map(f => f(view)), pos, side);
      if (change.from == moved) inAtomic = moved;
    }
    if (inAtomic > -1) {
      tr = {
        changes: change,
        selection: EditorSelection.cursor(change.from + change.insert.length, -1)
      };
    } else if (change.from >= sel.from && change.to <= sel.to && change.to - change.from >= (sel.to - sel.from) / 3 && (!newSel || newSel.main.empty && newSel.main.from == change.from + change.insert.length) && view.inputState.composing < 0) {
      let before = sel.from < change.from ? startState.sliceDoc(sel.from, change.from) : "";
      let after = sel.to > change.to ? startState.sliceDoc(change.to, sel.to) : "";
      tr = startState.replaceSelection(view.state.toText(before + change.insert.sliceString(0, undefined, view.state.lineBreak) + after));
    } else {
      let changes = startState.changes(change);
      let mainSel = newSel && newSel.main.to <= changes.newLength ? newSel.main : undefined;
      // Try to apply a composition change to all cursors
      if (startState.selection.ranges.length > 1 && (view.inputState.composing >= 0 || view.inputState.compositionPendingChange) && change.to <= sel.to + 10 && change.to >= sel.to - 10) {
        let replaced = view.state.sliceDoc(change.from, change.to);
        let compositionRange,
          composition = newSel && findCompositionNode(view, newSel.main.head);
        if (composition) {
          let dLen = change.insert.length - (change.to - change.from);
          compositionRange = {
            from: composition.from,
            to: composition.to - dLen
          };
        } else {
          compositionRange = view.state.doc.lineAt(sel.head);
        }
        let offset = sel.to - change.to;
        tr = startState.changeByRange(range => {
          if (range.from == sel.from && range.to == sel.to) return {
            changes,
            range: mainSel || range.map(changes)
          };
          let to = range.to - offset,
            from = to - replaced.length;
          if (view.state.sliceDoc(from, to) != replaced ||
          // Unfortunately, there's no way to make multiple
          // changes in the same node work without aborting
          // composition, so cursors in the composition range are
          // ignored.
          to >= compositionRange.from && from <= compositionRange.to) return {
            range
          };
          let rangeChanges = startState.changes({
              from,
              to,
              insert: change.insert
            }),
            selOff = range.to - sel.to;
          return {
            changes: rangeChanges,
            range: !mainSel ? range.map(rangeChanges) : EditorSelection.range(Math.max(0, mainSel.anchor + selOff), Math.max(0, mainSel.head + selOff))
          };
        });
      } else {
        tr = {
          changes,
          selection: mainSel && startState.selection.replaceRange(mainSel)
        };
      }
    }
    let userEvent = "input.type";
    if (view.composing || view.inputState.compositionPendingChange && view.inputState.compositionEndedAt > Date.now() - 50) {
      view.inputState.compositionPendingChange = false;
      userEvent += ".compose";
      if (view.inputState.compositionFirstChange) {
        userEvent += ".start";
        view.inputState.compositionFirstChange = false;
      }
    }
    return startState.update(tr, {
      userEvent,
      scrollIntoView: true
    });
  }
  function findDiff(a, b, preferredPos, preferredSide) {
    let minLen = Math.min(a.length, b.length);
    let from = 0;
    while (from < minLen && a.charCodeAt(from) == b.charCodeAt(from)) from++;
    if (from == minLen && a.length == b.length) return null;
    let toA = a.length,
      toB = b.length;
    while (toA > 0 && toB > 0 && a.charCodeAt(toA - 1) == b.charCodeAt(toB - 1)) {
      toA--;
      toB--;
    }
    if (preferredSide == "end") {
      let adjust = Math.max(0, from - Math.min(toA, toB));
      preferredPos -= toA + adjust - from;
    }
    if (toA < from && a.length < b.length) {
      let move = preferredPos <= from && preferredPos >= toA ? from - preferredPos : 0;
      from -= move;
      toB = from + (toB - toA);
      toA = from;
    } else if (toB < from) {
      let move = preferredPos <= from && preferredPos >= toB ? from - preferredPos : 0;
      from -= move;
      toA = from + (toA - toB);
      toB = from;
    }
    return {
      from,
      toA,
      toB
    };
  }
  function selectionPoints(view) {
    let result = [];
    if (view.root.activeElement != view.contentDOM) return result;
    let {
      anchorNode,
      anchorOffset,
      focusNode,
      focusOffset
    } = view.observer.selectionRange;
    if (anchorNode) {
      result.push(new DOMPoint(anchorNode, anchorOffset));
      if (focusNode != anchorNode || focusOffset != anchorOffset) result.push(new DOMPoint(focusNode, focusOffset));
    }
    return result;
  }
  function selectionFromPoints(points, base) {
    if (points.length == 0) return null;
    let anchor = points[0].pos,
      head = points.length == 2 ? points[1].pos : anchor;
    return anchor > -1 && head > -1 ? EditorSelection.single(anchor + base, head + base) : null;
  }
  function sameSelPos(selection, range) {
    return range.head == selection.main.head && range.anchor == selection.main.anchor;
  }
  class InputState {
    setSelectionOrigin(origin) {
      this.lastSelectionOrigin = origin;
      this.lastSelectionTime = Date.now();
    }
    constructor(view) {
      this.view = view;
      this.lastKeyCode = 0;
      this.lastKeyTime = 0;
      this.lastTouchTime = 0;
      this.lastTouchX = 0;
      this.lastTouchY = 0;
      this.lastFocusTime = 0;
      this.lastScrollTop = 0;
      this.lastScrollLeft = 0;
      this.lastWheelEvent = 0;
      // On iOS, some keys need to have their default behavior happen
      // (after which we retroactively handle them and reset the DOM) to
      // avoid messing up the virtual keyboard state.
      this.pendingIOSKey = undefined;
      /**
      When enabled (>-1), tab presses are not given to key handlers,
      leaving the browser's default behavior. If >0, the mode expires
      at that timestamp, and any other keypress clears it.
      Esc enables temporary tab focus mode for two seconds when not
      otherwise handled.
      */
      this.tabFocusMode = -1;
      this.lastSelectionOrigin = null;
      this.lastSelectionTime = 0;
      this.lastContextMenu = 0;
      this.scrollHandlers = [];
      this.handlers = Object.create(null);
      // -1 means not in a composition. Otherwise, this counts the number
      // of changes made during the composition. The count is used to
      // avoid treating the start state of the composition, before any
      // changes have been made, as part of the composition.
      this.composing = -1;
      // Tracks whether the next change should be marked as starting the
      // composition (null means no composition, true means next is the
      // first, false means first has already been marked for this
      // composition)
      this.compositionFirstChange = null;
      // End time of the previous composition
      this.compositionEndedAt = 0;
      // Used in a kludge to detect when an Enter keypress should be
      // considered part of the composition on Safari, which fires events
      // in the wrong order
      this.compositionPendingKey = false;
      // Used to categorize changes as part of a composition, even when
      // the mutation events fire shortly after the compositionend event
      this.compositionPendingChange = false;
      // Set by beforeinput, used in DOM change reader
      this.insertingText = "";
      this.insertingTextAt = 0;
      this.mouseSelection = null;
      // When a drag from the editor is active, this points at the range
      // being dragged.
      this.draggedContent = null;
      this.handleEvent = this.handleEvent.bind(this);
      this.notifiedFocused = view.hasFocus;
      // On Safari adding an input event handler somehow prevents an
      // issue where the composition vanishes when you press enter.
      if (browser.safari) view.contentDOM.addEventListener("input", () => null);
      if (browser.gecko) firefoxCopyCutHack(view.contentDOM.ownerDocument);
    }
    handleEvent(event) {
      if (!eventBelongsToEditor(this.view, event) || this.ignoreDuringComposition(event)) return;
      if (event.type == "keydown" && this.keydown(event)) return;
      if (this.view.updateState != 0 /* UpdateState.Idle */) Promise.resolve().then(() => this.runHandlers(event.type, event));else this.runHandlers(event.type, event);
    }
    runHandlers(type, event) {
      let handlers = this.handlers[type];
      if (handlers) {
        for (let observer of handlers.observers) observer(this.view, event);
        for (let handler of handlers.handlers) {
          if (event.defaultPrevented) break;
          if (handler(this.view, event)) {
            event.preventDefault();
            break;
          }
        }
      }
    }
    ensureHandlers(plugins) {
      let handlers = computeHandlers(plugins),
        prev = this.handlers,
        dom = this.view.contentDOM;
      for (let type in handlers) if (type != "scroll") {
        let passive = !handlers[type].handlers.length;
        let exists = prev[type];
        if (exists && passive != !exists.handlers.length) {
          dom.removeEventListener(type, this.handleEvent);
          exists = null;
        }
        if (!exists) dom.addEventListener(type, this.handleEvent, {
          passive
        });
      }
      for (let type in prev) if (type != "scroll" && !handlers[type]) dom.removeEventListener(type, this.handleEvent);
      this.handlers = handlers;
    }
    keydown(event) {
      // Must always run, even if a custom handler handled the event
      this.lastKeyCode = event.keyCode;
      this.lastKeyTime = Date.now();
      if (event.keyCode == 9 && this.tabFocusMode > -1 && (!this.tabFocusMode || Date.now() <= this.tabFocusMode)) return true;
      if (this.tabFocusMode > 0 && event.keyCode != 27 && modifierCodes.indexOf(event.keyCode) < 0) this.tabFocusMode = -1;
      // Chrome for Android usually doesn't fire proper key events, but
      // occasionally does, usually surrounded by a bunch of complicated
      // composition changes. When an enter or backspace key event is
      // seen, hold off on handling DOM events for a bit, and then
      // dispatch it.
      if (browser.android && browser.chrome && !event.synthetic && (event.keyCode == 13 || event.keyCode == 8)) {
        this.view.observer.delayAndroidKey(event.key, event.keyCode);
        return true;
      }
      // Preventing the default behavior of Enter on iOS makes the
      // virtual keyboard get stuck in the wrong (lowercase)
      // state. So we let it go through, and then, in
      // applyDOMChange, notify key handlers of it and reset to
      // the state they produce.
      let pending;
      if (browser.ios && !event.synthetic && !event.altKey && !event.metaKey && !event.shiftKey && ((pending = PendingKeys.find(key => key.keyCode == event.keyCode)) && !event.ctrlKey || EmacsyPendingKeys.indexOf(event.key) > -1 && event.ctrlKey)) {
        this.pendingIOSKey = pending || event;
        setTimeout(() => this.flushIOSKey(), 250);
        return true;
      }
      if (event.keyCode != 229) this.view.observer.forceFlush();
      return false;
    }
    flushIOSKey(change) {
      let key = this.pendingIOSKey;
      if (!key) return false;
      // This looks like an autocorrection before Enter
      if (key.key == "Enter" && change && change.from < change.to && /^\S+$/.test(change.insert.toString())) return false;
      this.pendingIOSKey = undefined;
      return dispatchKey(this.view.contentDOM, key.key, key.keyCode, key instanceof KeyboardEvent ? key : undefined);
    }
    ignoreDuringComposition(event) {
      if (!/^key/.test(event.type) || event.synthetic) return false;
      if (this.composing > 0) return true;
      // See https://www.stum.de/2016/06/24/handling-ime-events-in-javascript/.
      // On some input method editors (IMEs), the Enter key is used to
      // confirm character selection. On Safari, when Enter is pressed,
      // compositionend and keydown events are sometimes emitted in the
      // wrong order. The key event should still be ignored, even when
      // it happens after the compositionend event.
      if (browser.safari && !browser.ios && this.compositionPendingKey && Date.now() - this.compositionEndedAt < 100) {
        this.compositionPendingKey = false;
        return true;
      }
      return false;
    }
    startMouseSelection(mouseSelection) {
      if (this.mouseSelection) this.mouseSelection.destroy();
      this.mouseSelection = mouseSelection;
    }
    update(update) {
      this.view.observer.update(update);
      if (this.mouseSelection) this.mouseSelection.update(update);
      if (this.draggedContent && update.docChanged) this.draggedContent = this.draggedContent.map(update.changes);
      if (update.transactions.length) this.lastKeyCode = this.lastSelectionTime = 0;
    }
    destroy() {
      if (this.mouseSelection) this.mouseSelection.destroy();
    }
  }
  function bindHandler(plugin, handler) {
    return (view, event) => {
      try {
        return handler.call(plugin, event, view);
      } catch (e) {
        logException(view.state, e);
      }
    };
  }
  function computeHandlers(plugins) {
    let result = Object.create(null);
    function record(type) {
      return result[type] || (result[type] = {
        observers: [],
        handlers: []
      });
    }
    for (let plugin of plugins) {
      let spec = plugin.spec,
        handlers = spec && spec.plugin.domEventHandlers,
        observers = spec && spec.plugin.domEventObservers;
      if (handlers) for (let type in handlers) {
        let f = handlers[type];
        if (f) record(type).handlers.push(bindHandler(plugin.value, f));
      }
      if (observers) for (let type in observers) {
        let f = observers[type];
        if (f) record(type).observers.push(bindHandler(plugin.value, f));
      }
    }
    for (let type in handlers) record(type).handlers.push(handlers[type]);
    for (let type in observers) record(type).observers.push(observers[type]);
    return result;
  }
  const PendingKeys = [{
    key: "Backspace",
    keyCode: 8,
    inputType: "deleteContentBackward"
  }, {
    key: "Enter",
    keyCode: 13,
    inputType: "insertParagraph"
  }, {
    key: "Enter",
    keyCode: 13,
    inputType: "insertLineBreak"
  }, {
    key: "Delete",
    keyCode: 46,
    inputType: "deleteContentForward"
  }];
  const EmacsyPendingKeys = "dthko";
  // Key codes for modifier keys
  const modifierCodes = [16, 17, 18, 20, 91, 92, 224, 225];
  const dragScrollMargin = 6;
  function dragScrollSpeed(dist) {
    return Math.max(0, dist) * 0.7 + 8;
  }
  function dist(a, b) {
    return Math.max(Math.abs(a.clientX - b.clientX), Math.abs(a.clientY - b.clientY));
  }
  class MouseSelection {
    constructor(view, startEvent, style, mustSelect) {
      this.view = view;
      this.startEvent = startEvent;
      this.style = style;
      this.mustSelect = mustSelect;
      this.scrollSpeed = {
        x: 0,
        y: 0
      };
      this.scrolling = -1;
      this.lastEvent = startEvent;
      this.scrollParents = scrollableParents(view.contentDOM);
      this.atoms = view.state.facet(atomicRanges).map(f => f(view));
      let doc = view.contentDOM.ownerDocument;
      doc.addEventListener("mousemove", this.move = this.move.bind(this));
      doc.addEventListener("mouseup", this.up = this.up.bind(this));
      this.extend = startEvent.shiftKey;
      this.multiple = view.state.facet(EditorState.allowMultipleSelections) && addsSelectionRange(view, startEvent);
      this.dragging = isInPrimarySelection(view, startEvent) && getClickType(startEvent) == 1 ? null : false;
    }
    start(event) {
      // When clicking outside of the selection, immediately apply the
      // effect of starting the selection
      if (this.dragging === false) this.select(event);
    }
    move(event) {
      if (event.buttons == 0) return this.destroy();
      if (this.dragging || this.dragging == null && dist(this.startEvent, event) < 10) return;
      this.select(this.lastEvent = event);
      let sx = 0,
        sy = 0;
      let left = 0,
        top = 0,
        right = this.view.win.innerWidth,
        bottom = this.view.win.innerHeight;
      if (this.scrollParents.x) ({
        left,
        right
      } = this.scrollParents.x.getBoundingClientRect());
      if (this.scrollParents.y) ({
        top,
        bottom
      } = this.scrollParents.y.getBoundingClientRect());
      let margins = getScrollMargins(this.view);
      if (event.clientX - margins.left <= left + dragScrollMargin) sx = -dragScrollSpeed(left - event.clientX);else if (event.clientX + margins.right >= right - dragScrollMargin) sx = dragScrollSpeed(event.clientX - right);
      if (event.clientY - margins.top <= top + dragScrollMargin) sy = -dragScrollSpeed(top - event.clientY);else if (event.clientY + margins.bottom >= bottom - dragScrollMargin) sy = dragScrollSpeed(event.clientY - bottom);
      this.setScrollSpeed(sx, sy);
    }
    up(event) {
      if (this.dragging == null) this.select(this.lastEvent);
      if (!this.dragging) event.preventDefault();
      this.destroy();
    }
    destroy() {
      this.setScrollSpeed(0, 0);
      let doc = this.view.contentDOM.ownerDocument;
      doc.removeEventListener("mousemove", this.move);
      doc.removeEventListener("mouseup", this.up);
      this.view.inputState.mouseSelection = this.view.inputState.draggedContent = null;
    }
    setScrollSpeed(sx, sy) {
      this.scrollSpeed = {
        x: sx,
        y: sy
      };
      if (sx || sy) {
        if (this.scrolling < 0) this.scrolling = setInterval(() => this.scroll(), 50);
      } else if (this.scrolling > -1) {
        clearInterval(this.scrolling);
        this.scrolling = -1;
      }
    }
    scroll() {
      let {
        x,
        y
      } = this.scrollSpeed;
      if (x && this.scrollParents.x) {
        this.scrollParents.x.scrollLeft += x;
        x = 0;
      }
      if (y && this.scrollParents.y) {
        this.scrollParents.y.scrollTop += y;
        y = 0;
      }
      if (x || y) this.view.win.scrollBy(x, y);
      if (this.dragging === false) this.select(this.lastEvent);
    }
    select(event) {
      let {
          view
        } = this,
        selection = skipAtomsForSelection(this.atoms, this.style.get(event, this.extend, this.multiple));
      if (this.mustSelect || !selection.eq(view.state.selection, this.dragging === false)) this.view.dispatch({
        selection,
        userEvent: "select.pointer"
      });
      this.mustSelect = false;
    }
    update(update) {
      if (update.transactions.some(tr => tr.isUserEvent("input.type"))) this.destroy();else if (this.style.update(update)) setTimeout(() => this.select(this.lastEvent), 20);
    }
  }
  function addsSelectionRange(view, event) {
    let facet = view.state.facet(clickAddsSelectionRange);
    return facet.length ? facet[0](event) : browser.mac ? event.metaKey : event.ctrlKey;
  }
  function dragMovesSelection(view, event) {
    let facet = view.state.facet(dragMovesSelection$1);
    return facet.length ? facet[0](event) : browser.mac ? !event.altKey : !event.ctrlKey;
  }
  function isInPrimarySelection(view, event) {
    let {
      main
    } = view.state.selection;
    if (main.empty) return false;
    // On boundary clicks, check whether the coordinates are inside the
    // selection's client rectangles
    let sel = getSelection(view.root);
    if (!sel || sel.rangeCount == 0) return true;
    let rects = sel.getRangeAt(0).getClientRects();
    for (let i = 0; i < rects.length; i++) {
      let rect = rects[i];
      if (rect.left <= event.clientX && rect.right >= event.clientX && rect.top <= event.clientY && rect.bottom >= event.clientY) return true;
    }
    return false;
  }
  function eventBelongsToEditor(view, event) {
    if (!event.bubbles) return true;
    if (event.defaultPrevented) return false;
    for (let node = event.target, tile; node != view.contentDOM; node = node.parentNode) if (!node || node.nodeType == 11 || (tile = Tile.get(node)) && tile.isWidget() && !tile.isHidden && tile.widget.ignoreEvent(event)) return false;
    return true;
  }
  const handlers = /*@__PURE__*/Object.create(null);
  const observers = /*@__PURE__*/Object.create(null);
  // This is very crude, but unfortunately both these browsers _pretend_
  // that they have a clipboard API—all the objects and methods are
  // there, they just don't work, and they are hard to test.
  const brokenClipboardAPI = browser.ie && browser.ie_version < 15 || browser.ios && browser.webkit_version < 604;
  function capturePaste(view) {
    let parent = view.dom.parentNode;
    if (!parent) return;
    let target = parent.appendChild(document.createElement("textarea"));
    target.style.cssText = "position: fixed; left: -10000px; top: 10px";
    target.focus();
    setTimeout(() => {
      view.focus();
      target.remove();
      doPaste(view, target.value);
    }, 50);
  }
  function textFilter(state, facet, text) {
    for (let filter of state.facet(facet)) text = filter(text, state);
    return text;
  }
  function doPaste(view, input) {
    input = textFilter(view.state, clipboardInputFilter, input);
    let {
        state
      } = view,
      changes,
      i = 1,
      text = state.toText(input);
    let byLine = text.lines == state.selection.ranges.length;
    let linewise = lastLinewiseCopy != null && state.selection.ranges.every(r => r.empty) && lastLinewiseCopy == text.toString();
    if (linewise) {
      let lastLine = -1;
      changes = state.changeByRange(range => {
        let line = state.doc.lineAt(range.from);
        if (line.from == lastLine) return {
          range
        };
        lastLine = line.from;
        let insert = state.toText((byLine ? text.line(i++).text : input) + state.lineBreak);
        return {
          changes: {
            from: line.from,
            insert
          },
          range: EditorSelection.cursor(range.from + insert.length)
        };
      });
    } else if (byLine) {
      changes = state.changeByRange(range => {
        let line = text.line(i++);
        return {
          changes: {
            from: range.from,
            to: range.to,
            insert: line.text
          },
          range: EditorSelection.cursor(range.from + line.length)
        };
      });
    } else {
      changes = state.replaceSelection(text);
    }
    view.dispatch(changes, {
      userEvent: "input.paste",
      scrollIntoView: true
    });
  }
  observers.scroll = view => {
    view.inputState.lastScrollTop = view.scrollDOM.scrollTop;
    view.inputState.lastScrollLeft = view.scrollDOM.scrollLeft;
  };
  observers.wheel = observers.mousewheel = view => {
    view.inputState.lastWheelEvent = Date.now();
  };
  handlers.keydown = (view, event) => {
    view.inputState.setSelectionOrigin("select");
    if (event.keyCode == 27 && view.inputState.tabFocusMode != 0) view.inputState.tabFocusMode = Date.now() + 2000;
    return false;
  };
  observers.touchstart = (view, e) => {
    let iState = view.inputState,
      touch = e.targetTouches[0];
    iState.lastTouchTime = Date.now();
    if (touch) {
      iState.lastTouchX = touch.clientX;
      iState.lastTouchY = touch.clientY;
    }
    iState.setSelectionOrigin("select.pointer");
  };
  observers.touchmove = view => {
    view.inputState.setSelectionOrigin("select.pointer");
  };
  handlers.mousedown = (view, event) => {
    view.observer.flush();
    if (view.inputState.lastTouchTime > Date.now() - 2000) return false; // Ignore touch interaction
    let style = null;
    for (let makeStyle of view.state.facet(mouseSelectionStyle)) {
      style = makeStyle(view, event);
      if (style) break;
    }
    if (!style && event.button == 0) style = basicMouseSelection(view, event);
    if (style) {
      let mustFocus = !view.hasFocus;
      view.inputState.startMouseSelection(new MouseSelection(view, event, style, mustFocus));
      if (mustFocus) view.observer.ignore(() => {
        focusPreventScroll(view.contentDOM);
        let active = view.root.activeElement;
        if (active && !active.contains(view.contentDOM)) active.blur();
      });
      let mouseSel = view.inputState.mouseSelection;
      if (mouseSel) {
        mouseSel.start(event);
        return mouseSel.dragging === false;
      }
    } else {
      view.inputState.setSelectionOrigin("select.pointer");
    }
    return false;
  };
  function rangeForClick(view, pos, bias, type) {
    if (type == 1) {
      // Single click
      return EditorSelection.cursor(pos, bias);
    } else if (type == 2) {
      // Double click
      return groupAt(view.state, pos, bias);
    } else {
      // Triple click
      let visual = view.docView.lineAt(pos, bias),
        line = view.state.doc.lineAt(visual ? visual.posAtEnd : pos);
      let from = visual ? visual.posAtStart : line.from,
        to = visual ? visual.posAtEnd : line.to;
      if (to < view.state.doc.length && to == line.to) to++;
      return EditorSelection.range(from, to);
    }
  }
  const BadMouseDetail = browser.ie && browser.ie_version <= 11;
  let lastMouseDown = null,
    lastMouseDownCount = 0,
    lastMouseDownTime = 0;
  function getClickType(event) {
    if (!BadMouseDetail) return event.detail;
    let last = lastMouseDown,
      lastTime = lastMouseDownTime;
    lastMouseDown = event;
    lastMouseDownTime = Date.now();
    return lastMouseDownCount = !last || lastTime > Date.now() - 400 && Math.abs(last.clientX - event.clientX) < 2 && Math.abs(last.clientY - event.clientY) < 2 ? (lastMouseDownCount + 1) % 3 : 1;
  }
  function basicMouseSelection(view, event) {
    let start = view.posAndSideAtCoords({
        x: event.clientX,
        y: event.clientY
      }, false),
      type = getClickType(event);
    let startSel = view.state.selection;
    return {
      update(update) {
        if (update.docChanged) {
          start.pos = update.changes.mapPos(start.pos);
          startSel = startSel.map(update.changes);
        }
      },
      get(event, extend, multiple) {
        let cur = view.posAndSideAtCoords({
            x: event.clientX,
            y: event.clientY
          }, false),
          removed;
        let range = rangeForClick(view, cur.pos, cur.assoc, type);
        if (start.pos != cur.pos && !extend) {
          let startRange = rangeForClick(view, start.pos, start.assoc, type);
          let from = Math.min(startRange.from, range.from),
            to = Math.max(startRange.to, range.to);
          range = from < range.from ? EditorSelection.range(from, to, range.assoc) : EditorSelection.range(to, from, range.assoc);
        }
        if (extend) return startSel.replaceRange(startSel.main.extend(range.from, range.to, range.assoc));else if (multiple && type == 1 && startSel.ranges.length > 1 && (removed = removeRangeAround(startSel, cur.pos))) return removed;else if (multiple) return startSel.addRange(range);else return EditorSelection.create([range]);
      }
    };
  }
  function removeRangeAround(sel, pos) {
    for (let i = 0; i < sel.ranges.length; i++) {
      let {
        from,
        to
      } = sel.ranges[i];
      if (from <= pos && to >= pos) return EditorSelection.create(sel.ranges.slice(0, i).concat(sel.ranges.slice(i + 1)), sel.mainIndex == i ? 0 : sel.mainIndex - (sel.mainIndex > i ? 1 : 0));
    }
    return null;
  }
  handlers.dragstart = (view, event) => {
    let {
      selection: {
        main: range
      }
    } = view.state;
    if (event.target.draggable) {
      let tile = view.docView.tile.nearest(event.target);
      if (tile && tile.isWidget()) {
        let from = tile.posAtStart,
          to = from + tile.length;
        if (from >= range.to || to <= range.from) range = EditorSelection.range(from, to);
      }
    }
    let {
      inputState
    } = view;
    if (inputState.mouseSelection) inputState.mouseSelection.dragging = true;
    inputState.draggedContent = range;
    if (event.dataTransfer) {
      event.dataTransfer.setData("Text", textFilter(view.state, clipboardOutputFilter, view.state.sliceDoc(range.from, range.to)));
      event.dataTransfer.effectAllowed = "copyMove";
    }
    return false;
  };
  handlers.dragend = view => {
    view.inputState.draggedContent = null;
    return false;
  };
  function dropText(view, event, text, direct) {
    text = textFilter(view.state, clipboardInputFilter, text);
    if (!text) return;
    let dropPos = view.posAtCoords({
      x: event.clientX,
      y: event.clientY
    }, false);
    let {
      draggedContent
    } = view.inputState;
    let del = direct && draggedContent && dragMovesSelection(view, event) ? {
      from: draggedContent.from,
      to: draggedContent.to
    } : null;
    let ins = {
      from: dropPos,
      insert: text
    };
    let changes = view.state.changes(del ? [del, ins] : ins);
    view.focus();
    view.dispatch({
      changes,
      selection: {
        anchor: changes.mapPos(dropPos, -1),
        head: changes.mapPos(dropPos, 1)
      },
      userEvent: del ? "move.drop" : "input.drop"
    });
    view.inputState.draggedContent = null;
  }
  handlers.drop = (view, event) => {
    if (!event.dataTransfer) return false;
    if (view.state.readOnly) return true;
    let files = event.dataTransfer.files;
    if (files && files.length) {
      // For a file drop, read the file's text.
      let text = Array(files.length),
        read = 0;
      let finishFile = () => {
        if (++read == files.length) dropText(view, event, text.filter(s => s != null).join(view.state.lineBreak), false);
      };
      for (let i = 0; i < files.length; i++) {
        let reader = new FileReader();
        reader.onerror = finishFile;
        reader.onload = () => {
          if (!/[\x00-\x08\x0e-\x1f]{2}/.test(reader.result)) text[i] = reader.result;
          finishFile();
        };
        reader.readAsText(files[i]);
      }
      return true;
    } else {
      let text = event.dataTransfer.getData("Text");
      if (text) {
        dropText(view, event, text, true);
        return true;
      }
    }
    return false;
  };
  handlers.paste = (view, event) => {
    if (view.state.readOnly) return true;
    view.observer.flush();
    let data = brokenClipboardAPI ? null : event.clipboardData;
    if (data) {
      doPaste(view, data.getData("text/plain") || data.getData("text/uri-list"));
      return true;
    } else {
      capturePaste(view);
      return false;
    }
  };
  function captureCopy(view, text) {
    // The extra wrapper is somehow necessary on IE/Edge to prevent the
    // content from being mangled when it is put onto the clipboard
    let parent = view.dom.parentNode;
    if (!parent) return;
    let target = parent.appendChild(document.createElement("textarea"));
    target.style.cssText = "position: fixed; left: -10000px; top: 10px";
    target.value = text;
    target.focus();
    target.selectionEnd = text.length;
    target.selectionStart = 0;
    setTimeout(() => {
      target.remove();
      view.focus();
    }, 50);
  }
  function copiedRange(state) {
    let content = [],
      ranges = [],
      linewise = false;
    for (let range of state.selection.ranges) if (!range.empty) {
      content.push(state.sliceDoc(range.from, range.to));
      ranges.push(range);
    }
    if (!content.length) {
      // Nothing selected, do a line-wise copy
      let upto = -1;
      for (let {
        from
      } of state.selection.ranges) {
        let line = state.doc.lineAt(from);
        if (line.number > upto) {
          content.push(line.text);
          ranges.push({
            from: line.from,
            to: Math.min(state.doc.length, line.to + 1)
          });
        }
        upto = line.number;
      }
      linewise = true;
    }
    return {
      text: textFilter(state, clipboardOutputFilter, content.join(state.lineBreak)),
      ranges,
      linewise
    };
  }
  let lastLinewiseCopy = null;
  handlers.copy = handlers.cut = (view, event) => {
    // If the DOM selection is outside this editor, don't intercept.
    // This happens when a parent editor (like ProseMirror) selects content that
    // spans multiple elements including this CodeMirror. The copy event may
    // bubble through CodeMirror (e.g. when CodeMirror is the first or the last
    // element in the selection), but we should let the parent handle it.
    if (!hasSelection(view.contentDOM, view.observer.selectionRange)) return false;
    let {
      text,
      ranges,
      linewise
    } = copiedRange(view.state);
    if (!text && !linewise) return false;
    lastLinewiseCopy = linewise ? text : null;
    if (event.type == "cut" && !view.state.readOnly) view.dispatch({
      changes: ranges,
      scrollIntoView: true,
      userEvent: "delete.cut"
    });
    let data = brokenClipboardAPI ? null : event.clipboardData;
    if (data) {
      data.clearData();
      data.setData("text/plain", text);
      return true;
    } else {
      captureCopy(view, text);
      return false;
    }
  };
  const isFocusChange = /*@__PURE__*/Annotation.define();
  function focusChangeTransaction(state, focus) {
    let effects = [];
    for (let getEffect of state.facet(focusChangeEffect)) {
      let effect = getEffect(state, focus);
      if (effect) effects.push(effect);
    }
    return effects.length ? state.update({
      effects,
      annotations: isFocusChange.of(true)
    }) : null;
  }
  function updateForFocusChange(view) {
    setTimeout(() => {
      let focus = view.hasFocus;
      if (focus != view.inputState.notifiedFocused) {
        let tr = focusChangeTransaction(view.state, focus);
        if (tr) view.dispatch(tr);else view.update([]);
      }
    }, 10);
  }
  observers.focus = view => {
    view.inputState.lastFocusTime = Date.now();
    // When focusing reset the scroll position, move it back to where it was
    if (!view.scrollDOM.scrollTop && (view.inputState.lastScrollTop || view.inputState.lastScrollLeft)) {
      view.scrollDOM.scrollTop = view.inputState.lastScrollTop;
      view.scrollDOM.scrollLeft = view.inputState.lastScrollLeft;
    }
    updateForFocusChange(view);
  };
  observers.blur = view => {
    view.observer.clearSelectionRange();
    updateForFocusChange(view);
  };
  observers.compositionstart = observers.compositionupdate = view => {
    if (view.observer.editContext) return; // Composition handled by edit context
    if (view.inputState.compositionFirstChange == null) view.inputState.compositionFirstChange = true;
    if (view.inputState.composing < 0) {
      // FIXME possibly set a timeout to clear it again on Android
      view.inputState.composing = 0;
    }
  };
  observers.compositionend = view => {
    if (view.observer.editContext) return; // Composition handled by edit context
    view.inputState.composing = -1;
    view.inputState.compositionEndedAt = Date.now();
    view.inputState.compositionPendingKey = true;
    view.inputState.compositionPendingChange = view.observer.pendingRecords().length > 0;
    view.inputState.compositionFirstChange = null;
    if (browser.chrome && browser.android) {
      // Delay flushing for a bit on Android because it'll often fire a
      // bunch of contradictory changes in a row at end of composition
      view.observer.flushSoon();
    } else if (view.inputState.compositionPendingChange) {
      // If we found pending records, schedule a flush.
      Promise.resolve().then(() => view.observer.flush());
    } else {
      // Otherwise, make sure that, if no changes come in soon, the
      // composition view is cleared.
      setTimeout(() => {
        if (view.inputState.composing < 0 && view.docView.hasComposition) view.update([]);
      }, 50);
    }
  };
  observers.contextmenu = view => {
    view.inputState.lastContextMenu = Date.now();
  };
  handlers.beforeinput = (view, event) => {
    var _a, _b;
    if (event.inputType == "insertText" || event.inputType == "insertCompositionText") {
      view.inputState.insertingText = event.data;
      view.inputState.insertingTextAt = Date.now();
    }
    // In EditContext mode, we must handle insertReplacementText events
    // directly, to make spell checking corrections work
    if (event.inputType == "insertReplacementText" && view.observer.editContext) {
      let text = (_a = event.dataTransfer) === null || _a === void 0 ? void 0 : _a.getData("text/plain"),
        ranges = event.getTargetRanges();
      if (text && ranges.length) {
        let r = ranges[0];
        let from = view.posAtDOM(r.startContainer, r.startOffset),
          to = view.posAtDOM(r.endContainer, r.endOffset);
        applyDOMChangeInner(view, {
          from,
          to,
          insert: view.state.toText(text)
        }, null);
        return true;
      }
    }
    // Because Chrome Android doesn't fire useful key events, use
    // beforeinput to detect backspace (and possibly enter and delete,
    // but those usually don't even seem to fire beforeinput events at
    // the moment) and fake a key event for it.
    //
    // (preventDefault on beforeinput, though supported in the spec,
    // seems to do nothing at all on Chrome).
    let pending;
    if (browser.chrome && browser.android && (pending = PendingKeys.find(key => key.inputType == event.inputType))) {
      view.observer.delayAndroidKey(pending.key, pending.keyCode);
      if (pending.key == "Backspace" || pending.key == "Delete") {
        let startViewHeight = ((_b = window.visualViewport) === null || _b === void 0 ? void 0 : _b.height) || 0;
        setTimeout(() => {
          var _a;
          // Backspacing near uneditable nodes on Chrome Android sometimes
          // closes the virtual keyboard. This tries to crudely detect
          // that and refocus to get it back.
          if ((((_a = window.visualViewport) === null || _a === void 0 ? void 0 : _a.height) || 0) > startViewHeight + 10 && view.hasFocus) {
            view.contentDOM.blur();
            view.focus();
          }
        }, 100);
      }
    }
    if (browser.ios && event.inputType == "deleteContentForward") {
      // For some reason, DOM changes (and beforeinput) happen _before_
      // the key event for ctrl-d on iOS when using an external
      // keyboard.
      view.observer.flushSoon();
    }
    // Safari will occasionally forget to fire compositionend at the end of a dead-key composition
    if (browser.safari && event.inputType == "insertText" && view.inputState.composing >= 0) {
      setTimeout(() => observers.compositionend(view, event), 20);
    }
    return false;
  };
  const appliedFirefoxHack = /*@__PURE__*/new Set();
  // In Firefox, when cut/copy handlers are added to the document, that
  // somehow avoids a bug where those events aren't fired when the
  // selection is empty. See issue #1082 and
  // https://bugzilla.mozilla.org/show_bug.cgi?id=995961
  function firefoxCopyCutHack(doc) {
    if (!appliedFirefoxHack.has(doc)) {
      appliedFirefoxHack.add(doc);
      doc.addEventListener("copy", () => {});
      doc.addEventListener("cut", () => {});
    }
  }
  const wrappingWhiteSpace = ["pre-wrap", "normal", "pre-line", "break-spaces"];
  // Used to track, during updateHeight, if any actual heights changed
  let heightChangeFlag = false;
  function clearHeightChangeFlag() {
    heightChangeFlag = false;
  }
  class HeightOracle {
    constructor(lineWrapping) {
      this.lineWrapping = lineWrapping;
      this.doc = Text.empty;
      this.heightSamples = {};
      this.lineHeight = 14; // The height of an entire line (line-height)
      this.charWidth = 7;
      this.textHeight = 14; // The height of the actual font (font-size)
      this.lineLength = 30;
    }
    heightForGap(from, to) {
      let lines = this.doc.lineAt(to).number - this.doc.lineAt(from).number + 1;
      if (this.lineWrapping) lines += Math.max(0, Math.ceil((to - from - lines * this.lineLength * 0.5) / this.lineLength));
      return this.lineHeight * lines;
    }
    heightForLine(length) {
      if (!this.lineWrapping) return this.lineHeight;
      let lines = 1 + Math.max(0, Math.ceil((length - this.lineLength) / Math.max(1, this.lineLength - 5)));
      return lines * this.lineHeight;
    }
    setDoc(doc) {
      this.doc = doc;
      return this;
    }
    mustRefreshForWrapping(whiteSpace) {
      return wrappingWhiteSpace.indexOf(whiteSpace) > -1 != this.lineWrapping;
    }
    mustRefreshForHeights(lineHeights) {
      let newHeight = false;
      for (let i = 0; i < lineHeights.length; i++) {
        let h = lineHeights[i];
        if (h < 0) {
          i++;
        } else if (!this.heightSamples[Math.floor(h * 10)]) {
          // Round to .1 pixels
          newHeight = true;
          this.heightSamples[Math.floor(h * 10)] = true;
        }
      }
      return newHeight;
    }
    refresh(whiteSpace, lineHeight, charWidth, textHeight, lineLength, knownHeights) {
      let lineWrapping = wrappingWhiteSpace.indexOf(whiteSpace) > -1;
      let changed = Math.abs(lineHeight - this.lineHeight) > 0.3 || this.lineWrapping != lineWrapping;
      this.lineWrapping = lineWrapping;
      this.lineHeight = lineHeight;
      this.charWidth = charWidth;
      this.textHeight = textHeight;
      this.lineLength = lineLength;
      if (changed) {
        this.heightSamples = {};
        for (let i = 0; i < knownHeights.length; i++) {
          let h = knownHeights[i];
          if (h < 0) i++;else this.heightSamples[Math.floor(h * 10)] = true;
        }
      }
      return changed;
    }
  }
  // This object is used by `updateHeight` to make DOM measurements
  // arrive at the right nodes. The `heights` array is a sequence of
  // block heights, starting from position `from`.
  class MeasuredHeights {
    constructor(from, heights) {
      this.from = from;
      this.heights = heights;
      this.index = 0;
    }
    get more() {
      return this.index < this.heights.length;
    }
  }
  /**
  Record used to represent information about a block-level element
  in the editor view.
  */
  class BlockInfo {
    /**
    @internal
    */
    constructor(
    /**
    The start of the element in the document.
    */
    from,
    /**
    The length of the element.
    */
    length,
    /**
    The top position of the element (relative to the top of the
    document).
    */
    top,
    /**
    Its height.
    */
    height,
    /**
    @internal Weird packed field that holds an array of children
    for composite blocks, a decoration for block widgets, and a
    number indicating the amount of widget-created line breaks for
    text blocks.
    */
    _content) {
      this.from = from;
      this.length = length;
      this.top = top;
      this.height = height;
      this._content = _content;
    }
    /**
    The type of element this is. When querying lines, this may be
    an array of all the blocks that make up the line.
    */
    get type() {
      return typeof this._content == "number" ? BlockType.Text : Array.isArray(this._content) ? this._content : this._content.type;
    }
    /**
    The end of the element as a document position.
    */
    get to() {
      return this.from + this.length;
    }
    /**
    The bottom position of the element.
    */
    get bottom() {
      return this.top + this.height;
    }
    /**
    If this is a widget block, this will return the widget
    associated with it.
    */
    get widget() {
      return this._content instanceof PointDecoration ? this._content.widget : null;
    }
    /**
    If this is a textblock, this holds the number of line breaks
    that appear in widgets inside the block.
    */
    get widgetLineBreaks() {
      return typeof this._content == "number" ? this._content : 0;
    }
    /**
    @internal
    */
    join(other) {
      let content = (Array.isArray(this._content) ? this._content : [this]).concat(Array.isArray(other._content) ? other._content : [other]);
      return new BlockInfo(this.from, this.length + other.length, this.top, this.height + other.height, content);
    }
  }
  var QueryType = /*@__PURE__*/function (QueryType) {
    QueryType[QueryType["ByPos"] = 0] = "ByPos";
    QueryType[QueryType["ByHeight"] = 1] = "ByHeight";
    QueryType[QueryType["ByPosNoHeight"] = 2] = "ByPosNoHeight";
    return QueryType;
  }(QueryType || (QueryType = {}));
  const Epsilon = 1e-3;
  class HeightMap {
    constructor(length,
    // The number of characters covered
    height,
    // Height of this part of the document
    flags = 2 /* Flag.Outdated */) {
      this.length = length;
      this.height = height;
      this.flags = flags;
    }
    get outdated() {
      return (this.flags & 2 /* Flag.Outdated */) > 0;
    }
    set outdated(value) {
      this.flags = (value ? 2 /* Flag.Outdated */ : 0) | this.flags & -3 /* Flag.Outdated */;
    }
    setHeight(height) {
      if (this.height != height) {
        if (Math.abs(this.height - height) > Epsilon) heightChangeFlag = true;
        this.height = height;
      }
    }
    // Base case is to replace a leaf node, which simply builds a tree
    // from the new nodes and returns that (HeightMapBranch and
    // HeightMapGap override this to actually use from/to)
    replace(_from, _to, nodes) {
      return HeightMap.of(nodes);
    }
    // Again, these are base cases, and are overridden for branch and gap nodes.
    decomposeLeft(_to, result) {
      result.push(this);
    }
    decomposeRight(_from, result) {
      result.push(this);
    }
    applyChanges(decorations, oldDoc, oracle, changes) {
      let me = this,
        doc = oracle.doc;
      for (let i = changes.length - 1; i >= 0; i--) {
        let {
          fromA,
          toA,
          fromB,
          toB
        } = changes[i];
        let start = me.lineAt(fromA, QueryType.ByPosNoHeight, oracle.setDoc(oldDoc), 0, 0);
        let end = start.to >= toA ? start : me.lineAt(toA, QueryType.ByPosNoHeight, oracle, 0, 0);
        toB += end.to - toA;
        toA = end.to;
        while (i > 0 && start.from <= changes[i - 1].toA) {
          fromA = changes[i - 1].fromA;
          fromB = changes[i - 1].fromB;
          i--;
          if (fromA < start.from) start = me.lineAt(fromA, QueryType.ByPosNoHeight, oracle, 0, 0);
        }
        fromB += start.from - fromA;
        fromA = start.from;
        let nodes = NodeBuilder.build(oracle.setDoc(doc), decorations, fromB, toB);
        me = replace(me, me.replace(fromA, toA, nodes));
      }
      return me.updateHeight(oracle, 0);
    }
    static empty() {
      return new HeightMapText(0, 0, 0);
    }
    // nodes uses null values to indicate the position of line breaks.
    // There are never line breaks at the start or end of the array, or
    // two line breaks next to each other, and the array isn't allowed
    // to be empty (same restrictions as return value from the builder).
    static of(nodes) {
      if (nodes.length == 1) return nodes[0];
      let i = 0,
        j = nodes.length,
        before = 0,
        after = 0;
      for (;;) {
        if (i == j) {
          if (before > after * 2) {
            let split = nodes[i - 1];
            if (split.break) nodes.splice(--i, 1, split.left, null, split.right);else nodes.splice(--i, 1, split.left, split.right);
            j += 1 + split.break;
            before -= split.size;
          } else if (after > before * 2) {
            let split = nodes[j];
            if (split.break) nodes.splice(j, 1, split.left, null, split.right);else nodes.splice(j, 1, split.left, split.right);
            j += 2 + split.break;
            after -= split.size;
          } else {
            break;
          }
        } else if (before < after) {
          let next = nodes[i++];
          if (next) before += next.size;
        } else {
          let next = nodes[--j];
          if (next) after += next.size;
        }
      }
      let brk = 0;
      if (nodes[i - 1] == null) {
        brk = 1;
        i--;
      } else if (nodes[i] == null) {
        brk = 1;
        j++;
      }
      return new HeightMapBranch(HeightMap.of(nodes.slice(0, i)), brk, HeightMap.of(nodes.slice(j)));
    }
  }
  function replace(old, val) {
    if (old == val) return old;
    if (old.constructor != val.constructor) heightChangeFlag = true;
    return val;
  }
  HeightMap.prototype.size = 1;
  const SpaceDeco = /*@__PURE__*/Decoration.replace({});
  class HeightMapBlock extends HeightMap {
    constructor(length, height, deco) {
      super(length, height);
      this.deco = deco;
      this.spaceAbove = 0;
    }
    mainBlock(top, offset) {
      return new BlockInfo(offset, this.length, top + this.spaceAbove, this.height - this.spaceAbove, this.deco || 0);
    }
    blockAt(height, _oracle, top, offset) {
      return this.spaceAbove && height < top + this.spaceAbove ? new BlockInfo(offset, 0, top, this.spaceAbove, SpaceDeco) : this.mainBlock(top, offset);
    }
    lineAt(_value, _type, oracle, top, offset) {
      let main = this.mainBlock(top, offset);
      return this.spaceAbove ? this.blockAt(0, oracle, top, offset).join(main) : main;
    }
    forEachLine(from, to, oracle, top, offset, f) {
      if (from <= offset + this.length && to >= offset) f(this.lineAt(0, QueryType.ByPos, oracle, top, offset));
    }
    setMeasuredHeight(measured) {
      let next = measured.heights[measured.index++];
      if (next < 0) {
        this.spaceAbove = -next;
        next = measured.heights[measured.index++];
      } else {
        this.spaceAbove = 0;
      }
      this.setHeight(next);
    }
    updateHeight(oracle, offset = 0, _force = false, measured) {
      if (measured && measured.from <= offset && measured.more) this.setMeasuredHeight(measured);
      this.outdated = false;
      return this;
    }
    toString() {
      return `block(${this.length})`;
    }
  }
  class HeightMapText extends HeightMapBlock {
    constructor(length, height, above) {
      super(length, height, null);
      this.collapsed = 0; // Amount of collapsed content in the line
      this.widgetHeight = 0; // Maximum inline widget height
      this.breaks = 0; // Number of widget-introduced line breaks on the line
      this.spaceAbove = above;
    }
    mainBlock(top, offset) {
      return new BlockInfo(offset, this.length, top + this.spaceAbove, this.height - this.spaceAbove, this.breaks);
    }
    replace(_from, _to, nodes) {
      let node = nodes[0];
      if (nodes.length == 1 && (node instanceof HeightMapText || node instanceof HeightMapGap && node.flags & 4 /* Flag.SingleLine */) && Math.abs(this.length - node.length) < 10) {
        if (node instanceof HeightMapGap) node = new HeightMapText(node.length, this.height, this.spaceAbove);else node.height = this.height;
        if (!this.outdated) node.outdated = false;
        return node;
      } else {
        return HeightMap.of(nodes);
      }
    }
    updateHeight(oracle, offset = 0, force = false, measured) {
      if (measured && measured.from <= offset && measured.more) {
        this.setMeasuredHeight(measured);
      } else if (force || this.outdated) {
        this.spaceAbove = 0;
        this.setHeight(Math.max(this.widgetHeight, oracle.heightForLine(this.length - this.collapsed)) + this.breaks * oracle.lineHeight);
      }
      this.outdated = false;
      return this;
    }
    toString() {
      return `line(${this.length}${this.collapsed ? -this.collapsed : ""}${this.widgetHeight ? ":" + this.widgetHeight : ""})`;
    }
  }
  class HeightMapGap extends HeightMap {
    constructor(length) {
      super(length, 0);
    }
    heightMetrics(oracle, offset) {
      let firstLine = oracle.doc.lineAt(offset).number,
        lastLine = oracle.doc.lineAt(offset + this.length).number;
      let lines = lastLine - firstLine + 1;
      let perLine,
        perChar = 0;
      if (oracle.lineWrapping) {
        let totalPerLine = Math.min(this.height, oracle.lineHeight * lines);
        perLine = totalPerLine / lines;
        if (this.length > lines + 1) perChar = (this.height - totalPerLine) / (this.length - lines - 1);
      } else {
        perLine = this.height / lines;
      }
      return {
        firstLine,
        lastLine,
        perLine,
        perChar
      };
    }
    blockAt(height, oracle, top, offset) {
      let {
        firstLine,
        lastLine,
        perLine,
        perChar
      } = this.heightMetrics(oracle, offset);
      if (oracle.lineWrapping) {
        let guess = offset + (height < oracle.lineHeight ? 0 : Math.round(Math.max(0, Math.min(1, (height - top) / this.height)) * this.length));
        let line = oracle.doc.lineAt(guess),
          lineHeight = perLine + line.length * perChar;
        let lineTop = Math.max(top, height - lineHeight / 2);
        return new BlockInfo(line.from, line.length, lineTop, lineHeight, 0);
      } else {
        let line = Math.max(0, Math.min(lastLine - firstLine, Math.floor((height - top) / perLine)));
        let {
          from,
          length
        } = oracle.doc.line(firstLine + line);
        return new BlockInfo(from, length, top + perLine * line, perLine, 0);
      }
    }
    lineAt(value, type, oracle, top, offset) {
      if (type == QueryType.ByHeight) return this.blockAt(value, oracle, top, offset);
      if (type == QueryType.ByPosNoHeight) {
        let {
          from,
          to
        } = oracle.doc.lineAt(value);
        return new BlockInfo(from, to - from, 0, 0, 0);
      }
      let {
        firstLine,
        perLine,
        perChar
      } = this.heightMetrics(oracle, offset);
      let line = oracle.doc.lineAt(value),
        lineHeight = perLine + line.length * perChar;
      let linesAbove = line.number - firstLine;
      let lineTop = top + perLine * linesAbove + perChar * (line.from - offset - linesAbove);
      return new BlockInfo(line.from, line.length, Math.max(top, Math.min(lineTop, top + this.height - lineHeight)), lineHeight, 0);
    }
    forEachLine(from, to, oracle, top, offset, f) {
      from = Math.max(from, offset);
      to = Math.min(to, offset + this.length);
      let {
        firstLine,
        perLine,
        perChar
      } = this.heightMetrics(oracle, offset);
      for (let pos = from, lineTop = top; pos <= to;) {
        let line = oracle.doc.lineAt(pos);
        if (pos == from) {
          let linesAbove = line.number - firstLine;
          lineTop += perLine * linesAbove + perChar * (from - offset - linesAbove);
        }
        let lineHeight = perLine + perChar * line.length;
        f(new BlockInfo(line.from, line.length, lineTop, lineHeight, 0));
        lineTop += lineHeight;
        pos = line.to + 1;
      }
    }
    replace(from, to, nodes) {
      let after = this.length - to;
      if (after > 0) {
        let last = nodes[nodes.length - 1];
        if (last instanceof HeightMapGap) nodes[nodes.length - 1] = new HeightMapGap(last.length + after);else nodes.push(null, new HeightMapGap(after - 1));
      }
      if (from > 0) {
        let first = nodes[0];
        if (first instanceof HeightMapGap) nodes[0] = new HeightMapGap(from + first.length);else nodes.unshift(new HeightMapGap(from - 1), null);
      }
      return HeightMap.of(nodes);
    }
    decomposeLeft(to, result) {
      result.push(new HeightMapGap(to - 1), null);
    }
    decomposeRight(from, result) {
      result.push(null, new HeightMapGap(this.length - from - 1));
    }
    updateHeight(oracle, offset = 0, force = false, measured) {
      let end = offset + this.length;
      if (measured && measured.from <= offset + this.length && measured.more) {
        // Fill in part of this gap with measured lines. We know there
        // can't be widgets or collapsed ranges in those lines, because
        // they would already have been added to the heightmap (gaps
        // only contain plain text).
        let nodes = [],
          pos = Math.max(offset, measured.from),
          singleHeight = -1;
        if (measured.from > offset) nodes.push(new HeightMapGap(measured.from - offset - 1).updateHeight(oracle, offset));
        while (pos <= end && measured.more) {
          let len = oracle.doc.lineAt(pos).length;
          if (nodes.length) nodes.push(null);
          let height = measured.heights[measured.index++],
            above = 0;
          if (height < 0) {
            above = -height;
            height = measured.heights[measured.index++];
          }
          if (singleHeight == -1) singleHeight = height;else if (Math.abs(height - singleHeight) >= Epsilon) singleHeight = -2;
          let line = new HeightMapText(len, height, above);
          line.outdated = false;
          nodes.push(line);
          pos += len + 1;
        }
        if (pos <= end) nodes.push(null, new HeightMapGap(end - pos).updateHeight(oracle, pos));
        let result = HeightMap.of(nodes);
        if (singleHeight < 0 || Math.abs(result.height - this.height) >= Epsilon || Math.abs(singleHeight - this.heightMetrics(oracle, offset).perLine) >= Epsilon) heightChangeFlag = true;
        return replace(this, result);
      } else if (force || this.outdated) {
        this.setHeight(oracle.heightForGap(offset, offset + this.length));
        this.outdated = false;
      }
      return this;
    }
    toString() {
      return `gap(${this.length})`;
    }
  }
  class HeightMapBranch extends HeightMap {
    constructor(left, brk, right) {
      super(left.length + brk + right.length, left.height + right.height, brk | (left.outdated || right.outdated ? 2 /* Flag.Outdated */ : 0));
      this.left = left;
      this.right = right;
      this.size = left.size + right.size;
    }
    get break() {
      return this.flags & 1 /* Flag.Break */;
    }
    blockAt(height, oracle, top, offset) {
      let mid = top + this.left.height;
      return height < mid ? this.left.blockAt(height, oracle, top, offset) : this.right.blockAt(height, oracle, mid, offset + this.left.length + this.break);
    }
    lineAt(value, type, oracle, top, offset) {
      let rightTop = top + this.left.height,
        rightOffset = offset + this.left.length + this.break;
      let left = type == QueryType.ByHeight ? value < rightTop : value < rightOffset;
      let base = left ? this.left.lineAt(value, type, oracle, top, offset) : this.right.lineAt(value, type, oracle, rightTop, rightOffset);
      if (this.break || (left ? base.to < rightOffset : base.from > rightOffset)) return base;
      let subQuery = type == QueryType.ByPosNoHeight ? QueryType.ByPosNoHeight : QueryType.ByPos;
      if (left) return base.join(this.right.lineAt(rightOffset, subQuery, oracle, rightTop, rightOffset));else return this.left.lineAt(rightOffset, subQuery, oracle, top, offset).join(base);
    }
    forEachLine(from, to, oracle, top, offset, f) {
      let rightTop = top + this.left.height,
        rightOffset = offset + this.left.length + this.break;
      if (this.break) {
        if (from < rightOffset) this.left.forEachLine(from, to, oracle, top, offset, f);
        if (to >= rightOffset) this.right.forEachLine(from, to, oracle, rightTop, rightOffset, f);
      } else {
        let mid = this.lineAt(rightOffset, QueryType.ByPos, oracle, top, offset);
        if (from < mid.from) this.left.forEachLine(from, mid.from - 1, oracle, top, offset, f);
        if (mid.to >= from && mid.from <= to) f(mid);
        if (to > mid.to) this.right.forEachLine(mid.to + 1, to, oracle, rightTop, rightOffset, f);
      }
    }
    replace(from, to, nodes) {
      let rightStart = this.left.length + this.break;
      if (to < rightStart) return this.balanced(this.left.replace(from, to, nodes), this.right);
      if (from > this.left.length) return this.balanced(this.left, this.right.replace(from - rightStart, to - rightStart, nodes));
      let result = [];
      if (from > 0) this.decomposeLeft(from, result);
      let left = result.length;
      for (let node of nodes) result.push(node);
      if (from > 0) mergeGaps(result, left - 1);
      if (to < this.length) {
        let right = result.length;
        this.decomposeRight(to, result);
        mergeGaps(result, right);
      }
      return HeightMap.of(result);
    }
    decomposeLeft(to, result) {
      let left = this.left.length;
      if (to <= left) return this.left.decomposeLeft(to, result);
      result.push(this.left);
      if (this.break) {
        left++;
        if (to >= left) result.push(null);
      }
      if (to > left) this.right.decomposeLeft(to - left, result);
    }
    decomposeRight(from, result) {
      let left = this.left.length,
        right = left + this.break;
      if (from >= right) return this.right.decomposeRight(from - right, result);
      if (from < left) this.left.decomposeRight(from, result);
      if (this.break && from < right) result.push(null);
      result.push(this.right);
    }
    balanced(left, right) {
      if (left.size > 2 * right.size || right.size > 2 * left.size) return HeightMap.of(this.break ? [left, null, right] : [left, right]);
      this.left = replace(this.left, left);
      this.right = replace(this.right, right);
      this.setHeight(left.height + right.height);
      this.outdated = left.outdated || right.outdated;
      this.size = left.size + right.size;
      this.length = left.length + this.break + right.length;
      return this;
    }
    updateHeight(oracle, offset = 0, force = false, measured) {
      let {
          left,
          right
        } = this,
        rightStart = offset + left.length + this.break,
        rebalance = null;
      if (measured && measured.from <= offset + left.length && measured.more) rebalance = left = left.updateHeight(oracle, offset, force, measured);else left.updateHeight(oracle, offset, force);
      if (measured && measured.from <= rightStart + right.length && measured.more) rebalance = right = right.updateHeight(oracle, rightStart, force, measured);else right.updateHeight(oracle, rightStart, force);
      if (rebalance) return this.balanced(left, right);
      this.height = this.left.height + this.right.height;
      this.outdated = false;
      return this;
    }
    toString() {
      return this.left + (this.break ? " " : "-") + this.right;
    }
  }
  function mergeGaps(nodes, around) {
    let before, after;
    if (nodes[around] == null && (before = nodes[around - 1]) instanceof HeightMapGap && (after = nodes[around + 1]) instanceof HeightMapGap) nodes.splice(around - 1, 3, new HeightMapGap(before.length + 1 + after.length));
  }
  const relevantWidgetHeight = 5;
  class NodeBuilder {
    constructor(pos, oracle) {
      this.pos = pos;
      this.oracle = oracle;
      this.nodes = [];
      this.lineStart = -1;
      this.lineEnd = -1;
      this.covering = null;
      this.writtenTo = pos;
    }
    get isCovered() {
      return this.covering && this.nodes[this.nodes.length - 1] == this.covering;
    }
    span(_from, to) {
      if (this.lineStart > -1) {
        let end = Math.min(to, this.lineEnd),
          last = this.nodes[this.nodes.length - 1];
        if (last instanceof HeightMapText) last.length += end - this.pos;else if (end > this.pos || !this.isCovered) this.nodes.push(new HeightMapText(end - this.pos, -1, 0));
        this.writtenTo = end;
        if (to > end) {
          this.nodes.push(null);
          this.writtenTo++;
          this.lineStart = -1;
        }
      }
      this.pos = to;
    }
    point(from, to, deco) {
      if (from < to || deco.heightRelevant) {
        let height = deco.widget ? deco.widget.estimatedHeight : 0;
        let breaks = deco.widget ? deco.widget.lineBreaks : 0;
        if (height < 0) height = this.oracle.lineHeight;
        let len = to - from;
        if (deco.block) {
          this.addBlock(new HeightMapBlock(len, height, deco));
        } else if (len || breaks || height >= relevantWidgetHeight) {
          this.addLineDeco(height, breaks, len);
        }
      } else if (to > from) {
        this.span(from, to);
      }
      if (this.lineEnd > -1 && this.lineEnd < this.pos) this.lineEnd = this.oracle.doc.lineAt(this.pos).to;
    }
    enterLine() {
      if (this.lineStart > -1) return;
      let {
        from,
        to
      } = this.oracle.doc.lineAt(this.pos);
      this.lineStart = from;
      this.lineEnd = to;
      if (this.writtenTo < from) {
        if (this.writtenTo < from - 1 || this.nodes[this.nodes.length - 1] == null) this.nodes.push(this.blankContent(this.writtenTo, from - 1));
        this.nodes.push(null);
      }
      if (this.pos > from) this.nodes.push(new HeightMapText(this.pos - from, -1, 0));
      this.writtenTo = this.pos;
    }
    blankContent(from, to) {
      let gap = new HeightMapGap(to - from);
      if (this.oracle.doc.lineAt(from).to == to) gap.flags |= 4 /* Flag.SingleLine */;
      return gap;
    }
    ensureLine() {
      this.enterLine();
      let last = this.nodes.length ? this.nodes[this.nodes.length - 1] : null;
      if (last instanceof HeightMapText) return last;
      let line = new HeightMapText(0, -1, 0);
      this.nodes.push(line);
      return line;
    }
    addBlock(block) {
      this.enterLine();
      let deco = block.deco;
      if (deco && deco.startSide > 0 && !this.isCovered) this.ensureLine();
      this.nodes.push(block);
      this.writtenTo = this.pos = this.pos + block.length;
      if (deco && deco.endSide > 0) this.covering = block;
    }
    addLineDeco(height, breaks, length) {
      let line = this.ensureLine();
      line.length += length;
      line.collapsed += length;
      line.widgetHeight = Math.max(line.widgetHeight, height);
      line.breaks += breaks;
      this.writtenTo = this.pos = this.pos + length;
    }
    finish(from) {
      let last = this.nodes.length == 0 ? null : this.nodes[this.nodes.length - 1];
      if (this.lineStart > -1 && !(last instanceof HeightMapText) && !this.isCovered) this.nodes.push(new HeightMapText(0, -1, 0));else if (this.writtenTo < this.pos || last == null) this.nodes.push(this.blankContent(this.writtenTo, this.pos));
      let pos = from;
      for (let node of this.nodes) {
        if (node instanceof HeightMapText) node.updateHeight(this.oracle, pos);
        pos += node ? node.length : 1;
      }
      return this.nodes;
    }
    // Always called with a region that on both sides either stretches
    // to a line break or the end of the document.
    // The returned array uses null to indicate line breaks, but never
    // starts or ends in a line break, or has multiple line breaks next
    // to each other.
    static build(oracle, decorations, from, to) {
      let builder = new NodeBuilder(from, oracle);
      RangeSet.spans(decorations, from, to, builder, 0);
      return builder.finish(from);
    }
  }
  function heightRelevantDecoChanges(a, b, diff) {
    let comp = new DecorationComparator();
    RangeSet.compare(a, b, diff, comp, 0);
    return comp.changes;
  }
  class DecorationComparator {
    constructor() {
      this.changes = [];
    }
    compareRange() {}
    comparePoint(from, to, a, b) {
      if (from < to || a && a.heightRelevant || b && b.heightRelevant) addRange(from, to, this.changes, 5);
    }
  }
  function visiblePixelRange(dom, paddingTop) {
    let rect = dom.getBoundingClientRect();
    let doc = dom.ownerDocument,
      win = doc.defaultView || window;
    let left = Math.max(0, rect.left),
      right = Math.min(win.innerWidth, rect.right);
    let top = Math.max(0, rect.top),
      bottom = Math.min(win.innerHeight, rect.bottom);
    for (let parent = dom.parentNode; parent && parent != doc.body;) {
      if (parent.nodeType == 1) {
        let elt = parent;
        let style = window.getComputedStyle(elt);
        if ((elt.scrollHeight > elt.clientHeight || elt.scrollWidth > elt.clientWidth) && style.overflow != "visible") {
          let parentRect = elt.getBoundingClientRect();
          left = Math.max(left, parentRect.left);
          right = Math.min(right, parentRect.right);
          top = Math.max(top, parentRect.top);
          bottom = Math.min(parent == dom.parentNode ? win.innerHeight : bottom, parentRect.bottom);
        }
        parent = style.position == "absolute" || style.position == "fixed" ? elt.offsetParent : elt.parentNode;
      } else if (parent.nodeType == 11) {
        // Shadow root
        parent = parent.host;
      } else {
        break;
      }
    }
    return {
      left: left - rect.left,
      right: Math.max(left, right) - rect.left,
      top: top - (rect.top + paddingTop),
      bottom: Math.max(top, bottom) - (rect.top + paddingTop)
    };
  }
  function inWindow(elt) {
    let rect = elt.getBoundingClientRect(),
      win = elt.ownerDocument.defaultView || window;
    return rect.left < win.innerWidth && rect.right > 0 && rect.top < win.innerHeight && rect.bottom > 0;
  }
  function fullPixelRange(dom, paddingTop) {
    let rect = dom.getBoundingClientRect();
    return {
      left: 0,
      right: rect.right - rect.left,
      top: paddingTop,
      bottom: rect.bottom - (rect.top + paddingTop)
    };
  }
  // Line gaps are placeholder widgets used to hide pieces of overlong
  // lines within the viewport, as a kludge to keep the editor
  // responsive when a ridiculously long line is loaded into it.
  class LineGap {
    constructor(from, to, size, displaySize) {
      this.from = from;
      this.to = to;
      this.size = size;
      this.displaySize = displaySize;
    }
    static same(a, b) {
      if (a.length != b.length) return false;
      for (let i = 0; i < a.length; i++) {
        let gA = a[i],
          gB = b[i];
        if (gA.from != gB.from || gA.to != gB.to || gA.size != gB.size) return false;
      }
      return true;
    }
    draw(viewState, wrapping) {
      return Decoration.replace({
        widget: new LineGapWidget(this.displaySize * (wrapping ? viewState.scaleY : viewState.scaleX), wrapping)
      }).range(this.from, this.to);
    }
  }
  class LineGapWidget extends WidgetType {
    constructor(size, vertical) {
      super();
      this.size = size;
      this.vertical = vertical;
    }
    eq(other) {
      return other.size == this.size && other.vertical == this.vertical;
    }
    toDOM() {
      let elt = document.createElement("div");
      if (this.vertical) {
        elt.style.height = this.size + "px";
      } else {
        elt.style.width = this.size + "px";
        elt.style.height = "2px";
        elt.style.display = "inline-block";
      }
      return elt;
    }
    get estimatedHeight() {
      return this.vertical ? this.size : -1;
    }
  }
  class ViewState {
    constructor(view, state) {
      this.view = view;
      this.state = state;
      // These are contentDOM-local coordinates
      this.pixelViewport = {
        left: 0,
        right: window.innerWidth,
        top: 0,
        bottom: 0
      };
      this.inView = true;
      this.paddingTop = 0; // Padding above the document, scaled
      this.paddingBottom = 0; // Padding below the document, scaled
      this.contentDOMWidth = 0; // contentDOM.getBoundingClientRect().width
      this.contentDOMHeight = 0; // contentDOM.getBoundingClientRect().height
      this.editorHeight = 0; // scrollDOM.clientHeight, unscaled
      this.editorWidth = 0; // scrollDOM.clientWidth, unscaled
      // The CSS-transformation scale of the editor (transformed size /
      // concrete size)
      this.scaleX = 1;
      this.scaleY = 1;
      // Last seen vertical offset of the element at the top of the scroll
      // container, or top of the window if there's no wrapping scroller
      this.scrollOffset = 0;
      this.scrolledToBottom = false;
      // The vertical position (document-relative) to which to anchor the
      // scroll position. -1 means anchor to the end of the document.
      this.scrollAnchorPos = 0;
      // The height at the anchor position. Set by the DOM update phase.
      // -1 means no height available.
      this.scrollAnchorHeight = -1;
      // See VP.MaxDOMHeight
      this.scaler = IdScaler;
      this.scrollTarget = null;
      // Briefly set to true when printing, to disable viewport limiting
      this.printing = false;
      // Flag set when editor content was redrawn, so that the next
      // measure stage knows it must read DOM layout
      this.mustMeasureContent = true;
      this.defaultTextDirection = Direction.LTR;
      this.visibleRanges = [];
      // Cursor 'assoc' is only significant when the cursor is on a line
      // wrap point, where it must stick to the character that it is
      // associated with. Since browsers don't provide a reasonable
      // interface to set or query this, when a selection is set that
      // might cause this to be significant, this flag is set. The next
      // measure phase will check whether the cursor is on a line-wrapping
      // boundary and, if so, reset it to make sure it is positioned in
      // the right place.
      this.mustEnforceCursorAssoc = false;
      let guessWrapping = state.facet(contentAttributes).some(v => typeof v != "function" && v.class == "cm-lineWrapping");
      this.heightOracle = new HeightOracle(guessWrapping);
      this.stateDeco = staticDeco(state);
      this.heightMap = HeightMap.empty().applyChanges(this.stateDeco, Text.empty, this.heightOracle.setDoc(state.doc), [new ChangedRange(0, 0, 0, state.doc.length)]);
      for (let i = 0; i < 2; i++) {
        this.viewport = this.getViewport(0, null);
        if (!this.updateForViewport()) break;
      }
      this.updateViewportLines();
      this.lineGaps = this.ensureLineGaps([]);
      this.lineGapDeco = Decoration.set(this.lineGaps.map(gap => gap.draw(this, false)));
      this.scrollParent = view.scrollDOM;
      this.computeVisibleRanges();
    }
    updateForViewport() {
      let viewports = [this.viewport],
        {
          main
        } = this.state.selection;
      for (let i = 0; i <= 1; i++) {
        let pos = i ? main.head : main.anchor;
        if (!viewports.some(({
          from,
          to
        }) => pos >= from && pos <= to)) {
          let {
            from,
            to
          } = this.lineBlockAt(pos);
          viewports.push(new Viewport(from, to));
        }
      }
      this.viewports = viewports.sort((a, b) => a.from - b.from);
      return this.updateScaler();
    }
    updateScaler() {
      let scaler = this.scaler;
      this.scaler = this.heightMap.height <= 7000000 /* VP.MaxDOMHeight */ ? IdScaler : new BigScaler(this.heightOracle, this.heightMap, this.viewports);
      return scaler.eq(this.scaler) ? 0 : 2 /* UpdateFlag.Height */;
    }
    updateViewportLines() {
      this.viewportLines = [];
      this.heightMap.forEachLine(this.viewport.from, this.viewport.to, this.heightOracle.setDoc(this.state.doc), 0, 0, block => {
        this.viewportLines.push(scaleBlock(block, this.scaler));
      });
    }
    update(update, scrollTarget = null) {
      this.state = update.state;
      let prevDeco = this.stateDeco;
      this.stateDeco = staticDeco(this.state);
      let contentChanges = update.changedRanges;
      let heightChanges = ChangedRange.extendWithRanges(contentChanges, heightRelevantDecoChanges(prevDeco, this.stateDeco, update ? update.changes : ChangeSet.empty(this.state.doc.length)));
      let prevHeight = this.heightMap.height;
      let scrollAnchor = this.scrolledToBottom ? null : this.scrollAnchorAt(this.scrollOffset);
      clearHeightChangeFlag();
      this.heightMap = this.heightMap.applyChanges(this.stateDeco, update.startState.doc, this.heightOracle.setDoc(this.state.doc), heightChanges);
      if (this.heightMap.height != prevHeight || heightChangeFlag) update.flags |= 2 /* UpdateFlag.Height */;
      if (scrollAnchor) {
        this.scrollAnchorPos = update.changes.mapPos(scrollAnchor.from, -1);
        this.scrollAnchorHeight = scrollAnchor.top;
      } else {
        this.scrollAnchorPos = -1;
        this.scrollAnchorHeight = prevHeight;
      }
      let viewport = heightChanges.length ? this.mapViewport(this.viewport, update.changes) : this.viewport;
      if (scrollTarget && (scrollTarget.range.head < viewport.from || scrollTarget.range.head > viewport.to) || !this.viewportIsAppropriate(viewport)) viewport = this.getViewport(0, scrollTarget);
      let viewportChange = viewport.from != this.viewport.from || viewport.to != this.viewport.to;
      this.viewport = viewport;
      update.flags |= this.updateForViewport();
      if (viewportChange || !update.changes.empty || update.flags & 2 /* UpdateFlag.Height */) this.updateViewportLines();
      if (this.lineGaps.length || this.viewport.to - this.viewport.from > 2000 /* LG.Margin */ << 1) this.updateLineGaps(this.ensureLineGaps(this.mapLineGaps(this.lineGaps, update.changes)));
      update.flags |= this.computeVisibleRanges(update.changes);
      if (scrollTarget) this.scrollTarget = scrollTarget;
      if (!this.mustEnforceCursorAssoc && (update.selectionSet || update.focusChanged) && update.view.lineWrapping && update.state.selection.main.empty && update.state.selection.main.assoc && !update.state.facet(nativeSelectionHidden)) this.mustEnforceCursorAssoc = true;
    }
    measure() {
      let {
          view
        } = this,
        dom = view.contentDOM,
        style = window.getComputedStyle(dom);
      let oracle = this.heightOracle;
      let whiteSpace = style.whiteSpace;
      this.defaultTextDirection = style.direction == "rtl" ? Direction.RTL : Direction.LTR;
      let refresh = this.heightOracle.mustRefreshForWrapping(whiteSpace) || this.mustMeasureContent === "refresh";
      let domRect = dom.getBoundingClientRect();
      let measureContent = refresh || this.mustMeasureContent || this.contentDOMHeight != domRect.height;
      this.contentDOMHeight = domRect.height;
      this.mustMeasureContent = false;
      let result = 0,
        bias = 0;
      if (domRect.width && domRect.height) {
        let {
          scaleX,
          scaleY
        } = getScale(dom, domRect);
        if (scaleX > .005 && Math.abs(this.scaleX - scaleX) > .005 || scaleY > .005 && Math.abs(this.scaleY - scaleY) > .005) {
          this.scaleX = scaleX;
          this.scaleY = scaleY;
          result |= 16 /* UpdateFlag.Geometry */;
          refresh = measureContent = true;
        }
      }
      // Vertical padding
      let paddingTop = (parseInt(style.paddingTop) || 0) * this.scaleY;
      let paddingBottom = (parseInt(style.paddingBottom) || 0) * this.scaleY;
      if (this.paddingTop != paddingTop || this.paddingBottom != paddingBottom) {
        this.paddingTop = paddingTop;
        this.paddingBottom = paddingBottom;
        result |= 16 /* UpdateFlag.Geometry */ | 2 /* UpdateFlag.Height */;
      }
      if (this.editorWidth != view.scrollDOM.clientWidth) {
        if (oracle.lineWrapping) measureContent = true;
        this.editorWidth = view.scrollDOM.clientWidth;
        result |= 16 /* UpdateFlag.Geometry */;
      }
      let scrollParent = scrollableParents(this.view.contentDOM, false).y;
      if (scrollParent != this.scrollParent) {
        this.scrollParent = scrollParent;
        this.scrollAnchorHeight = -1;
        this.scrollOffset = 0;
      }
      let scrollOffset = this.getScrollOffset();
      if (this.scrollOffset != scrollOffset) {
        this.scrollAnchorHeight = -1;
        this.scrollOffset = scrollOffset;
      }
      this.scrolledToBottom = isScrolledToBottom(this.scrollParent || view.win);
      // Pixel viewport
      let pixelViewport = (this.printing ? fullPixelRange : visiblePixelRange)(dom, this.paddingTop);
      let dTop = pixelViewport.top - this.pixelViewport.top,
        dBottom = pixelViewport.bottom - this.pixelViewport.bottom;
      this.pixelViewport = pixelViewport;
      let inView = this.pixelViewport.bottom > this.pixelViewport.top && this.pixelViewport.right > this.pixelViewport.left;
      if (inView != this.inView) {
        this.inView = inView;
        if (inView) measureContent = true;
      }
      if (!this.inView && !this.scrollTarget && !inWindow(view.dom)) return 0;
      let contentWidth = domRect.width;
      if (this.contentDOMWidth != contentWidth || this.editorHeight != view.scrollDOM.clientHeight) {
        this.contentDOMWidth = domRect.width;
        this.editorHeight = view.scrollDOM.clientHeight;
        result |= 16 /* UpdateFlag.Geometry */;
      }
      if (measureContent) {
        let lineHeights = view.docView.measureVisibleLineHeights(this.viewport);
        if (oracle.mustRefreshForHeights(lineHeights)) refresh = true;
        if (refresh || oracle.lineWrapping && Math.abs(contentWidth - this.contentDOMWidth) > oracle.charWidth) {
          let {
            lineHeight,
            charWidth,
            textHeight
          } = view.docView.measureTextSize();
          refresh = lineHeight > 0 && oracle.refresh(whiteSpace, lineHeight, charWidth, textHeight, Math.max(5, contentWidth / charWidth), lineHeights);
          if (refresh) {
            view.docView.minWidth = 0;
            result |= 16 /* UpdateFlag.Geometry */;
          }
        }
        if (dTop > 0 && dBottom > 0) bias = Math.max(dTop, dBottom);else if (dTop < 0 && dBottom < 0) bias = Math.min(dTop, dBottom);
        clearHeightChangeFlag();
        for (let vp of this.viewports) {
          let heights = vp.from == this.viewport.from ? lineHeights : view.docView.measureVisibleLineHeights(vp);
          this.heightMap = (refresh ? HeightMap.empty().applyChanges(this.stateDeco, Text.empty, this.heightOracle, [new ChangedRange(0, 0, 0, view.state.doc.length)]) : this.heightMap).updateHeight(oracle, 0, refresh, new MeasuredHeights(vp.from, heights));
        }
        if (heightChangeFlag) result |= 2 /* UpdateFlag.Height */;
      }
      let viewportChange = !this.viewportIsAppropriate(this.viewport, bias) || this.scrollTarget && (this.scrollTarget.range.head < this.viewport.from || this.scrollTarget.range.head > this.viewport.to);
      if (viewportChange) {
        if (result & 2 /* UpdateFlag.Height */) result |= this.updateScaler();
        this.viewport = this.getViewport(bias, this.scrollTarget);
        result |= this.updateForViewport();
      }
      if (result & 2 /* UpdateFlag.Height */ || viewportChange) this.updateViewportLines();
      if (this.lineGaps.length || this.viewport.to - this.viewport.from > 2000 /* LG.Margin */ << 1) this.updateLineGaps(this.ensureLineGaps(refresh ? [] : this.lineGaps, view));
      result |= this.computeVisibleRanges();
      if (this.mustEnforceCursorAssoc) {
        this.mustEnforceCursorAssoc = false;
        // This is done in the read stage, because moving the selection
        // to a line end is going to trigger a layout anyway, so it
        // can't be a pure write. It should be rare that it does any
        // writing.
        view.docView.enforceCursorAssoc();
      }
      return result;
    }
    get visibleTop() {
      return this.scaler.fromDOM(this.pixelViewport.top);
    }
    get visibleBottom() {
      return this.scaler.fromDOM(this.pixelViewport.bottom);
    }
    getViewport(bias, scrollTarget) {
      // This will divide VP.Margin between the top and the
      // bottom, depending on the bias (the change in viewport position
      // since the last update). It'll hold a number between 0 and 1
      let marginTop = 0.5 - Math.max(-0.5, Math.min(0.5, bias / 1000 /* VP.Margin */ / 2));
      let map = this.heightMap,
        oracle = this.heightOracle;
      let {
        visibleTop,
        visibleBottom
      } = this;
      let viewport = new Viewport(map.lineAt(visibleTop - marginTop * 1000 /* VP.Margin */, QueryType.ByHeight, oracle, 0, 0).from, map.lineAt(visibleBottom + (1 - marginTop) * 1000 /* VP.Margin */, QueryType.ByHeight, oracle, 0, 0).to);
      // If scrollTarget is given, make sure the viewport includes that position
      if (scrollTarget) {
        let {
          head
        } = scrollTarget.range;
        if (head < viewport.from || head > viewport.to) {
          let viewHeight = Math.min(this.editorHeight, this.pixelViewport.bottom - this.pixelViewport.top);
          let block = map.lineAt(head, QueryType.ByPos, oracle, 0, 0),
            topPos;
          if (scrollTarget.y == "center") topPos = (block.top + block.bottom) / 2 - viewHeight / 2;else if (scrollTarget.y == "start" || scrollTarget.y == "nearest" && head < viewport.from) topPos = block.top;else topPos = block.bottom - viewHeight;
          viewport = new Viewport(map.lineAt(topPos - 1000 /* VP.Margin */ / 2, QueryType.ByHeight, oracle, 0, 0).from, map.lineAt(topPos + viewHeight + 1000 /* VP.Margin */ / 2, QueryType.ByHeight, oracle, 0, 0).to);
        }
      }
      return viewport;
    }
    mapViewport(viewport, changes) {
      let from = changes.mapPos(viewport.from, -1),
        to = changes.mapPos(viewport.to, 1);
      return new Viewport(this.heightMap.lineAt(from, QueryType.ByPos, this.heightOracle, 0, 0).from, this.heightMap.lineAt(to, QueryType.ByPos, this.heightOracle, 0, 0).to);
    }
    // Checks if a given viewport covers the visible part of the
    // document and not too much beyond that.
    viewportIsAppropriate({
      from,
      to
    }, bias = 0) {
      if (!this.inView) return true;
      let {
        top
      } = this.heightMap.lineAt(from, QueryType.ByPos, this.heightOracle, 0, 0);
      let {
        bottom
      } = this.heightMap.lineAt(to, QueryType.ByPos, this.heightOracle, 0, 0);
      let {
        visibleTop,
        visibleBottom
      } = this;
      return (from == 0 || top <= visibleTop - Math.max(10 /* VP.MinCoverMargin */, Math.min(-bias, 250 /* VP.MaxCoverMargin */))) && (to == this.state.doc.length || bottom >= visibleBottom + Math.max(10 /* VP.MinCoverMargin */, Math.min(bias, 250 /* VP.MaxCoverMargin */))) && top > visibleTop - 2 * 1000 /* VP.Margin */ && bottom < visibleBottom + 2 * 1000 /* VP.Margin */;
    }
    mapLineGaps(gaps, changes) {
      if (!gaps.length || changes.empty) return gaps;
      let mapped = [];
      for (let gap of gaps) if (!changes.touchesRange(gap.from, gap.to)) mapped.push(new LineGap(changes.mapPos(gap.from), changes.mapPos(gap.to), gap.size, gap.displaySize));
      return mapped;
    }
    // Computes positions in the viewport where the start or end of a
    // line should be hidden, trying to reuse existing line gaps when
    // appropriate to avoid unneccesary redraws.
    // Uses crude character-counting for the positioning and sizing,
    // since actual DOM coordinates aren't always available and
    // predictable. Relies on generous margins (see LG.Margin) to hide
    // the artifacts this might produce from the user.
    ensureLineGaps(current, mayMeasure) {
      let wrapping = this.heightOracle.lineWrapping;
      let margin = wrapping ? 10000 /* LG.MarginWrap */ : 2000 /* LG.Margin */,
        halfMargin = margin >> 1,
        doubleMargin = margin << 1;
      // The non-wrapping logic won't work at all in predominantly right-to-left text.
      if (this.defaultTextDirection != Direction.LTR && !wrapping) return [];
      let gaps = [];
      let addGap = (from, to, line, structure) => {
        if (to - from < halfMargin) return;
        let sel = this.state.selection.main,
          avoid = [sel.from];
        if (!sel.empty) avoid.push(sel.to);
        for (let pos of avoid) {
          if (pos > from && pos < to) {
            addGap(from, pos - 10 /* LG.SelectionMargin */, line, structure);
            addGap(pos + 10 /* LG.SelectionMargin */, to, line, structure);
            return;
          }
        }
        let gap = find(current, gap => gap.from >= line.from && gap.to <= line.to && Math.abs(gap.from - from) < halfMargin && Math.abs(gap.to - to) < halfMargin && !avoid.some(pos => gap.from < pos && gap.to > pos));
        if (!gap) {
          // When scrolling down, snap gap ends to line starts to avoid shifts in wrapping
          if (to < line.to && mayMeasure && wrapping && mayMeasure.visibleRanges.some(r => r.from <= to && r.to >= to)) {
            let lineStart = mayMeasure.moveToLineBoundary(EditorSelection.cursor(to), false, true).head;
            if (lineStart > from) to = lineStart;
          }
          let size = this.gapSize(line, from, to, structure);
          let displaySize = wrapping || size < 2000000 /* VP.MaxHorizGap */ ? size : 2000000 /* VP.MaxHorizGap */;
          gap = new LineGap(from, to, size, displaySize);
        }
        gaps.push(gap);
      };
      let checkLine = line => {
        if (line.length < doubleMargin || line.type != BlockType.Text) return;
        let structure = lineStructure(line.from, line.to, this.stateDeco);
        if (structure.total < doubleMargin) return;
        let target = this.scrollTarget ? this.scrollTarget.range.head : null;
        let viewFrom, viewTo;
        if (wrapping) {
          let marginHeight = margin / this.heightOracle.lineLength * this.heightOracle.lineHeight;
          let top, bot;
          if (target != null) {
            let targetFrac = findFraction(structure, target);
            let spaceFrac = ((this.visibleBottom - this.visibleTop) / 2 + marginHeight) / line.height;
            top = targetFrac - spaceFrac;
            bot = targetFrac + spaceFrac;
          } else {
            top = (this.visibleTop - line.top - marginHeight) / line.height;
            bot = (this.visibleBottom - line.top + marginHeight) / line.height;
          }
          viewFrom = findPosition(structure, top);
          viewTo = findPosition(structure, bot);
        } else {
          let totalWidth = structure.total * this.heightOracle.charWidth;
          let marginWidth = margin * this.heightOracle.charWidth;
          let horizOffset = 0;
          if (totalWidth > 2000000 /* VP.MaxHorizGap */) for (let old of current) {
            if (old.from >= line.from && old.from < line.to && old.size != old.displaySize && old.from * this.heightOracle.charWidth + horizOffset < this.pixelViewport.left) horizOffset = old.size - old.displaySize;
          }
          let pxLeft = this.pixelViewport.left + horizOffset,
            pxRight = this.pixelViewport.right + horizOffset;
          let left, right;
          if (target != null) {
            let targetFrac = findFraction(structure, target);
            let spaceFrac = ((pxRight - pxLeft) / 2 + marginWidth) / totalWidth;
            left = targetFrac - spaceFrac;
            right = targetFrac + spaceFrac;
          } else {
            left = (pxLeft - marginWidth) / totalWidth;
            right = (pxRight + marginWidth) / totalWidth;
          }
          viewFrom = findPosition(structure, left);
          viewTo = findPosition(structure, right);
        }
        if (viewFrom > line.from) addGap(line.from, viewFrom, line, structure);
        if (viewTo < line.to) addGap(viewTo, line.to, line, structure);
      };
      for (let line of this.viewportLines) {
        if (Array.isArray(line.type)) line.type.forEach(checkLine);else checkLine(line);
      }
      return gaps;
    }
    gapSize(line, from, to, structure) {
      let fraction = findFraction(structure, to) - findFraction(structure, from);
      if (this.heightOracle.lineWrapping) {
        return line.height * fraction;
      } else {
        return structure.total * this.heightOracle.charWidth * fraction;
      }
    }
    updateLineGaps(gaps) {
      if (!LineGap.same(gaps, this.lineGaps)) {
        this.lineGaps = gaps;
        this.lineGapDeco = Decoration.set(gaps.map(gap => gap.draw(this, this.heightOracle.lineWrapping)));
      }
    }
    computeVisibleRanges(changes) {
      let deco = this.stateDeco;
      if (this.lineGaps.length) deco = deco.concat(this.lineGapDeco);
      let ranges = [];
      RangeSet.spans(deco, this.viewport.from, this.viewport.to, {
        span(from, to) {
          ranges.push({
            from,
            to
          });
        },
        point() {}
      }, 20);
      let changed = 0;
      if (ranges.length != this.visibleRanges.length) {
        changed = 8 /* UpdateFlag.ViewportMoved */ | 4 /* UpdateFlag.Viewport */;
      } else {
        for (let i = 0; i < ranges.length && !(changed & 8 /* UpdateFlag.ViewportMoved */); i++) {
          let old = this.visibleRanges[i],
            nw = ranges[i];
          if (old.from != nw.from || old.to != nw.to) {
            changed |= 4 /* UpdateFlag.Viewport */;
            if (!(changes && changes.mapPos(old.from, -1) == nw.from && changes.mapPos(old.to, 1) == nw.to)) changed |= 8 /* UpdateFlag.ViewportMoved */;
          }
        }
      }
      this.visibleRanges = ranges;
      return changed;
    }
    lineBlockAt(pos) {
      return pos >= this.viewport.from && pos <= this.viewport.to && this.viewportLines.find(b => b.from <= pos && b.to >= pos) || scaleBlock(this.heightMap.lineAt(pos, QueryType.ByPos, this.heightOracle, 0, 0), this.scaler);
    }
    lineBlockAtHeight(height) {
      return height >= this.viewportLines[0].top && height <= this.viewportLines[this.viewportLines.length - 1].bottom && this.viewportLines.find(l => l.top <= height && l.bottom >= height) || scaleBlock(this.heightMap.lineAt(this.scaler.fromDOM(height), QueryType.ByHeight, this.heightOracle, 0, 0), this.scaler);
    }
    getScrollOffset() {
      let base = this.scrollParent == this.view.scrollDOM ? this.scrollParent.scrollTop : (this.scrollParent ? this.scrollParent.getBoundingClientRect().top : 0) - this.view.contentDOM.getBoundingClientRect().top;
      return base * this.scaleY;
    }
    scrollAnchorAt(scrollOffset) {
      let block = this.lineBlockAtHeight(scrollOffset + 8);
      return block.from >= this.viewport.from || this.viewportLines[0].top - scrollOffset > 200 ? block : this.viewportLines[0];
    }
    elementAtHeight(height) {
      return scaleBlock(this.heightMap.blockAt(this.scaler.fromDOM(height), this.heightOracle, 0, 0), this.scaler);
    }
    get docHeight() {
      return this.scaler.toDOM(this.heightMap.height);
    }
    get contentHeight() {
      return this.docHeight + this.paddingTop + this.paddingBottom;
    }
  }
  class Viewport {
    constructor(from, to) {
      this.from = from;
      this.to = to;
    }
  }
  function lineStructure(from, to, stateDeco) {
    let ranges = [],
      pos = from,
      total = 0;
    RangeSet.spans(stateDeco, from, to, {
      span() {},
      point(from, to) {
        if (from > pos) {
          ranges.push({
            from: pos,
            to: from
          });
          total += from - pos;
        }
        pos = to;
      }
    }, 20); // We're only interested in collapsed ranges of a significant size
    if (pos < to) {
      ranges.push({
        from: pos,
        to
      });
      total += to - pos;
    }
    return {
      total,
      ranges
    };
  }
  function findPosition({
    total,
    ranges
  }, ratio) {
    if (ratio <= 0) return ranges[0].from;
    if (ratio >= 1) return ranges[ranges.length - 1].to;
    let dist = Math.floor(total * ratio);
    for (let i = 0;; i++) {
      let {
          from,
          to
        } = ranges[i],
        size = to - from;
      if (dist <= size) return from + dist;
      dist -= size;
    }
  }
  function findFraction(structure, pos) {
    let counted = 0;
    for (let {
      from,
      to
    } of structure.ranges) {
      if (pos <= to) {
        counted += pos - from;
        break;
      }
      counted += to - from;
    }
    return counted / structure.total;
  }
  function find(array, f) {
    for (let val of array) if (f(val)) return val;
    return undefined;
  }
  // Don't scale when the document height is within the range of what
  // the DOM can handle.
  const IdScaler = {
    toDOM(n) {
      return n;
    },
    fromDOM(n) {
      return n;
    },
    scale: 1,
    eq(other) {
      return other == this;
    }
  };
  function staticDeco(state) {
    let deco = state.facet(decorations).filter(d => typeof d != "function");
    let outer = state.facet(outerDecorations).filter(d => typeof d != "function");
    if (outer.length) deco.push(RangeSet.join(outer));
    return deco;
  }
  // When the height is too big (> VP.MaxDOMHeight), scale down the
  // regions outside the viewports so that the total height is
  // VP.MaxDOMHeight.
  class BigScaler {
    constructor(oracle, heightMap, viewports) {
      let vpHeight = 0,
        base = 0,
        domBase = 0;
      this.viewports = viewports.map(({
        from,
        to
      }) => {
        let top = heightMap.lineAt(from, QueryType.ByPos, oracle, 0, 0).top;
        let bottom = heightMap.lineAt(to, QueryType.ByPos, oracle, 0, 0).bottom;
        vpHeight += bottom - top;
        return {
          from,
          to,
          top,
          bottom,
          domTop: 0,
          domBottom: 0
        };
      });
      this.scale = (7000000 /* VP.MaxDOMHeight */ - vpHeight) / (heightMap.height - vpHeight);
      for (let obj of this.viewports) {
        obj.domTop = domBase + (obj.top - base) * this.scale;
        domBase = obj.domBottom = obj.domTop + (obj.bottom - obj.top);
        base = obj.bottom;
      }
    }
    toDOM(n) {
      for (let i = 0, base = 0, domBase = 0;; i++) {
        let vp = i < this.viewports.length ? this.viewports[i] : null;
        if (!vp || n < vp.top) return domBase + (n - base) * this.scale;
        if (n <= vp.bottom) return vp.domTop + (n - vp.top);
        base = vp.bottom;
        domBase = vp.domBottom;
      }
    }
    fromDOM(n) {
      for (let i = 0, base = 0, domBase = 0;; i++) {
        let vp = i < this.viewports.length ? this.viewports[i] : null;
        if (!vp || n < vp.domTop) return base + (n - domBase) / this.scale;
        if (n <= vp.domBottom) return vp.top + (n - vp.domTop);
        base = vp.bottom;
        domBase = vp.domBottom;
      }
    }
    eq(other) {
      if (!(other instanceof BigScaler)) return false;
      return this.scale == other.scale && this.viewports.length == other.viewports.length && this.viewports.every((vp, i) => vp.from == other.viewports[i].from && vp.to == other.viewports[i].to);
    }
  }
  function scaleBlock(block, scaler) {
    if (scaler.scale == 1) return block;
    let bTop = scaler.toDOM(block.top),
      bBottom = scaler.toDOM(block.bottom);
    return new BlockInfo(block.from, block.length, bTop, bBottom - bTop, Array.isArray(block._content) ? block._content.map(b => scaleBlock(b, scaler)) : block._content);
  }
  const theme = /*@__PURE__*/Facet.define({
    combine: strs => strs.join(" ")
  });
  const darkTheme = /*@__PURE__*/Facet.define({
    combine: values => values.indexOf(true) > -1
  });
  const baseThemeID = /*@__PURE__*/StyleModule.newName(),
    baseLightID = /*@__PURE__*/StyleModule.newName(),
    baseDarkID = /*@__PURE__*/StyleModule.newName();
  const lightDarkIDs = {
    "&light": "." + baseLightID,
    "&dark": "." + baseDarkID
  };
  function buildTheme(main, spec, scopes) {
    return new StyleModule(spec, {
      finish(sel) {
        return /&/.test(sel) ? sel.replace(/&\w*/, m => {
          if (m == "&") return main;
          if (!scopes || !scopes[m]) throw new RangeError(`Unsupported selector: ${m}`);
          return scopes[m];
        }) : main + " " + sel;
      }
    });
  }
  const baseTheme$1 = /*@__PURE__*/buildTheme("." + baseThemeID, {
    "&": {
      position: "relative !important",
      boxSizing: "border-box",
      "&.cm-focused": {
        // Provide a simple default outline to make sure a focused
        // editor is visually distinct. Can't leave the default behavior
        // because that will apply to the content element, which is
        // inside the scrollable container and doesn't include the
        // gutters. We also can't use an 'auto' outline, since those
        // are, for some reason, drawn behind the element content, which
        // will cause things like the active line background to cover
        // the outline (#297).
        outline: "1px dotted #212121"
      },
      display: "flex !important",
      flexDirection: "column"
    },
    ".cm-scroller": {
      display: "flex !important",
      alignItems: "flex-start !important",
      fontFamily: "monospace",
      lineHeight: 1.4,
      height: "100%",
      overflowX: "auto",
      position: "relative",
      zIndex: 0,
      overflowAnchor: "none"
    },
    ".cm-content": {
      margin: 0,
      flexGrow: 2,
      flexShrink: 0,
      display: "block",
      whiteSpace: "pre",
      wordWrap: "normal",
      // Issue #456
      boxSizing: "border-box",
      minHeight: "100%",
      padding: "4px 0",
      outline: "none",
      "&[contenteditable=true]": {
        WebkitUserModify: "read-write-plaintext-only"
      }
    },
    ".cm-lineWrapping": {
      whiteSpace_fallback: "pre-wrap",
      // For IE
      whiteSpace: "break-spaces",
      wordBreak: "break-word",
      // For Safari, which doesn't support overflow-wrap: anywhere
      overflowWrap: "anywhere",
      flexShrink: 1
    },
    "&light .cm-content": {
      caretColor: "black"
    },
    "&dark .cm-content": {
      caretColor: "white"
    },
    ".cm-line": {
      display: "block",
      padding: "0 2px 0 6px"
    },
    ".cm-layer": {
      userSelect: "none",
      // #1708
      position: "absolute",
      left: 0,
      top: 0,
      contain: "size style",
      "& > *": {
        position: "absolute"
      }
    },
    "&light .cm-selectionBackground": {
      background: "#d9d9d9"
    },
    "&dark .cm-selectionBackground": {
      background: "#222"
    },
    "&light.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground": {
      background: "#d7d4f0"
    },
    "&dark.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground": {
      background: "#233"
    },
    ".cm-cursorLayer": {
      pointerEvents: "none"
    },
    "&.cm-focused > .cm-scroller > .cm-cursorLayer": {
      animation: "steps(1) cm-blink 1.2s infinite"
    },
    // Two animations defined so that we can switch between them to
    // restart the animation without forcing another style
    // recomputation.
    "@keyframes cm-blink": {
      "0%": {},
      "50%": {
        opacity: 0
      },
      "100%": {}
    },
    "@keyframes cm-blink2": {
      "0%": {},
      "50%": {
        opacity: 0
      },
      "100%": {}
    },
    ".cm-cursor, .cm-dropCursor": {
      borderLeft: "1.2px solid black",
      marginLeft: "-0.6px",
      pointerEvents: "none"
    },
    ".cm-cursor": {
      display: "none"
    },
    "&dark .cm-cursor": {
      borderLeftColor: "#ddd"
    },
    ".cm-selectionHandle": {
      backgroundColor: "currentColor",
      width: "1.5px"
    },
    ".cm-selectionHandle-start::before, .cm-selectionHandle-end::before": {
      content: '""',
      backgroundColor: "inherit",
      borderRadius: "50%",
      width: "8px",
      height: "8px",
      position: "absolute",
      left: "-3.25px"
    },
    ".cm-selectionHandle-start::before": {
      top: "-8px"
    },
    ".cm-selectionHandle-end::before": {
      bottom: "-8px"
    },
    ".cm-dropCursor": {
      position: "absolute"
    },
    "&.cm-focused > .cm-scroller > .cm-cursorLayer .cm-cursor": {
      display: "block"
    },
    ".cm-iso": {
      unicodeBidi: "isolate"
    },
    ".cm-announced": {
      position: "fixed",
      top: "-10000px"
    },
    "@media print": {
      ".cm-announced": {
        display: "none"
      }
    },
    "&light .cm-activeLine": {
      backgroundColor: "#cceeff44"
    },
    "&dark .cm-activeLine": {
      backgroundColor: "#99eeff33"
    },
    "&light .cm-specialChar": {
      color: "red"
    },
    "&dark .cm-specialChar": {
      color: "#f78"
    },
    ".cm-gutters": {
      flexShrink: 0,
      display: "flex",
      height: "100%",
      boxSizing: "border-box",
      zIndex: 200
    },
    ".cm-gutters-before": {
      insetInlineStart: 0
    },
    ".cm-gutters-after": {
      insetInlineEnd: 0
    },
    "&light .cm-gutters": {
      backgroundColor: "#f5f5f5",
      color: "#6c6c6c",
      border: "0px solid #ddd",
      "&.cm-gutters-before": {
        borderRightWidth: "1px"
      },
      "&.cm-gutters-after": {
        borderLeftWidth: "1px"
      }
    },
    "&dark .cm-gutters": {
      backgroundColor: "#333338",
      color: "#ccc"
    },
    ".cm-gutter": {
      display: "flex !important",
      // Necessary -- prevents margin collapsing
      flexDirection: "column",
      flexShrink: 0,
      boxSizing: "border-box",
      minHeight: "100%",
      overflow: "hidden"
    },
    ".cm-gutterElement": {
      boxSizing: "border-box"
    },
    ".cm-lineNumbers .cm-gutterElement": {
      padding: "0 3px 0 5px",
      minWidth: "20px",
      textAlign: "right",
      whiteSpace: "nowrap"
    },
    "&light .cm-activeLineGutter": {
      backgroundColor: "#e2f2ff"
    },
    "&dark .cm-activeLineGutter": {
      backgroundColor: "#222227"
    },
    ".cm-panels": {
      boxSizing: "border-box",
      position: "sticky",
      left: 0,
      right: 0,
      zIndex: 300
    },
    "&light .cm-panels": {
      backgroundColor: "#f5f5f5",
      color: "black"
    },
    "&light .cm-panels-top": {
      borderBottom: "1px solid #ddd"
    },
    "&light .cm-panels-bottom": {
      borderTop: "1px solid #ddd"
    },
    "&dark .cm-panels": {
      backgroundColor: "#333338",
      color: "white"
    },
    ".cm-dialog": {
      padding: "2px 19px 4px 6px",
      position: "relative",
      "& label": {
        fontSize: "80%"
      }
    },
    ".cm-dialog-close": {
      position: "absolute",
      top: "3px",
      right: "4px",
      backgroundColor: "inherit",
      border: "none",
      font: "inherit",
      fontSize: "14px",
      padding: "0"
    },
    ".cm-tab": {
      display: "inline-block",
      overflow: "hidden",
      verticalAlign: "bottom"
    },
    ".cm-widgetBuffer": {
      verticalAlign: "text-top",
      height: "1em",
      width: 0,
      display: "inline"
    },
    ".cm-placeholder": {
      color: "#888",
      display: "inline-block",
      verticalAlign: "top",
      userSelect: "none"
    },
    ".cm-highlightSpace": {
      backgroundImage: "radial-gradient(circle at 50% 55%, #aaa 20%, transparent 5%)",
      backgroundPosition: "center"
    },
    ".cm-highlightTab": {
      backgroundImage: `url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="200" height="20"><path stroke="%23888" stroke-width="1" fill="none" d="M1 10H196L190 5M190 15L196 10M197 4L197 16"/></svg>')`,
      backgroundSize: "auto 100%",
      backgroundPosition: "right 90%",
      backgroundRepeat: "no-repeat"
    },
    ".cm-trailingSpace": {
      backgroundColor: "#ff332255"
    },
    ".cm-button": {
      verticalAlign: "middle",
      color: "inherit",
      fontSize: "70%",
      padding: ".2em 1em",
      borderRadius: "1px"
    },
    "&light .cm-button": {
      backgroundImage: "linear-gradient(#eff1f5, #d9d9df)",
      border: "1px solid #888",
      "&:active": {
        backgroundImage: "linear-gradient(#b4b4b4, #d0d3d6)"
      }
    },
    "&dark .cm-button": {
      backgroundImage: "linear-gradient(#393939, #111)",
      border: "1px solid #888",
      "&:active": {
        backgroundImage: "linear-gradient(#111, #333)"
      }
    },
    ".cm-textfield": {
      verticalAlign: "middle",
      color: "inherit",
      fontSize: "70%",
      border: "1px solid silver",
      padding: ".2em .5em"
    },
    "&light .cm-textfield": {
      backgroundColor: "white"
    },
    "&dark .cm-textfield": {
      border: "1px solid #555",
      backgroundColor: "inherit"
    }
  }, lightDarkIDs);
  const observeOptions = {
    childList: true,
    characterData: true,
    subtree: true,
    attributes: true,
    characterDataOldValue: true
  };
  // IE11 has very broken mutation observers, so we also listen to
  // DOMCharacterDataModified there
  const useCharData = browser.ie && browser.ie_version <= 11;
  class DOMObserver {
    constructor(view) {
      this.view = view;
      this.active = false;
      this.editContext = null;
      // The known selection. Kept in our own object, as opposed to just
      // directly accessing the selection because:
      //  - Safari doesn't report the right selection in shadow DOM
      //  - Reading from the selection forces a DOM layout
      //  - This way, we can ignore selectionchange events if we have
      //    already seen the 'new' selection
      this.selectionRange = new DOMSelectionState();
      // Set when a selection change is detected, cleared on flush
      this.selectionChanged = false;
      this.delayedFlush = -1;
      this.resizeTimeout = -1;
      this.queue = [];
      this.delayedAndroidKey = null;
      this.flushingAndroidKey = -1;
      this.lastChange = 0;
      this.scrollTargets = [];
      this.intersection = null;
      this.resizeScroll = null;
      this.intersecting = false;
      this.gapIntersection = null;
      this.gaps = [];
      this.printQuery = null;
      // Timeout for scheduling check of the parents that need scroll handlers
      this.parentCheck = -1;
      this.dom = view.contentDOM;
      this.observer = new MutationObserver(mutations => {
        for (let mut of mutations) this.queue.push(mut);
        // IE11 will sometimes (on typing over a selection or
        // backspacing out a single character text node) call the
        // observer callback before actually updating the DOM.
        //
        // Unrelatedly, iOS Safari will, when ending a composition,
        // sometimes first clear it, deliver the mutations, and then
        // reinsert the finished text. CodeMirror's handling of the
        // deletion will prevent the reinsertion from happening,
        // breaking composition.
        if ((browser.ie && browser.ie_version <= 11 || browser.ios && view.composing) && mutations.some(m => m.type == "childList" && m.removedNodes.length || m.type == "characterData" && m.oldValue.length > m.target.nodeValue.length)) this.flushSoon();else this.flush();
      });
      if (window.EditContext && browser.android && view.constructor.EDIT_CONTEXT !== false &&
      // Chrome <126 doesn't support inverted selections in edit context (#1392)
      !(browser.chrome && browser.chrome_version < 126)) {
        this.editContext = new EditContextManager(view);
        if (view.state.facet(editable)) view.contentDOM.editContext = this.editContext.editContext;
      }
      if (useCharData) this.onCharData = event => {
        this.queue.push({
          target: event.target,
          type: "characterData",
          oldValue: event.prevValue
        });
        this.flushSoon();
      };
      this.onSelectionChange = this.onSelectionChange.bind(this);
      this.onResize = this.onResize.bind(this);
      this.onPrint = this.onPrint.bind(this);
      this.onScroll = this.onScroll.bind(this);
      if (window.matchMedia) this.printQuery = window.matchMedia("print");
      if (typeof ResizeObserver == "function") {
        this.resizeScroll = new ResizeObserver(() => {
          var _a;
          if (((_a = this.view.docView) === null || _a === void 0 ? void 0 : _a.lastUpdate) < Date.now() - 75) this.onResize();
        });
        this.resizeScroll.observe(view.scrollDOM);
      }
      this.addWindowListeners(this.win = view.win);
      this.start();
      if (typeof IntersectionObserver == "function") {
        this.intersection = new IntersectionObserver(entries => {
          if (this.parentCheck < 0) this.parentCheck = setTimeout(this.listenForScroll.bind(this), 1000);
          if (entries.length > 0 && entries[entries.length - 1].intersectionRatio > 0 != this.intersecting) {
            this.intersecting = !this.intersecting;
            if (this.intersecting != this.view.inView) this.onScrollChanged(document.createEvent("Event"));
          }
        }, {
          threshold: [0, .001]
        });
        this.intersection.observe(this.dom);
        this.gapIntersection = new IntersectionObserver(entries => {
          if (entries.length > 0 && entries[entries.length - 1].intersectionRatio > 0) this.onScrollChanged(document.createEvent("Event"));
        }, {});
      }
      this.listenForScroll();
      this.readSelectionRange();
    }
    onScrollChanged(e) {
      this.view.inputState.runHandlers("scroll", e);
      if (this.intersecting) this.view.measure();
    }
    onScroll(e) {
      if (this.intersecting) this.flush(false);
      if (this.editContext) this.view.requestMeasure(this.editContext.measureReq);
      this.onScrollChanged(e);
    }
    onResize() {
      if (this.resizeTimeout < 0) this.resizeTimeout = setTimeout(() => {
        this.resizeTimeout = -1;
        this.view.requestMeasure();
      }, 50);
    }
    onPrint(event) {
      if ((event.type == "change" || !event.type) && !event.matches) return;
      this.view.viewState.printing = true;
      this.view.measure();
      setTimeout(() => {
        this.view.viewState.printing = false;
        this.view.requestMeasure();
      }, 500);
    }
    updateGaps(gaps) {
      if (this.gapIntersection && (gaps.length != this.gaps.length || this.gaps.some((g, i) => g != gaps[i]))) {
        this.gapIntersection.disconnect();
        for (let gap of gaps) this.gapIntersection.observe(gap);
        this.gaps = gaps;
      }
    }
    onSelectionChange(event) {
      let wasChanged = this.selectionChanged;
      if (!this.readSelectionRange() || this.delayedAndroidKey) return;
      let {
          view
        } = this,
        sel = this.selectionRange;
      if (view.state.facet(editable) ? view.root.activeElement != this.dom : !hasSelection(this.dom, sel)) return;
      let context = sel.anchorNode && view.docView.tile.nearest(sel.anchorNode);
      if (context && context.isWidget() && context.widget.ignoreEvent(event)) {
        if (!wasChanged) this.selectionChanged = false;
        return;
      }
      // Deletions on IE11 fire their events in the wrong order, giving
      // us a selection change event before the DOM changes are
      // reported.
      // Chrome Android has a similar issue when backspacing out a
      // selection (#645).
      if ((browser.ie && browser.ie_version <= 11 || browser.android && browser.chrome) && !view.state.selection.main.empty &&
      // (Selection.isCollapsed isn't reliable on IE)
      sel.focusNode && isEquivalentPosition(sel.focusNode, sel.focusOffset, sel.anchorNode, sel.anchorOffset)) this.flushSoon();else this.flush(false);
    }
    readSelectionRange() {
      let {
        view
      } = this;
      // The Selection object is broken in shadow roots in Safari. See
      // issue #414
      let selection = getSelection(view.root);
      if (!selection) return false;
      let range = browser.safari && view.root.nodeType == 11 && view.root.activeElement == this.dom && safariSelectionRangeHack(this.view, selection) || selection;
      if (!range || this.selectionRange.eq(range)) return false;
      let local = hasSelection(this.dom, range);
      // Detect the situation where the browser has, on focus, moved the
      // selection to the start of the content element. Reset it to the
      // position from the editor state.
      if (local && !this.selectionChanged && view.inputState.lastFocusTime > Date.now() - 200 && view.inputState.lastTouchTime < Date.now() - 300 && atElementStart(this.dom, range)) {
        this.view.inputState.lastFocusTime = 0;
        view.docView.updateSelection();
        return false;
      }
      this.selectionRange.setRange(range);
      if (local) this.selectionChanged = true;
      return true;
    }
    setSelectionRange(anchor, head) {
      this.selectionRange.set(anchor.node, anchor.offset, head.node, head.offset);
      this.selectionChanged = false;
    }
    clearSelectionRange() {
      this.selectionRange.set(null, 0, null, 0);
    }
    listenForScroll() {
      this.parentCheck = -1;
      let i = 0,
        changed = null;
      for (let dom = this.dom; dom;) {
        if (dom.nodeType == 1) {
          if (!changed && i < this.scrollTargets.length && this.scrollTargets[i] == dom) i++;else if (!changed) changed = this.scrollTargets.slice(0, i);
          if (changed) changed.push(dom);
          dom = dom.assignedSlot || dom.parentNode;
        } else if (dom.nodeType == 11) {
          // Shadow root
          dom = dom.host;
        } else {
          break;
        }
      }
      if (i < this.scrollTargets.length && !changed) changed = this.scrollTargets.slice(0, i);
      if (changed) {
        for (let dom of this.scrollTargets) dom.removeEventListener("scroll", this.onScroll);
        for (let dom of this.scrollTargets = changed) dom.addEventListener("scroll", this.onScroll);
      }
    }
    ignore(f) {
      if (!this.active) return f();
      try {
        this.stop();
        return f();
      } finally {
        this.start();
        this.clear();
      }
    }
    start() {
      if (this.active) return;
      this.observer.observe(this.dom, observeOptions);
      if (useCharData) this.dom.addEventListener("DOMCharacterDataModified", this.onCharData);
      this.active = true;
    }
    stop() {
      if (!this.active) return;
      this.active = false;
      this.observer.disconnect();
      if (useCharData) this.dom.removeEventListener("DOMCharacterDataModified", this.onCharData);
    }
    // Throw away any pending changes
    clear() {
      this.processRecords();
      this.queue.length = 0;
      this.selectionChanged = false;
    }
    // Chrome Android, especially in combination with GBoard, not only
    // doesn't reliably fire regular key events, but also often
    // surrounds the effect of enter or backspace with a bunch of
    // composition events that, when interrupted, cause text duplication
    // or other kinds of corruption. This hack makes the editor back off
    // from handling DOM changes for a moment when such a key is
    // detected (via beforeinput or keydown), and then tries to flush
    // them or, if that has no effect, dispatches the given key.
    delayAndroidKey(key, keyCode) {
      var _a;
      if (!this.delayedAndroidKey) {
        let flush = () => {
          let key = this.delayedAndroidKey;
          if (key) {
            this.clearDelayedAndroidKey();
            this.view.inputState.lastKeyCode = key.keyCode;
            this.view.inputState.lastKeyTime = Date.now();
            let flushed = this.flush();
            if (!flushed && key.force) dispatchKey(this.dom, key.key, key.keyCode);
          }
        };
        this.flushingAndroidKey = this.view.win.requestAnimationFrame(flush);
      }
      // Since backspace beforeinput is sometimes signalled spuriously,
      // Enter always takes precedence.
      if (!this.delayedAndroidKey || key == "Enter") this.delayedAndroidKey = {
        key,
        keyCode,
        // Only run the key handler when no changes are detected if
        // this isn't coming right after another change, in which case
        // it is probably part of a weird chain of updates, and should
        // be ignored if it returns the DOM to its previous state.
        force: this.lastChange < Date.now() - 50 || !!((_a = this.delayedAndroidKey) === null || _a === void 0 ? void 0 : _a.force)
      };
    }
    clearDelayedAndroidKey() {
      this.win.cancelAnimationFrame(this.flushingAndroidKey);
      this.delayedAndroidKey = null;
      this.flushingAndroidKey = -1;
    }
    flushSoon() {
      if (this.delayedFlush < 0) this.delayedFlush = this.view.win.requestAnimationFrame(() => {
        this.delayedFlush = -1;
        this.flush();
      });
    }
    forceFlush() {
      if (this.delayedFlush >= 0) {
        this.view.win.cancelAnimationFrame(this.delayedFlush);
        this.delayedFlush = -1;
      }
      this.flush();
    }
    pendingRecords() {
      for (let mut of this.observer.takeRecords()) this.queue.push(mut);
      return this.queue;
    }
    processRecords() {
      let records = this.pendingRecords();
      if (records.length) this.queue = [];
      let from = -1,
        to = -1,
        typeOver = false;
      for (let record of records) {
        let range = this.readMutation(record);
        if (!range) continue;
        if (range.typeOver) typeOver = true;
        if (from == -1) {
          ({
            from,
            to
          } = range);
        } else {
          from = Math.min(range.from, from);
          to = Math.max(range.to, to);
        }
      }
      return {
        from,
        to,
        typeOver
      };
    }
    readChange() {
      let {
        from,
        to,
        typeOver
      } = this.processRecords();
      let newSel = this.selectionChanged && hasSelection(this.dom, this.selectionRange);
      if (from < 0 && !newSel) return null;
      if (from > -1) this.lastChange = Date.now();
      this.view.inputState.lastFocusTime = 0;
      this.selectionChanged = false;
      let change = new DOMChange(this.view, from, to, typeOver);
      this.view.docView.domChanged = {
        newSel: change.newSel ? change.newSel.main : null
      };
      return change;
    }
    // Apply pending changes, if any
    flush(readSelection = true) {
      // Completely hold off flushing when pending keys are set—the code
      // managing those will make sure processRecords is called and the
      // view is resynchronized after
      if (this.delayedFlush >= 0 || this.delayedAndroidKey) return false;
      if (readSelection) this.readSelectionRange();
      let domChange = this.readChange();
      if (!domChange) {
        this.view.requestMeasure();
        return false;
      }
      let startState = this.view.state;
      let handled = applyDOMChange(this.view, domChange);
      // The view wasn't updated but DOM/selection changes were seen. Reset the view.
      if (this.view.state == startState && (domChange.domChanged || domChange.newSel && !sameSelPos(this.view.state.selection, domChange.newSel.main))) this.view.update([]);
      return handled;
    }
    readMutation(rec) {
      let tile = this.view.docView.tile.nearest(rec.target);
      if (!tile || tile.isWidget()) return null;
      tile.markDirty(rec.type == "attributes");
      if (rec.type == "childList") {
        let childBefore = findChild(tile, rec.previousSibling || rec.target.previousSibling, -1);
        let childAfter = findChild(tile, rec.nextSibling || rec.target.nextSibling, 1);
        return {
          from: childBefore ? tile.posAfter(childBefore) : tile.posAtStart,
          to: childAfter ? tile.posBefore(childAfter) : tile.posAtEnd,
          typeOver: false
        };
      } else if (rec.type == "characterData") {
        return {
          from: tile.posAtStart,
          to: tile.posAtEnd,
          typeOver: rec.target.nodeValue == rec.oldValue
        };
      } else {
        return null;
      }
    }
    setWindow(win) {
      if (win != this.win) {
        this.removeWindowListeners(this.win);
        this.win = win;
        this.addWindowListeners(this.win);
      }
    }
    addWindowListeners(win) {
      win.addEventListener("resize", this.onResize);
      if (this.printQuery) {
        if (this.printQuery.addEventListener) this.printQuery.addEventListener("change", this.onPrint);else this.printQuery.addListener(this.onPrint);
      } else win.addEventListener("beforeprint", this.onPrint);
      win.addEventListener("scroll", this.onScroll);
      win.document.addEventListener("selectionchange", this.onSelectionChange);
    }
    removeWindowListeners(win) {
      win.removeEventListener("scroll", this.onScroll);
      win.removeEventListener("resize", this.onResize);
      if (this.printQuery) {
        if (this.printQuery.removeEventListener) this.printQuery.removeEventListener("change", this.onPrint);else this.printQuery.removeListener(this.onPrint);
      } else win.removeEventListener("beforeprint", this.onPrint);
      win.document.removeEventListener("selectionchange", this.onSelectionChange);
    }
    update(update) {
      if (this.editContext) {
        this.editContext.update(update);
        if (update.startState.facet(editable) != update.state.facet(editable)) update.view.contentDOM.editContext = update.state.facet(editable) ? this.editContext.editContext : null;
      }
    }
    destroy() {
      var _a, _b, _c;
      this.stop();
      (_a = this.intersection) === null || _a === void 0 ? void 0 : _a.disconnect();
      (_b = this.gapIntersection) === null || _b === void 0 ? void 0 : _b.disconnect();
      (_c = this.resizeScroll) === null || _c === void 0 ? void 0 : _c.disconnect();
      for (let dom of this.scrollTargets) dom.removeEventListener("scroll", this.onScroll);
      this.removeWindowListeners(this.win);
      clearTimeout(this.parentCheck);
      clearTimeout(this.resizeTimeout);
      this.win.cancelAnimationFrame(this.delayedFlush);
      this.win.cancelAnimationFrame(this.flushingAndroidKey);
      if (this.editContext) {
        this.view.contentDOM.editContext = null;
        this.editContext.destroy();
      }
    }
  }
  function findChild(tile, dom, dir) {
    while (dom) {
      let curTile = Tile.get(dom);
      if (curTile && curTile.parent == tile) return curTile;
      let parent = dom.parentNode;
      dom = parent != tile.dom ? parent : dir > 0 ? dom.nextSibling : dom.previousSibling;
    }
    return null;
  }
  function buildSelectionRangeFromRange(view, range) {
    let anchorNode = range.startContainer,
      anchorOffset = range.startOffset;
    let focusNode = range.endContainer,
      focusOffset = range.endOffset;
    let curAnchor = view.docView.domAtPos(view.state.selection.main.anchor, 1);
    // Since such a range doesn't distinguish between anchor and head,
    // use a heuristic that flips it around if its end matches the
    // current anchor.
    if (isEquivalentPosition(curAnchor.node, curAnchor.offset, focusNode, focusOffset)) [anchorNode, anchorOffset, focusNode, focusOffset] = [focusNode, focusOffset, anchorNode, anchorOffset];
    return {
      anchorNode,
      anchorOffset,
      focusNode,
      focusOffset
    };
  }
  // Used to work around a Safari Selection/shadow DOM bug (#414)
  function safariSelectionRangeHack(view, selection) {
    if (selection.getComposedRanges) {
      let range = selection.getComposedRanges(view.root)[0];
      if (range) return buildSelectionRangeFromRange(view, range);
    }
    let found = null;
    // Because Safari (at least in 2018-2021) doesn't provide regular
    // access to the selection inside a shadowroot, we have to perform a
    // ridiculous hack to get at it—using `execCommand` to trigger a
    // `beforeInput` event so that we can read the target range from the
    // event.
    function read(event) {
      event.preventDefault();
      event.stopImmediatePropagation();
      found = event.getTargetRanges()[0];
    }
    view.contentDOM.addEventListener("beforeinput", read, true);
    view.dom.ownerDocument.execCommand("indent");
    view.contentDOM.removeEventListener("beforeinput", read, true);
    return found ? buildSelectionRangeFromRange(view, found) : null;
  }
  class EditContextManager {
    constructor(view) {
      // The document window for which the text in the context is
      // maintained. For large documents, this may be smaller than the
      // editor document. This window always includes the selection head.
      this.from = 0;
      this.to = 0;
      // When applying a transaction, this is used to compare the change
      // made to the context content to the change in the transaction in
      // order to make the minimal changes to the context (since touching
      // that sometimes breaks series of multiple edits made for a single
      // user action on some Android keyboards)
      this.pendingContextChange = null;
      this.handlers = Object.create(null);
      // Kludge to work around the fact that EditContext does not respond
      // well to having its content updated during a composition (see #1472)
      this.composing = null;
      this.resetRange(view.state);
      let context = this.editContext = new window.EditContext({
        text: view.state.doc.sliceString(this.from, this.to),
        selectionStart: this.toContextPos(Math.max(this.from, Math.min(this.to, view.state.selection.main.anchor))),
        selectionEnd: this.toContextPos(view.state.selection.main.head)
      });
      this.handlers.textupdate = e => {
        let main = view.state.selection.main,
          {
            anchor,
            head
          } = main;
        let from = this.toEditorPos(e.updateRangeStart),
          to = this.toEditorPos(e.updateRangeEnd);
        if (view.inputState.composing >= 0 && !this.composing) this.composing = {
          contextBase: e.updateRangeStart,
          editorBase: from,
          drifted: false
        };
        let deletes = to - from > e.text.length;
        // If the window doesn't include the anchor, assume changes
        // adjacent to a side go up to the anchor.
        if (from == this.from && anchor < this.from) from = anchor;else if (to == this.to && anchor > this.to) to = anchor;
        let diff = findDiff(view.state.sliceDoc(from, to), e.text, (deletes ? main.from : main.to) - from, deletes ? "end" : null);
        // Edit contexts sometimes fire empty changes
        if (!diff) {
          let newSel = EditorSelection.single(this.toEditorPos(e.selectionStart), this.toEditorPos(e.selectionEnd));
          if (!sameSelPos(newSel, main)) view.dispatch({
            selection: newSel,
            userEvent: "select"
          });
          return;
        }
        let change = {
          from: diff.from + from,
          to: diff.toA + from,
          insert: Text.of(e.text.slice(diff.from, diff.toB).split("\n"))
        };
        if ((browser.mac || browser.android) && change.from == head - 1 && /^\. ?$/.test(e.text) && view.contentDOM.getAttribute("autocorrect") == "off") change = {
          from,
          to,
          insert: Text.of([e.text.replace(".", " ")])
        };
        this.pendingContextChange = change;
        if (!view.state.readOnly) {
          let newLen = this.to - this.from + (change.to - change.from + change.insert.length);
          applyDOMChangeInner(view, change, EditorSelection.single(this.toEditorPos(e.selectionStart, newLen), this.toEditorPos(e.selectionEnd, newLen)));
        }
        // If the transaction didn't flush our change, revert it so
        // that the context is in sync with the editor state again.
        if (this.pendingContextChange) {
          this.revertPending(view.state);
          this.setSelection(view.state);
        }
        // Work around missed compositionend events. See https://discuss.codemirror.net/t/a/9514
        if (change.from < change.to && !change.insert.length && view.inputState.composing >= 0 && !/[\\p{Alphabetic}\\p{Number}_]/.test(context.text.slice(Math.max(0, e.updateRangeStart - 1), Math.min(context.text.length, e.updateRangeStart + 1)))) this.handlers.compositionend(e);
      };
      this.handlers.characterboundsupdate = e => {
        let rects = [],
          prev = null;
        for (let i = this.toEditorPos(e.rangeStart), end = this.toEditorPos(e.rangeEnd); i < end; i++) {
          let rect = view.coordsForChar(i);
          prev = rect && new DOMRect(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top) || prev || new DOMRect();
          rects.push(prev);
        }
        context.updateCharacterBounds(e.rangeStart, rects);
      };
      this.handlers.textformatupdate = e => {
        let deco = [];
        for (let format of e.getTextFormats()) {
          let lineStyle = format.underlineStyle,
            thickness = format.underlineThickness;
          if (!/none/i.test(lineStyle) && !/none/i.test(thickness)) {
            let from = this.toEditorPos(format.rangeStart),
              to = this.toEditorPos(format.rangeEnd);
            if (from < to) {
              // These values changed from capitalized custom strings to lower-case CSS keywords in 2025
              let style = `text-decoration: underline ${/^[a-z]/.test(lineStyle) ? lineStyle + " " : lineStyle == "Dashed" ? "dashed " : lineStyle == "Squiggle" ? "wavy " : ""}${/thin/i.test(thickness) ? 1 : 2}px`;
              deco.push(Decoration.mark({
                attributes: {
                  style
                }
              }).range(from, to));
            }
          }
        }
        view.dispatch({
          effects: setEditContextFormatting.of(Decoration.set(deco))
        });
      };
      this.handlers.compositionstart = () => {
        if (view.inputState.composing < 0) {
          view.inputState.composing = 0;
          view.inputState.compositionFirstChange = true;
        }
      };
      this.handlers.compositionend = () => {
        view.inputState.composing = -1;
        view.inputState.compositionFirstChange = null;
        if (this.composing) {
          let {
            drifted
          } = this.composing;
          this.composing = null;
          if (drifted) this.reset(view.state);
        }
      };
      for (let event in this.handlers) context.addEventListener(event, this.handlers[event]);
      this.measureReq = {
        read: view => {
          this.editContext.updateControlBounds(view.contentDOM.getBoundingClientRect());
          let sel = getSelection(view.root);
          if (sel && sel.rangeCount) this.editContext.updateSelectionBounds(sel.getRangeAt(0).getBoundingClientRect());
        }
      };
    }
    applyEdits(update) {
      let off = 0,
        abort = false,
        pending = this.pendingContextChange;
      update.changes.iterChanges((fromA, toA, _fromB, _toB, insert) => {
        if (abort) return;
        let dLen = insert.length - (toA - fromA);
        if (pending && toA >= pending.to) {
          if (pending.from == fromA && pending.to == toA && pending.insert.eq(insert)) {
            pending = this.pendingContextChange = null; // Match
            off += dLen;
            this.to += dLen;
            return;
          } else {
            // Mismatch, revert
            pending = null;
            this.revertPending(update.state);
          }
        }
        fromA += off;
        toA += off;
        if (toA <= this.from) {
          // Before the window
          this.from += dLen;
          this.to += dLen;
        } else if (fromA < this.to) {
          // Overlaps with window
          if (fromA < this.from || toA > this.to || this.to - this.from + insert.length > 30000 /* CxVp.MaxSize */) {
            abort = true;
            return;
          }
          this.editContext.updateText(this.toContextPos(fromA), this.toContextPos(toA), insert.toString());
          this.to += dLen;
        }
        off += dLen;
      });
      if (pending && !abort) this.revertPending(update.state);
      return !abort;
    }
    update(update) {
      let reverted = this.pendingContextChange,
        startSel = update.startState.selection.main;
      if (this.composing && (this.composing.drifted || !update.changes.touchesRange(startSel.from, startSel.to) && update.transactions.some(tr => !tr.isUserEvent("input.type") && tr.changes.touchesRange(this.from, this.to)))) {
        this.composing.drifted = true;
        this.composing.editorBase = update.changes.mapPos(this.composing.editorBase);
      } else if (!this.applyEdits(update) || !this.rangeIsValid(update.state)) {
        this.pendingContextChange = null;
        this.reset(update.state);
      } else if (update.docChanged || update.selectionSet || reverted) {
        this.setSelection(update.state);
      }
      if (update.geometryChanged || update.docChanged || update.selectionSet) update.view.requestMeasure(this.measureReq);
    }
    resetRange(state) {
      let {
        head
      } = state.selection.main;
      this.from = Math.max(0, head - 10000 /* CxVp.Margin */);
      this.to = Math.min(state.doc.length, head + 10000 /* CxVp.Margin */);
    }
    reset(state) {
      this.resetRange(state);
      this.editContext.updateText(0, this.editContext.text.length, state.doc.sliceString(this.from, this.to));
      this.setSelection(state);
    }
    revertPending(state) {
      let pending = this.pendingContextChange;
      this.pendingContextChange = null;
      this.editContext.updateText(this.toContextPos(pending.from), this.toContextPos(pending.from + pending.insert.length), state.doc.sliceString(pending.from, pending.to));
    }
    setSelection(state) {
      let {
        main
      } = state.selection;
      let start = this.toContextPos(Math.max(this.from, Math.min(this.to, main.anchor)));
      let end = this.toContextPos(main.head);
      if (this.editContext.selectionStart != start || this.editContext.selectionEnd != end) this.editContext.updateSelection(start, end);
    }
    rangeIsValid(state) {
      let {
        head
      } = state.selection.main;
      return !(this.from > 0 && head - this.from < 500 /* CxVp.MinMargin */ || this.to < state.doc.length && this.to - head < 500 /* CxVp.MinMargin */ || this.to - this.from > 10000 /* CxVp.Margin */ * 3);
    }
    toEditorPos(contextPos, clipLen = this.to - this.from) {
      contextPos = Math.min(contextPos, clipLen);
      let c = this.composing;
      return c && c.drifted ? c.editorBase + (contextPos - c.contextBase) : contextPos + this.from;
    }
    toContextPos(editorPos) {
      let c = this.composing;
      return c && c.drifted ? c.contextBase + (editorPos - c.editorBase) : editorPos - this.from;
    }
    destroy() {
      for (let event in this.handlers) this.editContext.removeEventListener(event, this.handlers[event]);
    }
  }

  // The editor's update state machine looks something like this:
  //
  //     Idle → Updating ⇆ Idle (unchecked) → Measuring → Idle
  //                                         ↑      ↓
  //                                         Updating (measure)
  //
  // The difference between 'Idle' and 'Idle (unchecked)' lies in
  // whether a layout check has been scheduled. A regular update through
  // the `update` method updates the DOM in a write-only fashion, and
  // relies on a check (scheduled with `requestAnimationFrame`) to make
  // sure everything is where it should be and the viewport covers the
  // visible code. That check continues to measure and then optionally
  // update until it reaches a coherent state.
  /**
  An editor view represents the editor's user interface. It holds
  the editable DOM surface, and possibly other elements such as the
  line number gutter. It handles events and dispatches state
  transactions for editing actions.
  */
  class EditorView {
    /**
    The current editor state.
    */
    get state() {
      return this.viewState.state;
    }
    /**
    To be able to display large documents without consuming too much
    memory or overloading the browser, CodeMirror only draws the
    code that is visible (plus a margin around it) to the DOM. This
    property tells you the extent of the current drawn viewport, in
    document positions.
    */
    get viewport() {
      return this.viewState.viewport;
    }
    /**
    When there are, for example, large collapsed ranges in the
    viewport, its size can be a lot bigger than the actual visible
    content. Thus, if you are doing something like styling the
    content in the viewport, it is preferable to only do so for
    these ranges, which are the subset of the viewport that is
    actually drawn.
    */
    get visibleRanges() {
      return this.viewState.visibleRanges;
    }
    /**
    Returns false when the editor is entirely scrolled out of view
    or otherwise hidden.
    */
    get inView() {
      return this.viewState.inView;
    }
    /**
    Indicates whether the user is currently composing text via
    [IME](https://en.wikipedia.org/wiki/Input_method), and at least
    one change has been made in the current composition.
    */
    get composing() {
      return !!this.inputState && this.inputState.composing > 0;
    }
    /**
    Indicates whether the user is currently in composing state. Note
    that on some platforms, like Android, this will be the case a
    lot, since just putting the cursor on a word starts a
    composition there.
    */
    get compositionStarted() {
      return !!this.inputState && this.inputState.composing >= 0;
    }
    /**
    The document or shadow root that the view lives in.
    */
    get root() {
      return this._root;
    }
    /**
    @internal
    */
    get win() {
      return this.dom.ownerDocument.defaultView || window;
    }
    /**
    Construct a new view. You'll want to either provide a `parent`
    option, or put `view.dom` into your document after creating a
    view, so that the user can see the editor.
    */
    constructor(config = {}) {
      var _a;
      this.plugins = [];
      this.pluginMap = new Map();
      this.editorAttrs = {};
      this.contentAttrs = {};
      this.bidiCache = [];
      this.destroyed = false;
      /**
      @internal
      */
      this.updateState = 2 /* UpdateState.Updating */;
      /**
      @internal
      */
      this.measureScheduled = -1;
      /**
      @internal
      */
      this.measureRequests = [];
      this.contentDOM = document.createElement("div");
      this.scrollDOM = document.createElement("div");
      this.scrollDOM.tabIndex = -1;
      this.scrollDOM.className = "cm-scroller";
      this.scrollDOM.appendChild(this.contentDOM);
      this.announceDOM = document.createElement("div");
      this.announceDOM.className = "cm-announced";
      this.announceDOM.setAttribute("aria-live", "polite");
      this.dom = document.createElement("div");
      this.dom.appendChild(this.announceDOM);
      this.dom.appendChild(this.scrollDOM);
      if (config.parent) config.parent.appendChild(this.dom);
      let {
        dispatch
      } = config;
      this.dispatchTransactions = config.dispatchTransactions || dispatch && (trs => trs.forEach(tr => dispatch(tr, this))) || (trs => this.update(trs));
      this.dispatch = this.dispatch.bind(this);
      this._root = config.root || getRoot(config.parent) || document;
      this.viewState = new ViewState(this, config.state || EditorState.create(config));
      if (config.scrollTo && config.scrollTo.is(scrollIntoView)) this.viewState.scrollTarget = config.scrollTo.value.clip(this.viewState.state);
      this.plugins = this.state.facet(viewPlugin).map(spec => new PluginInstance(spec));
      for (let plugin of this.plugins) plugin.update(this);
      this.observer = new DOMObserver(this);
      this.inputState = new InputState(this);
      this.inputState.ensureHandlers(this.plugins);
      this.docView = new DocView(this);
      this.mountStyles();
      this.updateAttrs();
      this.updateState = 0 /* UpdateState.Idle */;
      this.requestMeasure();
      if ((_a = document.fonts) === null || _a === void 0 ? void 0 : _a.ready) document.fonts.ready.then(() => {
        this.viewState.mustMeasureContent = "refresh";
        this.requestMeasure();
      });
    }
    dispatch(...input) {
      let trs = input.length == 1 && input[0] instanceof Transaction ? input : input.length == 1 && Array.isArray(input[0]) ? input[0] : [this.state.update(...input)];
      this.dispatchTransactions(trs, this);
    }
    /**
    Update the view for the given array of transactions. This will
    update the visible document and selection to match the state
    produced by the transactions, and notify view plugins of the
    change. You should usually call
    [`dispatch`](https://codemirror.net/6/docs/ref/#view.EditorView.dispatch) instead, which uses this
    as a primitive.
    */
    update(transactions) {
      if (this.updateState != 0 /* UpdateState.Idle */) throw new Error("Calls to EditorView.update are not allowed while an update is in progress");
      let redrawn = false,
        attrsChanged = false,
        update;
      let state = this.state;
      for (let tr of transactions) {
        if (tr.startState != state) throw new RangeError("Trying to update state with a transaction that doesn't start from the previous state.");
        state = tr.state;
      }
      if (this.destroyed) {
        this.viewState.state = state;
        return;
      }
      let focus = this.hasFocus,
        focusFlag = 0,
        dispatchFocus = null;
      if (transactions.some(tr => tr.annotation(isFocusChange))) {
        this.inputState.notifiedFocused = focus;
        // If a focus-change transaction is being dispatched, set this update flag.
        focusFlag = 1 /* UpdateFlag.Focus */;
      } else if (focus != this.inputState.notifiedFocused) {
        this.inputState.notifiedFocused = focus;
        // Schedule a separate focus transaction if necessary, otherwise
        // add a flag to this update
        dispatchFocus = focusChangeTransaction(state, focus);
        if (!dispatchFocus) focusFlag = 1 /* UpdateFlag.Focus */;
      }
      // If there was a pending DOM change, eagerly read it and try to
      // apply it after the given transactions.
      let pendingKey = this.observer.delayedAndroidKey,
        domChange = null;
      if (pendingKey) {
        this.observer.clearDelayedAndroidKey();
        domChange = this.observer.readChange();
        // Only try to apply DOM changes if the transactions didn't
        // change the doc or selection.
        if (domChange && !this.state.doc.eq(state.doc) || !this.state.selection.eq(state.selection)) domChange = null;
      } else {
        this.observer.clear();
      }
      // When the phrases change, redraw the editor
      if (state.facet(EditorState.phrases) != this.state.facet(EditorState.phrases)) return this.setState(state);
      update = ViewUpdate.create(this, state, transactions);
      update.flags |= focusFlag;
      let scrollTarget = this.viewState.scrollTarget;
      try {
        this.updateState = 2 /* UpdateState.Updating */;
        for (let tr of transactions) {
          if (scrollTarget) scrollTarget = scrollTarget.map(tr.changes);
          if (tr.scrollIntoView) {
            let {
              main
            } = tr.state.selection;
            let {
              x,
              y
            } = this.state.facet(EditorView.cursorScrollMargin);
            scrollTarget = new ScrollTarget(main.empty ? main : EditorSelection.cursor(main.head, main.head > main.anchor ? -1 : 1), "nearest", "nearest", y, x);
          }
          for (let e of tr.effects) if (e.is(scrollIntoView)) scrollTarget = e.value.clip(this.state);
        }
        this.viewState.update(update, scrollTarget);
        this.bidiCache = CachedOrder.update(this.bidiCache, update.changes);
        if (!update.empty) {
          this.updatePlugins(update);
          this.inputState.update(update);
        }
        redrawn = this.docView.update(update);
        if (this.state.facet(styleModule) != this.styleModules) this.mountStyles();
        attrsChanged = this.updateAttrs();
        this.showAnnouncements(transactions);
        this.docView.updateSelection(redrawn, transactions.some(tr => tr.isUserEvent("select.pointer")));
      } finally {
        this.updateState = 0 /* UpdateState.Idle */;
      }
      if (update.startState.facet(theme) != update.state.facet(theme)) this.viewState.mustMeasureContent = true;
      if (redrawn || attrsChanged || scrollTarget || this.viewState.mustEnforceCursorAssoc || this.viewState.mustMeasureContent) this.requestMeasure();
      if (redrawn) this.docViewUpdate();
      if (!update.empty) for (let listener of this.state.facet(updateListener)) {
        try {
          listener(update);
        } catch (e) {
          logException(this.state, e, "update listener");
        }
      }
      if (dispatchFocus || domChange) Promise.resolve().then(() => {
        if (dispatchFocus && this.state == dispatchFocus.startState) this.dispatch(dispatchFocus);
        if (domChange) {
          if (!applyDOMChange(this, domChange) && pendingKey.force) dispatchKey(this.contentDOM, pendingKey.key, pendingKey.keyCode);
        }
      });
    }
    /**
    Reset the view to the given state. (This will cause the entire
    document to be redrawn and all view plugins to be reinitialized,
    so you should probably only use it when the new state isn't
    derived from the old state. Otherwise, use
    [`dispatch`](https://codemirror.net/6/docs/ref/#view.EditorView.dispatch) instead.)
    */
    setState(newState) {
      if (this.updateState != 0 /* UpdateState.Idle */) throw new Error("Calls to EditorView.setState are not allowed while an update is in progress");
      if (this.destroyed) {
        this.viewState.state = newState;
        return;
      }
      this.updateState = 2 /* UpdateState.Updating */;
      let hadFocus = this.hasFocus;
      try {
        for (let plugin of this.plugins) plugin.destroy(this);
        this.viewState = new ViewState(this, newState);
        this.plugins = newState.facet(viewPlugin).map(spec => new PluginInstance(spec));
        this.pluginMap.clear();
        for (let plugin of this.plugins) plugin.update(this);
        this.docView.destroy();
        this.docView = new DocView(this);
        this.inputState.ensureHandlers(this.plugins);
        this.mountStyles();
        this.updateAttrs();
        this.bidiCache = [];
      } finally {
        this.updateState = 0 /* UpdateState.Idle */;
      }
      if (hadFocus) this.focus();
      this.requestMeasure();
    }
    updatePlugins(update) {
      let prevSpecs = update.startState.facet(viewPlugin),
        specs = update.state.facet(viewPlugin);
      if (prevSpecs != specs) {
        let newPlugins = [];
        for (let spec of specs) {
          let found = prevSpecs.indexOf(spec);
          if (found < 0) {
            newPlugins.push(new PluginInstance(spec));
          } else {
            let plugin = this.plugins[found];
            plugin.mustUpdate = update;
            newPlugins.push(plugin);
          }
        }
        for (let plugin of this.plugins) if (plugin.mustUpdate != update) plugin.destroy(this);
        this.plugins = newPlugins;
        this.pluginMap.clear();
      } else {
        for (let p of this.plugins) p.mustUpdate = update;
      }
      for (let i = 0; i < this.plugins.length; i++) this.plugins[i].update(this);
      if (prevSpecs != specs) this.inputState.ensureHandlers(this.plugins);
    }
    docViewUpdate() {
      for (let plugin of this.plugins) {
        let val = plugin.value;
        if (val && val.docViewUpdate) {
          try {
            val.docViewUpdate(this);
          } catch (e) {
            logException(this.state, e, "doc view update listener");
          }
        }
      }
    }
    /**
    @internal
    */
    measure(flush = true) {
      if (this.destroyed) return;
      if (this.measureScheduled > -1) this.win.cancelAnimationFrame(this.measureScheduled);
      if (this.observer.delayedAndroidKey) {
        this.measureScheduled = -1;
        this.requestMeasure();
        return;
      }
      this.measureScheduled = 0; // Prevent requestMeasure calls from scheduling another animation frame
      if (flush) this.observer.forceFlush();
      let updated = null;
      let scroll = this.viewState.scrollParent,
        scrollOffset = this.viewState.getScrollOffset();
      let {
        scrollAnchorPos,
        scrollAnchorHeight
      } = this.viewState;
      if (Math.abs(scrollOffset - this.viewState.scrollOffset) > 1) scrollAnchorHeight = -1;
      this.viewState.scrollAnchorHeight = -1;
      try {
        for (let i = 0;; i++) {
          if (scrollAnchorHeight < 0) {
            if (isScrolledToBottom(scroll || this.win)) {
              scrollAnchorPos = -1;
              scrollAnchorHeight = this.viewState.heightMap.height;
            } else {
              let block = this.viewState.scrollAnchorAt(scrollOffset);
              scrollAnchorPos = block.from;
              scrollAnchorHeight = block.top;
            }
          }
          this.updateState = 1 /* UpdateState.Measuring */;
          let changed = this.viewState.measure();
          if (!changed && !this.measureRequests.length && this.viewState.scrollTarget == null) break;
          if (i > 5) {
            console.warn(this.measureRequests.length ? "Measure loop restarted more than 5 times" : "Viewport failed to stabilize");
            break;
          }
          let measuring = [];
          // Only run measure requests in this cycle when the viewport didn't change
          if (!(changed & 4 /* UpdateFlag.Viewport */)) [this.measureRequests, measuring] = [measuring, this.measureRequests];
          let measured = measuring.map(m => {
            try {
              return m.read(this);
            } catch (e) {
              logException(this.state, e);
              return BadMeasure;
            }
          });
          let update = ViewUpdate.create(this, this.state, []),
            redrawn = false;
          update.flags |= changed;
          if (!updated) updated = update;else updated.flags |= changed;
          this.updateState = 2 /* UpdateState.Updating */;
          if (!update.empty) {
            this.updatePlugins(update);
            this.inputState.update(update);
            this.updateAttrs();
            redrawn = this.docView.update(update);
            if (redrawn) this.docViewUpdate();
          }
          for (let i = 0; i < measuring.length; i++) if (measured[i] != BadMeasure) {
            try {
              let m = measuring[i];
              if (m.write) m.write(measured[i], this);
            } catch (e) {
              logException(this.state, e);
            }
          }
          if (redrawn) this.docView.updateSelection(true);
          if (!update.viewportChanged && this.measureRequests.length == 0) {
            if (this.viewState.editorHeight) {
              if (this.viewState.scrollTarget) {
                this.docView.scrollIntoView(this.viewState.scrollTarget);
                this.viewState.scrollTarget = null;
                scrollAnchorHeight = -1;
                continue;
              } else {
                let newAnchorHeight = scrollAnchorPos < 0 ? this.viewState.heightMap.height : this.viewState.lineBlockAt(scrollAnchorPos).top;
                let diff = (newAnchorHeight - scrollAnchorHeight) / this.scaleY;
                if ((diff > 1 || diff < -1) && (scroll == this.scrollDOM || this.hasFocus || Math.max(this.inputState.lastWheelEvent, this.inputState.lastTouchTime) > Date.now() - 100)) {
                  scrollOffset = scrollOffset + diff;
                  if (scroll) scroll.scrollTop += diff;else this.win.scrollBy(0, diff);
                  scrollAnchorHeight = -1;
                  continue;
                }
              }
            }
            break;
          }
        }
      } finally {
        this.updateState = 0 /* UpdateState.Idle */;
        this.measureScheduled = -1;
      }
      if (updated && !updated.empty) for (let listener of this.state.facet(updateListener)) listener(updated);
    }
    /**
    Get the CSS classes for the currently active editor themes.
    */
    get themeClasses() {
      return baseThemeID + " " + (this.state.facet(darkTheme) ? baseDarkID : baseLightID) + " " + this.state.facet(theme);
    }
    updateAttrs() {
      let editorAttrs = attrsFromFacet(this, editorAttributes, {
        class: "cm-editor" + (this.hasFocus ? " cm-focused " : " ") + this.themeClasses
      });
      let contentAttrs = {
        spellcheck: "false",
        autocorrect: "off",
        autocapitalize: "off",
        writingsuggestions: "false",
        translate: "no",
        contenteditable: !this.state.facet(editable) ? "false" : "true",
        class: "cm-content",
        style: `${browser.tabSize}: ${this.state.tabSize}`,
        role: "textbox",
        "aria-multiline": "true"
      };
      if (this.state.readOnly) contentAttrs["aria-readonly"] = "true";
      attrsFromFacet(this, contentAttributes, contentAttrs);
      let changed = this.observer.ignore(() => {
        let changedContent = updateAttrs(this.contentDOM, this.contentAttrs, contentAttrs);
        let changedEditor = updateAttrs(this.dom, this.editorAttrs, editorAttrs);
        return changedContent || changedEditor;
      });
      this.editorAttrs = editorAttrs;
      this.contentAttrs = contentAttrs;
      return changed;
    }
    showAnnouncements(trs) {
      let first = true;
      for (let tr of trs) for (let effect of tr.effects) if (effect.is(EditorView.announce)) {
        if (first) this.announceDOM.textContent = "";
        first = false;
        let div = this.announceDOM.appendChild(document.createElement("div"));
        div.textContent = effect.value;
      }
    }
    mountStyles() {
      this.styleModules = this.state.facet(styleModule);
      let nonce = this.state.facet(EditorView.cspNonce);
      StyleModule.mount(this.root, this.styleModules.concat(baseTheme$1).reverse(), nonce ? {
        nonce
      } : undefined);
    }
    readMeasured() {
      if (this.updateState == 2 /* UpdateState.Updating */) throw new Error("Reading the editor layout isn't allowed during an update");
      if (this.updateState == 0 /* UpdateState.Idle */ && this.measureScheduled > -1) this.measure(false);
    }
    /**
    Schedule a layout measurement, optionally providing callbacks to
    do custom DOM measuring followed by a DOM write phase. Using
    this is preferable reading DOM layout directly from, for
    example, an event handler, because it'll make sure measuring and
    drawing done by other components is synchronized, avoiding
    unnecessary DOM layout computations.
    */
    requestMeasure(request) {
      if (this.measureScheduled < 0) this.measureScheduled = this.win.requestAnimationFrame(() => this.measure());
      if (request) {
        if (this.measureRequests.indexOf(request) > -1) return;
        if (request.key != null) for (let i = 0; i < this.measureRequests.length; i++) {
          if (this.measureRequests[i].key === request.key) {
            this.measureRequests[i] = request;
            return;
          }
        }
        this.measureRequests.push(request);
      }
    }
    /**
    Get the value of a specific plugin, if present. Note that
    plugins that crash can be dropped from a view, so even when you
    know you registered a given plugin, it is recommended to check
    the return value of this method.
    */
    plugin(plugin) {
      let known = this.pluginMap.get(plugin);
      if (known === undefined || known && known.plugin != plugin) this.pluginMap.set(plugin, known = this.plugins.find(p => p.plugin == plugin) || null);
      return known && known.update(this).value;
    }
    /**
    The top position of the document, in screen coordinates. This
    may be negative when the editor is scrolled down. Points
    directly to the top of the first line, not above the padding.
    */
    get documentTop() {
      return this.contentDOM.getBoundingClientRect().top + this.viewState.paddingTop;
    }
    /**
    Reports the padding above and below the document.
    */
    get documentPadding() {
      return {
        top: this.viewState.paddingTop,
        bottom: this.viewState.paddingBottom
      };
    }
    /**
    If the editor is transformed with CSS, this provides the scale
    along the X axis. Otherwise, it will just be 1. Note that
    transforms other than translation and scaling are not supported.
    */
    get scaleX() {
      return this.viewState.scaleX;
    }
    /**
    Provide the CSS transformed scale along the Y axis.
    */
    get scaleY() {
      return this.viewState.scaleY;
    }
    /**
    Find the text line or block widget at the given vertical
    position (which is interpreted as relative to the [top of the
    document](https://codemirror.net/6/docs/ref/#view.EditorView.documentTop)).
    */
    elementAtHeight(height) {
      this.readMeasured();
      return this.viewState.elementAtHeight(height);
    }
    /**
    Find the line block (see
    [`lineBlockAt`](https://codemirror.net/6/docs/ref/#view.EditorView.lineBlockAt)) at the given
    height, again interpreted relative to the [top of the
    document](https://codemirror.net/6/docs/ref/#view.EditorView.documentTop).
    */
    lineBlockAtHeight(height) {
      this.readMeasured();
      return this.viewState.lineBlockAtHeight(height);
    }
    /**
    Get the extent and vertical position of all [line
    blocks](https://codemirror.net/6/docs/ref/#view.EditorView.lineBlockAt) in the viewport. Positions
    are relative to the [top of the
    document](https://codemirror.net/6/docs/ref/#view.EditorView.documentTop);
    */
    get viewportLineBlocks() {
      return this.viewState.viewportLines;
    }
    /**
    Find the line block around the given document position. A line
    block is a range delimited on both sides by either a
    non-[hidden](https://codemirror.net/6/docs/ref/#view.Decoration^replace) line break, or the
    start/end of the document. It will usually just hold a line of
    text, but may be broken into multiple textblocks by block
    widgets.
    */
    lineBlockAt(pos) {
      return this.viewState.lineBlockAt(pos);
    }
    /**
    The editor's total content height.
    */
    get contentHeight() {
      return this.viewState.contentHeight;
    }
    /**
    Move a cursor position by [grapheme
    cluster](https://codemirror.net/6/docs/ref/#state.findClusterBreak). `forward` determines whether
    the motion is away from the line start, or towards it. In
    bidirectional text, the line is traversed in visual order, using
    the editor's [text direction](https://codemirror.net/6/docs/ref/#view.EditorView.textDirection).
    When the start position was the last one on the line, the
    returned position will be across the line break. If there is no
    further line, the original position is returned.
    
    By default, this method moves over a single cluster. The
    optional `by` argument can be used to move across more. It will
    be called with the first cluster as argument, and should return
    a predicate that determines, for each subsequent cluster,
    whether it should also be moved over.
    */
    moveByChar(start, forward, by) {
      return skipAtoms(this, start, moveByChar(this, start, forward, by));
    }
    /**
    Move a cursor position across the next group of either
    [letters](https://codemirror.net/6/docs/ref/#state.EditorState.charCategorizer) or non-letter
    non-whitespace characters.
    */
    moveByGroup(start, forward) {
      return skipAtoms(this, start, moveByChar(this, start, forward, initial => byGroup(this, start.head, initial)));
    }
    /**
    Get the cursor position visually at the start or end of a line.
    Note that this may differ from the _logical_ position at its
    start or end (which is simply at `line.from`/`line.to`) if text
    at the start or end goes against the line's base text direction.
    */
    visualLineSide(line, end) {
      let order = this.bidiSpans(line),
        dir = this.textDirectionAt(line.from);
      let span = order[end ? order.length - 1 : 0];
      return EditorSelection.cursor(span.side(end, dir) + line.from, span.forward(!end, dir) ? 1 : -1);
    }
    /**
    Move to the next line boundary in the given direction. If
    `includeWrap` is true, line wrapping is on, and there is a
    further wrap point on the current line, the wrap point will be
    returned. Otherwise this function will return the start or end
    of the line.
    */
    moveToLineBoundary(start, forward, includeWrap = true) {
      return moveToLineBoundary(this, start, forward, includeWrap);
    }
    /**
    Move a cursor position vertically. When `distance` isn't given,
    it defaults to moving to the next line (including wrapped
    lines). Otherwise, `distance` should provide a positive distance
    in pixels.
    
    When `start` has a
    [`goalColumn`](https://codemirror.net/6/docs/ref/#state.SelectionRange.goalColumn), the vertical
    motion will use that as a target horizontal position. Otherwise,
    the cursor's own horizontal position is used. The returned
    cursor will have its goal column set to whichever column was
    used.
    */
    moveVertically(start, forward, distance) {
      return skipAtoms(this, start, moveVertically(this, start, forward, distance));
    }
    /**
    Find the DOM parent node and offset (child offset if `node` is
    an element, character offset when it is a text node) at the
    given document position.
    
    Note that for positions that aren't currently in
    `visibleRanges`, the resulting DOM position isn't necessarily
    meaningful (it may just point before or after a placeholder
    element).
    */
    domAtPos(pos, side = 1) {
      return this.docView.domAtPos(pos, side);
    }
    /**
    Find the document position at the given DOM node. Can be useful
    for associating positions with DOM events. Will raise an error
    when `node` isn't part of the editor content.
    */
    posAtDOM(node, offset = 0) {
      return this.docView.posFromDOM(node, offset);
    }
    posAtCoords(coords, precise = true) {
      this.readMeasured();
      let found = posAtCoords(this, coords, precise);
      return found && found.pos;
    }
    posAndSideAtCoords(coords, precise = true) {
      this.readMeasured();
      return posAtCoords(this, coords, precise);
    }
    /**
    Get the screen coordinates at the given document position.
    `side` determines whether the coordinates are based on the
    element before (-1) or after (1) the position (if no element is
    available on the given side, the method will transparently use
    another strategy to get reasonable coordinates).
    */
    coordsAtPos(pos, side = 1) {
      this.readMeasured();
      let rect = this.docView.coordsAt(pos, side);
      if (!rect || rect.left == rect.right) return rect;
      let line = this.state.doc.lineAt(pos),
        order = this.bidiSpans(line);
      let span = order[BidiSpan.find(order, pos - line.from, -1, side)];
      return flattenRect(rect, span.dir == Direction.LTR == side > 0);
    }
    /**
    Return the rectangle around a given character. If `pos` does not
    point in front of a character that is in the viewport and
    rendered (i.e. not replaced, not a line break), this will return
    null. For space characters that are a line wrap point, this will
    return the position before the line break.
    */
    coordsForChar(pos) {
      this.readMeasured();
      return this.docView.coordsForChar(pos);
    }
    /**
    The default width of a character in the editor. May not
    accurately reflect the width of all characters (given variable
    width fonts or styling of invididual ranges).
    */
    get defaultCharacterWidth() {
      return this.viewState.heightOracle.charWidth;
    }
    /**
    The default height of a line in the editor. May not be accurate
    for all lines.
    */
    get defaultLineHeight() {
      return this.viewState.heightOracle.lineHeight;
    }
    /**
    The text direction
    ([`direction`](https://developer.mozilla.org/en-US/docs/Web/CSS/direction)
    CSS property) of the editor's content element.
    */
    get textDirection() {
      return this.viewState.defaultTextDirection;
    }
    /**
    Find the text direction of the block at the given position, as
    assigned by CSS. If
    [`perLineTextDirection`](https://codemirror.net/6/docs/ref/#view.EditorView^perLineTextDirection)
    isn't enabled, or the given position is outside of the viewport,
    this will always return the same as
    [`textDirection`](https://codemirror.net/6/docs/ref/#view.EditorView.textDirection). Note that
    this may trigger a DOM layout.
    */
    textDirectionAt(pos) {
      let perLine = this.state.facet(perLineTextDirection);
      if (!perLine || pos < this.viewport.from || pos > this.viewport.to) return this.textDirection;
      this.readMeasured();
      return this.docView.textDirectionAt(pos);
    }
    /**
    Whether this editor [wraps lines](https://codemirror.net/6/docs/ref/#view.EditorView.lineWrapping)
    (as determined by the
    [`white-space`](https://developer.mozilla.org/en-US/docs/Web/CSS/white-space)
    CSS property of its content element).
    */
    get lineWrapping() {
      return this.viewState.heightOracle.lineWrapping;
    }
    /**
    Returns the bidirectional text structure of the given line
    (which should be in the current document) as an array of span
    objects. The order of these spans matches the [text
    direction](https://codemirror.net/6/docs/ref/#view.EditorView.textDirection)—if that is
    left-to-right, the leftmost spans come first, otherwise the
    rightmost spans come first.
    */
    bidiSpans(line) {
      if (line.length > MaxBidiLine) return trivialOrder(line.length);
      let dir = this.textDirectionAt(line.from),
        isolates;
      for (let entry of this.bidiCache) {
        if (entry.from == line.from && entry.dir == dir && (entry.fresh || isolatesEq(entry.isolates, isolates = getIsolatedRanges(this, line)))) return entry.order;
      }
      if (!isolates) isolates = getIsolatedRanges(this, line);
      let order = computeOrder(line.text, dir, isolates);
      this.bidiCache.push(new CachedOrder(line.from, line.to, dir, isolates, true, order));
      return order;
    }
    /**
    Check whether the editor has focus.
    */
    get hasFocus() {
      var _a;
      // Safari return false for hasFocus when the context menu is open
      // or closing, which leads us to ignore selection changes from the
      // context menu because it looks like the editor isn't focused.
      // This kludges around that.
      return (this.dom.ownerDocument.hasFocus() || browser.safari && ((_a = this.inputState) === null || _a === void 0 ? void 0 : _a.lastContextMenu) > Date.now() - 3e4) && this.root.activeElement == this.contentDOM;
    }
    /**
    Put focus on the editor.
    */
    focus() {
      this.observer.ignore(() => {
        focusPreventScroll(this.contentDOM);
        this.docView.updateSelection();
      });
    }
    /**
    Update the [root](https://codemirror.net/6/docs/ref/##view.EditorViewConfig.root) in which the editor lives. This is only
    necessary when moving the editor's existing DOM to a new window or shadow root.
    */
    setRoot(root) {
      if (this._root != root) {
        this._root = root;
        this.observer.setWindow((root.nodeType == 9 ? root : root.ownerDocument).defaultView || window);
        this.mountStyles();
      }
    }
    /**
    Clean up this editor view, removing its element from the
    document, unregistering event handlers, and notifying
    plugins. The view instance can no longer be used after
    calling this.
    */
    destroy() {
      if (this.root.activeElement == this.contentDOM) this.contentDOM.blur();
      for (let plugin of this.plugins) plugin.destroy(this);
      this.plugins = [];
      this.inputState.destroy();
      this.docView.destroy();
      this.dom.remove();
      this.observer.destroy();
      if (this.measureScheduled > -1) this.win.cancelAnimationFrame(this.measureScheduled);
      this.destroyed = true;
    }
    /**
    Returns an effect that can be
    [added](https://codemirror.net/6/docs/ref/#state.TransactionSpec.effects) to a transaction to
    cause it to scroll the given position or range into view.
    */
    static scrollIntoView(pos, options = {}) {
      var _a, _b, _c, _d;
      return scrollIntoView.of(new ScrollTarget(typeof pos == "number" ? EditorSelection.cursor(pos) : pos, (_a = options.y) !== null && _a !== void 0 ? _a : "nearest", (_b = options.x) !== null && _b !== void 0 ? _b : "nearest", (_c = options.yMargin) !== null && _c !== void 0 ? _c : 5, (_d = options.xMargin) !== null && _d !== void 0 ? _d : 5));
    }
    /**
    Return an effect that resets the editor to its current (at the
    time this method was called) scroll position. Note that this
    only affects the editor's own scrollable element, not parents.
    See also
    [`EditorViewConfig.scrollTo`](https://codemirror.net/6/docs/ref/#view.EditorViewConfig.scrollTo).
    
    The effect should be used with a document identical to the one
    it was created for. Failing to do so is not an error, but may
    not scroll to the expected position. You can
    [map](https://codemirror.net/6/docs/ref/#state.StateEffect.map) the effect to account for changes.
    */
    scrollSnapshot() {
      let {
        scrollTop,
        scrollLeft
      } = this.scrollDOM;
      let ref = this.viewState.scrollAnchorAt(scrollTop);
      return scrollIntoView.of(new ScrollTarget(EditorSelection.cursor(ref.from), "start", "start", ref.top - scrollTop, scrollLeft, true));
    }
    /**
    Enable or disable tab-focus mode, which disables key bindings
    for Tab and Shift-Tab, letting the browser's default
    focus-changing behavior go through instead. This is useful to
    prevent trapping keyboard users in your editor.
    
    Without argument, this toggles the mode. With a boolean, it
    enables (true) or disables it (false). Given a number, it
    temporarily enables the mode until that number of milliseconds
    have passed or another non-Tab key is pressed.
    */
    setTabFocusMode(to) {
      if (to == null) this.inputState.tabFocusMode = this.inputState.tabFocusMode < 0 ? 0 : -1;else if (typeof to == "boolean") this.inputState.tabFocusMode = to ? 0 : -1;else if (this.inputState.tabFocusMode != 0) this.inputState.tabFocusMode = Date.now() + to;
    }
    /**
    Returns an extension that can be used to add DOM event handlers.
    The value should be an object mapping event names to handler
    functions. For any given event, such functions are ordered by
    extension precedence, and the first handler to return true will
    be assumed to have handled that event, and no other handlers or
    built-in behavior will be activated for it. These are registered
    on the [content element](https://codemirror.net/6/docs/ref/#view.EditorView.contentDOM), except
    for `scroll` handlers, which will be called any time the
    editor's [scroll element](https://codemirror.net/6/docs/ref/#view.EditorView.scrollDOM) or one of
    its parent nodes is scrolled.
    */
    static domEventHandlers(handlers) {
      return ViewPlugin.define(() => ({}), {
        eventHandlers: handlers
      });
    }
    /**
    Create an extension that registers DOM event observers. Contrary
    to event [handlers](https://codemirror.net/6/docs/ref/#view.EditorView^domEventHandlers),
    observers can't be prevented from running by a higher-precedence
    handler returning true. They also don't prevent other handlers
    and observers from running when they return true, and should not
    call `preventDefault`.
    */
    static domEventObservers(observers) {
      return ViewPlugin.define(() => ({}), {
        eventObservers: observers
      });
    }
    /**
    Create a theme extension. The first argument can be a
    [`style-mod`](https://code.haverbeke.berlin/marijn/style-mod#documentation)
    style spec providing the styles for the theme. These will be
    prefixed with a generated class for the style.
    
    Because the selectors will be prefixed with a scope class, rule
    that directly match the editor's [wrapper
    element](https://codemirror.net/6/docs/ref/#view.EditorView.dom)—to which the scope class will be
    added—need to be explicitly differentiated by adding an `&` to
    the selector for that element—for example
    `&.cm-focused`.
    
    When `dark` is set to true, the theme will be marked as dark,
    which will cause the `&dark` rules from [base
    themes](https://codemirror.net/6/docs/ref/#view.EditorView^baseTheme) to be used (as opposed to
    `&light` when a light theme is active).
    */
    static theme(spec, options) {
      let prefix = StyleModule.newName();
      let result = [theme.of(prefix), styleModule.of(buildTheme(`.${prefix}`, spec))];
      if (options && options.dark) result.push(darkTheme.of(true));
      return result;
    }
    /**
    Create an extension that adds styles to the base theme. Like
    with [`theme`](https://codemirror.net/6/docs/ref/#view.EditorView^theme), use `&` to indicate the
    place of the editor wrapper element when directly targeting
    that. You can also use `&dark` or `&light` instead to only
    target editors with a dark or light theme.
    */
    static baseTheme(spec) {
      return Prec.lowest(styleModule.of(buildTheme("." + baseThemeID, spec, lightDarkIDs)));
    }
    /**
    Retrieve an editor view instance from the view's DOM
    representation.
    */
    static findFromDOM(dom) {
      var _a;
      let content = dom.querySelector(".cm-content");
      let tile = content && Tile.get(content) || Tile.get(dom);
      return ((_a = tile === null || tile === void 0 ? void 0 : tile.root) === null || _a === void 0 ? void 0 : _a.view) || null;
    }
  }
  /**
  Facet to add a [style
  module](https://code.haverbeke.berlin/marijn/style-mod#documentation) to
  an editor view. The view will ensure that the module is
  mounted in its [document
  root](https://codemirror.net/6/docs/ref/#view.EditorView.constructor^config.root).
  */
  EditorView.styleModule = styleModule;
  /**
  An input handler can override the way changes to the editable
  DOM content are handled. Handlers are passed the document
  positions between which the change was found, and the new
  content. When one returns true, no further input handlers are
  called and the default behavior is prevented.

  The `insert` argument can be used to get the default transaction
  that would be applied for this input. This can be useful when
  dispatching the custom behavior as a separate transaction.
  */
  EditorView.inputHandler = inputHandler;
  /**
  Functions provided in this facet will be used to transform text
  pasted or dropped into the editor.
  */
  EditorView.clipboardInputFilter = clipboardInputFilter;
  /**
  Transform text copied or dragged from the editor.
  */
  EditorView.clipboardOutputFilter = clipboardOutputFilter;
  /**
  Scroll handlers can override how things are scrolled into view.
  If they return `true`, no further handling happens for the
  scrolling. If they return false, the default scroll behavior is
  applied. Scroll handlers should never initiate editor updates.
  */
  EditorView.scrollHandler = scrollHandler;
  /**
  This facet can be used to provide functions that create effects
  to be dispatched when the editor's focus state changes.
  */
  EditorView.focusChangeEffect = focusChangeEffect;
  /**
  By default, the editor assumes all its content has the same
  [text direction](https://codemirror.net/6/docs/ref/#view.Direction). Configure this with a `true`
  value to make it read the text direction of every (rendered)
  line separately.
  */
  EditorView.perLineTextDirection = perLineTextDirection;
  /**
  Allows you to provide a function that should be called when the
  library catches an exception from an extension (mostly from view
  plugins, but may be used by other extensions to route exceptions
  from user-code-provided callbacks). This is mostly useful for
  debugging and logging. See [`logException`](https://codemirror.net/6/docs/ref/#view.logException).
  */
  EditorView.exceptionSink = exceptionSink;
  /**
  A facet that can be used to register a function to be called
  every time the view updates.
  */
  EditorView.updateListener = updateListener;
  /**
  Facet that controls whether the editor content DOM is editable.
  When its highest-precedence value is `false`, the element will
  not have its `contenteditable` attribute set. (Note that this
  doesn't affect API calls that change the editor content, even
  when those are bound to keys or buttons. See the
  [`readOnly`](https://codemirror.net/6/docs/ref/#state.EditorState.readOnly) facet for that.)
  */
  EditorView.editable = editable;
  /**
  Allows you to influence the way mouse selection happens. The
  functions in this facet will be called for a `mousedown` event
  on the editor, and can return an object that overrides the way a
  selection is computed from that mouse click or drag.
  */
  EditorView.mouseSelectionStyle = mouseSelectionStyle;
  /**
  Facet used to configure whether a given selection drag event
  should move or copy the selection. The given predicate will be
  called with the `mousedown` event, and can return `true` when
  the drag should move the content.
  */
  EditorView.dragMovesSelection = dragMovesSelection$1;
  /**
  Facet used to configure whether a given selecting click adds a
  new range to the existing selection or replaces it entirely. The
  default behavior is to check `event.metaKey` on macOS, and
  `event.ctrlKey` elsewhere.
  */
  EditorView.clickAddsSelectionRange = clickAddsSelectionRange;
  /**
  A facet that determines which [decorations](https://codemirror.net/6/docs/ref/#view.Decoration)
  are shown in the view. Decorations can be provided in two
  ways—directly, or via a function that takes an editor view.

  Only decoration sets provided directly are allowed to influence
  the editor's vertical layout structure. The ones provided as
  functions are called _after_ the new viewport has been computed,
  and thus **must not** introduce block widgets or replacing
  decorations that cover line breaks.

  If you want decorated ranges to behave like atomic units for
  cursor motion and deletion purposes, also provide the range set
  containing the decorations to
  [`EditorView.atomicRanges`](https://codemirror.net/6/docs/ref/#view.EditorView^atomicRanges).
  */
  EditorView.decorations = decorations;
  /**
  [Block wrappers](https://codemirror.net/6/docs/ref/#view.BlockWrapper) provide a way to add DOM
  structure around editor lines and block widgets. Sets of
  wrappers are provided in a similar way to decorations, and are
  nested in a similar way when they overlap. A wrapper affects all
  lines and block widgets that start inside its range.
  */
  EditorView.blockWrappers = blockWrappers;
  /**
  Facet that works much like
  [`decorations`](https://codemirror.net/6/docs/ref/#view.EditorView^decorations), but puts its
  inputs at the very bottom of the precedence stack, meaning mark
  decorations provided here will only be split by other, partially
  overlapping `outerDecorations` ranges, and wrap around all
  regular decorations. Use this for mark elements that should, as
  much as possible, remain in one piece.
  */
  EditorView.outerDecorations = outerDecorations;
  /**
  Used to provide ranges that should be treated as atoms as far as
  cursor motion is concerned. This causes methods like
  [`moveByChar`](https://codemirror.net/6/docs/ref/#view.EditorView.moveByChar) and
  [`moveVertically`](https://codemirror.net/6/docs/ref/#view.EditorView.moveVertically) (and the
  commands built on top of them) to skip across such regions when
  a selection endpoint would enter them. This does _not_ prevent
  direct programmatic [selection
  updates](https://codemirror.net/6/docs/ref/#state.TransactionSpec.selection) from moving into such
  regions.
  */
  EditorView.atomicRanges = atomicRanges;
  /**
  When range decorations add a `unicode-bidi: isolate` style, they
  should also include a
  [`bidiIsolate`](https://codemirror.net/6/docs/ref/#view.MarkDecorationSpec.bidiIsolate) property
  in their decoration spec, and be exposed through this facet, so
  that the editor can compute the proper text order. (Other values
  for `unicode-bidi`, except of course `normal`, are not
  supported.)
  */
  EditorView.bidiIsolatedRanges = bidiIsolatedRanges;
  /**
  Can be used to specify the distance that scrolling cursor into
  view keeps it away from the sides of the editor, either as a
  single pixel number or two different values for the different
  axes. Defaults to 5 pixels on both axes.
  */
  EditorView.cursorScrollMargin = /*@__PURE__*/Facet.define({
    combine: inputs => {
      let x = 5,
        y = 5;
      for (let i of inputs) {
        if (typeof i == "number") x = y = i;else ({
          x,
          y
        } = i);
      }
      return {
        x,
        y
      };
    }
  });
  /**
  Facet that allows extensions to provide additional scroll
  margins (space around the sides of the scrolling element that
  should be considered invisible). This can be useful when the
  plugin introduces elements that cover part of that element (for
  example a horizontally fixed gutter). Not to be confused with
  [`cursorScrollMargin`](https://codemirror.net/6/docs/ref/#view.EditorView^cursorScrollMargin).
  */
  EditorView.scrollMargins = scrollMargins;
  /**
  This facet records whether a dark theme is active. The extension
  returned by [`theme`](https://codemirror.net/6/docs/ref/#view.EditorView^theme) automatically
  includes an instance of this when the `dark` option is set to
  true.
  */
  EditorView.darkTheme = darkTheme;
  /**
  Provides a Content Security Policy nonce to use when creating
  the style sheets for the editor. Holds the empty string when no
  nonce has been provided.
  */
  EditorView.cspNonce = /*@__PURE__*/Facet.define({
    combine: values => values.length ? values[0] : ""
  });
  /**
  Facet that provides additional DOM attributes for the editor's
  editable DOM element.
  */
  EditorView.contentAttributes = contentAttributes;
  /**
  Facet that provides DOM attributes for the editor's outer
  element.
  */
  EditorView.editorAttributes = editorAttributes;
  /**
  An extension that enables line wrapping in the editor (by
  setting CSS `white-space` to `pre-wrap` in the content).
  */
  EditorView.lineWrapping = /*@__PURE__*/EditorView.contentAttributes.of({
    "class": "cm-lineWrapping"
  });
  /**
  State effect used to include screen reader announcements in a
  transaction. These will be added to the DOM in a visually hidden
  element with `aria-live="polite"` set, and should be used to
  describe effects that are visually obvious but may not be
  noticed by screen reader users (such as moving to the next
  search match).
  */
  EditorView.announce = /*@__PURE__*/StateEffect.define();
  // Maximum line length for which we compute accurate bidi info
  const MaxBidiLine = 4096;
  const BadMeasure = {};
  class CachedOrder {
    constructor(from, to, dir, isolates, fresh, order) {
      this.from = from;
      this.to = to;
      this.dir = dir;
      this.isolates = isolates;
      this.fresh = fresh;
      this.order = order;
    }
    static update(cache, changes) {
      if (changes.empty && !cache.some(c => c.fresh)) return cache;
      let result = [],
        lastDir = cache.length ? cache[cache.length - 1].dir : Direction.LTR;
      for (let i = Math.max(0, cache.length - 10); i < cache.length; i++) {
        let entry = cache[i];
        if (entry.dir == lastDir && !changes.touchesRange(entry.from, entry.to)) result.push(new CachedOrder(changes.mapPos(entry.from, 1), changes.mapPos(entry.to, -1), entry.dir, entry.isolates, false, entry.order));
      }
      return result;
    }
  }
  function attrsFromFacet(view, facet, base) {
    for (let sources = view.state.facet(facet), i = sources.length - 1; i >= 0; i--) {
      let source = sources[i],
        value = typeof source == "function" ? source(view) : source;
      if (value) combineAttrs(value, base);
    }
    return base;
  }
  const Outside = "-10000px";
  class TooltipViewManager {
    constructor(view, facet, createTooltipView, removeTooltipView) {
      this.facet = facet;
      this.createTooltipView = createTooltipView;
      this.removeTooltipView = removeTooltipView;
      this.input = view.state.facet(facet);
      this.tooltips = this.input.filter(t => t);
      let prev = null;
      this.tooltipViews = this.tooltips.map(t => prev = createTooltipView(t, prev));
    }
    update(update, above) {
      var _a;
      let input = update.state.facet(this.facet);
      let tooltips = input.filter(x => x);
      if (input === this.input) {
        for (let t of this.tooltipViews) if (t.update) t.update(update);
        return false;
      }
      let tooltipViews = [],
        newAbove = above ? [] : null;
      for (let i = 0; i < tooltips.length; i++) {
        let tip = tooltips[i],
          known = -1;
        if (!tip) continue;
        for (let i = 0; i < this.tooltips.length; i++) {
          let other = this.tooltips[i];
          if (other && other.create == tip.create) known = i;
        }
        if (known < 0) {
          tooltipViews[i] = this.createTooltipView(tip, i ? tooltipViews[i - 1] : null);
          if (newAbove) newAbove[i] = !!tip.above;
        } else {
          let tooltipView = tooltipViews[i] = this.tooltipViews[known];
          if (newAbove) newAbove[i] = above[known];
          if (tooltipView.update) tooltipView.update(update);
        }
      }
      for (let t of this.tooltipViews) if (tooltipViews.indexOf(t) < 0) {
        this.removeTooltipView(t);
        (_a = t.destroy) === null || _a === void 0 ? void 0 : _a.call(t);
      }
      if (above) {
        newAbove.forEach((val, i) => above[i] = val);
        above.length = newAbove.length;
      }
      this.input = input;
      this.tooltips = tooltips;
      this.tooltipViews = tooltipViews;
      return true;
    }
  }
  function windowSpace(view) {
    let docElt = view.dom.ownerDocument.documentElement;
    return {
      top: 0,
      left: 0,
      bottom: docElt.clientHeight,
      right: docElt.clientWidth
    };
  }
  const tooltipConfig = /*@__PURE__*/Facet.define({
    combine: values => {
      var _a, _b, _c;
      return {
        position: browser.ios ? "absolute" : ((_a = values.find(conf => conf.position)) === null || _a === void 0 ? void 0 : _a.position) || "fixed",
        parent: ((_b = values.find(conf => conf.parent)) === null || _b === void 0 ? void 0 : _b.parent) || null,
        tooltipSpace: ((_c = values.find(conf => conf.tooltipSpace)) === null || _c === void 0 ? void 0 : _c.tooltipSpace) || windowSpace
      };
    }
  });
  const knownHeight = /*@__PURE__*/new WeakMap();
  const tooltipPlugin = /*@__PURE__*/ViewPlugin.fromClass(class {
    constructor(view) {
      this.view = view;
      this.above = [];
      this.inView = true;
      this.madeAbsolute = false;
      this.lastTransaction = 0;
      this.measureTimeout = -1;
      let config = view.state.facet(tooltipConfig);
      this.position = config.position;
      this.parent = config.parent;
      this.classes = view.themeClasses;
      this.createContainer();
      this.measureReq = {
        read: this.readMeasure.bind(this),
        write: this.writeMeasure.bind(this),
        key: this
      };
      this.resizeObserver = typeof ResizeObserver == "function" ? new ResizeObserver(() => this.measureSoon()) : null;
      this.manager = new TooltipViewManager(view, showTooltip, (t, p) => this.createTooltip(t, p), t => {
        if (this.resizeObserver) this.resizeObserver.unobserve(t.dom);
        t.dom.remove();
      });
      this.above = this.manager.tooltips.map(t => !!t.above);
      this.intersectionObserver = typeof IntersectionObserver == "function" ? new IntersectionObserver(entries => {
        if (Date.now() > this.lastTransaction - 50 && entries.length > 0 && entries[entries.length - 1].intersectionRatio < 1) this.measureSoon();
      }, {
        threshold: [1]
      }) : null;
      this.observeIntersection();
      view.win.addEventListener("resize", this.measureSoon = this.measureSoon.bind(this));
      this.maybeMeasure();
    }
    createContainer() {
      if (this.parent) {
        this.container = document.createElement("div");
        this.container.style.position = "relative";
        this.container.className = this.view.themeClasses;
        this.parent.appendChild(this.container);
      } else {
        this.container = this.view.dom;
      }
    }
    observeIntersection() {
      if (this.intersectionObserver) {
        this.intersectionObserver.disconnect();
        for (let tooltip of this.manager.tooltipViews) this.intersectionObserver.observe(tooltip.dom);
      }
    }
    measureSoon() {
      if (this.measureTimeout < 0) this.measureTimeout = setTimeout(() => {
        this.measureTimeout = -1;
        this.maybeMeasure();
      }, 50);
    }
    update(update) {
      if (update.transactions.length) this.lastTransaction = Date.now();
      let updated = this.manager.update(update, this.above);
      if (updated) this.observeIntersection();
      let shouldMeasure = updated || update.geometryChanged;
      let newConfig = update.state.facet(tooltipConfig);
      if (newConfig.position != this.position && !this.madeAbsolute) {
        this.position = newConfig.position;
        for (let t of this.manager.tooltipViews) t.dom.style.position = this.position;
        shouldMeasure = true;
      }
      if (newConfig.parent != this.parent) {
        if (this.parent) this.container.remove();
        this.parent = newConfig.parent;
        this.createContainer();
        for (let t of this.manager.tooltipViews) this.container.appendChild(t.dom);
        shouldMeasure = true;
      } else if (this.parent && this.view.themeClasses != this.classes) {
        this.classes = this.container.className = this.view.themeClasses;
      }
      if (shouldMeasure) this.maybeMeasure();
    }
    createTooltip(tooltip, prev) {
      let tooltipView = tooltip.create(this.view);
      let before = prev ? prev.dom : null;
      tooltipView.dom.classList.add("cm-tooltip");
      if (tooltip.arrow && !tooltipView.dom.querySelector(".cm-tooltip > .cm-tooltip-arrow")) {
        let arrow = document.createElement("div");
        arrow.className = "cm-tooltip-arrow";
        tooltipView.dom.appendChild(arrow);
      }
      tooltipView.dom.style.position = this.position;
      tooltipView.dom.style.top = Outside;
      tooltipView.dom.style.left = "0px";
      this.container.insertBefore(tooltipView.dom, before);
      if (tooltipView.mount) tooltipView.mount(this.view);
      if (this.resizeObserver) this.resizeObserver.observe(tooltipView.dom);
      return tooltipView;
    }
    destroy() {
      var _a, _b, _c;
      this.view.win.removeEventListener("resize", this.measureSoon);
      for (let tooltipView of this.manager.tooltipViews) {
        tooltipView.dom.remove();
        (_a = tooltipView.destroy) === null || _a === void 0 ? void 0 : _a.call(tooltipView);
      }
      if (this.parent) this.container.remove();
      (_b = this.resizeObserver) === null || _b === void 0 ? void 0 : _b.disconnect();
      (_c = this.intersectionObserver) === null || _c === void 0 ? void 0 : _c.disconnect();
      clearTimeout(this.measureTimeout);
    }
    readMeasure() {
      let scaleX = 1,
        scaleY = 1,
        makeAbsolute = false;
      if (this.position == "fixed" && this.manager.tooltipViews.length) {
        let {
          dom
        } = this.manager.tooltipViews[0];
        if (browser.safari) {
          // Safari always sets offsetParent to null, even if a fixed
          // element is positioned relative to a transformed parent. So
          // we use this kludge to try and detect this.
          let rect = dom.getBoundingClientRect();
          makeAbsolute = Math.abs(rect.top + 10000) > 1 || Math.abs(rect.left) > 1;
        } else {
          // More conforming browsers will set offsetParent to the
          // transformed element.
          makeAbsolute = !!dom.offsetParent && dom.offsetParent != this.container.ownerDocument.body;
        }
      }
      if (makeAbsolute || this.position == "absolute") {
        if (this.parent) {
          let rect = this.parent.getBoundingClientRect();
          if (rect.width && rect.height) {
            scaleX = rect.width / this.parent.offsetWidth;
            scaleY = rect.height / this.parent.offsetHeight;
          }
        } else {
          ({
            scaleX,
            scaleY
          } = this.view.viewState);
        }
      }
      let visible = this.view.scrollDOM.getBoundingClientRect(),
        margins = getScrollMargins(this.view);
      return {
        visible: {
          left: visible.left + margins.left,
          top: visible.top + margins.top,
          right: visible.right - margins.right,
          bottom: visible.bottom - margins.bottom
        },
        parent: this.parent ? this.container.getBoundingClientRect() : this.view.dom.getBoundingClientRect(),
        pos: this.manager.tooltips.map((t, i) => {
          let tv = this.manager.tooltipViews[i];
          return tv.getCoords ? tv.getCoords(t.pos) : this.view.coordsAtPos(t.pos);
        }),
        size: this.manager.tooltipViews.map(({
          dom
        }) => dom.getBoundingClientRect()),
        space: this.view.state.facet(tooltipConfig).tooltipSpace(this.view),
        scaleX,
        scaleY,
        makeAbsolute
      };
    }
    writeMeasure(measured) {
      var _a;
      if (measured.makeAbsolute) {
        this.madeAbsolute = true;
        this.position = "absolute";
        for (let t of this.manager.tooltipViews) t.dom.style.position = "absolute";
      }
      let {
        visible,
        space,
        scaleX,
        scaleY
      } = measured;
      let others = [];
      for (let i = 0; i < this.manager.tooltips.length; i++) {
        let tooltip = this.manager.tooltips[i],
          tView = this.manager.tooltipViews[i],
          {
            dom
          } = tView;
        let pos = measured.pos[i],
          size = measured.size[i];
        // Hide tooltips that are outside of the editor.
        if (!pos || tooltip.clip !== false && (pos.bottom <= Math.max(visible.top, space.top) || pos.top >= Math.min(visible.bottom, space.bottom) || pos.right < Math.max(visible.left, space.left) - .1 || pos.left > Math.min(visible.right, space.right) + .1)) {
          dom.style.top = Outside;
          continue;
        }
        let arrow = tooltip.arrow ? tView.dom.querySelector(".cm-tooltip-arrow") : null;
        let arrowHeight = arrow ? 7 /* Arrow.Size */ : 0;
        let width = size.right - size.left,
          height = (_a = knownHeight.get(tView)) !== null && _a !== void 0 ? _a : size.bottom - size.top;
        let offset = tView.offset || noOffset,
          ltr = this.view.textDirection == Direction.LTR;
        let left = size.width > space.right - space.left ? ltr ? space.left : space.right - size.width : ltr ? Math.max(space.left, Math.min(pos.left - (arrow ? 14 /* Arrow.Offset */ : 0) + offset.x, space.right - width)) : Math.min(Math.max(space.left, pos.left - width + (arrow ? 14 /* Arrow.Offset */ : 0) - offset.x), space.right - width);
        let above = this.above[i];
        if (!tooltip.strictSide && (above ? pos.top - height - arrowHeight - offset.y < space.top : pos.bottom + height + arrowHeight + offset.y > space.bottom) && above == space.bottom - pos.bottom > pos.top - space.top) above = this.above[i] = !above;
        let spaceVert = (above ? pos.top - space.top : space.bottom - pos.bottom) - arrowHeight;
        if (spaceVert < height && tView.resize !== false) {
          if (spaceVert < this.view.defaultLineHeight) {
            dom.style.top = Outside;
            continue;
          }
          knownHeight.set(tView, height);
          dom.style.height = (height = spaceVert) / scaleY + "px";
        } else if (dom.style.height) {
          dom.style.height = "";
        }
        let top = above ? pos.top - height - arrowHeight - offset.y : pos.bottom + arrowHeight + offset.y;
        let right = left + width;
        if (tView.overlap !== true) for (let r of others) if (r.left < right && r.right > left && r.top < top + height && r.bottom > top) top = above ? r.top - height - 2 - arrowHeight : r.bottom + arrowHeight + 2;
        if (this.position == "absolute") {
          dom.style.top = (top - measured.parent.top) / scaleY + "px";
          setLeftStyle(dom, (left - measured.parent.left) / scaleX);
        } else {
          dom.style.top = top / scaleY + "px";
          setLeftStyle(dom, left / scaleX);
        }
        if (arrow) {
          let arrowLeft = pos.left + (ltr ? offset.x : -offset.x) - (left + 14 /* Arrow.Offset */ - 7 /* Arrow.Size */);
          arrow.style.left = arrowLeft / scaleX + "px";
        }
        if (tView.overlap !== true) others.push({
          left,
          top,
          right,
          bottom: top + height
        });
        dom.classList.toggle("cm-tooltip-above", above);
        dom.classList.toggle("cm-tooltip-below", !above);
        if (tView.positioned) tView.positioned(measured.space);
      }
    }
    maybeMeasure() {
      if (this.manager.tooltips.length) {
        if (this.view.inView) this.view.requestMeasure(this.measureReq);
        if (this.inView != this.view.inView) {
          this.inView = this.view.inView;
          if (!this.inView) for (let tv of this.manager.tooltipViews) tv.dom.style.top = Outside;
        }
      }
    }
  }, {
    eventObservers: {
      scroll() {
        this.maybeMeasure();
      }
    }
  });
  function setLeftStyle(elt, value) {
    let current = parseInt(elt.style.left, 10);
    if (isNaN(current) || Math.abs(value - current) > 1) elt.style.left = value + "px";
  }
  const baseTheme$2 = /*@__PURE__*/EditorView.baseTheme({
    ".cm-tooltip": {
      zIndex: 500,
      boxSizing: "border-box"
    },
    "&light .cm-tooltip": {
      border: "1px solid #bbb",
      backgroundColor: "#f5f5f5"
    },
    "&light .cm-tooltip-section:not(:first-child)": {
      borderTop: "1px solid #bbb"
    },
    "&dark .cm-tooltip": {
      backgroundColor: "#333338",
      color: "white"
    },
    ".cm-tooltip-arrow": {
      height: `${7 /* Arrow.Size */}px`,
      width: `${7 /* Arrow.Size */ * 2}px`,
      position: "absolute",
      zIndex: -1,
      overflow: "hidden",
      "&:before, &:after": {
        content: "''",
        position: "absolute",
        width: 0,
        height: 0,
        borderLeft: `${7 /* Arrow.Size */}px solid transparent`,
        borderRight: `${7 /* Arrow.Size */}px solid transparent`
      },
      ".cm-tooltip-above &": {
        bottom: `-${7 /* Arrow.Size */}px`,
        "&:before": {
          borderTop: `${7 /* Arrow.Size */}px solid #bbb`
        },
        "&:after": {
          borderTop: `${7 /* Arrow.Size */}px solid #f5f5f5`,
          bottom: "1px"
        }
      },
      ".cm-tooltip-below &": {
        top: `-${7 /* Arrow.Size */}px`,
        "&:before": {
          borderBottom: `${7 /* Arrow.Size */}px solid #bbb`
        },
        "&:after": {
          borderBottom: `${7 /* Arrow.Size */}px solid #f5f5f5`,
          top: "1px"
        }
      }
    },
    "&dark .cm-tooltip .cm-tooltip-arrow": {
      "&:before": {
        borderTopColor: "#333338",
        borderBottomColor: "#333338"
      },
      "&:after": {
        borderTopColor: "transparent",
        borderBottomColor: "transparent"
      }
    }
  });
  const noOffset = {
    x: 0,
    y: 0
  };
  /**
  Facet to which an extension can add a value to show a tooltip.
  */
  const showTooltip = /*@__PURE__*/Facet.define({
    enables: [tooltipPlugin, baseTheme$2]
  });
  const showHoverTooltip = /*@__PURE__*/Facet.define({
    combine: inputs => inputs.reduce((a, i) => a.concat(i), [])
  });
  class HoverTooltipHost {
    // Needs to be static so that host tooltip instances always match
    static create(view) {
      return new HoverTooltipHost(view);
    }
    constructor(view) {
      this.view = view;
      this.mounted = false;
      this.dom = document.createElement("div");
      this.dom.classList.add("cm-tooltip-hover");
      this.manager = new TooltipViewManager(view, showHoverTooltip, (t, p) => this.createHostedView(t, p), t => t.dom.remove());
    }
    createHostedView(tooltip, prev) {
      let hostedView = tooltip.create(this.view);
      hostedView.dom.classList.add("cm-tooltip-section");
      this.dom.insertBefore(hostedView.dom, prev ? prev.dom.nextSibling : this.dom.firstChild);
      if (this.mounted && hostedView.mount) hostedView.mount(this.view);
      return hostedView;
    }
    mount(view) {
      for (let hostedView of this.manager.tooltipViews) {
        if (hostedView.mount) hostedView.mount(view);
      }
      this.mounted = true;
    }
    positioned(space) {
      for (let hostedView of this.manager.tooltipViews) {
        if (hostedView.positioned) hostedView.positioned(space);
      }
    }
    update(update) {
      this.manager.update(update);
    }
    destroy() {
      var _a;
      for (let t of this.manager.tooltipViews) (_a = t.destroy) === null || _a === void 0 ? void 0 : _a.call(t);
    }
    passProp(name) {
      let value = undefined;
      for (let view of this.manager.tooltipViews) {
        let given = view[name];
        if (given !== undefined) {
          if (value === undefined) value = given;else if (value !== given) return undefined;
        }
      }
      return value;
    }
    get offset() {
      return this.passProp("offset");
    }
    get getCoords() {
      return this.passProp("getCoords");
    }
    get overlap() {
      return this.passProp("overlap");
    }
    get resize() {
      return this.passProp("resize");
    }
  }
  const showHoverTooltipHost = /*@__PURE__*/showTooltip.compute([showHoverTooltip], state => {
    let tooltips = state.facet(showHoverTooltip);
    if (tooltips.length === 0) return null;
    return {
      pos: Math.min(...tooltips.map(t => t.pos)),
      end: Math.max(...tooltips.map(t => {
        var _a;
        return (_a = t.end) !== null && _a !== void 0 ? _a : t.pos;
      })),
      create: HoverTooltipHost.create,
      above: tooltips[0].above,
      arrow: tooltips.some(t => t.arrow)
    };
  });
  const hoverPlugin = /*@__PURE__*/Facet.define();
  class HoverPlugin {
    constructor(view, source, field, locked, setHover, hoverTime) {
      this.view = view;
      this.source = source;
      this.field = field;
      this.locked = locked;
      this.setHover = setHover;
      this.hoverTime = hoverTime;
      this.hoverTimeout = -1;
      this.restartTimeout = -1;
      this.pending = null;
      this.lastMove = {
        x: 0,
        y: 0,
        target: view.dom,
        time: 0
      };
      this.checkHover = this.checkHover.bind(this);
      view.dom.addEventListener("mouseleave", this.mouseleave = this.mouseleave.bind(this));
      view.dom.addEventListener("mousemove", this.mousemove = this.mousemove.bind(this));
    }
    update(update) {
      if (this.pending) {
        this.pending = null;
        clearTimeout(this.restartTimeout);
        this.restartTimeout = setTimeout(() => this.startHover(), 20);
      }
    }
    get active() {
      return this.view.state.field(this.field);
    }
    checkHover() {
      this.hoverTimeout = -1;
      if (this.active.length) return;
      let hovered = Date.now() - this.lastMove.time;
      if (hovered < this.hoverTime) this.hoverTimeout = setTimeout(this.checkHover, this.hoverTime - hovered);else this.startHover();
    }
    startHover() {
      clearTimeout(this.restartTimeout);
      let {
        view,
        lastMove
      } = this;
      let tile = view.docView.tile.nearest(lastMove.target);
      if (!tile) return;
      let pos,
        side = 1;
      if (tile.isWidget()) {
        pos = tile.posAtStart;
      } else {
        pos = view.posAtCoords(lastMove);
        if (pos == null) return;
        let posCoords = view.coordsAtPos(pos);
        if (!posCoords || lastMove.y < posCoords.top || lastMove.y > posCoords.bottom || lastMove.x < posCoords.left - view.defaultCharacterWidth || lastMove.x > posCoords.right + view.defaultCharacterWidth) return;
        let bidi = view.bidiSpans(view.state.doc.lineAt(pos)).find(s => s.from <= pos && s.to >= pos);
        let rtl = bidi && bidi.dir == Direction.RTL ? -1 : 1;
        side = lastMove.x < posCoords.left ? -rtl : rtl;
      }
      this.activateHover(view, pos, side);
    }
    activateHover(view, pos, side, locked) {
      let open = this.source(view, pos, side);
      let done = value => {
        if (value && !(Array.isArray(value) && !value.length)) {
          let tooltips = Array.isArray(value) ? value : [value];
          if (locked) this.locked.set(tooltips, locked);
          view.dispatch({
            effects: this.setHover.of(tooltips)
          });
        }
      };
      if (open && "then" in open) {
        let pending = this.pending = {
          pos
        };
        open.then(result => {
          if (this.pending == pending) {
            this.pending = null;
            done(result);
          }
        }, e => logException(view.state, e, "hover tooltip"));
      } else {
        done(open);
      }
    }
    get tooltip() {
      let plugin = this.view.plugin(tooltipPlugin);
      let index = plugin ? plugin.manager.tooltips.findIndex(t => t.create == HoverTooltipHost.create) : -1;
      return index > -1 ? plugin.manager.tooltipViews[index] : null;
    }
    mousemove(event) {
      var _a, _b;
      this.lastMove = {
        x: event.clientX,
        y: event.clientY,
        target: event.target,
        time: Date.now()
      };
      if (this.hoverTimeout < 0) this.hoverTimeout = setTimeout(this.checkHover, this.hoverTime);
      let {
        active,
        tooltip
      } = this;
      if (active.length && !this.locked.has(active) && tooltip && !isInTooltip(tooltip.dom, event) || this.pending) {
        let {
            pos
          } = active[0] || this.pending,
          end = (_b = (_a = active[0]) === null || _a === void 0 ? void 0 : _a.end) !== null && _b !== void 0 ? _b : pos;
        if (pos == end ? this.view.posAtCoords(this.lastMove) != pos : !isOverRange(this.view, pos, end, event.clientX, event.clientY)) {
          this.view.dispatch({
            effects: this.setHover.of([])
          });
          this.pending = null;
        }
      }
    }
    mouseleave(event) {
      clearTimeout(this.hoverTimeout);
      this.hoverTimeout = -1;
      let {
        active
      } = this;
      if (active.length && !this.locked.has(active)) {
        let {
          tooltip
        } = this;
        let inTooltip = tooltip && tooltip.dom.contains(event.relatedTarget);
        if (!inTooltip) this.view.dispatch({
          effects: this.setHover.of([])
        });else this.watchTooltipLeave(tooltip.dom);
      }
    }
    watchTooltipLeave(tooltip) {
      let watch = event => {
        tooltip.removeEventListener("mouseleave", watch);
        let {
          active
        } = this;
        if (active.length && !this.locked.has(active) && !this.view.dom.contains(event.relatedTarget)) this.view.dispatch({
          effects: this.setHover.of([])
        });
      };
      tooltip.addEventListener("mouseleave", watch);
    }
    destroy() {
      clearTimeout(this.hoverTimeout);
      clearTimeout(this.restartTimeout);
      this.view.dom.removeEventListener("mouseleave", this.mouseleave);
      this.view.dom.removeEventListener("mousemove", this.mousemove);
    }
  }
  const tooltipMargin = 4;
  function isInTooltip(tooltip, event) {
    let {
        left,
        right,
        top,
        bottom
      } = tooltip.getBoundingClientRect(),
      arrow;
    if (arrow = tooltip.querySelector(".cm-tooltip-arrow")) {
      let arrowRect = arrow.getBoundingClientRect();
      top = Math.min(arrowRect.top, top);
      bottom = Math.max(arrowRect.bottom, bottom);
    }
    return event.clientX >= left - tooltipMargin && event.clientX <= right + tooltipMargin && event.clientY >= top - tooltipMargin && event.clientY <= bottom + tooltipMargin;
  }
  function isOverRange(view, from, to, x, y, margin) {
    let rect = view.scrollDOM.getBoundingClientRect();
    let docBottom = view.documentTop + view.documentPadding.top + view.contentHeight;
    if (rect.left > x || rect.right < x || rect.top > y || Math.min(rect.bottom, docBottom) < y) return false;
    let pos = view.posAtCoords({
      x,
      y
    }, false);
    return pos >= from && pos <= to;
  }
  /**
  Set up a hover tooltip, which shows up when the pointer hovers
  over ranges of text. The callback is called when the mouse hovers
  over the document text. It should, if there is a tooltip
  associated with position `pos`, return the tooltip description
  (either directly or in a promise). The `side` argument indicates
  on which side of the position the pointer is—it will be -1 if the
  pointer is before the position, 1 if after the position.

  Note that all hover tooltips are hosted within a single tooltip
  container element. This allows multiple tooltips over the same
  range to be "merged" together without overlapping.

  The return value is a valid [editor extension](https://codemirror.net/6/docs/ref/#state.Extension)
  but also provides an `active` property holding a state field that
  can be used to read the currently active tooltips produced by this
  extension.
  */
  function hoverTooltip(source, options = {}) {
    let setHover = StateEffect.define();
    // This would be better stored in the state field, but we've set
    // down the type of the field in our interface, so it's indirectly
    // stored by array identity.
    let locked = new WeakMap();
    let hoverState = StateField.define({
      create() {
        return [];
      },
      update(value, tr) {
        let lock = locked.get(value);
        if (value.length) {
          if (options.hideOnChange && (tr.docChanged || tr.selection)) value = [];else if (lock && lock(tr)) value = [];else if (options.hideOn) value = value.filter(v => !options.hideOn(tr, v));
        }
        if (tr.docChanged && value.length) {
          let mapped = [];
          for (let tooltip of value) {
            let newPos = tr.changes.mapPos(tooltip.pos, -1, MapMode.TrackDel);
            if (newPos != null) {
              let copy = Object.assign(Object.create(null), tooltip);
              copy.pos = newPos;
              if (copy.end != null) copy.end = tr.changes.mapPos(copy.end);
              mapped.push(copy);
            }
          }
          value = mapped;
        }
        for (let effect of tr.effects) {
          if (effect.is(setHover)) {
            value = effect.value;
            lock = undefined;
          }
          if (effect.is(closeHoverTooltipEffect) && !effect.value || effect.value == hoverState) value = [];
        }
        if (value.length && lock) locked.set(value, lock);
        return value;
      },
      provide: f => showHoverTooltip.from(f)
    });
    const plugin = ViewPlugin.define(view => new HoverPlugin(view, source, hoverState, locked, setHover, options.hoverTime || 300 /* Hover.Time */));
    return {
      active: hoverState,
      extension: [hoverState, plugin, hoverPlugin.of(plugin), showHoverTooltipHost]
    };
  }
  const closeHoverTooltipEffect = /*@__PURE__*/StateEffect.define();
  const panelConfig = /*@__PURE__*/Facet.define({
    combine(configs) {
      let topContainer, bottomContainer;
      for (let c of configs) {
        topContainer = topContainer || c.topContainer;
        bottomContainer = bottomContainer || c.bottomContainer;
      }
      return {
        topContainer,
        bottomContainer
      };
    }
  });
  const panelPlugin = /*@__PURE__*/ViewPlugin.fromClass(class {
    constructor(view) {
      this.input = view.state.facet(showPanel);
      this.specs = this.input.filter(s => s);
      this.panels = this.specs.map(spec => spec(view));
      let conf = view.state.facet(panelConfig);
      this.top = new PanelGroup(view, true, conf.topContainer);
      this.bottom = new PanelGroup(view, false, conf.bottomContainer);
      this.top.sync(this.panels.filter(p => p.top));
      this.bottom.sync(this.panels.filter(p => !p.top));
      for (let p of this.panels) {
        p.dom.classList.add("cm-panel");
        if (p.mount) p.mount();
      }
    }
    update(update) {
      let conf = update.state.facet(panelConfig);
      if (this.top.container != conf.topContainer) {
        this.top.sync([]);
        this.top = new PanelGroup(update.view, true, conf.topContainer);
      }
      if (this.bottom.container != conf.bottomContainer) {
        this.bottom.sync([]);
        this.bottom = new PanelGroup(update.view, false, conf.bottomContainer);
      }
      this.top.syncClasses();
      this.bottom.syncClasses();
      let input = update.state.facet(showPanel);
      if (input != this.input) {
        let specs = input.filter(x => x);
        let panels = [],
          top = [],
          bottom = [],
          mount = [];
        for (let spec of specs) {
          let known = this.specs.indexOf(spec),
            panel;
          if (known < 0) {
            panel = spec(update.view);
            mount.push(panel);
          } else {
            panel = this.panels[known];
            if (panel.update) panel.update(update);
          }
          panels.push(panel);
          (panel.top ? top : bottom).push(panel);
        }
        this.specs = specs;
        this.panels = panels;
        this.top.sync(top);
        this.bottom.sync(bottom);
        for (let p of mount) {
          p.dom.classList.add("cm-panel");
          if (p.mount) p.mount();
        }
      } else {
        for (let p of this.panels) if (p.update) p.update(update);
      }
    }
    destroy() {
      this.top.sync([]);
      this.bottom.sync([]);
    }
  }, {
    provide: plugin => EditorView.scrollMargins.of(view => {
      let value = view.plugin(plugin);
      return value && {
        top: value.top.scrollMargin(),
        bottom: value.bottom.scrollMargin()
      };
    })
  });
  class PanelGroup {
    constructor(view, top, container) {
      this.view = view;
      this.top = top;
      this.container = container;
      this.dom = undefined;
      this.classes = "";
      this.panels = [];
      this.syncClasses();
    }
    sync(panels) {
      for (let p of this.panels) if (p.destroy && panels.indexOf(p) < 0) p.destroy();
      this.panels = panels;
      this.syncDOM();
    }
    syncDOM() {
      if (this.panels.length == 0) {
        if (this.dom) {
          this.dom.remove();
          this.dom = undefined;
        }
        return;
      }
      if (!this.dom) {
        this.dom = document.createElement("div");
        this.dom.className = this.top ? "cm-panels cm-panels-top" : "cm-panels cm-panels-bottom";
        this.dom.style[this.top ? "top" : "bottom"] = "0";
        let parent = this.container || this.view.dom;
        parent.insertBefore(this.dom, this.top ? parent.firstChild : null);
      }
      let curDOM = this.dom.firstChild;
      for (let panel of this.panels) {
        if (panel.dom.parentNode == this.dom) {
          while (curDOM != panel.dom) curDOM = rm(curDOM);
          curDOM = curDOM.nextSibling;
        } else {
          this.dom.insertBefore(panel.dom, curDOM);
        }
      }
      while (curDOM) curDOM = rm(curDOM);
    }
    scrollMargin() {
      return !this.dom || this.container ? 0 : Math.max(0, this.top ? this.dom.getBoundingClientRect().bottom - Math.max(0, this.view.scrollDOM.getBoundingClientRect().top) : Math.min(innerHeight, this.view.scrollDOM.getBoundingClientRect().bottom) - this.dom.getBoundingClientRect().top);
    }
    syncClasses() {
      if (!this.container || this.classes == this.view.themeClasses) return;
      for (let cls of this.classes.split(" ")) if (cls) this.container.classList.remove(cls);
      for (let cls of (this.classes = this.view.themeClasses).split(" ")) if (cls) this.container.classList.add(cls);
    }
  }
  function rm(node) {
    let next = node.nextSibling;
    node.remove();
    return next;
  }
  /**
  Opening a panel is done by providing a constructor function for
  the panel through this facet. (The panel is closed again when its
  constructor is no longer provided.) Values of `null` are ignored.
  */
  const showPanel = /*@__PURE__*/Facet.define({
    enables: panelPlugin
  });

  /**
  A gutter marker represents a bit of information attached to a line
  in a specific gutter. Your own custom markers have to extend this
  class.
  */
  class GutterMarker extends RangeValue {
    /**
    @internal
    */
    compare(other) {
      return this == other || this.constructor == other.constructor && this.eq(other);
    }
    /**
    Compare this marker to another marker of the same type.
    */
    eq(other) {
      return false;
    }
    /**
    Called if the marker has a `toDOM` method and its representation
    was removed from a gutter.
    */
    destroy(dom) {}
  }
  GutterMarker.prototype.elementClass = "";
  GutterMarker.prototype.toDOM = undefined;
  GutterMarker.prototype.mapMode = MapMode.TrackBefore;
  GutterMarker.prototype.startSide = GutterMarker.prototype.endSide = -1;
  GutterMarker.prototype.point = true;

  /**
  The default maximum length of a `TreeBuffer` node.
  */
  const DefaultBufferLength = 1024;
  let nextPropID = 0;
  class Range {
    constructor(from, to) {
      this.from = from;
      this.to = to;
    }
  }
  /**
  Each [node type](#common.NodeType) or [individual tree](#common.Tree)
  can have metadata associated with it in props. Instances of this
  class represent prop names.
  */
  class NodeProp {
    /**
    Create a new node prop type.
    */
    constructor(config = {}) {
      this.id = nextPropID++;
      this.perNode = !!config.perNode;
      this.deserialize = config.deserialize || (() => {
        throw new Error("This node type doesn't define a deserialize function");
      });
      this.combine = config.combine || null;
    }
    /**
    This is meant to be used with
    [`NodeSet.extend`](#common.NodeSet.extend) or
    [`LRParser.configure`](#lr.ParserConfig.props) to compute
    prop values for each node type in the set. Takes a [match
    object](#common.NodeType^match) or function that returns undefined
    if the node type doesn't get this prop, and the prop's value if
    it does.
    */
    add(match) {
      if (this.perNode) throw new RangeError("Can't add per-node props to node types");
      if (typeof match != "function") match = NodeType.match(match);
      return type => {
        let result = match(type);
        return result === undefined ? null : [this, result];
      };
    }
  }
  /**
  Prop that is used to describe matching delimiters. For opening
  delimiters, this holds an array of node names (written as a
  space-separated string when declaring this prop in a grammar)
  for the node types of closing delimiters that match it.
  */
  NodeProp.closedBy = new NodeProp({
    deserialize: str => str.split(" ")
  });
  /**
  The inverse of [`closedBy`](#common.NodeProp^closedBy). This is
  attached to closing delimiters, holding an array of node names
  of types of matching opening delimiters.
  */
  NodeProp.openedBy = new NodeProp({
    deserialize: str => str.split(" ")
  });
  /**
  Used to assign node types to groups (for example, all node
  types that represent an expression could be tagged with an
  `"Expression"` group).
  */
  NodeProp.group = new NodeProp({
    deserialize: str => str.split(" ")
  });
  /**
  Attached to nodes to indicate these should be
  [displayed](https://codemirror.net/docs/ref/#language.syntaxTree)
  in a bidirectional text isolate, so that direction-neutral
  characters on their sides don't incorrectly get associated with
  surrounding text. You'll generally want to set this for nodes
  that contain arbitrary text, like strings and comments, and for
  nodes that appear _inside_ arbitrary text, like HTML tags. When
  not given a value, in a grammar declaration, defaults to
  `"auto"`.
  */
  NodeProp.isolate = new NodeProp({
    deserialize: value => {
      if (value && value != "rtl" && value != "ltr" && value != "auto") throw new RangeError("Invalid value for isolate: " + value);
      return value || "auto";
    }
  });
  /**
  The hash of the [context](#lr.ContextTracker.constructor)
  that the node was parsed in, if any. Used to limit reuse of
  contextual nodes.
  */
  NodeProp.contextHash = new NodeProp({
    perNode: true
  });
  /**
  The distance beyond the end of the node that the tokenizer
  looked ahead for any of the tokens inside the node. (The LR
  parser only stores this when it is larger than 25, for
  efficiency reasons.)
  */
  NodeProp.lookAhead = new NodeProp({
    perNode: true
  });
  /**
  This per-node prop is used to replace a given node, or part of a
  node, with another tree. This is useful to include trees from
  different languages in mixed-language parsers.
  */
  NodeProp.mounted = new NodeProp({
    perNode: true
  });
  /**
  A mounted tree, which can be [stored](#common.NodeProp^mounted) on
  a tree node to indicate that parts of its content are
  represented by another tree.
  */
  class MountedTree {
    constructor(
    /**
    The inner tree.
    */
    tree,
    /**
    If this is null, this tree replaces the entire node (it will
    be included in the regular iteration instead of its host
    node). If not, only the given ranges are considered to be
    covered by this tree. This is used for trees that are mixed in
    a way that isn't strictly hierarchical. Such mounted trees are
    only entered by [`resolveInner`](#common.Tree.resolveInner)
    and [`enter`](#common.SyntaxNode.enter).
    */
    overlay,
    /**
    The parser used to create this subtree.
    */
    parser,
    /**
    [Indicates](#common.IterMode.EnterBracketed) that the nested
    content is delineated with some kind
    of bracket token.
    */
    bracketed = false) {
      this.tree = tree;
      this.overlay = overlay;
      this.parser = parser;
      this.bracketed = bracketed;
    }
    /**
    @internal
    */
    static get(tree) {
      return tree && tree.props && tree.props[NodeProp.mounted.id];
    }
  }
  const noProps = Object.create(null);
  /**
  Each node in a syntax tree has a node type associated with it.
  */
  class NodeType {
    /**
    @internal
    */
    constructor(
    /**
    The name of the node type. Not necessarily unique, but if the
    grammar was written properly, different node types with the
    same name within a node set should play the same semantic
    role.
    */
    name,
    /**
    @internal
    */
    props,
    /**
    The id of this node in its set. Corresponds to the term ids
    used in the parser.
    */
    id,
    /**
    @internal
    */
    flags = 0) {
      this.name = name;
      this.props = props;
      this.id = id;
      this.flags = flags;
    }
    /**
    Define a node type.
    */
    static define(spec) {
      let props = spec.props && spec.props.length ? Object.create(null) : noProps;
      let flags = (spec.top ? 1 /* NodeFlag.Top */ : 0) | (spec.skipped ? 2 /* NodeFlag.Skipped */ : 0) | (spec.error ? 4 /* NodeFlag.Error */ : 0) | (spec.name == null ? 8 /* NodeFlag.Anonymous */ : 0);
      let type = new NodeType(spec.name || "", props, spec.id, flags);
      if (spec.props) for (let src of spec.props) {
        if (!Array.isArray(src)) src = src(type);
        if (src) {
          if (src[0].perNode) throw new RangeError("Can't store a per-node prop on a node type");
          props[src[0].id] = src[1];
        }
      }
      return type;
    }
    /**
    Retrieves a node prop for this type. Will return `undefined` if
    the prop isn't present on this node.
    */
    prop(prop) {
      return this.props[prop.id];
    }
    /**
    True when this is the top node of a grammar.
    */
    get isTop() {
      return (this.flags & 1 /* NodeFlag.Top */) > 0;
    }
    /**
    True when this node is produced by a skip rule.
    */
    get isSkipped() {
      return (this.flags & 2 /* NodeFlag.Skipped */) > 0;
    }
    /**
    Indicates whether this is an error node.
    */
    get isError() {
      return (this.flags & 4 /* NodeFlag.Error */) > 0;
    }
    /**
    When true, this node type doesn't correspond to a user-declared
    named node, for example because it is used to cache repetition.
    */
    get isAnonymous() {
      return (this.flags & 8 /* NodeFlag.Anonymous */) > 0;
    }
    /**
    Returns true when this node's name or one of its
    [groups](#common.NodeProp^group) matches the given string.
    */
    is(name) {
      if (typeof name == 'string') {
        if (this.name == name) return true;
        let group = this.prop(NodeProp.group);
        return group ? group.indexOf(name) > -1 : false;
      }
      return this.id == name;
    }
    /**
    Create a function from node types to arbitrary values by
    specifying an object whose property names are node or
    [group](#common.NodeProp^group) names. Often useful with
    [`NodeProp.add`](#common.NodeProp.add). You can put multiple
    names, separated by spaces, in a single property name to map
    multiple node names to a single value.
    */
    static match(map) {
      let direct = Object.create(null);
      for (let prop in map) for (let name of prop.split(" ")) direct[name] = map[prop];
      return node => {
        for (let groups = node.prop(NodeProp.group), i = -1; i < (groups ? groups.length : 0); i++) {
          let found = direct[i < 0 ? node.name : groups[i]];
          if (found) return found;
        }
      };
    }
  }
  /**
  An empty dummy node type to use when no actual type is available.
  */
  NodeType.none = new NodeType("", Object.create(null), 0, 8 /* NodeFlag.Anonymous */);
  const CachedNode = new WeakMap(),
    CachedInnerNode = new WeakMap();
  /**
  Options that control iteration. Can be combined with the `|`
  operator to enable multiple ones.
  */
  var IterMode;
  (function (IterMode) {
    /**
    When enabled, iteration will only visit [`Tree`](#common.Tree)
    objects, not nodes packed into
    [`TreeBuffer`](#common.TreeBuffer)s.
    */
    IterMode[IterMode["ExcludeBuffers"] = 1] = "ExcludeBuffers";
    /**
    Enable this to make iteration include anonymous nodes (such as
    the nodes that wrap repeated grammar constructs into a balanced
    tree).
    */
    IterMode[IterMode["IncludeAnonymous"] = 2] = "IncludeAnonymous";
    /**
    By default, regular [mounted](#common.NodeProp^mounted) nodes
    replace their base node in iteration. Enable this to ignore them
    instead.
    */
    IterMode[IterMode["IgnoreMounts"] = 4] = "IgnoreMounts";
    /**
    This option only applies in
    [`enter`](#common.SyntaxNode.enter)-style methods. It tells the
    library to not enter mounted overlays if one covers the given
    position.
    */
    IterMode[IterMode["IgnoreOverlays"] = 8] = "IgnoreOverlays";
    /**
    When set, positions on the boundary of a mounted overlay tree
    that has its [`bracketed`](#common.NestedParse.bracketed) flag
    set will enter that tree regardless of side. Only supported in
    [`enter`](#common.SyntaxNode.enter), not in cursors.
    */
    IterMode[IterMode["EnterBracketed"] = 16] = "EnterBracketed";
  })(IterMode || (IterMode = {}));
  /**
  A piece of syntax tree. There are two ways to approach these
  trees: the way they are actually stored in memory, and the
  convenient way.

  Syntax trees are stored as a tree of `Tree` and `TreeBuffer`
  objects. By packing detail information into `TreeBuffer` leaf
  nodes, the representation is made a lot more memory-efficient.

  However, when you want to actually work with tree nodes, this
  representation is very awkward, so most client code will want to
  use the [`TreeCursor`](#common.TreeCursor) or
  [`SyntaxNode`](#common.SyntaxNode) interface instead, which provides
  a view on some part of this data structure, and can be used to
  move around to adjacent nodes.
  */
  class Tree {
    /**
    Construct a new tree. See also [`Tree.build`](#common.Tree^build).
    */
    constructor(
    /**
    The type of the top node.
    */
    type,
    /**
    This node's child nodes.
    */
    children,
    /**
    The positions (offsets relative to the start of this tree) of
    the children.
    */
    positions,
    /**
    The total length of this tree
    */
    length,
    /**
    Per-node [node props](#common.NodeProp) to associate with this node.
    */
    props) {
      this.type = type;
      this.children = children;
      this.positions = positions;
      this.length = length;
      /**
      @internal
      */
      this.props = null;
      if (props && props.length) {
        this.props = Object.create(null);
        for (let [prop, value] of props) this.props[typeof prop == "number" ? prop : prop.id] = value;
      }
    }
    /**
    @internal
    */
    toString() {
      let mounted = MountedTree.get(this);
      if (mounted && !mounted.overlay) return mounted.tree.toString();
      let children = "";
      for (let ch of this.children) {
        let str = ch.toString();
        if (str) {
          if (children) children += ",";
          children += str;
        }
      }
      return !this.type.name ? children : (/\W/.test(this.type.name) && !this.type.isError ? JSON.stringify(this.type.name) : this.type.name) + (children.length ? "(" + children + ")" : "");
    }
    /**
    Get a [tree cursor](#common.TreeCursor) positioned at the top of
    the tree. Mode can be used to [control](#common.IterMode) which
    nodes the cursor visits.
    */
    cursor(mode = 0) {
      return new TreeCursor(this.topNode, mode);
    }
    /**
    Get a [tree cursor](#common.TreeCursor) pointing into this tree
    at the given position and side (see
    [`moveTo`](#common.TreeCursor.moveTo).
    */
    cursorAt(pos, side = 0, mode = 0) {
      let scope = CachedNode.get(this) || this.topNode;
      let cursor = new TreeCursor(scope);
      cursor.moveTo(pos, side);
      CachedNode.set(this, cursor._tree);
      return cursor;
    }
    /**
    Get a [syntax node](#common.SyntaxNode) object for the top of the
    tree.
    */
    get topNode() {
      return new TreeNode(this, 0, 0, null);
    }
    /**
    Get the [syntax node](#common.SyntaxNode) at the given position.
    If `side` is -1, this will move into nodes that end at the
    position. If 1, it'll move into nodes that start at the
    position. With 0, it'll only enter nodes that cover the position
    from both sides.
    
    Note that this will not enter
    [overlays](#common.MountedTree.overlay), and you often want
    [`resolveInner`](#common.Tree.resolveInner) instead.
    */
    resolve(pos, side = 0) {
      let node = resolveNode(CachedNode.get(this) || this.topNode, pos, side, false);
      CachedNode.set(this, node);
      return node;
    }
    /**
    Like [`resolve`](#common.Tree.resolve), but will enter
    [overlaid](#common.MountedTree.overlay) nodes, producing a syntax node
    pointing into the innermost overlaid tree at the given position
    (with parent links going through all parent structure, including
    the host trees).
    */
    resolveInner(pos, side = 0) {
      let node = resolveNode(CachedInnerNode.get(this) || this.topNode, pos, side, true);
      CachedInnerNode.set(this, node);
      return node;
    }
    /**
    In some situations, it can be useful to iterate through all
    nodes around a position, including those in overlays that don't
    directly cover the position. This method gives you an iterator
    that will produce all nodes, from small to big, around the given
    position.
    */
    resolveStack(pos, side = 0) {
      return stackIterator(this, pos, side);
    }
    /**
    Iterate over the tree and its children, calling `enter` for any
    node that touches the `from`/`to` region (if given) before
    running over such a node's children, and `leave` (if given) when
    leaving the node. When `enter` returns `false`, that node will
    not have its children iterated over (or `leave` called).
    */
    iterate(spec) {
      let {
        enter,
        leave,
        from = 0,
        to = this.length
      } = spec;
      let mode = spec.mode || 0,
        anon = (mode & IterMode.IncludeAnonymous) > 0;
      for (let c = this.cursor(mode | IterMode.IncludeAnonymous);;) {
        let entered = false;
        if (c.from <= to && c.to >= from && (!anon && c.type.isAnonymous || enter(c) !== false)) {
          if (c.firstChild()) continue;
          entered = true;
        }
        for (;;) {
          if (entered && leave && (anon || !c.type.isAnonymous)) leave(c);
          if (c.nextSibling()) break;
          if (!c.parent()) return;
          entered = true;
        }
      }
    }
    /**
    Get the value of the given [node prop](#common.NodeProp) for this
    node. Works with both per-node and per-type props.
    */
    prop(prop) {
      return !prop.perNode ? this.type.prop(prop) : this.props ? this.props[prop.id] : undefined;
    }
    /**
    Returns the node's [per-node props](#common.NodeProp.perNode) in a
    format that can be passed to the [`Tree`](#common.Tree)
    constructor.
    */
    get propValues() {
      let result = [];
      if (this.props) for (let id in this.props) result.push([+id, this.props[id]]);
      return result;
    }
    /**
    Balance the direct children of this tree, producing a copy of
    which may have children grouped into subtrees with type
    [`NodeType.none`](#common.NodeType^none).
    */
    balance(config = {}) {
      return this.children.length <= 8 /* Balance.BranchFactor */ ? this : balanceRange(NodeType.none, this.children, this.positions, 0, this.children.length, 0, this.length, (children, positions, length) => new Tree(this.type, children, positions, length, this.propValues), config.makeTree || ((children, positions, length) => new Tree(NodeType.none, children, positions, length)));
    }
    /**
    Build a tree from a postfix-ordered buffer of node information,
    or a cursor over such a buffer.
    */
    static build(data) {
      return buildTree(data);
    }
  }
  /**
  The empty tree
  */
  Tree.empty = new Tree(NodeType.none, [], [], 0);
  class FlatBufferCursor {
    constructor(buffer, index) {
      this.buffer = buffer;
      this.index = index;
    }
    get id() {
      return this.buffer[this.index - 4];
    }
    get start() {
      return this.buffer[this.index - 3];
    }
    get end() {
      return this.buffer[this.index - 2];
    }
    get size() {
      return this.buffer[this.index - 1];
    }
    get pos() {
      return this.index;
    }
    next() {
      this.index -= 4;
    }
    fork() {
      return new FlatBufferCursor(this.buffer, this.index);
    }
  }
  /**
  Tree buffers contain (type, start, end, endIndex) quads for each
  node. In such a buffer, nodes are stored in prefix order (parents
  before children, with the endIndex of the parent indicating which
  children belong to it).
  */
  class TreeBuffer {
    /**
    Create a tree buffer.
    */
    constructor(
    /**
    The buffer's content.
    */
    buffer,
    /**
    The total length of the group of nodes in the buffer.
    */
    length,
    /**
    The node set used in this buffer.
    */
    set) {
      this.buffer = buffer;
      this.length = length;
      this.set = set;
    }
    /**
    @internal
    */
    get type() {
      return NodeType.none;
    }
    /**
    @internal
    */
    toString() {
      let result = [];
      for (let index = 0; index < this.buffer.length;) {
        result.push(this.childString(index));
        index = this.buffer[index + 3];
      }
      return result.join(",");
    }
    /**
    @internal
    */
    childString(index) {
      let id = this.buffer[index],
        endIndex = this.buffer[index + 3];
      let type = this.set.types[id],
        result = type.name;
      if (/\W/.test(result) && !type.isError) result = JSON.stringify(result);
      index += 4;
      if (endIndex == index) return result;
      let children = [];
      while (index < endIndex) {
        children.push(this.childString(index));
        index = this.buffer[index + 3];
      }
      return result + "(" + children.join(",") + ")";
    }
    /**
    @internal
    */
    findChild(startIndex, endIndex, dir, pos, side) {
      let {
          buffer
        } = this,
        pick = -1;
      for (let i = startIndex; i != endIndex; i = buffer[i + 3]) {
        if (checkSide(side, pos, buffer[i + 1], buffer[i + 2])) {
          pick = i;
          if (dir > 0) break;
        }
      }
      return pick;
    }
    /**
    @internal
    */
    slice(startI, endI, from) {
      let b = this.buffer;
      let copy = new Uint16Array(endI - startI),
        len = 0;
      for (let i = startI, j = 0; i < endI;) {
        copy[j++] = b[i++];
        copy[j++] = b[i++] - from;
        let to = copy[j++] = b[i++] - from;
        copy[j++] = b[i++] - startI;
        len = Math.max(len, to);
      }
      return new TreeBuffer(copy, len, this.set);
    }
  }
  function checkSide(side, pos, from, to) {
    switch (side) {
      case -2 /* Side.Before */:
        return from < pos;
      case -1 /* Side.AtOrBefore */:
        return to >= pos && from < pos;
      case 0 /* Side.Around */:
        return from < pos && to > pos;
      case 1 /* Side.AtOrAfter */:
        return from <= pos && to > pos;
      case 2 /* Side.After */:
        return to > pos;
      case 4 /* Side.DontCare */:
        return true;
    }
  }
  function resolveNode(node, pos, side, overlays) {
    var _a;
    // Move up to a node that actually holds the position, if possible
    while (node.from == node.to || (side < 1 ? node.from >= pos : node.from > pos) || (side > -1 ? node.to <= pos : node.to < pos)) {
      let parent = !overlays && node instanceof TreeNode && node.index < 0 ? null : node.parent;
      if (!parent) return node;
      node = parent;
    }
    let mode = overlays ? 0 : IterMode.IgnoreOverlays;
    // Must go up out of overlays when those do not overlap with pos
    if (overlays) for (let scan = node, parent = scan.parent; parent; scan = parent, parent = scan.parent) {
      if (scan instanceof TreeNode && scan.index < 0 && ((_a = parent.enter(pos, side, mode)) === null || _a === void 0 ? void 0 : _a.from) != scan.from) node = parent;
    }
    for (;;) {
      let inner = node.enter(pos, side, mode);
      if (!inner) return node;
      node = inner;
    }
  }
  class BaseNode {
    cursor(mode = 0) {
      return new TreeCursor(this, mode);
    }
    getChild(type, before = null, after = null) {
      let r = getChildren(this, type, before, after);
      return r.length ? r[0] : null;
    }
    getChildren(type, before = null, after = null) {
      return getChildren(this, type, before, after);
    }
    resolve(pos, side = 0) {
      return resolveNode(this, pos, side, false);
    }
    resolveInner(pos, side = 0) {
      return resolveNode(this, pos, side, true);
    }
    matchContext(context) {
      return matchNodeContext(this.parent, context);
    }
    enterUnfinishedNodesBefore(pos) {
      let scan = this.childBefore(pos),
        node = this;
      while (scan) {
        let last = scan.lastChild;
        if (!last || last.to != scan.to) break;
        if (last.type.isError && last.from == last.to) {
          node = scan;
          scan = last.prevSibling;
        } else {
          scan = last;
        }
      }
      return node;
    }
    get node() {
      return this;
    }
    get next() {
      return this.parent;
    }
  }
  class TreeNode extends BaseNode {
    constructor(_tree, from,
    // Index in parent node, set to -1 if the node is not a direct child of _parent.node (overlay)
    index, _parent) {
      super();
      this._tree = _tree;
      this.from = from;
      this.index = index;
      this._parent = _parent;
    }
    get type() {
      return this._tree.type;
    }
    get name() {
      return this._tree.type.name;
    }
    get to() {
      return this.from + this._tree.length;
    }
    nextChild(i, dir, pos, side, mode = 0) {
      for (let parent = this;;) {
        for (let {
            children,
            positions
          } = parent._tree, e = dir > 0 ? children.length : -1; i != e; i += dir) {
          let next = children[i],
            start = positions[i] + parent.from,
            mounted;
          if (!(mode & IterMode.EnterBracketed && next instanceof Tree && (mounted = MountedTree.get(next)) && !mounted.overlay && mounted.bracketed && pos >= start && pos <= start + next.length) && !checkSide(side, pos, start, start + next.length)) continue;
          if (next instanceof TreeBuffer) {
            if (mode & IterMode.ExcludeBuffers) continue;
            let index = next.findChild(0, next.buffer.length, dir, pos - start, side);
            if (index > -1) return new BufferNode(new BufferContext(parent, next, i, start), null, index);
          } else if (mode & IterMode.IncludeAnonymous || !next.type.isAnonymous || hasChild(next)) {
            let mounted;
            if (!(mode & IterMode.IgnoreMounts) && (mounted = MountedTree.get(next)) && !mounted.overlay) return new TreeNode(mounted.tree, start, i, parent);
            let inner = new TreeNode(next, start, i, parent);
            return mode & IterMode.IncludeAnonymous || !inner.type.isAnonymous ? inner : inner.nextChild(dir < 0 ? next.children.length - 1 : 0, dir, pos, side, mode);
          }
        }
        if (mode & IterMode.IncludeAnonymous || !parent.type.isAnonymous) return null;
        if (parent.index >= 0) i = parent.index + dir;else i = dir < 0 ? -1 : parent._parent._tree.children.length;
        parent = parent._parent;
        if (!parent) return null;
      }
    }
    get firstChild() {
      return this.nextChild(0, 1, 0, 4 /* Side.DontCare */);
    }
    get lastChild() {
      return this.nextChild(this._tree.children.length - 1, -1, 0, 4 /* Side.DontCare */);
    }
    childAfter(pos) {
      return this.nextChild(0, 1, pos, 2 /* Side.After */);
    }
    childBefore(pos) {
      return this.nextChild(this._tree.children.length - 1, -1, pos, -2 /* Side.Before */);
    }
    prop(prop) {
      return this._tree.prop(prop);
    }
    enter(pos, side, mode = 0) {
      let mounted;
      if (!(mode & IterMode.IgnoreOverlays) && (mounted = MountedTree.get(this._tree)) && mounted.overlay) {
        let rPos = pos - this.from,
          enterBracketed = mode & IterMode.EnterBracketed && mounted.bracketed;
        for (let {
          from,
          to
        } of mounted.overlay) {
          if ((side > 0 || enterBracketed ? from <= rPos : from < rPos) && (side < 0 || enterBracketed ? to >= rPos : to > rPos)) return new TreeNode(mounted.tree, mounted.overlay[0].from + this.from, -1, this);
        }
      }
      return this.nextChild(0, 1, pos, side, mode);
    }
    nextSignificantParent() {
      let val = this;
      while (val.type.isAnonymous && val._parent) val = val._parent;
      return val;
    }
    get parent() {
      return this._parent ? this._parent.nextSignificantParent() : null;
    }
    get nextSibling() {
      return this._parent && this.index >= 0 ? this._parent.nextChild(this.index + 1, 1, 0, 4 /* Side.DontCare */) : null;
    }
    get prevSibling() {
      return this._parent && this.index >= 0 ? this._parent.nextChild(this.index - 1, -1, 0, 4 /* Side.DontCare */) : null;
    }
    get tree() {
      return this._tree;
    }
    toTree() {
      return this._tree;
    }
    /**
    @internal
    */
    toString() {
      return this._tree.toString();
    }
  }
  function getChildren(node, type, before, after) {
    let cur = node.cursor(),
      result = [];
    if (!cur.firstChild()) return result;
    if (before != null) for (let found = false; !found;) {
      found = cur.type.is(before);
      if (!cur.nextSibling()) return result;
    }
    for (;;) {
      if (after != null && cur.type.is(after)) return result;
      if (cur.type.is(type)) result.push(cur.node);
      if (!cur.nextSibling()) return after == null ? result : [];
    }
  }
  function matchNodeContext(node, context, i = context.length - 1) {
    for (let p = node; i >= 0; p = p.parent) {
      if (!p) return false;
      if (!p.type.isAnonymous) {
        if (context[i] && context[i] != p.name) return false;
        i--;
      }
    }
    return true;
  }
  class BufferContext {
    constructor(parent, buffer, index, start) {
      this.parent = parent;
      this.buffer = buffer;
      this.index = index;
      this.start = start;
    }
  }
  class BufferNode extends BaseNode {
    get name() {
      return this.type.name;
    }
    get from() {
      return this.context.start + this.context.buffer.buffer[this.index + 1];
    }
    get to() {
      return this.context.start + this.context.buffer.buffer[this.index + 2];
    }
    constructor(context, _parent, index) {
      super();
      this.context = context;
      this._parent = _parent;
      this.index = index;
      this.type = context.buffer.set.types[context.buffer.buffer[index]];
    }
    child(dir, pos, side) {
      let {
        buffer
      } = this.context;
      let index = buffer.findChild(this.index + 4, buffer.buffer[this.index + 3], dir, pos - this.context.start, side);
      return index < 0 ? null : new BufferNode(this.context, this, index);
    }
    get firstChild() {
      return this.child(1, 0, 4 /* Side.DontCare */);
    }
    get lastChild() {
      return this.child(-1, 0, 4 /* Side.DontCare */);
    }
    childAfter(pos) {
      return this.child(1, pos, 2 /* Side.After */);
    }
    childBefore(pos) {
      return this.child(-1, pos, -2 /* Side.Before */);
    }
    prop(prop) {
      return this.type.prop(prop);
    }
    enter(pos, side, mode = 0) {
      if (mode & IterMode.ExcludeBuffers) return null;
      let {
        buffer
      } = this.context;
      let index = buffer.findChild(this.index + 4, buffer.buffer[this.index + 3], side > 0 ? 1 : -1, pos - this.context.start, side);
      return index < 0 ? null : new BufferNode(this.context, this, index);
    }
    get parent() {
      return this._parent || this.context.parent.nextSignificantParent();
    }
    externalSibling(dir) {
      return this._parent ? null : this.context.parent.nextChild(this.context.index + dir, dir, 0, 4 /* Side.DontCare */);
    }
    get nextSibling() {
      let {
        buffer
      } = this.context;
      let after = buffer.buffer[this.index + 3];
      if (after < (this._parent ? buffer.buffer[this._parent.index + 3] : buffer.buffer.length)) return new BufferNode(this.context, this._parent, after);
      return this.externalSibling(1);
    }
    get prevSibling() {
      let {
        buffer
      } = this.context;
      let parentStart = this._parent ? this._parent.index + 4 : 0;
      if (this.index == parentStart) return this.externalSibling(-1);
      return new BufferNode(this.context, this._parent, buffer.findChild(parentStart, this.index, -1, 0, 4 /* Side.DontCare */));
    }
    get tree() {
      return null;
    }
    toTree() {
      let children = [],
        positions = [];
      let {
        buffer
      } = this.context;
      let startI = this.index + 4,
        endI = buffer.buffer[this.index + 3];
      if (endI > startI) {
        let from = buffer.buffer[this.index + 1];
        children.push(buffer.slice(startI, endI, from));
        positions.push(0);
      }
      return new Tree(this.type, children, positions, this.to - this.from);
    }
    /**
    @internal
    */
    toString() {
      return this.context.buffer.childString(this.index);
    }
  }
  function iterStack(heads) {
    if (!heads.length) return null;
    let pick = 0,
      picked = heads[0];
    for (let i = 1; i < heads.length; i++) {
      let node = heads[i];
      if (node.from > picked.from || node.to < picked.to) {
        picked = node;
        pick = i;
      }
    }
    let next = picked instanceof TreeNode && picked.index < 0 ? null : picked.parent;
    let newHeads = heads.slice();
    if (next) newHeads[pick] = next;else newHeads.splice(pick, 1);
    return new StackIterator(newHeads, picked);
  }
  class StackIterator {
    constructor(heads, node) {
      this.heads = heads;
      this.node = node;
    }
    get next() {
      return iterStack(this.heads);
    }
  }
  function stackIterator(tree, pos, side) {
    let inner = tree.resolveInner(pos, side),
      layers = null;
    for (let scan = inner instanceof TreeNode ? inner : inner.context.parent; scan; scan = scan.parent) {
      if (scan.index < 0) {
        // This is an overlay root
        let parent = scan.parent;
        (layers || (layers = [inner])).push(parent.resolve(pos, side));
        scan = parent;
      } else {
        let mount = MountedTree.get(scan.tree);
        // Relevant overlay branching off
        if (mount && mount.overlay && mount.overlay[0].from <= pos && mount.overlay[mount.overlay.length - 1].to >= pos) {
          let root = new TreeNode(mount.tree, mount.overlay[0].from + scan.from, -1, scan);
          (layers || (layers = [inner])).push(resolveNode(root, pos, side, false));
        }
      }
    }
    return layers ? iterStack(layers) : inner;
  }
  /**
  A tree cursor object focuses on a given node in a syntax tree, and
  allows you to move to adjacent nodes.
  */
  class TreeCursor {
    /**
    Shorthand for `.type.name`.
    */
    get name() {
      return this.type.name;
    }
    /**
    @internal
    */
    constructor(node, mode = 0) {
      /**
      @internal
      */
      this.buffer = null;
      this.stack = [];
      /**
      @internal
      */
      this.index = 0;
      this.bufferNode = null;
      this.mode = mode & ~IterMode.EnterBracketed;
      if (node instanceof TreeNode) {
        this.yieldNode(node);
      } else {
        this._tree = node.context.parent;
        this.buffer = node.context;
        for (let n = node._parent; n; n = n._parent) this.stack.unshift(n.index);
        this.bufferNode = node;
        this.yieldBuf(node.index);
      }
    }
    yieldNode(node) {
      if (!node) return false;
      this._tree = node;
      this.type = node.type;
      this.from = node.from;
      this.to = node.to;
      return true;
    }
    yieldBuf(index, type) {
      this.index = index;
      let {
        start,
        buffer
      } = this.buffer;
      this.type = type || buffer.set.types[buffer.buffer[index]];
      this.from = start + buffer.buffer[index + 1];
      this.to = start + buffer.buffer[index + 2];
      return true;
    }
    /**
    @internal
    */
    yield(node) {
      if (!node) return false;
      if (node instanceof TreeNode) {
        this.buffer = null;
        return this.yieldNode(node);
      }
      this.buffer = node.context;
      return this.yieldBuf(node.index, node.type);
    }
    /**
    @internal
    */
    toString() {
      return this.buffer ? this.buffer.buffer.childString(this.index) : this._tree.toString();
    }
    /**
    @internal
    */
    enterChild(dir, pos, side) {
      if (!this.buffer) return this.yield(this._tree.nextChild(dir < 0 ? this._tree._tree.children.length - 1 : 0, dir, pos, side, this.mode));
      let {
        buffer
      } = this.buffer;
      let index = buffer.findChild(this.index + 4, buffer.buffer[this.index + 3], dir, pos - this.buffer.start, side);
      if (index < 0) return false;
      this.stack.push(this.index);
      return this.yieldBuf(index);
    }
    /**
    Move the cursor to this node's first child. When this returns
    false, the node has no child, and the cursor has not been moved.
    */
    firstChild() {
      return this.enterChild(1, 0, 4 /* Side.DontCare */);
    }
    /**
    Move the cursor to this node's last child.
    */
    lastChild() {
      return this.enterChild(-1, 0, 4 /* Side.DontCare */);
    }
    /**
    Move the cursor to the first child that ends after `pos`.
    */
    childAfter(pos) {
      return this.enterChild(1, pos, 2 /* Side.After */);
    }
    /**
    Move to the last child that starts before `pos`.
    */
    childBefore(pos) {
      return this.enterChild(-1, pos, -2 /* Side.Before */);
    }
    /**
    Move the cursor to the child around `pos`. If side is -1 the
    child may end at that position, when 1 it may start there. This
    will also enter [overlaid](#common.MountedTree.overlay)
    [mounted](#common.NodeProp^mounted) trees unless `overlays` is
    set to false.
    */
    enter(pos, side, mode = this.mode) {
      if (!this.buffer) return this.yield(this._tree.enter(pos, side, mode));
      return mode & IterMode.ExcludeBuffers ? false : this.enterChild(1, pos, side);
    }
    /**
    Move to the node's parent node, if this isn't the top node.
    */
    parent() {
      if (!this.buffer) return this.yieldNode(this.mode & IterMode.IncludeAnonymous ? this._tree._parent : this._tree.parent);
      if (this.stack.length) return this.yieldBuf(this.stack.pop());
      let parent = this.mode & IterMode.IncludeAnonymous ? this.buffer.parent : this.buffer.parent.nextSignificantParent();
      this.buffer = null;
      return this.yieldNode(parent);
    }
    /**
    @internal
    */
    sibling(dir) {
      if (!this.buffer) return !this._tree._parent ? false : this.yield(this._tree.index < 0 ? null : this._tree._parent.nextChild(this._tree.index + dir, dir, 0, 4 /* Side.DontCare */, this.mode));
      let {
          buffer
        } = this.buffer,
        d = this.stack.length - 1;
      if (dir < 0) {
        let parentStart = d < 0 ? 0 : this.stack[d] + 4;
        if (this.index != parentStart) return this.yieldBuf(buffer.findChild(parentStart, this.index, -1, 0, 4 /* Side.DontCare */));
      } else {
        let after = buffer.buffer[this.index + 3];
        if (after < (d < 0 ? buffer.buffer.length : buffer.buffer[this.stack[d] + 3])) return this.yieldBuf(after);
      }
      return d < 0 ? this.yield(this.buffer.parent.nextChild(this.buffer.index + dir, dir, 0, 4 /* Side.DontCare */, this.mode)) : false;
    }
    /**
    Move to this node's next sibling, if any.
    */
    nextSibling() {
      return this.sibling(1);
    }
    /**
    Move to this node's previous sibling, if any.
    */
    prevSibling() {
      return this.sibling(-1);
    }
    atLastNode(dir) {
      let index,
        parent,
        {
          buffer
        } = this;
      if (buffer) {
        if (dir > 0) {
          if (this.index < buffer.buffer.buffer.length) return false;
        } else {
          for (let i = 0; i < this.index; i++) if (buffer.buffer.buffer[i + 3] < this.index) return false;
        }
        ({
          index,
          parent
        } = buffer);
      } else {
        ({
          index,
          _parent: parent
        } = this._tree);
      }
      for (; parent; {
        index,
        _parent: parent
      } = parent) {
        if (index > -1) for (let i = index + dir, e = dir < 0 ? -1 : parent._tree.children.length; i != e; i += dir) {
          let child = parent._tree.children[i];
          if (this.mode & IterMode.IncludeAnonymous || child instanceof TreeBuffer || !child.type.isAnonymous || hasChild(child)) return false;
        }
      }
      return true;
    }
    move(dir, enter) {
      if (enter && this.enterChild(dir, 0, 4 /* Side.DontCare */)) return true;
      for (;;) {
        if (this.sibling(dir)) return true;
        if (this.atLastNode(dir) || !this.parent()) return false;
      }
    }
    /**
    Move to the next node in a
    [pre-order](https://en.wikipedia.org/wiki/Tree_traversal#Pre-order,_NLR)
    traversal, going from a node to its first child or, if the
    current node is empty or `enter` is false, its next sibling or
    the next sibling of the first parent node that has one.
    */
    next(enter = true) {
      return this.move(1, enter);
    }
    /**
    Move to the next node in a last-to-first pre-order traversal. A
    node is followed by its last child or, if it has none, its
    previous sibling or the previous sibling of the first parent
    node that has one.
    */
    prev(enter = true) {
      return this.move(-1, enter);
    }
    /**
    Move the cursor to the innermost node that covers `pos`. If
    `side` is -1, it will enter nodes that end at `pos`. If it is 1,
    it will enter nodes that start at `pos`.
    */
    moveTo(pos, side = 0) {
      // Move up to a node that actually holds the position, if possible
      while (this.from == this.to || (side < 1 ? this.from >= pos : this.from > pos) || (side > -1 ? this.to <= pos : this.to < pos)) if (!this.parent()) break;
      // Then scan down into child nodes as far as possible
      while (this.enterChild(1, pos, side)) {}
      return this;
    }
    /**
    Get a [syntax node](#common.SyntaxNode) at the cursor's current
    position.
    */
    get node() {
      if (!this.buffer) return this._tree;
      let cache = this.bufferNode,
        result = null,
        depth = 0;
      if (cache && cache.context == this.buffer) {
        scan: for (let index = this.index, d = this.stack.length; d >= 0;) {
          for (let c = cache; c; c = c._parent) if (c.index == index) {
            if (index == this.index) return c;
            result = c;
            depth = d + 1;
            break scan;
          }
          index = this.stack[--d];
        }
      }
      for (let i = depth; i < this.stack.length; i++) result = new BufferNode(this.buffer, result, this.stack[i]);
      return this.bufferNode = new BufferNode(this.buffer, result, this.index);
    }
    /**
    Get the [tree](#common.Tree) that represents the current node, if
    any. Will return null when the node is in a [tree
    buffer](#common.TreeBuffer).
    */
    get tree() {
      return this.buffer ? null : this._tree._tree;
    }
    /**
    Iterate over the current node and all its descendants, calling
    `enter` when entering a node and `leave`, if given, when leaving
    one. When `enter` returns `false`, any children of that node are
    skipped, and `leave` isn't called for it.
    */
    iterate(enter, leave) {
      for (let depth = 0;;) {
        let mustLeave = false;
        if (this.type.isAnonymous || enter(this) !== false) {
          if (this.firstChild()) {
            depth++;
            continue;
          }
          if (!this.type.isAnonymous) mustLeave = true;
        }
        for (;;) {
          if (mustLeave && leave) leave(this);
          mustLeave = this.type.isAnonymous;
          if (!depth) return;
          if (this.nextSibling()) break;
          this.parent();
          depth--;
          mustLeave = true;
        }
      }
    }
    /**
    Test whether the current node matches a given context—a sequence
    of direct parent node names. Empty strings in the context array
    are treated as wildcards.
    */
    matchContext(context) {
      if (!this.buffer) return matchNodeContext(this.node.parent, context);
      let {
          buffer
        } = this.buffer,
        {
          types
        } = buffer.set;
      for (let i = context.length - 1, d = this.stack.length - 1; i >= 0; d--) {
        if (d < 0) return matchNodeContext(this._tree, context, i);
        let type = types[buffer.buffer[this.stack[d]]];
        if (!type.isAnonymous) {
          if (context[i] && context[i] != type.name) return false;
          i--;
        }
      }
      return true;
    }
  }
  function hasChild(tree) {
    return tree.children.some(ch => ch instanceof TreeBuffer || !ch.type.isAnonymous || hasChild(ch));
  }
  function buildTree(data) {
    var _a;
    let {
      buffer,
      nodeSet,
      maxBufferLength = DefaultBufferLength,
      reused = [],
      minRepeatType = nodeSet.types.length
    } = data;
    let cursor = Array.isArray(buffer) ? new FlatBufferCursor(buffer, buffer.length) : buffer;
    let types = nodeSet.types;
    let contextHash = 0,
      lookAhead = 0;
    function takeNode(parentStart, minPos, children, positions, inRepeat, depth) {
      let {
        id,
        start,
        end,
        size
      } = cursor;
      let lookAheadAtStart = lookAhead,
        contextAtStart = contextHash;
      if (size < 0) {
        cursor.next();
        if (size == -1 /* SpecialRecord.Reuse */) {
          let node = reused[id];
          children.push(node);
          positions.push(start - parentStart);
          return;
        } else if (size == -3 /* SpecialRecord.ContextChange */) {
          // Context change
          contextHash = id;
          return;
        } else if (size == -4 /* SpecialRecord.LookAhead */) {
          lookAhead = id;
          return;
        } else {
          throw new RangeError(`Unrecognized record size: ${size}`);
        }
      }
      let type = types[id],
        node,
        buffer;
      let startPos = start - parentStart;
      if (end - start <= maxBufferLength && (buffer = findBufferSize(cursor.pos - minPos, inRepeat))) {
        // Small enough for a buffer, and no reused nodes inside
        let data = new Uint16Array(buffer.size - buffer.skip);
        let endPos = cursor.pos - buffer.size,
          index = data.length;
        while (cursor.pos > endPos) index = copyToBuffer(buffer.start, data, index);
        node = new TreeBuffer(data, end - buffer.start, nodeSet);
        startPos = buffer.start - parentStart;
      } else {
        // Make it a node
        let endPos = cursor.pos - size;
        cursor.next();
        let localChildren = [],
          localPositions = [];
        let localInRepeat = id >= minRepeatType ? id : -1;
        let lastGroup = 0,
          lastEnd = end;
        while (cursor.pos > endPos) {
          if (localInRepeat >= 0 && cursor.id == localInRepeat && cursor.size >= 0) {
            if (cursor.end <= lastEnd - maxBufferLength) {
              makeRepeatLeaf(localChildren, localPositions, start, lastGroup, cursor.end, lastEnd, localInRepeat, lookAheadAtStart, contextAtStart);
              lastGroup = localChildren.length;
              lastEnd = cursor.end;
            }
            cursor.next();
          } else if (depth > 2500 /* CutOff.Depth */) {
            takeFlatNode(start, endPos, localChildren, localPositions);
          } else {
            takeNode(start, endPos, localChildren, localPositions, localInRepeat, depth + 1);
          }
        }
        if (localInRepeat >= 0 && lastGroup > 0 && lastGroup < localChildren.length) makeRepeatLeaf(localChildren, localPositions, start, lastGroup, start, lastEnd, localInRepeat, lookAheadAtStart, contextAtStart);
        localChildren.reverse();
        localPositions.reverse();
        if (localInRepeat > -1 && lastGroup > 0) {
          let make = makeBalanced(type, contextAtStart);
          node = balanceRange(type, localChildren, localPositions, 0, localChildren.length, 0, end - start, make, make);
        } else {
          node = makeTree(type, localChildren, localPositions, end - start, lookAheadAtStart - end, contextAtStart);
        }
      }
      children.push(node);
      positions.push(startPos);
    }
    function takeFlatNode(parentStart, minPos, children, positions) {
      let nodes = []; // Temporary, inverted array of leaf nodes found, with absolute positions
      let nodeCount = 0,
        stopAt = -1;
      while (cursor.pos > minPos) {
        let {
          id,
          start,
          end,
          size
        } = cursor;
        if (size > 4) {
          // Not a leaf
          cursor.next();
        } else if (stopAt > -1 && start < stopAt) {
          break;
        } else {
          if (stopAt < 0) stopAt = end - maxBufferLength;
          nodes.push(id, start, end);
          nodeCount++;
          cursor.next();
        }
      }
      if (nodeCount) {
        let buffer = new Uint16Array(nodeCount * 4);
        let start = nodes[nodes.length - 2];
        for (let i = nodes.length - 3, j = 0; i >= 0; i -= 3) {
          buffer[j++] = nodes[i];
          buffer[j++] = nodes[i + 1] - start;
          buffer[j++] = nodes[i + 2] - start;
          buffer[j++] = j;
        }
        children.push(new TreeBuffer(buffer, nodes[2] - start, nodeSet));
        positions.push(start - parentStart);
      }
    }
    function makeBalanced(type, contextHash) {
      return (children, positions, length) => {
        let lookAhead = 0,
          lastI = children.length - 1,
          last,
          lookAheadProp;
        if (lastI >= 0 && (last = children[lastI]) instanceof Tree) {
          if (!lastI && last.type == type && last.length == length) return last;
          if (lookAheadProp = last.prop(NodeProp.lookAhead)) lookAhead = positions[lastI] + last.length + lookAheadProp;
        }
        return makeTree(type, children, positions, length, lookAhead, contextHash);
      };
    }
    function makeRepeatLeaf(children, positions, base, i, from, to, type, lookAhead, contextHash) {
      let localChildren = [],
        localPositions = [];
      while (children.length > i) {
        localChildren.push(children.pop());
        localPositions.push(positions.pop() + base - from);
      }
      children.push(makeTree(nodeSet.types[type], localChildren, localPositions, to - from, lookAhead - to, contextHash));
      positions.push(from - base);
    }
    function makeTree(type, children, positions, length, lookAhead, contextHash, props) {
      if (contextHash) {
        let pair = [NodeProp.contextHash, contextHash];
        props = props ? [pair].concat(props) : [pair];
      }
      if (lookAhead > 25) {
        let pair = [NodeProp.lookAhead, lookAhead];
        props = props ? [pair].concat(props) : [pair];
      }
      return new Tree(type, children, positions, length, props);
    }
    function findBufferSize(maxSize, inRepeat) {
      // Scan through the buffer to find previous siblings that fit
      // together in a TreeBuffer, and don't contain any reused nodes
      // (which can't be stored in a buffer).
      // If `inRepeat` is > -1, ignore node boundaries of that type for
      // nesting, but make sure the end falls either at the start
      // (`maxSize`) or before such a node.
      let fork = cursor.fork();
      let size = 0,
        start = 0,
        skip = 0,
        minStart = fork.end - maxBufferLength;
      let result = {
        size: 0,
        start: 0,
        skip: 0
      };
      scan: for (let minPos = fork.pos - maxSize; fork.pos > minPos;) {
        let nodeSize = fork.size;
        // Pretend nested repeat nodes of the same type don't exist
        if (fork.id == inRepeat && nodeSize >= 0) {
          // Except that we store the current state as a valid return
          // value.
          result.size = size;
          result.start = start;
          result.skip = skip;
          skip += 4;
          size += 4;
          fork.next();
          continue;
        }
        let startPos = fork.pos - nodeSize;
        if (nodeSize < 0 || startPos < minPos || fork.start < minStart) break;
        let localSkipped = fork.id >= minRepeatType ? 4 : 0;
        let nodeStart = fork.start;
        fork.next();
        while (fork.pos > startPos) {
          if (fork.size < 0) {
            if (fork.size == -3 /* SpecialRecord.ContextChange */ || fork.size == -4 /* SpecialRecord.LookAhead */) localSkipped += 4;else break scan;
          } else if (fork.id >= minRepeatType) {
            localSkipped += 4;
          }
          fork.next();
        }
        start = nodeStart;
        size += nodeSize;
        skip += localSkipped;
      }
      if (inRepeat < 0 || size == maxSize) {
        result.size = size;
        result.start = start;
        result.skip = skip;
      }
      return result.size > 4 ? result : undefined;
    }
    function copyToBuffer(bufferStart, buffer, index) {
      let {
        id,
        start,
        end,
        size
      } = cursor;
      cursor.next();
      if (size >= 0 && id < minRepeatType) {
        let startIndex = index;
        if (size > 4) {
          let endPos = cursor.pos - (size - 4);
          while (cursor.pos > endPos) index = copyToBuffer(bufferStart, buffer, index);
        }
        buffer[--index] = startIndex;
        buffer[--index] = end - bufferStart;
        buffer[--index] = start - bufferStart;
        buffer[--index] = id;
      } else if (size == -3 /* SpecialRecord.ContextChange */) {
        contextHash = id;
      } else if (size == -4 /* SpecialRecord.LookAhead */) {
        lookAhead = id;
      }
      return index;
    }
    let children = [],
      positions = [];
    while (cursor.pos > 0) takeNode(data.start || 0, data.bufferStart || 0, children, positions, -1, 0);
    let length = (_a = data.length) !== null && _a !== void 0 ? _a : children.length ? positions[0] + children[0].length : 0;
    return new Tree(types[data.topID], children.reverse(), positions.reverse(), length);
  }
  const nodeSizeCache = new WeakMap();
  function nodeSize(balanceType, node) {
    if (!balanceType.isAnonymous || node instanceof TreeBuffer || node.type != balanceType) return 1;
    let size = nodeSizeCache.get(node);
    if (size == null) {
      size = 1;
      for (let child of node.children) {
        if (child.type != balanceType || !(child instanceof Tree)) {
          size = 1;
          break;
        }
        size += nodeSize(balanceType, child);
      }
      nodeSizeCache.set(node, size);
    }
    return size;
  }
  function balanceRange(
  // The type the balanced tree's inner nodes.
  balanceType,
  // The direct children and their positions
  children, positions,
  // The index range in children/positions to use
  from, to,
  // The start position of the nodes, relative to their parent.
  start,
  // Length of the outer node
  length,
  // Function to build the top node of the balanced tree
  mkTop,
  // Function to build internal nodes for the balanced tree
  mkTree) {
    let total = 0;
    for (let i = from; i < to; i++) total += nodeSize(balanceType, children[i]);
    let maxChild = Math.ceil(total * 1.5 / 8 /* Balance.BranchFactor */);
    let localChildren = [],
      localPositions = [];
    function divide(children, positions, from, to, offset) {
      for (let i = from; i < to;) {
        let groupFrom = i,
          groupStart = positions[i],
          groupSize = nodeSize(balanceType, children[i]);
        i++;
        for (; i < to; i++) {
          let nextSize = nodeSize(balanceType, children[i]);
          if (groupSize + nextSize >= maxChild) break;
          groupSize += nextSize;
        }
        if (i == groupFrom + 1) {
          if (groupSize > maxChild) {
            let only = children[groupFrom]; // Only trees can have a size > 1
            divide(only.children, only.positions, 0, only.children.length, positions[groupFrom] + offset);
            continue;
          }
          localChildren.push(children[groupFrom]);
        } else {
          let length = positions[i - 1] + children[i - 1].length - groupStart;
          localChildren.push(balanceRange(balanceType, children, positions, groupFrom, i, groupStart, length, null, mkTree));
        }
        localPositions.push(groupStart + offset - start);
      }
    }
    divide(children, positions, from, to, 0);
    return (mkTop || mkTree)(localChildren, localPositions, length);
  }

  /**
  Tree fragments are used during [incremental
  parsing](#common.Parser.startParse) to track parts of old trees
  that can be reused in a new parse. An array of fragments is used
  to track regions of an old tree whose nodes might be reused in new
  parses. Use the static
  [`applyChanges`](#common.TreeFragment^applyChanges) method to
  update fragments for document changes.
  */
  class TreeFragment {
    /**
    Construct a tree fragment. You'll usually want to use
    [`addTree`](#common.TreeFragment^addTree) and
    [`applyChanges`](#common.TreeFragment^applyChanges) instead of
    calling this directly.
    */
    constructor(
    /**
    The start of the unchanged range pointed to by this fragment.
    This refers to an offset in the _updated_ document (as opposed
    to the original tree).
    */
    from,
    /**
    The end of the unchanged range.
    */
    to,
    /**
    The tree that this fragment is based on.
    */
    tree,
    /**
    The offset between the fragment's tree and the document that
    this fragment can be used against. Add this when going from
    document to tree positions, subtract it to go from tree to
    document positions.
    */
    offset, openStart = false, openEnd = false) {
      this.from = from;
      this.to = to;
      this.tree = tree;
      this.offset = offset;
      this.open = (openStart ? 1 /* Open.Start */ : 0) | (openEnd ? 2 /* Open.End */ : 0);
    }
    /**
    Whether the start of the fragment represents the start of a
    parse, or the end of a change. (In the second case, it may not
    be safe to reuse some nodes at the start, depending on the
    parsing algorithm.)
    */
    get openStart() {
      return (this.open & 1 /* Open.Start */) > 0;
    }
    /**
    Whether the end of the fragment represents the end of a
    full-document parse, or the start of a change.
    */
    get openEnd() {
      return (this.open & 2 /* Open.End */) > 0;
    }
    /**
    Create a set of fragments from a freshly parsed tree, or update
    an existing set of fragments by replacing the ones that overlap
    with a tree with content from the new tree. When `partial` is
    true, the parse is treated as incomplete, and the resulting
    fragment has [`openEnd`](#common.TreeFragment.openEnd) set to
    true.
    */
    static addTree(tree, fragments = [], partial = false) {
      let result = [new TreeFragment(0, tree.length, tree, 0, false, partial)];
      for (let f of fragments) if (f.to > tree.length) result.push(f);
      return result;
    }
    /**
    Apply a set of edits to an array of fragments, removing or
    splitting fragments as necessary to remove edited ranges, and
    adjusting offsets for fragments that moved.
    */
    static applyChanges(fragments, changes, minGap = 128) {
      if (!changes.length) return fragments;
      let result = [];
      let fI = 1,
        nextF = fragments.length ? fragments[0] : null;
      for (let cI = 0, pos = 0, off = 0;; cI++) {
        let nextC = cI < changes.length ? changes[cI] : null;
        let nextPos = nextC ? nextC.fromA : 1e9;
        if (nextPos - pos >= minGap) while (nextF && nextF.from < nextPos) {
          let cut = nextF;
          if (pos >= cut.from || nextPos <= cut.to || off) {
            let fFrom = Math.max(cut.from, pos) - off,
              fTo = Math.min(cut.to, nextPos) - off;
            cut = fFrom >= fTo ? null : new TreeFragment(fFrom, fTo, cut.tree, cut.offset + off, cI > 0, !!nextC);
          }
          if (cut) result.push(cut);
          if (nextF.to > nextPos) break;
          nextF = fI < fragments.length ? fragments[fI++] : null;
        }
        if (!nextC) break;
        pos = nextC.toA;
        off = nextC.toA - nextC.toB;
      }
      return result;
    }
  }
  /**
  A superclass that parsers should extend.
  */
  class Parser {
    /**
    Start a parse, returning a [partial parse](#common.PartialParse)
    object. [`fragments`](#common.TreeFragment) can be passed in to
    make the parse incremental.
    
    By default, the entire input is parsed. You can pass `ranges`,
    which should be a sorted array of non-empty, non-overlapping
    ranges, to parse only those ranges. The tree returned in that
    case will start at `ranges[0].from`.
    */
    startParse(input, fragments, ranges) {
      if (typeof input == "string") input = new StringInput(input);
      ranges = !ranges ? [new Range(0, input.length)] : ranges.length ? ranges.map(r => new Range(r.from, r.to)) : [new Range(0, 0)];
      return this.createParse(input, fragments || [], ranges);
    }
    /**
    Run a full parse, returning the resulting tree.
    */
    parse(input, fragments, ranges) {
      let parse = this.startParse(input, fragments, ranges);
      for (;;) {
        let done = parse.advance();
        if (done) return done;
      }
    }
  }
  class StringInput {
    constructor(string) {
      this.string = string;
    }
    get length() {
      return this.string.length;
    }
    chunk(from) {
      return this.string.slice(from);
    }
    get lineChunks() {
      return false;
    }
    read(from, to) {
      return this.string.slice(from, to);
    }
  }
  new NodeProp({
    perNode: true
  });

  let nextTagID = 0;
  /**
  Highlighting tags are markers that denote a highlighting category.
  They are [associated](#highlight.styleTags) with parts of a syntax
  tree by a language mode, and then mapped to an actual CSS style by
  a [highlighter](#highlight.Highlighter).

  Because syntax tree node types and highlight styles have to be
  able to talk the same language, CodeMirror uses a mostly _closed_
  [vocabulary](#highlight.tags) of syntax tags (as opposed to
  traditional open string-based systems, which make it hard for
  highlighting themes to cover all the tokens produced by the
  various languages).

  It _is_ possible to [define](#highlight.Tag^define) your own
  highlighting tags for system-internal use (where you control both
  the language package and the highlighter), but such tags will not
  be picked up by regular highlighters (though you can derive them
  from standard tags to allow highlighters to fall back to those).
  */
  class Tag {
    /**
    @internal
    */
    constructor(
    /**
    The optional name of the base tag @internal
    */
    name,
    /**
    The set of this tag and all its parent tags, starting with
    this one itself and sorted in order of decreasing specificity.
    */
    set,
    /**
    The base unmodified tag that this one is based on, if it's
    modified @internal
    */
    base,
    /**
    The modifiers applied to this.base @internal
    */
    modified) {
      this.name = name;
      this.set = set;
      this.base = base;
      this.modified = modified;
      /**
      @internal
      */
      this.id = nextTagID++;
    }
    toString() {
      let {
        name
      } = this;
      for (let mod of this.modified) if (mod.name) name = `${mod.name}(${name})`;
      return name;
    }
    static define(nameOrParent, parent) {
      let name = typeof nameOrParent == "string" ? nameOrParent : "?";
      if (nameOrParent instanceof Tag) parent = nameOrParent;
      if (parent === null || parent === void 0 ? void 0 : parent.base) throw new Error("Can not derive from a modified tag");
      let tag = new Tag(name, [], null, []);
      tag.set.push(tag);
      if (parent) for (let t of parent.set) tag.set.push(t);
      return tag;
    }
    /**
    Define a tag _modifier_, which is a function that, given a tag,
    will return a tag that is a subtag of the original. Applying the
    same modifier to a twice tag will return the same value (`m1(t1)
    == m1(t1)`) and applying multiple modifiers will, regardless or
    order, produce the same tag (`m1(m2(t1)) == m2(m1(t1))`).
    
    When multiple modifiers are applied to a given base tag, each
    smaller set of modifiers is registered as a parent, so that for
    example `m1(m2(m3(t1)))` is a subtype of `m1(m2(t1))`,
    `m1(m3(t1)`, and so on.
    */
    static defineModifier(name) {
      let mod = new Modifier(name);
      return tag => {
        if (tag.modified.indexOf(mod) > -1) return tag;
        return Modifier.get(tag.base || tag, tag.modified.concat(mod).sort((a, b) => a.id - b.id));
      };
    }
  }
  let nextModifierID = 0;
  class Modifier {
    constructor(name) {
      this.name = name;
      this.instances = [];
      this.id = nextModifierID++;
    }
    static get(base, mods) {
      if (!mods.length) return base;
      let exists = mods[0].instances.find(t => t.base == base && sameArray(mods, t.modified));
      if (exists) return exists;
      let set = [],
        tag = new Tag(base.name, set, base, mods);
      for (let m of mods) m.instances.push(tag);
      let configs = powerSet(mods);
      for (let parent of base.set) if (!parent.modified.length) for (let config of configs) set.push(Modifier.get(parent, config));
      return tag;
    }
  }
  function sameArray(a, b) {
    return a.length == b.length && a.every((x, i) => x == b[i]);
  }
  function powerSet(array) {
    let sets = [[]];
    for (let i = 0; i < array.length; i++) {
      for (let j = 0, e = sets.length; j < e; j++) {
        sets.push(sets[j].concat(array[i]));
      }
    }
    return sets.sort((a, b) => b.length - a.length);
  }
  /**
  This function is used to add a set of tags to a language syntax
  via [`NodeSet.extend`](#common.NodeSet.extend) or
  [`LRParser.configure`](#lr.LRParser.configure).

  The argument object maps node selectors to [highlighting
  tags](#highlight.Tag) or arrays of tags.

  Node selectors may hold one or more (space-separated) node paths.
  Such a path can be a [node name](#common.NodeType.name), or
  multiple node names (or `*` wildcards) separated by slash
  characters, as in `"Block/Declaration/VariableName"`. Such a path
  matches the final node but only if its direct parent nodes are the
  other nodes mentioned. A `*` in such a path matches any parent,
  but only a single level—wildcards that match multiple parents
  aren't supported, both for efficiency reasons and because Lezer
  trees make it rather hard to reason about what they would match.)

  A path can be ended with `/...` to indicate that the tag assigned
  to the node should also apply to all child nodes, even if they
  match their own style (by default, only the innermost style is
  used).

  When a path ends in `!`, as in `Attribute!`, no further matching
  happens for the node's child nodes, and the entire node gets the
  given style.

  In this notation, node names that contain `/`, `!`, `*`, or `...`
  must be quoted as JSON strings.

  For example:

  ```javascript
  parser.configure({props: [
    styleTags({
      // Style Number and BigNumber nodes
      "Number BigNumber": tags.number,
      // Style Escape nodes whose parent is String
      "String/Escape": tags.escape,
      // Style anything inside Attributes nodes
      "Attributes!": tags.meta,
      // Add a style to all content inside Italic nodes
      "Italic/...": tags.emphasis,
      // Style InvalidString nodes as both `string` and `invalid`
      "InvalidString": [tags.string, tags.invalid],
      // Style the node named "/" as punctuation
      '"/"': tags.punctuation
    })
  ]})
  ```
  */
  function styleTags(spec) {
    let byName = Object.create(null);
    for (let prop in spec) {
      let tags = spec[prop];
      if (!Array.isArray(tags)) tags = [tags];
      for (let part of prop.split(" ")) if (part) {
        let pieces = [],
          mode = 2 /* Mode.Normal */,
          rest = part;
        for (let pos = 0;;) {
          if (rest == "..." && pos > 0 && pos + 3 == part.length) {
            mode = 1 /* Mode.Inherit */;
            break;
          }
          let m = /^"(?:[^"\\]|\\.)*?"|[^\/!]+/.exec(rest);
          if (!m) throw new RangeError("Invalid path: " + part);
          pieces.push(m[0] == "*" ? "" : m[0][0] == '"' ? JSON.parse(m[0]) : m[0]);
          pos += m[0].length;
          if (pos == part.length) break;
          let next = part[pos++];
          if (pos == part.length && next == "!") {
            mode = 0 /* Mode.Opaque */;
            break;
          }
          if (next != "/") throw new RangeError("Invalid path: " + part);
          rest = part.slice(pos);
        }
        let last = pieces.length - 1,
          inner = pieces[last];
        if (!inner) throw new RangeError("Invalid path: " + part);
        let rule = new Rule(tags, mode, last > 0 ? pieces.slice(0, last) : null);
        byName[inner] = rule.sort(byName[inner]);
      }
    }
    return ruleNodeProp.add(byName);
  }
  const ruleNodeProp = new NodeProp({
    combine(a, b) {
      let cur, root, take;
      while (a || b) {
        if (!a || b && a.depth >= b.depth) {
          take = b;
          b = b.next;
        } else {
          take = a;
          a = a.next;
        }
        if (cur && cur.mode == take.mode && !take.context && !cur.context) continue;
        let copy = new Rule(take.tags, take.mode, take.context);
        if (cur) cur.next = copy;else root = copy;
        cur = copy;
      }
      return root;
    }
  });
  class Rule {
    constructor(tags, mode, context, next) {
      this.tags = tags;
      this.mode = mode;
      this.context = context;
      this.next = next;
    }
    get opaque() {
      return this.mode == 0 /* Mode.Opaque */;
    }
    get inherit() {
      return this.mode == 1 /* Mode.Inherit */;
    }
    sort(other) {
      if (!other || other.depth < this.depth) {
        this.next = other;
        return this;
      }
      other.next = this.sort(other.next);
      return other;
    }
    get depth() {
      return this.context ? this.context.length : 0;
    }
  }
  Rule.empty = new Rule([], 2 /* Mode.Normal */, null);
  /**
  Define a [highlighter](#highlight.Highlighter) from an array of
  tag/class pairs. Classes associated with more specific tags will
  take precedence.
  */
  function tagHighlighter(tags, options) {
    let map = Object.create(null);
    for (let style of tags) {
      if (!Array.isArray(style.tag)) map[style.tag.id] = style.class;else for (let tag of style.tag) map[tag.id] = style.class;
    }
    let {
      scope,
      all = null
    } = options || {};
    return {
      style: tags => {
        let cls = all;
        for (let tag of tags) {
          for (let sub of tag.set) {
            let tagClass = map[sub.id];
            if (tagClass) {
              cls = cls ? cls + " " + tagClass : tagClass;
              break;
            }
          }
        }
        return cls;
      },
      scope
    };
  }
  function highlightTags(highlighters, tags) {
    let result = null;
    for (let highlighter of highlighters) {
      let value = highlighter.style(tags);
      if (value) result = result ? result + " " + value : value;
    }
    return result;
  }
  /**
  Highlight the given [tree](#common.Tree) with the given
  [highlighter](#highlight.Highlighter). Often, the higher-level
  [`highlightCode`](#highlight.highlightCode) function is easier to
  use.
  */
  function highlightTree(tree, highlighter,
  /**
  Assign styling to a region of the text. Will be called, in order
  of position, for any ranges where more than zero classes apply.
  `classes` is a space separated string of CSS classes.
  */
  putStyle,
  /**
  The start of the range to highlight.
  */
  from = 0,
  /**
  The end of the range.
  */
  to = tree.length) {
    let builder = new HighlightBuilder(from, Array.isArray(highlighter) ? highlighter : [highlighter], putStyle);
    builder.highlightRange(tree.cursor(), from, to, "", builder.highlighters);
    builder.flush(to);
  }
  class HighlightBuilder {
    constructor(at, highlighters, span) {
      this.at = at;
      this.highlighters = highlighters;
      this.span = span;
      this.class = "";
    }
    startSpan(at, cls) {
      if (cls != this.class) {
        this.flush(at);
        if (at > this.at) this.at = at;
        this.class = cls;
      }
    }
    flush(to) {
      if (to > this.at && this.class) this.span(this.at, to, this.class);
    }
    highlightRange(cursor, from, to, inheritedClass, highlighters) {
      let {
        type,
        from: start,
        to: end
      } = cursor;
      if (start >= to || end <= from) return;
      if (type.isTop) highlighters = this.highlighters.filter(h => !h.scope || h.scope(type));
      let cls = inheritedClass;
      let rule = getStyleTags(cursor) || Rule.empty;
      let tagCls = highlightTags(highlighters, rule.tags);
      if (tagCls) {
        if (cls) cls += " ";
        cls += tagCls;
        if (rule.mode == 1 /* Mode.Inherit */) inheritedClass += (inheritedClass ? " " : "") + tagCls;
      }
      this.startSpan(Math.max(from, start), cls);
      if (rule.opaque) return;
      let mounted = cursor.tree && cursor.tree.prop(NodeProp.mounted);
      if (mounted && mounted.overlay) {
        let inner = cursor.node.enter(mounted.overlay[0].from + start, 1);
        let innerHighlighters = this.highlighters.filter(h => !h.scope || h.scope(mounted.tree.type));
        let hasChild = cursor.firstChild();
        for (let i = 0, pos = start;; i++) {
          let next = i < mounted.overlay.length ? mounted.overlay[i] : null;
          let nextPos = next ? next.from + start : end;
          let rangeFrom = Math.max(from, pos),
            rangeTo = Math.min(to, nextPos);
          if (rangeFrom < rangeTo && hasChild) {
            while (cursor.from < rangeTo) {
              this.highlightRange(cursor, rangeFrom, rangeTo, inheritedClass, highlighters);
              this.startSpan(Math.min(rangeTo, cursor.to), cls);
              if (cursor.to >= nextPos || !cursor.nextSibling()) break;
            }
          }
          if (!next || nextPos > to) break;
          pos = next.to + start;
          if (pos > from) {
            this.highlightRange(inner.cursor(), Math.max(from, next.from + start), Math.min(to, pos), "", innerHighlighters);
            this.startSpan(Math.min(to, pos), cls);
          }
        }
        if (hasChild) cursor.parent();
      } else if (cursor.firstChild()) {
        if (mounted) inheritedClass = "";
        do {
          if (cursor.to <= from) continue;
          if (cursor.from >= to) break;
          this.highlightRange(cursor, from, to, inheritedClass, highlighters);
          this.startSpan(Math.min(to, cursor.to), cls);
        } while (cursor.nextSibling());
        cursor.parent();
      }
    }
  }
  /**
  Match a syntax node's [highlight rules](#highlight.styleTags). If
  there's a match, return its set of tags, and whether it is
  opaque (uses a `!`) or applies to all child nodes (`/...`).
  */
  function getStyleTags(node) {
    let rule = node.type.prop(ruleNodeProp);
    while (rule && rule.context && !node.matchContext(rule.context)) rule = rule.next;
    return rule || null;
  }
  const t = Tag.define;
  const comment = t(),
    name = t(),
    typeName = t(name),
    propertyName = t(name),
    literal = t(),
    string = t(literal),
    number = t(literal),
    content = t(),
    heading = t(content),
    keyword = t(),
    operator = t(),
    punctuation = t(),
    bracket = t(punctuation),
    meta = t();
  /**
  The default set of highlighting [tags](#highlight.Tag).

  This collection is heavily biased towards programming languages,
  and necessarily incomplete. A full ontology of syntactic
  constructs would fill a stack of books, and be impractical to
  write themes for. So try to make do with this set. If all else
  fails, [open an
  issue](https://github.com/codemirror/codemirror.next) to propose a
  new tag, or [define](#highlight.Tag^define) a local custom tag for
  your use case.

  Note that it is not obligatory to always attach the most specific
  tag possible to an element—if your grammar can't easily
  distinguish a certain type of element (such as a local variable),
  it is okay to style it as its more general variant (a variable).

  For tags that extend some parent tag, the documentation links to
  the parent.
  */
  const tags = {
    /**
    A comment.
    */
    comment,
    /**
    A line [comment](#highlight.tags.comment).
    */
    lineComment: t(comment),
    /**
    A block [comment](#highlight.tags.comment).
    */
    blockComment: t(comment),
    /**
    A documentation [comment](#highlight.tags.comment).
    */
    docComment: t(comment),
    /**
    Any kind of identifier.
    */
    name,
    /**
    The [name](#highlight.tags.name) of a variable.
    */
    variableName: t(name),
    /**
    A type [name](#highlight.tags.name).
    */
    typeName: typeName,
    /**
    A tag name (subtag of [`typeName`](#highlight.tags.typeName)).
    */
    tagName: t(typeName),
    /**
    A property or field [name](#highlight.tags.name).
    */
    propertyName: propertyName,
    /**
    An attribute name (subtag of [`propertyName`](#highlight.tags.propertyName)).
    */
    attributeName: t(propertyName),
    /**
    The [name](#highlight.tags.name) of a class.
    */
    className: t(name),
    /**
    A label [name](#highlight.tags.name).
    */
    labelName: t(name),
    /**
    A namespace [name](#highlight.tags.name).
    */
    namespace: t(name),
    /**
    The [name](#highlight.tags.name) of a macro.
    */
    macroName: t(name),
    /**
    A literal value.
    */
    literal,
    /**
    A string [literal](#highlight.tags.literal).
    */
    string,
    /**
    A documentation [string](#highlight.tags.string).
    */
    docString: t(string),
    /**
    A character literal (subtag of [string](#highlight.tags.string)).
    */
    character: t(string),
    /**
    An attribute value (subtag of [string](#highlight.tags.string)).
    */
    attributeValue: t(string),
    /**
    A number [literal](#highlight.tags.literal).
    */
    number,
    /**
    An integer [number](#highlight.tags.number) literal.
    */
    integer: t(number),
    /**
    A floating-point [number](#highlight.tags.number) literal.
    */
    float: t(number),
    /**
    A boolean [literal](#highlight.tags.literal).
    */
    bool: t(literal),
    /**
    Regular expression [literal](#highlight.tags.literal).
    */
    regexp: t(literal),
    /**
    An escape [literal](#highlight.tags.literal), for example a
    backslash escape in a string.
    */
    escape: t(literal),
    /**
    A color [literal](#highlight.tags.literal).
    */
    color: t(literal),
    /**
    A URL [literal](#highlight.tags.literal).
    */
    url: t(literal),
    /**
    A language keyword.
    */
    keyword,
    /**
    The [keyword](#highlight.tags.keyword) for the self or this
    object.
    */
    self: t(keyword),
    /**
    The [keyword](#highlight.tags.keyword) for null.
    */
    null: t(keyword),
    /**
    A [keyword](#highlight.tags.keyword) denoting some atomic value.
    */
    atom: t(keyword),
    /**
    A [keyword](#highlight.tags.keyword) that represents a unit.
    */
    unit: t(keyword),
    /**
    A modifier [keyword](#highlight.tags.keyword).
    */
    modifier: t(keyword),
    /**
    A [keyword](#highlight.tags.keyword) that acts as an operator.
    */
    operatorKeyword: t(keyword),
    /**
    A control-flow related [keyword](#highlight.tags.keyword).
    */
    controlKeyword: t(keyword),
    /**
    A [keyword](#highlight.tags.keyword) that defines something.
    */
    definitionKeyword: t(keyword),
    /**
    A [keyword](#highlight.tags.keyword) related to defining or
    interfacing with modules.
    */
    moduleKeyword: t(keyword),
    /**
    An operator.
    */
    operator,
    /**
    An [operator](#highlight.tags.operator) that dereferences something.
    */
    derefOperator: t(operator),
    /**
    Arithmetic-related [operator](#highlight.tags.operator).
    */
    arithmeticOperator: t(operator),
    /**
    Logical [operator](#highlight.tags.operator).
    */
    logicOperator: t(operator),
    /**
    Bit [operator](#highlight.tags.operator).
    */
    bitwiseOperator: t(operator),
    /**
    Comparison [operator](#highlight.tags.operator).
    */
    compareOperator: t(operator),
    /**
    [Operator](#highlight.tags.operator) that updates its operand.
    */
    updateOperator: t(operator),
    /**
    [Operator](#highlight.tags.operator) that defines something.
    */
    definitionOperator: t(operator),
    /**
    Type-related [operator](#highlight.tags.operator).
    */
    typeOperator: t(operator),
    /**
    Control-flow [operator](#highlight.tags.operator).
    */
    controlOperator: t(operator),
    /**
    Program or markup punctuation.
    */
    punctuation,
    /**
    [Punctuation](#highlight.tags.punctuation) that separates
    things.
    */
    separator: t(punctuation),
    /**
    Bracket-style [punctuation](#highlight.tags.punctuation).
    */
    bracket,
    /**
    Angle [brackets](#highlight.tags.bracket) (usually `<` and `>`
    tokens).
    */
    angleBracket: t(bracket),
    /**
    Square [brackets](#highlight.tags.bracket) (usually `[` and `]`
    tokens).
    */
    squareBracket: t(bracket),
    /**
    Parentheses (usually `(` and `)` tokens). Subtag of
    [bracket](#highlight.tags.bracket).
    */
    paren: t(bracket),
    /**
    Braces (usually `{` and `}` tokens). Subtag of
    [bracket](#highlight.tags.bracket).
    */
    brace: t(bracket),
    /**
    Content, for example plain text in XML or markup documents.
    */
    content,
    /**
    [Content](#highlight.tags.content) that represents a heading.
    */
    heading,
    /**
    A level 1 [heading](#highlight.tags.heading).
    */
    heading1: t(heading),
    /**
    A level 2 [heading](#highlight.tags.heading).
    */
    heading2: t(heading),
    /**
    A level 3 [heading](#highlight.tags.heading).
    */
    heading3: t(heading),
    /**
    A level 4 [heading](#highlight.tags.heading).
    */
    heading4: t(heading),
    /**
    A level 5 [heading](#highlight.tags.heading).
    */
    heading5: t(heading),
    /**
    A level 6 [heading](#highlight.tags.heading).
    */
    heading6: t(heading),
    /**
    A prose [content](#highlight.tags.content) separator (such as a horizontal rule).
    */
    contentSeparator: t(content),
    /**
    [Content](#highlight.tags.content) that represents a list.
    */
    list: t(content),
    /**
    [Content](#highlight.tags.content) that represents a quote.
    */
    quote: t(content),
    /**
    [Content](#highlight.tags.content) that is emphasized.
    */
    emphasis: t(content),
    /**
    [Content](#highlight.tags.content) that is styled strong.
    */
    strong: t(content),
    /**
    [Content](#highlight.tags.content) that is part of a link.
    */
    link: t(content),
    /**
    [Content](#highlight.tags.content) that is styled as code or
    monospace.
    */
    monospace: t(content),
    /**
    [Content](#highlight.tags.content) that has a strike-through
    style.
    */
    strikethrough: t(content),
    /**
    Inserted text in a change-tracking format.
    */
    inserted: t(),
    /**
    Deleted text.
    */
    deleted: t(),
    /**
    Changed text.
    */
    changed: t(),
    /**
    An invalid or unsyntactic element.
    */
    invalid: t(),
    /**
    Metadata or meta-instruction.
    */
    meta,
    /**
    [Metadata](#highlight.tags.meta) that applies to the entire
    document.
    */
    documentMeta: t(meta),
    /**
    [Metadata](#highlight.tags.meta) that annotates or adds
    attributes to a given syntactic element.
    */
    annotation: t(meta),
    /**
    Processing instruction or preprocessor directive. Subtag of
    [meta](#highlight.tags.meta).
    */
    processingInstruction: t(meta),
    /**
    [Modifier](#highlight.Tag^defineModifier) that indicates that a
    given element is being defined. Expected to be used with the
    various [name](#highlight.tags.name) tags.
    */
    definition: Tag.defineModifier("definition"),
    /**
    [Modifier](#highlight.Tag^defineModifier) that indicates that
    something is constant. Mostly expected to be used with
    [variable names](#highlight.tags.variableName).
    */
    constant: Tag.defineModifier("constant"),
    /**
    [Modifier](#highlight.Tag^defineModifier) used to indicate that
    a [variable](#highlight.tags.variableName) or [property
    name](#highlight.tags.propertyName) is being called or defined
    as a function.
    */
    function: Tag.defineModifier("function"),
    /**
    [Modifier](#highlight.Tag^defineModifier) that can be applied to
    [names](#highlight.tags.name) to indicate that they belong to
    the language's standard environment.
    */
    standard: Tag.defineModifier("standard"),
    /**
    [Modifier](#highlight.Tag^defineModifier) that indicates a given
    [names](#highlight.tags.name) is local to some scope.
    */
    local: Tag.defineModifier("local"),
    /**
    A generic variant [modifier](#highlight.Tag^defineModifier) that
    can be used to tag language-specific alternative variants of
    some common tag. It is recommended for themes to define special
    forms of at least the [string](#highlight.tags.string) and
    [variable name](#highlight.tags.variableName) tags, since those
    come up a lot.
    */
    special: Tag.defineModifier("special")
  };
  for (let name in tags) {
    let val = tags[name];
    if (val instanceof Tag) val.name = name;
  }
  /**
  This is a highlighter that adds stable, predictable classes to
  tokens, for styling with external CSS.

  The following tags are mapped to their name prefixed with `"tok-"`
  (for example `"tok-comment"`):

  * [`link`](#highlight.tags.link)
  * [`heading`](#highlight.tags.heading)
  * [`emphasis`](#highlight.tags.emphasis)
  * [`strong`](#highlight.tags.strong)
  * [`keyword`](#highlight.tags.keyword)
  * [`atom`](#highlight.tags.atom)
  * [`bool`](#highlight.tags.bool)
  * [`url`](#highlight.tags.url)
  * [`labelName`](#highlight.tags.labelName)
  * [`inserted`](#highlight.tags.inserted)
  * [`deleted`](#highlight.tags.deleted)
  * [`literal`](#highlight.tags.literal)
  * [`string`](#highlight.tags.string)
  * [`number`](#highlight.tags.number)
  * [`variableName`](#highlight.tags.variableName)
  * [`typeName`](#highlight.tags.typeName)
  * [`namespace`](#highlight.tags.namespace)
  * [`className`](#highlight.tags.className)
  * [`macroName`](#highlight.tags.macroName)
  * [`propertyName`](#highlight.tags.propertyName)
  * [`operator`](#highlight.tags.operator)
  * [`comment`](#highlight.tags.comment)
  * [`meta`](#highlight.tags.meta)
  * [`punctuation`](#highlight.tags.punctuation)
  * [`invalid`](#highlight.tags.invalid)

  In addition, these mappings are provided:

  * [`regexp`](#highlight.tags.regexp),
    [`escape`](#highlight.tags.escape), and
    [`special`](#highlight.tags.special)[`(string)`](#highlight.tags.string)
    are mapped to `"tok-string2"`
  * [`special`](#highlight.tags.special)[`(variableName)`](#highlight.tags.variableName)
    to `"tok-variableName2"`
  * [`local`](#highlight.tags.local)[`(variableName)`](#highlight.tags.variableName)
    to `"tok-variableName tok-local"`
  * [`definition`](#highlight.tags.definition)[`(variableName)`](#highlight.tags.variableName)
    to `"tok-variableName tok-definition"`
  * [`definition`](#highlight.tags.definition)[`(propertyName)`](#highlight.tags.propertyName)
    to `"tok-propertyName tok-definition"`
  */
  tagHighlighter([{
    tag: tags.link,
    class: "tok-link"
  }, {
    tag: tags.heading,
    class: "tok-heading"
  }, {
    tag: tags.emphasis,
    class: "tok-emphasis"
  }, {
    tag: tags.strong,
    class: "tok-strong"
  }, {
    tag: tags.keyword,
    class: "tok-keyword"
  }, {
    tag: tags.atom,
    class: "tok-atom"
  }, {
    tag: tags.bool,
    class: "tok-bool"
  }, {
    tag: tags.url,
    class: "tok-url"
  }, {
    tag: tags.labelName,
    class: "tok-labelName"
  }, {
    tag: tags.inserted,
    class: "tok-inserted"
  }, {
    tag: tags.deleted,
    class: "tok-deleted"
  }, {
    tag: tags.literal,
    class: "tok-literal"
  }, {
    tag: tags.string,
    class: "tok-string"
  }, {
    tag: tags.number,
    class: "tok-number"
  }, {
    tag: [tags.regexp, tags.escape, tags.special(tags.string)],
    class: "tok-string2"
  }, {
    tag: tags.variableName,
    class: "tok-variableName"
  }, {
    tag: tags.local(tags.variableName),
    class: "tok-variableName tok-local"
  }, {
    tag: tags.definition(tags.variableName),
    class: "tok-variableName tok-definition"
  }, {
    tag: tags.special(tags.variableName),
    class: "tok-variableName2"
  }, {
    tag: tags.definition(tags.propertyName),
    class: "tok-propertyName tok-definition"
  }, {
    tag: tags.typeName,
    class: "tok-typeName"
  }, {
    tag: tags.namespace,
    class: "tok-namespace"
  }, {
    tag: tags.className,
    class: "tok-className"
  }, {
    tag: tags.macroName,
    class: "tok-macroName"
  }, {
    tag: tags.propertyName,
    class: "tok-propertyName"
  }, {
    tag: tags.operator,
    class: "tok-operator"
  }, {
    tag: tags.comment,
    class: "tok-comment"
  }, {
    tag: tags.meta,
    class: "tok-meta"
  }, {
    tag: tags.invalid,
    class: "tok-invalid"
  }, {
    tag: tags.punctuation,
    class: "tok-punctuation"
  }]);

  var _a;
  /**
  Node prop stored in a parser's top syntax node to provide the
  facet that stores language-specific data for that language.
  */
  const languageDataProp = /*@__PURE__*/new NodeProp();
  /**
  Syntax node prop used to register sublanguages. Should be added to
  the top level node type for the language.
  */
  const sublanguageProp = /*@__PURE__*/new NodeProp();
  /**
  A language object manages parsing and per-language
  [metadata](https://codemirror.net/6/docs/ref/#state.EditorState.languageDataAt). Parse data is
  managed as a [Lezer](https://lezer.codemirror.net) tree. The class
  can be used directly, via the [`LRLanguage`](https://codemirror.net/6/docs/ref/#language.LRLanguage)
  subclass for [Lezer](https://lezer.codemirror.net/) LR parsers, or
  via the [`StreamLanguage`](https://codemirror.net/6/docs/ref/#language.StreamLanguage) subclass
  for stream parsers.
  */
  class Language {
    /**
    Construct a language object. If you need to invoke this
    directly, first define a data facet with
    [`defineLanguageFacet`](https://codemirror.net/6/docs/ref/#language.defineLanguageFacet), and then
    configure your parser to [attach](https://codemirror.net/6/docs/ref/#language.languageDataProp) it
    to the language's outer syntax node.
    */
    constructor(
    /**
    The [language data](https://codemirror.net/6/docs/ref/#state.EditorState.languageDataAt) facet
    used for this language.
    */
    data, parser, extraExtensions = [],
    /**
    A language name.
    */
    name = "") {
      this.data = data;
      this.name = name;
      // Kludge to define EditorState.tree as a debugging helper,
      // without the EditorState package actually knowing about
      // languages and lezer trees.
      if (!EditorState.prototype.hasOwnProperty("tree")) Object.defineProperty(EditorState.prototype, "tree", {
        get() {
          return syntaxTree(this);
        }
      });
      this.parser = parser;
      this.extension = [language.of(this), EditorState.languageData.of((state, pos, side) => {
        let top = topNodeAt(state, pos, side),
          data = top.type.prop(languageDataProp);
        if (!data) return [];
        let base = state.facet(data),
          sub = top.type.prop(sublanguageProp);
        if (sub) {
          let innerNode = top.resolve(pos - top.from, side);
          for (let sublang of sub) if (sublang.test(innerNode, state)) {
            let data = state.facet(sublang.facet);
            return sublang.type == "replace" ? data : data.concat(base);
          }
        }
        return base;
      })].concat(extraExtensions);
    }
    /**
    Query whether this language is active at the given position.
    */
    isActiveAt(state, pos, side = -1) {
      return topNodeAt(state, pos, side).type.prop(languageDataProp) == this.data;
    }
    /**
    Find the document regions that were parsed using this language.
    The returned regions will _include_ any nested languages rooted
    in this language, when those exist.
    */
    findRegions(state) {
      let lang = state.facet(language);
      if ((lang === null || lang === void 0 ? void 0 : lang.data) == this.data) return [{
        from: 0,
        to: state.doc.length
      }];
      if (!lang || !lang.allowsNesting) return [];
      let result = [];
      let explore = (tree, from) => {
        if (tree.prop(languageDataProp) == this.data) {
          result.push({
            from,
            to: from + tree.length
          });
          return;
        }
        let mount = tree.prop(NodeProp.mounted);
        if (mount) {
          if (mount.tree.prop(languageDataProp) == this.data) {
            if (mount.overlay) for (let r of mount.overlay) result.push({
              from: r.from + from,
              to: r.to + from
            });else result.push({
              from: from,
              to: from + tree.length
            });
            return;
          } else if (mount.overlay) {
            let size = result.length;
            explore(mount.tree, mount.overlay[0].from + from);
            if (result.length > size) return;
          }
        }
        for (let i = 0; i < tree.children.length; i++) {
          let ch = tree.children[i];
          if (ch instanceof Tree) explore(ch, tree.positions[i] + from);
        }
      };
      explore(syntaxTree(state), 0);
      return result;
    }
    /**
    Indicates whether this language allows nested languages. The
    default implementation returns true.
    */
    get allowsNesting() {
      return true;
    }
  }
  /**
  @internal
  */
  Language.setState = /*@__PURE__*/StateEffect.define();
  function topNodeAt(state, pos, side) {
    let topLang = state.facet(language),
      tree = syntaxTree(state).topNode;
    if (!topLang || topLang.allowsNesting) {
      for (let node = tree; node; node = node.enter(pos, side, IterMode.ExcludeBuffers | IterMode.EnterBracketed)) if (node.type.isTop) tree = node;
    }
    return tree;
  }
  /**
  Get the syntax tree for a state, which is the current (possibly
  incomplete) parse tree of the active
  [language](https://codemirror.net/6/docs/ref/#language.Language), or the empty tree if there is no
  language available.
  */
  function syntaxTree(state) {
    let field = state.field(Language.state, false);
    return field ? field.tree : Tree.empty;
  }
  /**
  Lezer-style
  [`Input`](https://lezer.codemirror.net/docs/ref#common.Input)
  object for a [`Text`](https://codemirror.net/6/docs/ref/#state.Text) object.
  */
  class DocInput {
    /**
    Create an input object for the given document.
    */
    constructor(doc) {
      this.doc = doc;
      this.cursorPos = 0;
      this.string = "";
      this.cursor = doc.iter();
    }
    get length() {
      return this.doc.length;
    }
    syncTo(pos) {
      this.string = this.cursor.next(pos - this.cursorPos).value;
      this.cursorPos = pos + this.string.length;
      return this.cursorPos - this.string.length;
    }
    chunk(pos) {
      this.syncTo(pos);
      return this.string;
    }
    get lineChunks() {
      return true;
    }
    read(from, to) {
      let stringStart = this.cursorPos - this.string.length;
      if (from < stringStart || to >= this.cursorPos) return this.doc.sliceString(from, to);else return this.string.slice(from - stringStart, to - stringStart);
    }
  }
  let currentContext = null;
  /**
  A parse context provided to parsers working on the editor content.
  */
  class ParseContext {
    constructor(parser,
    /**
    The current editor state.
    */
    state,
    /**
    Tree fragments that can be reused by incremental re-parses.
    */
    fragments = [],
    /**
    @internal
    */
    tree,
    /**
    @internal
    */
    treeLen,
    /**
    The current editor viewport (or some overapproximation
    thereof). Intended to be used for opportunistically avoiding
    work (in which case
    [`skipUntilInView`](https://codemirror.net/6/docs/ref/#language.ParseContext.skipUntilInView)
    should be called to make sure the parser is restarted when the
    skipped region becomes visible).
    */
    viewport,
    /**
    @internal
    */
    skipped,
    /**
    This is where skipping parsers can register a promise that,
    when resolved, will schedule a new parse. It is cleared when
    the parse worker picks up the promise. @internal
    */
    scheduleOn) {
      this.parser = parser;
      this.state = state;
      this.fragments = fragments;
      this.tree = tree;
      this.treeLen = treeLen;
      this.viewport = viewport;
      this.skipped = skipped;
      this.scheduleOn = scheduleOn;
      this.parse = null;
      /**
      @internal
      */
      this.tempSkipped = [];
    }
    /**
    @internal
    */
    static create(parser, state, viewport) {
      return new ParseContext(parser, state, [], Tree.empty, 0, viewport, [], null);
    }
    startParse() {
      return this.parser.startParse(new DocInput(this.state.doc), this.fragments);
    }
    /**
    @internal
    */
    work(until, upto) {
      if (upto != null && upto >= this.state.doc.length) upto = undefined;
      if (this.tree != Tree.empty && this.isDone(upto !== null && upto !== void 0 ? upto : this.state.doc.length)) {
        this.takeTree();
        return true;
      }
      return this.withContext(() => {
        var _a;
        if (typeof until == "number") {
          let endTime = Date.now() + until;
          until = () => Date.now() > endTime;
        }
        if (!this.parse) this.parse = this.startParse();
        if (upto != null && (this.parse.stoppedAt == null || this.parse.stoppedAt > upto) && upto < this.state.doc.length) this.parse.stopAt(upto);
        for (;;) {
          let done = this.parse.advance();
          if (done) {
            this.fragments = this.withoutTempSkipped(TreeFragment.addTree(done, this.fragments, this.parse.stoppedAt != null));
            this.treeLen = (_a = this.parse.stoppedAt) !== null && _a !== void 0 ? _a : this.state.doc.length;
            this.tree = done;
            this.parse = null;
            if (this.treeLen < (upto !== null && upto !== void 0 ? upto : this.state.doc.length)) this.parse = this.startParse();else return true;
          }
          if (until()) return false;
        }
      });
    }
    /**
    @internal
    */
    takeTree() {
      let pos, tree;
      if (this.parse && (pos = this.parse.parsedPos) >= this.treeLen) {
        if (this.parse.stoppedAt == null || this.parse.stoppedAt > pos) this.parse.stopAt(pos);
        this.withContext(() => {
          while (!(tree = this.parse.advance())) {}
        });
        this.treeLen = pos;
        this.tree = tree;
        this.fragments = this.withoutTempSkipped(TreeFragment.addTree(this.tree, this.fragments, true));
        this.parse = null;
      }
    }
    withContext(f) {
      let prev = currentContext;
      currentContext = this;
      try {
        return f();
      } finally {
        currentContext = prev;
      }
    }
    withoutTempSkipped(fragments) {
      for (let r; r = this.tempSkipped.pop();) fragments = cutFragments(fragments, r.from, r.to);
      return fragments;
    }
    /**
    @internal
    */
    changes(changes, newState) {
      let {
        fragments,
        tree,
        treeLen,
        viewport,
        skipped
      } = this;
      this.takeTree();
      if (!changes.empty) {
        let ranges = [];
        changes.iterChangedRanges((fromA, toA, fromB, toB) => ranges.push({
          fromA,
          toA,
          fromB,
          toB
        }));
        fragments = TreeFragment.applyChanges(fragments, ranges);
        tree = Tree.empty;
        treeLen = 0;
        viewport = {
          from: changes.mapPos(viewport.from, -1),
          to: changes.mapPos(viewport.to, 1)
        };
        if (this.skipped.length) {
          skipped = [];
          for (let r of this.skipped) {
            let from = changes.mapPos(r.from, 1),
              to = changes.mapPos(r.to, -1);
            if (from < to) skipped.push({
              from,
              to
            });
          }
        }
      }
      return new ParseContext(this.parser, newState, fragments, tree, treeLen, viewport, skipped, this.scheduleOn);
    }
    /**
    @internal
    */
    updateViewport(viewport) {
      if (this.viewport.from == viewport.from && this.viewport.to == viewport.to) return false;
      this.viewport = viewport;
      let startLen = this.skipped.length;
      for (let i = 0; i < this.skipped.length; i++) {
        let {
          from,
          to
        } = this.skipped[i];
        if (from < viewport.to && to > viewport.from) {
          this.fragments = cutFragments(this.fragments, from, to);
          this.skipped.splice(i--, 1);
        }
      }
      if (this.skipped.length >= startLen) return false;
      this.reset();
      return true;
    }
    /**
    @internal
    */
    reset() {
      if (this.parse) {
        this.takeTree();
        this.parse = null;
      }
    }
    /**
    Notify the parse scheduler that the given region was skipped
    because it wasn't in view, and the parse should be restarted
    when it comes into view.
    */
    skipUntilInView(from, to) {
      this.skipped.push({
        from,
        to
      });
    }
    /**
    Returns a parser intended to be used as placeholder when
    asynchronously loading a nested parser. It'll skip its input and
    mark it as not-really-parsed, so that the next update will parse
    it again.
    
    When `until` is given, a reparse will be scheduled when that
    promise resolves.
    */
    static getSkippingParser(until) {
      return new class extends Parser {
        createParse(input, fragments, ranges) {
          let from = ranges[0].from,
            to = ranges[ranges.length - 1].to;
          let parser = {
            parsedPos: from,
            advance() {
              let cx = currentContext;
              if (cx) {
                for (let r of ranges) cx.tempSkipped.push(r);
                if (until) cx.scheduleOn = cx.scheduleOn ? Promise.all([cx.scheduleOn, until]) : until;
              }
              this.parsedPos = to;
              return new Tree(NodeType.none, [], [], to - from);
            },
            stoppedAt: null,
            stopAt() {}
          };
          return parser;
        }
      }();
    }
    /**
    @internal
    */
    isDone(upto) {
      upto = Math.min(upto, this.state.doc.length);
      let frags = this.fragments;
      return this.treeLen >= upto && frags.length && frags[0].from == 0 && frags[0].to >= upto;
    }
    /**
    Get the context for the current parse, or `null` if no editor
    parse is in progress.
    */
    static get() {
      return currentContext;
    }
  }
  function cutFragments(fragments, from, to) {
    return TreeFragment.applyChanges(fragments, [{
      fromA: from,
      toA: to,
      fromB: from,
      toB: to
    }]);
  }
  class LanguageState {
    constructor(
    // A mutable parse state that is used to preserve work done during
    // the lifetime of a state when moving to the next state.
    context) {
      this.context = context;
      this.tree = context.tree;
    }
    apply(tr) {
      if (!tr.docChanged && this.tree == this.context.tree) return this;
      let newCx = this.context.changes(tr.changes, tr.state);
      // If the previous parse wasn't done, go forward only up to its
      // end position or the end of the viewport, to avoid slowing down
      // state updates with parse work beyond the viewport.
      let upto = this.context.treeLen == tr.startState.doc.length ? undefined : Math.max(tr.changes.mapPos(this.context.treeLen), newCx.viewport.to);
      if (!newCx.work(20 /* Work.Apply */, upto)) newCx.takeTree();
      return new LanguageState(newCx);
    }
    static init(state) {
      let vpTo = Math.min(3000 /* Work.InitViewport */, state.doc.length);
      let parseState = ParseContext.create(state.facet(language).parser, state, {
        from: 0,
        to: vpTo
      });
      if (!parseState.work(20 /* Work.Apply */, vpTo)) parseState.takeTree();
      return new LanguageState(parseState);
    }
  }
  Language.state = /*@__PURE__*/StateField.define({
    create: LanguageState.init,
    update(value, tr) {
      for (let e of tr.effects) if (e.is(Language.setState)) return e.value;
      if (tr.startState.facet(language) != tr.state.facet(language)) return LanguageState.init(tr.state);
      return value.apply(tr);
    }
  });
  let requestIdle = callback => {
    let timeout = setTimeout(() => callback(), 500 /* Work.MaxPause */);
    return () => clearTimeout(timeout);
  };
  if (typeof requestIdleCallback != "undefined") requestIdle = callback => {
    let idle = -1,
      timeout = setTimeout(() => {
        idle = requestIdleCallback(callback, {
          timeout: 500 /* Work.MaxPause */ - 100 /* Work.MinPause */
        });
      }, 100 /* Work.MinPause */);
    return () => idle < 0 ? clearTimeout(timeout) : cancelIdleCallback(idle);
  };
  const isInputPending = typeof navigator != "undefined" && ((_a = navigator.scheduling) === null || _a === void 0 ? void 0 : _a.isInputPending) ? () => navigator.scheduling.isInputPending() : null;
  const parseWorker = /*@__PURE__*/ViewPlugin.fromClass(class ParseWorker {
    constructor(view) {
      this.view = view;
      this.working = null;
      this.workScheduled = 0;
      // End of the current time chunk
      this.chunkEnd = -1;
      // Milliseconds of budget left for this chunk
      this.chunkBudget = -1;
      this.work = this.work.bind(this);
      this.scheduleWork();
    }
    update(update) {
      let cx = this.view.state.field(Language.state).context;
      if (cx.updateViewport(update.view.viewport) || this.view.viewport.to > cx.treeLen) this.scheduleWork();
      if (update.docChanged || update.selectionSet) {
        if (this.view.hasFocus) this.chunkBudget += 50 /* Work.ChangeBonus */;
        this.scheduleWork();
      }
      this.checkAsyncSchedule(cx);
    }
    scheduleWork() {
      if (this.working) return;
      let {
          state
        } = this.view,
        field = state.field(Language.state);
      if (field.tree != field.context.tree || !field.context.isDone(state.doc.length)) this.working = requestIdle(this.work);
    }
    work(deadline) {
      this.working = null;
      let now = Date.now();
      if (this.chunkEnd < now && (this.chunkEnd < 0 || this.view.hasFocus)) {
        // Start a new chunk
        this.chunkEnd = now + 30000 /* Work.ChunkTime */;
        this.chunkBudget = 3000 /* Work.ChunkBudget */;
      }
      if (this.chunkBudget <= 0) return; // No more budget
      let {
          state,
          viewport: {
            to: vpTo
          }
        } = this.view,
        field = state.field(Language.state);
      if (field.tree == field.context.tree && field.context.isDone(vpTo + 100000 /* Work.MaxParseAhead */)) return;
      let endTime = Date.now() + Math.min(this.chunkBudget, 100 /* Work.Slice */, deadline && !isInputPending ? Math.max(25 /* Work.MinSlice */, deadline.timeRemaining() - 5) : 1e9);
      let viewportFirst = field.context.treeLen < vpTo && state.doc.length > vpTo + 1000;
      let done = field.context.work(() => {
        return isInputPending && isInputPending() || Date.now() > endTime;
      }, vpTo + (viewportFirst ? 0 : 100000 /* Work.MaxParseAhead */));
      this.chunkBudget -= Date.now() - now;
      if (done || this.chunkBudget <= 0) {
        field.context.takeTree();
        this.view.dispatch({
          effects: Language.setState.of(new LanguageState(field.context))
        });
      }
      if (this.chunkBudget > 0 && !(done && !viewportFirst)) this.scheduleWork();
      this.checkAsyncSchedule(field.context);
    }
    checkAsyncSchedule(cx) {
      if (cx.scheduleOn) {
        this.workScheduled++;
        cx.scheduleOn.then(() => this.scheduleWork()).catch(err => logException(this.view.state, err)).then(() => this.workScheduled--);
        cx.scheduleOn = null;
      }
    }
    destroy() {
      if (this.working) this.working();
    }
    isWorking() {
      return !!(this.working || this.workScheduled > 0);
    }
  }, {
    eventHandlers: {
      focus() {
        this.scheduleWork();
      }
    }
  });
  /**
  The facet used to associate a language with an editor state. Used
  by `Language` object's `extension` property (so you don't need to
  manually wrap your languages in this). Can be used to access the
  current language on a state.
  */
  const language = /*@__PURE__*/Facet.define({
    combine(languages) {
      return languages.length ? languages[0] : null;
    },
    enables: language => [Language.state, parseWorker, EditorView.contentAttributes.compute([language], state => {
      let lang = state.facet(language);
      return lang && lang.name ? {
        "data-language": lang.name
      } : {};
    })]
  });

  /**
  A highlight style associates CSS styles with highlighting
  [tags](https://lezer.codemirror.net/docs/ref#highlight.Tag).
  */
  class HighlightStyle {
    constructor(
    /**
    The tag styles used to create this highlight style.
    */
    specs, options) {
      this.specs = specs;
      let modSpec;
      function def(spec) {
        let cls = StyleModule.newName();
        (modSpec || (modSpec = Object.create(null)))["." + cls] = spec;
        return cls;
      }
      const all = typeof options.all == "string" ? options.all : options.all ? def(options.all) : undefined;
      const scopeOpt = options.scope;
      this.scope = scopeOpt instanceof Language ? type => type.prop(languageDataProp) == scopeOpt.data : scopeOpt ? type => type == scopeOpt : undefined;
      this.style = tagHighlighter(specs.map(style => ({
        tag: style.tag,
        class: style.class || def(Object.assign({}, style, {
          tag: null
        }))
      })), {
        all
      }).style;
      this.module = modSpec ? new StyleModule(modSpec) : null;
      this.themeType = options.themeType;
    }
    /**
    Create a highlighter style that associates the given styles to
    the given tags. The specs must be objects that hold a style tag
    or array of tags in their `tag` property, and either a single
    `class` property providing a static CSS class (for highlighter
    that rely on external styling), or a
    [`style-mod`](https://github.com/marijnh/style-mod#documentation)-style
    set of CSS properties (which define the styling for those tags).
    
    The CSS rules created for a highlighter will be emitted in the
    order of the spec's properties. That means that for elements that
    have multiple tags associated with them, styles defined further
    down in the list will have a higher CSS precedence than styles
    defined earlier.
    */
    static define(specs, options) {
      return new HighlightStyle(specs, options || {});
    }
  }
  const highlighterFacet = /*@__PURE__*/Facet.define();
  const fallbackHighlighter = /*@__PURE__*/Facet.define({
    combine(values) {
      return values.length ? [values[0]] : null;
    }
  });
  function getHighlighters(state) {
    let main = state.facet(highlighterFacet);
    return main.length ? main : state.facet(fallbackHighlighter);
  }
  /**
  Wrap a highlighter in an editor extension that uses it to apply
  syntax highlighting to the editor content.

  When multiple (non-fallback) styles are provided, the styling
  applied is the union of the classes they emit.
  */
  function syntaxHighlighting(highlighter, options) {
    let ext = [treeHighlighter],
      themeType;
    if (highlighter instanceof HighlightStyle) {
      if (highlighter.module) ext.push(EditorView.styleModule.of(highlighter.module));
      themeType = highlighter.themeType;
    }
    if (themeType) ext.push(highlighterFacet.computeN([EditorView.darkTheme], state => {
      return state.facet(EditorView.darkTheme) == (themeType == "dark") ? [highlighter] : [];
    }));else ext.push(highlighterFacet.of(highlighter));
    return ext;
  }
  class TreeHighlighter {
    constructor(view) {
      this.markCache = Object.create(null);
      this.tree = syntaxTree(view.state);
      this.decorations = this.buildDeco(view, getHighlighters(view.state));
      this.decoratedTo = view.viewport.to;
    }
    update(update) {
      let tree = syntaxTree(update.state),
        highlighters = getHighlighters(update.state);
      let styleChange = highlighters != getHighlighters(update.startState);
      let {
          viewport
        } = update.view,
        decoratedToMapped = update.changes.mapPos(this.decoratedTo, 1);
      if (tree.length < viewport.to && !styleChange && tree.type == this.tree.type && decoratedToMapped >= viewport.to) {
        this.decorations = this.decorations.map(update.changes);
        this.decoratedTo = decoratedToMapped;
      } else if (tree != this.tree || update.viewportChanged || styleChange) {
        this.tree = tree;
        this.decorations = this.buildDeco(update.view, highlighters);
        this.decoratedTo = viewport.to;
      }
    }
    buildDeco(view, highlighters) {
      if (!highlighters || !this.tree.length) return Decoration.none;
      let builder = new RangeSetBuilder();
      for (let {
        from,
        to
      } of view.visibleRanges) {
        highlightTree(this.tree, highlighters, (from, to, style) => {
          builder.add(from, to, this.markCache[style] || (this.markCache[style] = Decoration.mark({
            class: style
          })));
        }, from, to);
      }
      return builder.finish();
    }
  }
  const treeHighlighter = /*@__PURE__*/Prec.high(/*@__PURE__*/ViewPlugin.fromClass(TreeHighlighter, {
    decorations: v => v.decorations
  }));
  const noTokens = /*@__PURE__*/Object.create(null);
  const typeArray = [NodeType.none];
  const warned = [];
  // Cache of node types by name and tags
  const byTag = /*@__PURE__*/Object.create(null);
  const defaultTable = /*@__PURE__*/Object.create(null);
  for (let [legacyName, name] of [["variable", "variableName"], ["variable-2", "variableName.special"], ["string-2", "string.special"], ["def", "variableName.definition"], ["tag", "tagName"], ["attribute", "attributeName"], ["type", "typeName"], ["builtin", "variableName.standard"], ["qualifier", "modifier"], ["error", "invalid"], ["header", "heading"], ["property", "propertyName"]]) defaultTable[legacyName] = /*@__PURE__*/createTokenType(noTokens, name);
  function warnForPart(part, msg) {
    if (warned.indexOf(part) > -1) return;
    warned.push(part);
    console.warn(msg);
  }
  function createTokenType(extra, tagStr) {
    let tags$1 = [];
    for (let name of tagStr.split(" ")) {
      let found = [];
      for (let part of name.split(".")) {
        let value = extra[part] || tags[part];
        if (!value) {
          warnForPart(part, `Unknown highlighting tag ${part}`);
        } else if (typeof value == "function") {
          if (!found.length) warnForPart(part, `Modifier ${part} used at start of tag`);else found = found.map(value);
        } else {
          if (found.length) warnForPart(part, `Tag ${part} used as modifier`);else found = Array.isArray(value) ? value : [value];
        }
      }
      for (let tag of found) tags$1.push(tag);
    }
    if (!tags$1.length) return 0;
    let name = tagStr.replace(/ /g, "_"),
      key = name + " " + tags$1.map(t => t.id);
    let known = byTag[key];
    if (known) return known.id;
    let type = byTag[key] = NodeType.define({
      id: typeArray.length,
      name,
      props: [styleTags({
        [name]: tags$1
      })]
    });
    typeArray.push(type);
    return type.id;
  }
  ({
    rtl: /*@__PURE__*/Decoration.mark({
      class: "cm-iso",
      inclusive: true,
      attributes: {
        dir: "rtl"
      },
      bidiIsolate: Direction.RTL
    }),
    ltr: /*@__PURE__*/Decoration.mark({
      class: "cm-iso",
      inclusive: true,
      attributes: {
        dir: "ltr"
      },
      bidiIsolate: Direction.LTR
    })});

  class SelectedDiagnostic {
    constructor(from, to, diagnostic) {
      this.from = from;
      this.to = to;
      this.diagnostic = diagnostic;
    }
  }
  class LintState {
    constructor(diagnostics, panel, selected) {
      this.diagnostics = diagnostics;
      this.panel = panel;
      this.selected = selected;
    }
    static init(diagnostics, panel, state) {
      // Filter the list of diagnostics for which to create markers
      let diagnosticFilter = state.facet(lintConfig).markerFilter;
      if (diagnosticFilter) diagnostics = diagnosticFilter(diagnostics, state);
      let sorted = diagnostics.slice().sort((a, b) => a.from - b.from || a.to - b.to);
      let deco = new RangeSetBuilder(),
        active = [],
        pos = 0;
      let scan = state.doc.iter(),
        scanPos = 0,
        docLen = state.doc.length;
      for (let i = 0;;) {
        let next = i == sorted.length ? null : sorted[i];
        if (!next && !active.length) break;
        let from, to;
        if (active.length) {
          from = pos;
          to = active.reduce((p, d) => Math.min(p, d.to), next && next.from > from ? next.from : 1e8);
        } else {
          from = next.from;
          if (from > docLen) break;
          to = next.to;
          active.push(next);
          i++;
        }
        while (i < sorted.length) {
          let next = sorted[i];
          if (next.from == from && (next.to > next.from || next.to == from)) {
            active.push(next);
            i++;
            to = Math.min(next.to, to);
          } else {
            to = Math.min(next.from, to);
            break;
          }
        }
        to = Math.min(to, docLen);
        let widget = false;
        if (active.some(d => d.from == from && (d.to == to || to == docLen))) {
          widget = from == to;
          if (!widget && to - from < 10) {
            let behind = from - (scanPos + scan.value.length);
            if (behind > 0) {
              scan.next(behind);
              scanPos = from;
            }
            for (let check = from;;) {
              if (check >= to) {
                widget = true;
                break;
              }
              if (!scan.lineBreak && scanPos + scan.value.length > check) break;
              check = scanPos + scan.value.length;
              scanPos += scan.value.length;
              scan.next();
            }
          }
        }
        let sev = maxSeverity(active);
        if (widget) {
          deco.add(from, from, Decoration.widget({
            widget: new DiagnosticWidget(sev),
            diagnostics: active.slice()
          }));
        } else {
          let markClass = active.reduce((c, d) => d.markClass ? c + " " + d.markClass : c, "");
          deco.add(from, to, Decoration.mark({
            class: "cm-lintRange cm-lintRange-" + sev + markClass,
            diagnostics: active.slice(),
            inclusiveEnd: active.some(a => a.to > to)
          }));
        }
        pos = to;
        if (pos == docLen) break;
        for (let i = 0; i < active.length; i++) if (active[i].to <= pos) active.splice(i--, 1);
      }
      let set = deco.finish();
      return new LintState(set, panel, findDiagnostic(set));
    }
  }
  function findDiagnostic(diagnostics, diagnostic = null, after = 0) {
    let found = null;
    diagnostics.between(after, 1e9, (from, to, {
      spec
    }) => {
      if (diagnostic && spec.diagnostics.indexOf(diagnostic) < 0) return;
      if (!found) found = new SelectedDiagnostic(from, to, diagnostic || spec.diagnostics[0]);else if (spec.diagnostics.indexOf(found.diagnostic) < 0) return false;else found = new SelectedDiagnostic(found.from, to, found.diagnostic);
    });
    return found;
  }
  function hideTooltip(tr, tooltip) {
    let from = tooltip.pos,
      to = tooltip.end || from;
    let result = tr.state.facet(lintConfig).hideOn(tr, from, to);
    if (result != null) return result;
    let line = tr.startState.doc.lineAt(tooltip.pos);
    return !!(tr.effects.some(e => e.is(setDiagnosticsEffect)) || tr.changes.touchesRange(line.from, Math.max(line.to, to)));
  }
  function maybeEnableLint(state, effects) {
    return state.field(lintState, false) ? effects : effects.concat(StateEffect.appendConfig.of(lintExtensions));
  }
  /**
  Returns a transaction spec which updates the current set of
  diagnostics, and enables the lint extension if if wasn't already
  active.
  */
  function setDiagnostics(state, diagnostics) {
    return {
      effects: maybeEnableLint(state, [setDiagnosticsEffect.of(diagnostics)])
    };
  }
  /**
  The state effect that updates the set of active diagnostics. Can
  be useful when writing an extension that needs to track these.
  */
  const setDiagnosticsEffect = /*@__PURE__*/StateEffect.define();
  const togglePanel = /*@__PURE__*/StateEffect.define();
  const movePanelSelection = /*@__PURE__*/StateEffect.define();
  const lintState = /*@__PURE__*/StateField.define({
    create() {
      return new LintState(Decoration.none, null, null);
    },
    update(value, tr) {
      if (tr.docChanged && value.diagnostics.size) {
        let mapped = value.diagnostics.map(tr.changes),
          selected = null,
          panel = value.panel;
        if (value.selected) {
          let selPos = tr.changes.mapPos(value.selected.from, 1);
          selected = findDiagnostic(mapped, value.selected.diagnostic, selPos) || findDiagnostic(mapped, null, selPos);
        }
        if (!mapped.size && panel && tr.state.facet(lintConfig).autoPanel) panel = null;
        value = new LintState(mapped, panel, selected);
      }
      for (let effect of tr.effects) {
        if (effect.is(setDiagnosticsEffect)) {
          let panel = !tr.state.facet(lintConfig).autoPanel ? value.panel : effect.value.length ? LintPanel.open : null;
          value = LintState.init(effect.value, panel, tr.state);
        } else if (effect.is(togglePanel)) {
          value = new LintState(value.diagnostics, effect.value ? LintPanel.open : null, value.selected);
        } else if (effect.is(movePanelSelection)) {
          value = new LintState(value.diagnostics, value.panel, effect.value);
        }
      }
      return value;
    },
    provide: f => [showPanel.from(f, val => val.panel), EditorView.decorations.from(f, s => s.diagnostics)]
  });
  const activeMark = /*@__PURE__*/Decoration.mark({
    class: "cm-lintRange cm-lintRange-active"
  });
  function lintTooltip(view, pos, side) {
    let {
      diagnostics
    } = view.state.field(lintState);
    let found,
      start = -1,
      end = -1;
    diagnostics.between(pos - (side < 0 ? 1 : 0), pos + (side > 0 ? 1 : 0), (from, to, {
      spec
    }) => {
      if (pos >= from && pos <= to && (from == to || (pos > from || side > 0) && (pos < to || side < 0))) {
        found = spec.diagnostics;
        start = from;
        end = to;
        return false;
      }
    });
    let diagnosticFilter = view.state.facet(lintConfig).tooltipFilter;
    if (found && diagnosticFilter) found = diagnosticFilter(found, view.state);
    if (!found) return null;
    return {
      pos: start,
      end: end,
      above: true,
      create() {
        return {
          dom: diagnosticsTooltip(view, found)
        };
      }
    };
  }
  function diagnosticsTooltip(view, diagnostics) {
    return crelt("ul", {
      class: "cm-tooltip-lint"
    }, diagnostics.map(d => renderDiagnostic(view, d, false)));
  }
  /**
  Command to close the lint panel, when open.
  */
  const closeLintPanel = view => {
    let field = view.state.field(lintState, false);
    if (!field || !field.panel) return false;
    view.dispatch({
      effects: togglePanel.of(false)
    });
    return true;
  };
  const lintPlugin = /*@__PURE__*/ViewPlugin.fromClass(class {
    constructor(view) {
      this.view = view;
      this.timeout = -1;
      this.set = true;
      let {
        delay
      } = view.state.facet(lintConfig);
      this.lintTime = Date.now() + delay;
      this.run = this.run.bind(this);
      this.timeout = setTimeout(this.run, delay);
    }
    run() {
      clearTimeout(this.timeout);
      let now = Date.now();
      if (now < this.lintTime - 10) {
        this.timeout = setTimeout(this.run, this.lintTime - now);
      } else {
        this.set = false;
        let {
            state
          } = this.view,
          {
            sources
          } = state.facet(lintConfig);
        if (sources.length) batchResults(sources.map(s => Promise.resolve(s(this.view))), annotations => {
          if (this.view.state.doc == state.doc) this.view.dispatch(setDiagnostics(this.view.state, annotations.reduce((a, b) => a.concat(b))));
        }, error => {
          logException(this.view.state, error);
        });
      }
    }
    update(update) {
      let config = update.state.facet(lintConfig);
      if (update.docChanged || config != update.startState.facet(lintConfig) || config.needsRefresh && config.needsRefresh(update)) {
        this.lintTime = Date.now() + config.delay;
        if (!this.set) {
          this.set = true;
          this.timeout = setTimeout(this.run, config.delay);
        }
      }
    }
    force() {
      if (this.set) {
        this.lintTime = Date.now();
        this.run();
      }
    }
    destroy() {
      clearTimeout(this.timeout);
    }
  });
  function batchResults(promises, sink, error) {
    let collected = [],
      timeout = -1;
    for (let p of promises) p.then(value => {
      collected.push(value);
      clearTimeout(timeout);
      if (collected.length == promises.length) sink(collected);else timeout = setTimeout(() => sink(collected), 200);
    }, error);
  }
  const lintConfig = /*@__PURE__*/Facet.define({
    combine(input) {
      return {
        sources: input.map(i => i.source).filter(x => x != null),
        ...combineConfig(input.map(i => i.config), {
          delay: 750,
          markerFilter: null,
          tooltipFilter: null,
          needsRefresh: null,
          hideOn: () => null
        }, {
          delay: Math.max,
          markerFilter: combineFilter,
          tooltipFilter: combineFilter,
          needsRefresh: (a, b) => !a ? b : !b ? a : u => a(u) || b(u),
          hideOn: (a, b) => !a ? b : !b ? a : (t, x, y) => a(t, x, y) || b(t, x, y),
          autoPanel: (a, b) => a || b
        })
      };
    }
  });
  function combineFilter(a, b) {
    return !a ? b : !b ? a : (d, s) => b(a(d, s), s);
  }
  /**
  Given a diagnostic source, this function returns an extension that
  enables linting with that source. It will be called whenever the
  editor is idle (after its content changed).

  Note that settings given here will apply to all linters active in
  the editor. If `null` is given as source, this only configures the
  lint extension.
  */
  function linter(source, config = {}) {
    return [lintConfig.of({
      source,
      config
    }), lintPlugin, lintExtensions];
  }
  function assignKeys(actions) {
    let assigned = [];
    if (actions) actions: for (let {
      name
    } of actions) {
      for (let i = 0; i < name.length; i++) {
        let ch = name[i];
        if (/[a-zA-Z]/.test(ch) && !assigned.some(c => c.toLowerCase() == ch.toLowerCase())) {
          assigned.push(ch);
          continue actions;
        }
      }
      assigned.push("");
    }
    return assigned;
  }
  function renderDiagnostic(view, diagnostic, inPanel) {
    var _a;
    let keys = inPanel ? assignKeys(diagnostic.actions) : [];
    return crelt("li", {
      class: "cm-diagnostic cm-diagnostic-" + diagnostic.severity
    }, crelt("span", {
      class: "cm-diagnosticText"
    }, diagnostic.renderMessage ? diagnostic.renderMessage(view) : diagnostic.message), (_a = diagnostic.actions) === null || _a === void 0 ? void 0 : _a.map((action, i) => {
      let fired = false,
        click = e => {
          e.preventDefault();
          if (fired) return;
          fired = true;
          let found = findDiagnostic(view.state.field(lintState).diagnostics, diagnostic);
          if (found) action.apply(view, found.from, found.to);
        };
      let {
          name
        } = action,
        keyIndex = keys[i] ? name.indexOf(keys[i]) : -1;
      let nameElt = keyIndex < 0 ? name : [name.slice(0, keyIndex), crelt("u", name.slice(keyIndex, keyIndex + 1)), name.slice(keyIndex + 1)];
      let markClass = action.markClass ? " " + action.markClass : "";
      return crelt("button", {
        type: "button",
        class: "cm-diagnosticAction" + markClass,
        onclick: click,
        onmousedown: click,
        "aria-label": ` Action: ${name}${keyIndex < 0 ? "" : ` (access key "${keys[i]})"`}.`
      }, nameElt);
    }), diagnostic.source && crelt("div", {
      class: "cm-diagnosticSource"
    }, diagnostic.source));
  }
  class DiagnosticWidget extends WidgetType {
    constructor(sev) {
      super();
      this.sev = sev;
    }
    eq(other) {
      return other.sev == this.sev;
    }
    toDOM() {
      return crelt("span", {
        class: "cm-lintPoint cm-lintPoint-" + this.sev
      });
    }
  }
  class PanelItem {
    constructor(view, diagnostic) {
      this.diagnostic = diagnostic;
      this.id = "item_" + Math.floor(Math.random() * 0xffffffff).toString(16);
      this.dom = renderDiagnostic(view, diagnostic, true);
      this.dom.id = this.id;
      this.dom.setAttribute("role", "option");
    }
  }
  class LintPanel {
    constructor(view) {
      this.view = view;
      this.items = [];
      let onkeydown = event => {
        if (event.ctrlKey || event.altKey || event.metaKey) return;
        if (event.keyCode == 27) {
          // Escape
          closeLintPanel(this.view);
          this.view.focus();
        } else if (event.keyCode == 38 || event.keyCode == 33) {
          // ArrowUp, PageUp
          this.moveSelection((this.selectedIndex - 1 + this.items.length) % this.items.length);
        } else if (event.keyCode == 40 || event.keyCode == 34) {
          // ArrowDown, PageDown
          this.moveSelection((this.selectedIndex + 1) % this.items.length);
        } else if (event.keyCode == 36) {
          // Home
          this.moveSelection(0);
        } else if (event.keyCode == 35) {
          // End
          this.moveSelection(this.items.length - 1);
        } else if (event.keyCode == 13) {
          // Enter
          this.view.focus();
        } else if (event.keyCode >= 65 && event.keyCode <= 90 && this.selectedIndex >= 0) {
          // A-Z
          let {
              diagnostic
            } = this.items[this.selectedIndex],
            keys = assignKeys(diagnostic.actions);
          for (let i = 0; i < keys.length; i++) if (keys[i].toUpperCase().charCodeAt(0) == event.keyCode) {
            let found = findDiagnostic(this.view.state.field(lintState).diagnostics, diagnostic);
            if (found) diagnostic.actions[i].apply(view, found.from, found.to);
          }
        } else {
          return;
        }
        event.preventDefault();
      };
      let onclick = event => {
        for (let i = 0; i < this.items.length; i++) {
          if (this.items[i].dom.contains(event.target)) this.moveSelection(i);
        }
      };
      this.list = crelt("ul", {
        tabIndex: 0,
        role: "listbox",
        "aria-label": this.view.state.phrase("Diagnostics"),
        onkeydown,
        onclick
      });
      this.dom = crelt("div", {
        class: "cm-panel-lint"
      }, this.list, crelt("button", {
        type: "button",
        name: "close",
        "aria-label": this.view.state.phrase("close"),
        onclick: () => closeLintPanel(this.view)
      }, "×"));
      this.update();
    }
    get selectedIndex() {
      let selected = this.view.state.field(lintState).selected;
      if (!selected) return -1;
      for (let i = 0; i < this.items.length; i++) if (this.items[i].diagnostic == selected.diagnostic) return i;
      return -1;
    }
    update() {
      let {
        diagnostics,
        selected
      } = this.view.state.field(lintState);
      let i = 0,
        needsSync = false,
        newSelectedItem = null;
      let seen = new Set();
      diagnostics.between(0, this.view.state.doc.length, (_start, _end, {
        spec
      }) => {
        for (let diagnostic of spec.diagnostics) {
          if (seen.has(diagnostic)) continue;
          seen.add(diagnostic);
          let found = -1,
            item;
          for (let j = i; j < this.items.length; j++) if (this.items[j].diagnostic == diagnostic) {
            found = j;
            break;
          }
          if (found < 0) {
            item = new PanelItem(this.view, diagnostic);
            this.items.splice(i, 0, item);
            needsSync = true;
          } else {
            item = this.items[found];
            if (found > i) {
              this.items.splice(i, found - i);
              needsSync = true;
            }
          }
          if (selected && item.diagnostic == selected.diagnostic) {
            if (!item.dom.hasAttribute("aria-selected")) {
              item.dom.setAttribute("aria-selected", "true");
              newSelectedItem = item;
            }
          } else if (item.dom.hasAttribute("aria-selected")) {
            item.dom.removeAttribute("aria-selected");
          }
          i++;
        }
      });
      while (i < this.items.length && !(this.items.length == 1 && this.items[0].diagnostic.from < 0)) {
        needsSync = true;
        this.items.pop();
      }
      if (this.items.length == 0) {
        this.items.push(new PanelItem(this.view, {
          from: -1,
          to: -1,
          severity: "info",
          message: this.view.state.phrase("No diagnostics")
        }));
        needsSync = true;
      }
      if (newSelectedItem) {
        this.list.setAttribute("aria-activedescendant", newSelectedItem.id);
        this.view.requestMeasure({
          key: this,
          read: () => ({
            sel: newSelectedItem.dom.getBoundingClientRect(),
            panel: this.list.getBoundingClientRect()
          }),
          write: ({
            sel,
            panel
          }) => {
            let scaleY = panel.height / this.list.offsetHeight;
            if (sel.top < panel.top) this.list.scrollTop -= (panel.top - sel.top) / scaleY;else if (sel.bottom > panel.bottom) this.list.scrollTop += (sel.bottom - panel.bottom) / scaleY;
          }
        });
      } else if (this.selectedIndex < 0) {
        this.list.removeAttribute("aria-activedescendant");
      }
      if (needsSync) this.sync();
    }
    sync() {
      let domPos = this.list.firstChild;
      function rm() {
        let prev = domPos;
        domPos = prev.nextSibling;
        prev.remove();
      }
      for (let item of this.items) {
        if (item.dom.parentNode == this.list) {
          while (domPos != item.dom) rm();
          domPos = item.dom.nextSibling;
        } else {
          this.list.insertBefore(item.dom, domPos);
        }
      }
      while (domPos) rm();
    }
    moveSelection(selectedIndex) {
      if (this.selectedIndex < 0) return;
      let field = this.view.state.field(lintState);
      let selection = findDiagnostic(field.diagnostics, this.items[selectedIndex].diagnostic);
      if (!selection) return;
      this.view.dispatch({
        selection: {
          anchor: selection.from,
          head: selection.to
        },
        scrollIntoView: true,
        effects: movePanelSelection.of(selection)
      });
    }
    static open(view) {
      return new LintPanel(view);
    }
  }
  function svg(content, attrs = `viewBox="0 0 40 40"`) {
    return `url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" ${attrs}>${encodeURIComponent(content)}</svg>')`;
  }
  function underline(color) {
    return svg(`<path d="m0 2.5 l2 -1.5 l1 0 l2 1.5 l1 0" stroke="${color}" fill="none" stroke-width=".7"/>`, `width="6" height="3"`);
  }
  const baseTheme = /*@__PURE__*/EditorView.baseTheme({
    ".cm-diagnostic": {
      padding: "3px 6px 3px 8px",
      marginLeft: "-1px",
      display: "block",
      whiteSpace: "pre-wrap"
    },
    ".cm-diagnostic-error": {
      borderLeft: "5px solid #d11"
    },
    ".cm-diagnostic-warning": {
      borderLeft: "5px solid orange"
    },
    ".cm-diagnostic-info": {
      borderLeft: "5px solid #999"
    },
    ".cm-diagnostic-hint": {
      borderLeft: "5px solid #66d"
    },
    ".cm-diagnosticAction": {
      font: "inherit",
      border: "none",
      padding: "2px 4px",
      backgroundColor: "#444",
      color: "white",
      borderRadius: "3px",
      marginLeft: "8px",
      cursor: "pointer"
    },
    ".cm-diagnosticSource": {
      fontSize: "70%",
      opacity: .7
    },
    ".cm-lintRange": {
      backgroundPosition: "left bottom",
      backgroundRepeat: "repeat-x",
      paddingBottom: "0.7px"
    },
    ".cm-lintRange-error": {
      backgroundImage: /*@__PURE__*/underline("#f11")
    },
    ".cm-lintRange-warning": {
      backgroundImage: /*@__PURE__*/underline("orange")
    },
    ".cm-lintRange-info": {
      backgroundImage: /*@__PURE__*/underline("#999")
    },
    ".cm-lintRange-hint": {
      backgroundImage: /*@__PURE__*/underline("#66d")
    },
    ".cm-lintRange-active": {
      backgroundColor: "#ffdd9980"
    },
    ".cm-tooltip-lint": {
      padding: 0,
      margin: 0
    },
    ".cm-lintPoint": {
      position: "relative",
      "&:after": {
        content: '""',
        position: "absolute",
        bottom: 0,
        left: "-2px",
        borderLeft: "3px solid transparent",
        borderRight: "3px solid transparent",
        borderBottom: "4px solid #d11"
      }
    },
    ".cm-lintPoint-warning": {
      "&:after": {
        borderBottomColor: "orange"
      }
    },
    ".cm-lintPoint-info": {
      "&:after": {
        borderBottomColor: "#999"
      }
    },
    ".cm-lintPoint-hint": {
      "&:after": {
        borderBottomColor: "#66d"
      }
    },
    ".cm-panel.cm-panel-lint": {
      position: "relative",
      "& ul": {
        maxHeight: "100px",
        overflowY: "auto",
        "& [aria-selected]": {
          backgroundColor: "#ddd",
          "& u": {
            textDecoration: "underline"
          }
        },
        "&:focus [aria-selected]": {
          background_fallback: "#bdf",
          backgroundColor: "Highlight",
          color_fallback: "white",
          color: "HighlightText"
        },
        "& u": {
          textDecoration: "none"
        },
        padding: 0,
        margin: 0
      },
      "& [name=close]": {
        position: "absolute",
        top: "0",
        right: "2px",
        background: "inherit",
        border: "none",
        font: "inherit",
        padding: 0,
        margin: 0
      }
    },
    "&dark .cm-lintRange-active": {
      backgroundColor: "#86714a80"
    },
    "&dark .cm-panel.cm-panel-lint ul": {
      "& [aria-selected]": {
        backgroundColor: "#2e343e"
      }
    }
  });
  function severityWeight(sev) {
    return sev == "error" ? 4 : sev == "warning" ? 3 : sev == "info" ? 2 : 1;
  }
  function maxSeverity(diagnostics) {
    let sev = "hint",
      weight = 1;
    for (let d of diagnostics) {
      let w = severityWeight(d.severity);
      if (w > weight) {
        weight = w;
        sev = d.severity;
      }
    }
    return sev;
  }
  const lintHover = /*@__PURE__*/hoverTooltip(lintTooltip, {
    hideOn: hideTooltip
  });
  const lintExtensions = [lintState, /*@__PURE__*/EditorView.decorations.compute([lintState], state => {
    let {
      selected,
      panel
    } = state.field(lintState);
    return !selected || !panel || selected.from == selected.to ? Decoration.none : Decoration.set([activeMark.range(selected.from, selected.to)]);
  }), lintHover, baseTheme];

  /**
   * @typedef {import('@lezer/common').Tree} Tree
   * @typedef {import('@codemirror/lint').Diagnostic} LintMessage
   */

  /**
   * Create an array of syntax errors in the given tree.
   *
   * @param {Tree} syntaxTree
   * @returns {LintMessage[]} array of syntax errors
   */
  function lintSyntax(syntaxTree) {
    const lintMessages = [];
    syntaxTree.iterate({
      enter: ref => {
        const node = ref.node;
        if (!node.type.isError) {
          return;
        }
        const parent = node.parent;
        const next = getNextNode(node);
        const message = {
          from: node.from,
          to: node.to,
          severity: 'error',
          type: 'Syntax Error'
        };
        if (node.from !== node.to) {
          message.message = `Unrecognized token in <${parent.name}>`;
        } else if (next) {
          message.message = `Unrecognized token <${next.name}> in <${parent.name}>`;
          message.to = next.to;
        } else {
          const before = parent.enterUnfinishedNodesBefore(node.to);
          message.message = `Incomplete <${(before || parent).name}>`;
        }
        lintMessages.push(message);
      }
    });
    return lintMessages;
  }
  function getNextNode(node) {
    if (!node) {
      return null;
    }
    return node.nextSibling || getNextNode(node.parent);
  }

  /**
   * @typedef {object} Context
   * @property {function} report
   * @property {(from: number, to: number) => string} readContent
   * @property {(from: number, to: number, content: string) => void} updateContent
   */

  const RULE_NAME = 'first-item';
  var firstItem = {
    create(/** @type {Context} */context) {
      return {
        enter(node) {
          if (node.name !== 'FilterExpression') {
            return;
          }
          const content = context.readContent(node.from, node.to);
          if (zeroIndexPattern().test(content)) {
            const {
              from,
              to
            } = node;
            context.report({
              from,
              to,
              message: 'First item is accessed via [1]',
              severity: 'warning',
              type: RULE_NAME,
              actions: [{
                name: 'fix',
                apply(_, start = from, end = to) {
                  context.updateContent(start, end, content.replace(zeroIndexPattern(), '[1]'));
                }
              }]
            });
          }
        }
      };
    }
  };
  function zeroIndexPattern() {
    return /\[\s*0\s*\]$/;
  }

  /**
   * @typedef {import('@lezer/common').Tree} Tree
   * @typedef {import('@codemirror/lint').Diagnostic} LintMessage
   * @typedef {import('./index').LintAllContext} LintAllContext
   */

  const RULES = [firstItem];

  /**
   * Create an array of messages reported from rules in the given tree.
   *
   * @param {LintAllContext} context
   * @returns {LintMessage[]} array of syntax errors
   */
  function lintRules(context) {
    const {
      readContent,
      syntaxTree,
      updateContent
    } = context;
    const lintMessages = [];
    const ruleContext = {
      readContent,
      report: message => {
        lintMessages.push(message);
      },
      updateContent
    };
    const rules = RULES.map(rule => rule.create(ruleContext));
    syntaxTree.iterate({
      enter: ref => {
        for (const rule of rules) {
          rule.enter && rule.enter(ref);
        }
      },
      leave: ref => {
        for (const rule of rules) {
          rule.leave && rule.leave(ref);
        }
      }
    });
    return lintMessages;
  }

  /**
   * @typedef {import('@lezer/common').Tree} Tree
   * @typedef {import('@codemirror/lint').Diagnostic} LintMessage
   */

  /**
   * @typedef {object} LintAllContext
   * @property {Tree} syntaxTree
   * @property {(from: number, to: number) => string} readContent
   * @property {(from: number, to: number, content: string) => void} updateContent
   */

  /**
   * Generates lint messages for the given context.
   *
   * @param {LintAllContext} context
   * @returns {LintMessage[]} array of all lint messages
   */
  function lintAll(context) {
    const lintMessages = [...lintSyntax(context.syntaxTree), ...lintRules(context)];
    return lintMessages;
  }

  /**
   * CodeMirror extension that provides linting for FEEL expressions.
   *
   * @returns {import('@codemirror/lint').LintSource} CodeMirror linting source
   */
  const cmFeelLinter = () => editorView => {
    // don't lint if the Editor is empty
    if (editorView.state.doc.length === 0) {
      return [];
    }
    const tree = syntaxTree(editorView.state);
    const messages = lintAll({
      syntaxTree: tree,
      readContent: (from, to) => editorView.state.sliceDoc(from, to),
      updateContent: (from, to, content) => editorView.dispatch({
        changes: {
          from,
          to,
          insert: content
        }
      })
    });
    return messages.map(message => ({
      ...message,
      source: message.type
    }));
  };

  /**
   * WARNING
   *
   * The lib file is auto-generated by the `compile:builtins` (or `update:builtins`) task.
   *
   * Make sure you edit the template file `tasks/camundaBuiltins.template.js` and run `compile:builtins` (or `update:builtins`) to update the file in lib.
   */

  /**
   * @typedef { {
   *   name: string,
   *   info: string,
   *   type?: 'function',
   *   params?: Array<{
   *     name: string;
   *   }>,
   *   engines?: Record<string, string>
   * } } Builtin
   */

  /**
   * List of standard FEEL built-in functions (excluding Camunda-specific extensions).
   *
   * @type { Builtin[] }
   */
  const feelBuiltins = [{
    "name": "not",
    "type": "function",
    "params": [{
      "name": "negand"
    }],
    "info": "<p>Returns the logical negation of the given value.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">not(negand: boolean): boolean\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">not(true)\n// false\n\nnot(null)\n// null\n</code></pre>\n"
  }, {
    "name": "get value",
    "type": "function",
    "params": [{
      "name": "context"
    }, {
      "name": "key"
    }],
    "info": "<p>Returns the value of the context entry with the given key.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">get value(context: context, key: string): Any\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">get value({foo: 123}, &quot;foo&quot;)\n// 123\n\nget value({a: 1}, &quot;b&quot;)\n// null\n</code></pre>\n"
  }, {
    "name": "get entries",
    "type": "function",
    "params": [{
      "name": "context"
    }],
    "info": "<p>Returns the entries of the context as a list of key-value-pairs.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">get entries(context: context): list&lt;context&gt;\n</code></pre>\n<p>The return value is a list of contexts. Each context contains two entries for &quot;key&quot; and &quot;value&quot;.</p>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">get entries({foo: 123})\n// [{key: &quot;foo&quot;, value: 123}]\n</code></pre>\n"
  }, {
    "name": "context put",
    "type": "function",
    "params": [{
      "name": "context"
    }, {
      "name": "keys"
    }, {
      "name": "value"
    }],
    "info": "<p>Adds a new entry with the given value to the context. The path of the entry is defined by the keys. Returns a new context that includes the entry.</p>\n<p>If <code>keys</code> contains the keys <code>[k1, k2]</code> then it adds the nested entry <code>k1.k2 = value</code> to the context.</p>\n<p>If an entry for the same keys already exists in the context, it overrides the value.</p>\n<p>If <code>keys</code> are empty, it returns <code>null</code>.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">context put(context: context, keys: list&lt;string&gt;, value: Any): context\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">context put({x:1}, [&quot;y&quot;], 2)\n// {x:1, y:2}\n\ncontext put({x:1, y: {z:0}}, [&quot;y&quot;, &quot;z&quot;], 2)\n// {x:1, y: {z:2}}\n\ncontext put({x:1}, [&quot;y&quot;, &quot;z&quot;], 2)\n// {x:1, y: {z:2}}\n</code></pre>\n"
  }, {
    "name": "string",
    "type": "function",
    "params": [{
      "name": "from"
    }],
    "info": "<p>Returns the given value as a string representation.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">string(from: Any): string\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">string(1.1)\n// &quot;1.1&quot;\n\nstring(date(&quot;2012-12-25&quot;))\n// &quot;2012-12-25&quot;\n</code></pre>\n"
  }, {
    "name": "number",
    "type": "function",
    "params": [{
      "name": "from"
    }],
    "info": "<p>Parses the given string to a number.</p>\n<p>Returns <code>null</code> if the string is not a number.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">number(from: string): number\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">number(&quot;1500.5&quot;)\n// 1500.5\n</code></pre>\n"
  }, {
    "name": "number",
    "type": "function",
    "params": [{
      "name": "from"
    }, {
      "name": "grouping separator"
    }],
    "info": "<p>Parses the given string to a number using the specified grouping separator.</p>\n<p>Returns <code>null</code> if the string is not a number.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">number(from: string, grouping separator: string): number\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">number(&quot;1,500&quot;, &quot;,&quot;)\n// 1500\n</code></pre>\n"
  }, {
    "name": "number",
    "type": "function",
    "params": [{
      "name": "from"
    }, {
      "name": "grouping separator"
    }, {
      "name": "decimal separator"
    }],
    "info": "<p>Parses the given string to a number using the specified grouping and decimal separators.</p>\n<p>Returns <code>null</code> if the string is not a number.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">number(from: string, grouping separator: string, decimal separator: string): number\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">number(&quot;1 500.5&quot;, &quot; &quot;, &quot;.&quot;)\n// 1500.5\n</code></pre>\n"
  }, {
    "name": "context",
    "type": "function",
    "params": [{
      "name": "entries"
    }],
    "info": "<p>Constructs a context of the given list of key-value pairs. It is the reverse function to <a href=\"feel-built-in-functions-context.md#get-entriescontext\">get entries()</a>.</p>\n<p>Each key-value pair must be a context with two entries: <code>key</code> and <code>value</code>. The entry with name <code>key</code> must have a value of the type <code>string</code>.</p>\n<p>It might override context entries if the keys are equal. The entries are overridden in the same order as the contexts in the given list.</p>\n<p>Returns <code>null</code> if one of the entries is not a context or if a context doesn&#39;t contain the required entries.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">context(entries: list&lt;context&gt;): context\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">context([{&quot;key&quot;:&quot;a&quot;, &quot;value&quot;:1}, {&quot;key&quot;:&quot;b&quot;, &quot;value&quot;:2}])\n// {a:1, b:2}\n</code></pre>\n"
  }, {
    "name": "date",
    "type": "function",
    "params": [{
      "name": "from"
    }],
    "info": "<p>Returns a date from the given value.</p>\n<p>Returns <code>null</code> if the string is not a valid calendar date. For example, <code>&quot;2024-06-31&quot;</code> is invalid because June has\nonly 30 days.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">date(from: string): date\n</code></pre>\n<p>Parses the given string into a date.</p>\n<pre><code class=\"language-feel\">date(from: date and time): date\n</code></pre>\n<p>Extracts the date component from the given date and time.</p>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">date(&quot;2018-04-29&quot;)\n// date(&quot;2018-04-29&quot;)\n\ndate(date and time(&quot;2012-12-25T11:00:00&quot;))\n// date(&quot;2012-12-25&quot;)\n</code></pre>\n"
  }, {
    "name": "date",
    "type": "function",
    "params": [{
      "name": "year"
    }, {
      "name": "month"
    }, {
      "name": "day"
    }],
    "info": "<p>Returns a date from the given components.</p>\n<p>Returns <code>null</code> if the components don&#39;t represent a valid calendar date. For example, <code>2024,6,31</code> is invalid because\nJune has only 30 days.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">date(year: number, month: number, day: number): date\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">date(2012, 12, 25)\n// date(&quot;2012-12-25&quot;)\n</code></pre>\n"
  }, {
    "name": "time",
    "type": "function",
    "params": [{
      "name": "from"
    }],
    "info": "<p>Returns a time from the given value.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">time(from: string): time\n</code></pre>\n<p>Parses the given string into a time.</p>\n<pre><code class=\"language-feel\">time(from: date and time): time\n</code></pre>\n<p>Extracts the time component from the given date and time.</p>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">time(&quot;12:00:00&quot;)\n// time(&quot;12:00:00&quot;)\n\ntime(date and time(&quot;2012-12-25T11:00:00&quot;))\n// time(&quot;11:00:00&quot;)\n</code></pre>\n"
  }, {
    "name": "time",
    "type": "function",
    "params": [{
      "name": "hour"
    }, {
      "name": "minute"
    }, {
      "name": "second"
    }],
    "info": "<p>Returns a time from the given components.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">time(hour: number, minute: number, second: number): time\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">time(23, 59, 0)\n// time(&quot;23:59:00&quot;)\n</code></pre>\n"
  }, {
    "name": "time",
    "type": "function",
    "params": [{
      "name": "hour"
    }, {
      "name": "minute"
    }, {
      "name": "second"
    }, {
      "name": "offset"
    }],
    "info": "<p>Returns a time from the given components, including a timezone offset.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">time(hour: number, minute: number, second: number, offset: days and time duration): time\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">time(14, 30, 0, duration(&quot;PT1H&quot;))\n// time(&quot;14:30:00+01:00&quot;)\n</code></pre>\n"
  }, {
    "name": "date and time",
    "type": "function",
    "params": [{
      "name": "from"
    }],
    "info": "<p>Parses the given string into a date and time. The function supports strings in the format <code>YYYY-MM-DDThh:mm:ss</code> with\noptional timezone information either as offset (e.g., <code>+01:00</code> or <code>Z</code>), as IANA timezone ID (e.g., <code>@Europe/Berlin</code>), or\nas a combination of both (e.g., <code>+01:00[Europe/Berlin]</code>).</p>\n<p>Returns <code>null</code> if the string is not a valid calendar date. For example, <code>&quot;2024-06-31T10:00:00&quot;</code> is invalid because\nJune has only 30 days.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">date and time(from: string): date and time\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">date and time(&quot;2018-04-29T09:30:00&quot;)\n// date and time(&quot;2018-04-29T09:30:00&quot;)\n\ndate and time(&quot;2018-04-29T09:30:00+02:00&quot;)\n// date and time(&quot;2018-04-29T09:30:00+02:00&quot;)\n\ndate and time(&quot;2018-04-29T09:30:00@Europe/Berlin&quot;)\n// date and time(&quot;2018-04-29T09:30:00@Europe/Berlin&quot;)\n\ndate and time(&quot;2018-04-29T09:30:00+02:00[Europe/Berlin]&quot;)\n// date and time(&quot;2018-04-29T09:30:00@Europe/Berlin&quot;)\n</code></pre>\n"
  }, {
    "name": "date and time",
    "type": "function",
    "params": [{
      "name": "date"
    }, {
      "name": "time"
    }],
    "info": "<p>Returns a date and time from the given components.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">date and time(date: date, time: time): date and time\n</code></pre>\n<pre><code class=\"language-feel\">date and time(date: date and time, time: time): date and time\n</code></pre>\n<p>Returns a date and time value that consists of the date component of <code>date</code> combined with <code>time</code>.</p>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">date and time(date(&quot;2012-12-24&quot;),time(&quot;T23:59:00&quot;))\n// date and time(&quot;2012-12-24T23:59:00&quot;)\n\ndate and time(date and time(&quot;2012-12-25T11:00:00&quot;),time(&quot;T23:59:00&quot;))\n// date and time(&quot;2012-12-25T23:59:00&quot;)\n</code></pre>\n"
  }, {
    "name": "duration",
    "type": "function",
    "params": [{
      "name": "from"
    }],
    "info": "<p>Parses the given string into a duration. The duration is either a days and time duration or a years and months duration.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">duration(from: string): days and time duration\n</code></pre>\n<pre><code class=\"language-feel\">duration(from: string): years and months duration\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">duration(&quot;P5D&quot;)\n// duration(&quot;P5D&quot;)\n\nduration(&quot;P32Y&quot;)\n// duration(&quot;P32Y&quot;)\n</code></pre>\n"
  }, {
    "name": "years and months duration",
    "type": "function",
    "params": [{
      "name": "from"
    }, {
      "name": "to"
    }],
    "info": "<p>Returns the years and months duration between <code>from</code> and <code>to</code>.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">years and months duration(from: date, to: date): years and months duration\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">years and months duration(date(&quot;2011-12-22&quot;), date(&quot;2013-08-24&quot;))\n// duration(&quot;P1Y8M&quot;)\n</code></pre>\n"
  }, {
    "name": "from json",
    "type": "function",
    "params": [{
      "name": "value"
    }],
    "info": "<p>Parses a JSON string into a FEEL value. The function converts JSON primitives, objects, and arrays into their corresponding FEEL types.</p>\n<p>Returns <code>null</code> if the string is not a valid JSON value.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">from json(value: string): Any\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">from json(&quot;{\\&quot;a\\&quot;: 1, \\&quot;b\\&quot;: 2}&quot;)\n// {a: 1, b: 2}\n\nfrom json(&quot;true&quot;)\n// true\n\nfrom json(&quot;\\&quot;2023-06-14\\&quot;&quot;)\n// &quot;2023-06-14&quot;\n</code></pre>\n",
    "engines": {
      "camunda": ">=8.9"
    }
  }, {
    "name": "to json",
    "type": "function",
    "params": [{
      "name": "value"
    }],
    "info": "<p>Converts a FEEL value into a JSON string. The function converts FEEL primitives, contexts, and lists into their\ncorresponding JSON types. Temporal values are converted to their ISO 8601 string representation, including timezone\ninformation for date and time values (format: <code>2025-11-24T10:00:00+01:00[Europe/Berlin]</code>).</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">to json(value: Any): string\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">to json({a: 1, b: 2})\n// &quot;{\\&quot;a\\&quot;:1,\\&quot;b\\&quot;:2}&quot;\n\nto json(true)\n// &quot;true&quot;\n\nto json(@&quot;2023-06-14&quot;)\n// &quot;\\&quot;2023-06-14\\&quot;&quot;\n\nto json(@&quot;2025-11-24T10:00:00@Europe/Berlin&quot;)\n// &quot;\\&quot;2025-11-24T10:00:00+01:00[Europe/Berlin]\\&quot;&quot;\n\nto json(@&quot;P3Y&quot;)\n// &quot;\\&quot;P3Y\\&quot;&quot;\n</code></pre>\n",
    "engines": {
      "camunda": ">=8.9"
    }
  }, {
    "name": "list contains",
    "type": "function",
    "params": [{
      "name": "list"
    }, {
      "name": "element"
    }],
    "info": "<p>Returns <code>true</code> if the given list contains the element. Otherwise, returns <code>false</code>.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">list contains(list: list, element: Any): boolean\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">list contains([1,2,3], 2)\n// true\n</code></pre>\n"
  }, {
    "name": "count",
    "type": "function",
    "params": [{
      "name": "list"
    }],
    "info": "<p>Returns the number of elements of the given list.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">count(list: list): number\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">count([1,2,3])\n// 3\n</code></pre>\n"
  }, {
    "name": "min",
    "type": "function",
    "params": [{
      "name": "list"
    }],
    "info": "<p>Returns the minimum of the given list.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">min(list: list): Any\n</code></pre>\n<p>All elements in <code>list</code> should have the same type and be comparable.</p>\n<p>The parameter <code>list</code> can be passed as a list or as a sequence of elements.</p>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">min([1,2,3])\n// 1\n\nmin(1,2,3)\n// 1\n</code></pre>\n"
  }, {
    "name": "max",
    "type": "function",
    "params": [{
      "name": "list"
    }],
    "info": "<p>Returns the maximum of the given list.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">max(list: list): Any\n</code></pre>\n<p>All elements in <code>list</code> should have the same type and be comparable.</p>\n<p>The parameter <code>list</code> can be passed as a list or as a sequence of elements.</p>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">max([1,2,3])\n// 3\n\nmax(1,2,3)\n// 3\n</code></pre>\n"
  }, {
    "name": "sum",
    "type": "function",
    "params": [{
      "name": "list"
    }],
    "info": "<p>Returns the sum of the given list of numbers.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">sum(list: list&lt;number&gt;): number\n</code></pre>\n<p>The parameter <code>list</code> can be passed as a list or as a sequence of elements.</p>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">sum([1,2,3])\n// 6\n\nsum(1,2,3)\n// 6\n</code></pre>\n"
  }, {
    "name": "product",
    "type": "function",
    "params": [{
      "name": "list"
    }],
    "info": "<p>Returns the product of the given list of numbers.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">product(list: list&lt;number&gt;): number\n</code></pre>\n<p>The parameter <code>list</code> can be passed as a list or as a sequence of elements.</p>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">product([2, 3, 4])\n// 24\n\nproduct(2, 3, 4)\n// 24\n</code></pre>\n"
  }, {
    "name": "mean",
    "type": "function",
    "params": [{
      "name": "list"
    }],
    "info": "<p>Returns the arithmetic mean (i.e. average) of the given list of numbers.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">mean(list: list&lt;number&gt;): number\n</code></pre>\n<p>The parameter <code>list</code> can be passed as a list or as a sequence of elements.</p>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">mean([1,2,3])\n// 2\n\nmean(1,2,3)\n// 2\n</code></pre>\n"
  }, {
    "name": "median",
    "type": "function",
    "params": [{
      "name": "list"
    }],
    "info": "<p>Returns the median element of the given list of numbers.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">median(list: list&lt;number&gt;): number\n</code></pre>\n<p>The parameter <code>list</code> can be passed as a list or as a sequence of elements.</p>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">median(8, 2, 5, 3, 4)\n// 4\n\nmedian([6, 1, 2, 3])\n// 2.5\n</code></pre>\n"
  }, {
    "name": "stddev",
    "type": "function",
    "params": [{
      "name": "list"
    }],
    "info": "<p>Returns the standard deviation of the given list of numbers.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">stddev(list: list&lt;number&gt;): number\n</code></pre>\n<p>The parameter <code>list</code> can be passed as a list or as a sequence of elements.</p>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">stddev(2, 4, 7, 5)\n// 2.0816659994661326\n\nstddev([2, 4, 7, 5])\n// 2.0816659994661326\n</code></pre>\n"
  }, {
    "name": "mode",
    "type": "function",
    "params": [{
      "name": "list"
    }],
    "info": "<p>Returns the mode of the given list of numbers.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">mode(list: list&lt;number&gt;): number\n</code></pre>\n<p>The parameter <code>list</code> can be passed as a list or as a sequence of elements.</p>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">mode(6, 3, 9, 6, 6)\n// [6]\n\nmode([6, 1, 9, 6, 1])\n// [1, 6]\n</code></pre>\n"
  }, {
    "name": "all",
    "type": "function",
    "params": [{
      "name": "list"
    }],
    "info": "<p>Returns <code>false</code> if any element of the given list is <code>false</code>. Otherwise, returns <code>true</code>.</p>\n<p>If the given list is empty, it returns <code>true</code>.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">all(list: list&lt;boolean&gt;): boolean\n</code></pre>\n<p>The parameter <code>list</code> can be passed as a list or as a sequence of elements.</p>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">all([true,false])\n// false\n\nall(false,null,true)\n// false\n</code></pre>\n<p>:::info\nThe function <code>all()</code> replaced the previous function <code>and()</code>. The previous function is deprecated and\nshould not be used anymore.\n:::</p>\n"
  }, {
    "name": "any",
    "type": "function",
    "params": [{
      "name": "list"
    }],
    "info": "<p>Returns <code>true</code> if any element of the given list is <code>true</code>. Otherwise, returns <code>false</code>.</p>\n<p>If the given list is empty, it returns <code>false</code>.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">any(list: list&lt;boolean&gt;): boolean\n</code></pre>\n<p>The parameter <code>list</code> can be passed as a list or as a sequence of elements.</p>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">any([false,true])\n// true\n\nany(false,null,true)\n// true\n</code></pre>\n<p>:::info\nThe function <code>any()</code> replaced the previous function <code>or()</code>. The previous function is deprecated and\nshould not be used anymore.\n:::</p>\n"
  }, {
    "name": "sublist",
    "type": "function",
    "params": [{
      "name": "list"
    }, {
      "name": "start position"
    }],
    "info": "<p>Returns a partial list of the given value starting at <code>start position</code>.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">sublist(list: list, start position: number): list\n</code></pre>\n<p>The <code>start position</code> starts at the index <code>1</code>. The last position is <code>-1</code>.</p>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">sublist([1,2,3], 2)\n// [2,3]\n</code></pre>\n"
  }, {
    "name": "sublist",
    "type": "function",
    "params": [{
      "name": "list"
    }, {
      "name": "start position"
    }, {
      "name": "length"
    }],
    "info": "<p>Returns a partial list of the given value starting at <code>start position</code>.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">sublist(list: list, start position: number, length: number): list\n</code></pre>\n<p>The <code>start position</code> starts at the index <code>1</code>. The last position is <code>-1</code>.</p>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">sublist([1,2,3], 1, 2)\n// [1,2]\n</code></pre>\n"
  }, {
    "name": "append",
    "type": "function",
    "params": [{
      "name": "list"
    }, {
      "name": "items"
    }],
    "info": "<p>Returns the given list with all <code>items</code> appended.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">append(list: list, items: Any): list\n</code></pre>\n<p>The parameter <code>items</code> can be a single element or a sequence of elements.</p>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">append([1], 2, 3)\n// [1,2,3]\n</code></pre>\n"
  }, {
    "name": "concatenate",
    "type": "function",
    "params": [{
      "name": "lists"
    }],
    "info": "<p>Returns a list that includes all elements of the given lists.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">concatenate(lists: list): list\n</code></pre>\n<p>The parameter <code>lists</code> is a sequence of lists.</p>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">concatenate([1,2],[3])\n// [1,2,3]\n\nconcatenate([1],[2],[3])\n// [1,2,3]\n</code></pre>\n"
  }, {
    "name": "insert before",
    "type": "function",
    "params": [{
      "name": "list"
    }, {
      "name": "position"
    }, {
      "name": "newItem"
    }],
    "info": "<p>Returns the given list with <code>newItem</code> inserted at <code>position</code>.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">insert before(list: list, position: number, newItem: Any): list\n</code></pre>\n<p>The <code>position</code> starts at the index <code>1</code>. The last position is <code>-1</code>.</p>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">insert before([1,3],1,2)\n// [2,1,3]\n</code></pre>\n"
  }, {
    "name": "remove",
    "type": "function",
    "params": [{
      "name": "list"
    }, {
      "name": "position"
    }],
    "info": "<p>Returns the given list without the element at <code>position</code>.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">remove(list: list, position: number): list\n</code></pre>\n<p>The <code>position</code> starts at the index <code>1</code>. The last position is <code>-1</code>.</p>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">remove([1,2,3], 2)\n// [1,3]\n</code></pre>\n"
  }, {
    "name": "reverse",
    "type": "function",
    "params": [{
      "name": "list"
    }],
    "info": "<p>Returns the given list in revered order.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">reverse(list: list): list\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">reverse([1,2,3])\n// [3,2,1]\n</code></pre>\n"
  }, {
    "name": "index of",
    "type": "function",
    "params": [{
      "name": "list"
    }, {
      "name": "match"
    }],
    "info": "<p>Returns an ascending list of positions containing <code>match</code>.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">index of(list: list, match: Any): list&lt;number&gt;\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">index of([1,2,3,2],2)\n// [2,4]\n</code></pre>\n"
  }, {
    "name": "union",
    "type": "function",
    "params": [{
      "name": "list"
    }],
    "info": "<p>Returns a list that includes all elements of the given lists without duplicates.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">union(list: list): list\n</code></pre>\n<p>The parameter <code>list</code> is a sequence of lists.</p>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">union([1,2],[2,3])\n// [1,2,3]\n</code></pre>\n"
  }, {
    "name": "distinct values",
    "type": "function",
    "params": [{
      "name": "list"
    }],
    "info": "<p>Returns the given list without duplicates.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">distinct values(list: list): list\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">distinct values([1,2,3,2,1])\n// [1,2,3]\n</code></pre>\n"
  }, {
    "name": "flatten",
    "type": "function",
    "params": [{
      "name": "list"
    }],
    "info": "<p>Returns a list that includes all elements of the given list without nested lists.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">flatten(list: list): list\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">flatten([[1,2],[[3]], 4])\n// [1,2,3,4]\n</code></pre>\n"
  }, {
    "name": "sort",
    "type": "function",
    "params": [{
      "name": "list"
    }, {
      "name": "precedes"
    }],
    "info": "<p>Returns the given list sorted by the <code>precedes</code> function.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">sort(list: list, precedes: function&lt;(Any, Any) -&gt; boolean&gt;): list\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">sort(list: [3,1,4,5,2], precedes: function(x,y) x &lt; y)\n// [1,2,3,4,5]\n</code></pre>\n"
  }, {
    "name": "string join",
    "type": "function",
    "params": [{
      "name": "list"
    }],
    "info": "<p>Joins a list of strings into a single string. This is similar to\nJava&#39;s <a href=\"https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/stream/Collectors.html#joining(java.lang.CharSequence,java.lang.CharSequence,java.lang.CharSequence)\">joining</a>\nfunction.</p>\n<p>If an item of the list is <code>null</code>, the item is ignored for the result string. If an item is\nneither a string nor <code>null</code>, the function returns <code>null</code> instead of a string.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">string join(list: list&lt;string&gt;): string\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">string join([&quot;a&quot;,&quot;b&quot;,&quot;c&quot;])\n// &quot;abc&quot;\n\nstring join([&quot;a&quot;,null,&quot;c&quot;])\n// &quot;ac&quot;\n\nstring join([])\n// &quot;&quot;\n</code></pre>\n"
  }, {
    "name": "string join",
    "type": "function",
    "params": [{
      "name": "list"
    }, {
      "name": "delimiter"
    }],
    "info": "<p>Joins a list of strings into a single string. This is similar to\nJava&#39;s <a href=\"https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/stream/Collectors.html#joining(java.lang.CharSequence,java.lang.CharSequence,java.lang.CharSequence)\">joining</a>\nfunction.</p>\n<p>If an item of the list is <code>null</code>, the item is ignored for the result string. If an item is\nneither a string nor <code>null</code>, the function returns <code>null</code> instead of a string.</p>\n<p>The resulting string contains a <code>delimiter</code> between each element.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">string join(list: list&lt;string&gt;, delimiter: string): string\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">string join([&quot;a&quot;], &quot;X&quot;)\n// &quot;a&quot;\n\nstring join([&quot;a&quot;,&quot;b&quot;,&quot;c&quot;], &quot;, &quot;)\n// &quot;a, b, c&quot;\n</code></pre>\n"
  }, {
    "name": "decimal",
    "type": "function",
    "params": [{
      "name": "n"
    }, {
      "name": "scale"
    }],
    "info": "<p>Rounds the given value at the given scale.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">decimal(n: number, scale: number): number\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">decimal(1/3, 2)\n// .33\n\ndecimal(1.5, 0)\n// 2\n</code></pre>\n"
  }, {
    "name": "floor",
    "type": "function",
    "params": [{
      "name": "n"
    }],
    "info": "<p>Rounds the given value with rounding mode flooring.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">floor(n: number): number\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">floor(1.5)\n// 1\n\nfloor(-1.5)\n// -2\n</code></pre>\n"
  }, {
    "name": "floor",
    "type": "function",
    "params": [{
      "name": "n"
    }, {
      "name": "scale"
    }],
    "info": "<p>Rounds the given value with rounding mode flooring at the given scale.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">floor(n: number, scale: number): number\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">floor(-1.56, 1)\n// -1.6\n</code></pre>\n"
  }, {
    "name": "ceiling",
    "type": "function",
    "params": [{
      "name": "n"
    }],
    "info": "<p>Rounds the given value with rounding mode ceiling.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">ceiling(n: number): number\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">ceiling(1.5)\n// 2\n\nceiling(-1.5)\n// -1\n</code></pre>\n"
  }, {
    "name": "ceiling",
    "type": "function",
    "params": [{
      "name": "n"
    }, {
      "name": "scale"
    }],
    "info": "<p>Rounds the given value with rounding mode ceiling at the given scale.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">ceiling(n: number, scale: number): number\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">ceiling(-1.56, 1)\n// -1.5\n</code></pre>\n"
  }, {
    "name": "round up",
    "type": "function",
    "params": [{
      "name": "n"
    }, {
      "name": "scale"
    }],
    "info": "<p>Rounds the given value with the rounding mode round-up at the given scale.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">round up(n: number, scale: number): number\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">round up(5.5)\n// 6\n\nround up(-5.5)\n// -6\n\nround up(1.121, 2)\n// 1.13\n\nround up(-1.126, 2)\n// -1.13\n</code></pre>\n"
  }, {
    "name": "round down",
    "type": "function",
    "params": [{
      "name": "n"
    }, {
      "name": "scale"
    }],
    "info": "<p>Rounds the given value with the rounding mode round-down at the given scale.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">round down(n: number, scale: number): number\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">round down(5.5, 0)\n// 5\n\nround down (-5.5, 0)\n// -5\n\nround down (1.121, 2)\n// 1.12\n\nround down (-1.126, 2)\n// -1.12\n</code></pre>\n"
  }, {
    "name": "round half up",
    "type": "function",
    "params": [{
      "name": "n"
    }, {
      "name": "scale"
    }],
    "info": "<p>Rounds the given value with the rounding mode round-half-up at the given scale.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">round half up(n: number, scale: number): number\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">round half up(5.5, 0)\n// 6\n\nround half up(-5.5, 0)\n// -6\n\nround half up(1.121, 2)\n// 1.12\n\nround half up(-1.126, 2)\n// -1.13\n</code></pre>\n"
  }, {
    "name": "round half down",
    "type": "function",
    "params": [{
      "name": "n"
    }, {
      "name": "scale"
    }],
    "info": "<p>Rounds the given value with the rounding mode round-half-down at the given scale.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">round half down(n: number, scale: number): number\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">round half down (5.5, 0)\n// 5\n\nround half down (-5.5, 0)\n// -5\n\nround half down (1.121, 2)\n// 1.12\n\nround half down (-1.126, 2)\n// -1.13\n</code></pre>\n"
  }, {
    "name": "abs",
    "type": "function",
    "params": [{
      "name": "number"
    }],
    "info": "<p>Returns the absolute value of the given numeric value.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">abs(number: number): number\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">abs(10)\n// 10\n\nabs(-10)\n// 10\n</code></pre>\n"
  }, {
    "name": "modulo",
    "type": "function",
    "params": [{
      "name": "dividend"
    }, {
      "name": "divisor"
    }],
    "info": "<p>Returns the remainder of the division of dividend by divisor.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">modulo(dividend: number, divisor: number): number\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">modulo(12, 5)\n// 2\n</code></pre>\n"
  }, {
    "name": "sqrt",
    "type": "function",
    "params": [{
      "name": "number"
    }],
    "info": "<p>Returns the square root of the given value.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">sqrt(number: number): number\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">sqrt(16)\n// 4\n</code></pre>\n"
  }, {
    "name": "log",
    "type": "function",
    "params": [{
      "name": "number"
    }],
    "info": "<p>Returns the natural logarithm (base e) of the given value.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">log(number: number): number\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">log(10)\n// 2.302585092994046\n</code></pre>\n"
  }, {
    "name": "exp",
    "type": "function",
    "params": [{
      "name": "number"
    }],
    "info": "<p>Returns the Euler’s number e raised to the power of the given number .</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">exp(number: number): number\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">exp(5)\n// 148.4131591025766\n</code></pre>\n"
  }, {
    "name": "odd",
    "type": "function",
    "params": [{
      "name": "number"
    }],
    "info": "<p>Returns <code>true</code> if the given value is odd. Otherwise, returns <code>false</code>.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">odd(number: number): boolean\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">odd(5)\n// true\n\nodd(2)\n// false\n</code></pre>\n"
  }, {
    "name": "even",
    "type": "function",
    "params": [{
      "name": "number"
    }],
    "info": "<p>Returns <code>true</code> if the given is even. Otherwise, returns <code>false</code>.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">even(number: number): boolean\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">even(5)\n// false\n\neven(2)\n// true\n</code></pre>\n"
  }, {
    "name": "before",
    "type": "function",
    "params": [{
      "name": "point1"
    }, {
      "name": "point2"
    }],
    "info": "<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">before(point1: Any, point2: Any): boolean\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">before(1, 10)\n// true\n\nbefore(10, 1)\n// false\n</code></pre>\n"
  }, {
    "name": "before",
    "type": "function",
    "params": [{
      "name": "range"
    }, {
      "name": "point"
    }],
    "info": "<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">before(range: range, point: Any): boolean\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">before([1..5], 10)\n// true\n</code></pre>\n"
  }, {
    "name": "before",
    "type": "function",
    "params": [{
      "name": "point"
    }, {
      "name": "range"
    }],
    "info": "<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">before(point: Any, range: range): boolean\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">before(1, [2..5])\n// true\n</code></pre>\n"
  }, {
    "name": "before",
    "type": "function",
    "params": [{
      "name": "range1"
    }, {
      "name": "range2"
    }],
    "info": "<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">before(range1: range, range2: range): boolean\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">before([1..5], [6..10])\n// true\n\nbefore([1..5),[5..10])\n// true\n</code></pre>\n"
  }, {
    "name": "after",
    "type": "function",
    "params": [{
      "name": "point1"
    }, {
      "name": "point2"
    }],
    "info": "<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">after(point1: Any, point2: Any): boolean\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">after(10, 1)\n// true\n\nafter(1, 10)\n// false\n</code></pre>\n"
  }, {
    "name": "after",
    "type": "function",
    "params": [{
      "name": "range"
    }, {
      "name": "point"
    }],
    "info": "<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">after(range: range, point: Any): boolean\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">after([1..5], 10)\n// false\n</code></pre>\n"
  }, {
    "name": "after",
    "type": "function",
    "params": [{
      "name": "point"
    }, {
      "name": "range"
    }],
    "info": "<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">after(point: Any, range: range): boolean\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">after(12, [2..5])\n// true\n</code></pre>\n"
  }, {
    "name": "after",
    "type": "function",
    "params": [{
      "name": "range1"
    }, {
      "name": "range2"
    }],
    "info": "<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">after(range1: range, range2: range): boolean\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">after([6..10], [1..5])\n// true\n\nafter([5..10], [1..5))\n// true\n</code></pre>\n"
  }, {
    "name": "meets",
    "type": "function",
    "params": [{
      "name": "range1"
    }, {
      "name": "range2"
    }],
    "info": "<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">meets(range1: range, range2: range): boolean\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">meets([1..5], [5..10])\n// true\n\nmeets([1..3], [4..6])\n// false\n\nmeets([1..3], [3..5])\n// true\n\nmeets([1..5], (5..8])\n// false\n</code></pre>\n"
  }, {
    "name": "met by",
    "type": "function",
    "params": [{
      "name": "range1"
    }, {
      "name": "range2"
    }],
    "info": "<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">met by(range1: range, range2: range): boolean\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">met by([5..10], [1..5])\n// true\n\nmet by([3..4], [1..2])\n// false\n\nmet by([3..5], [1..3])\n// true\n\nmet by((5..8], [1..5))\n// false\n\nmet by([5..10], [1..5))\n// false\n</code></pre>\n"
  }, {
    "name": "overlaps",
    "type": "function",
    "params": [{
      "name": "range1"
    }, {
      "name": "range2"
    }],
    "info": "<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">overlaps(range1: range, range2: range): boolean\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">overlaps([5..10], [1..6])\n// true\n\noverlaps((3..7], [1..4])\n// true\n\noverlaps([1..3], (3..6])\n// false\n\noverlaps((5..8], [1..5))\n// false\n\noverlaps([4..10], [1..5))\n// true\n</code></pre>\n"
  }, {
    "name": "overlaps before",
    "type": "function",
    "params": [{
      "name": "range1"
    }, {
      "name": "range2"
    }],
    "info": "<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">overlaps before(range1: range, range2: range): boolean\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">overlaps before([1..5], [4..10])\n// true\n\noverlaps before([3..4], [1..2])\n// false\n\noverlaps before([1..3], (3..5])\n// false\n\noverlaps before([1..5), (3..8])\n// true\n\noverlaps before([1..5), [5..10])\n// false\n</code></pre>\n"
  }, {
    "name": "overlaps after",
    "type": "function",
    "params": [{
      "name": "range1"
    }, {
      "name": "range2"
    }],
    "info": "<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">overlaps after(range1: range, range2: range): boolean\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">overlaps after([4..10], [1..5])\n// true\n\noverlaps after([3..4], [1..2])\n// false\n\noverlaps after([3..5], [1..3))\n// false\n\noverlaps after((5..8], [1..5))\n// false\n\noverlaps after([4..10], [1..5))\n// true\n</code></pre>\n"
  }, {
    "name": "finishes",
    "type": "function",
    "params": [{
      "name": "point"
    }, {
      "name": "range"
    }],
    "info": "<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">finishes(point: Any, range: range): boolean\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">finishes(5, [1..5])\n// true\n\nfinishes(10, [1..7])\n// false\n</code></pre>\n"
  }, {
    "name": "finishes",
    "type": "function",
    "params": [{
      "name": "range1"
    }, {
      "name": "range2"
    }],
    "info": "<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">finishes(range1: range, range2: range): boolean\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">finishes([3..5], [1..5])\n// true\n\nfinishes((1..5], [1..5))\n// false\n\nfinishes([5..10], [1..10))\n// false\n</code></pre>\n"
  }, {
    "name": "finished by",
    "type": "function",
    "params": [{
      "name": "range"
    }, {
      "name": "point"
    }],
    "info": "<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">finished by(range: range, point: Any): boolean\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">finished by([5..10], 10)\n// true\n\nfinished by([3..4], 2)\n// false\n</code></pre>\n"
  }, {
    "name": "finished by",
    "type": "function",
    "params": [{
      "name": "range1"
    }, {
      "name": "range2"
    }],
    "info": "<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">finished by(range1: range, range2: range): boolean\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">finished by([1..5], [3..5])\n// true\n\nfinished by((5..8], [1..5))\n// false\n\nfinished by([5..10], (1..10))\n// false\n</code></pre>\n"
  }, {
    "name": "includes",
    "type": "function",
    "params": [{
      "name": "range"
    }, {
      "name": "point"
    }],
    "info": "<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">includes(range: range, point: Any): boolean\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">includes([5..10], 6)\n// true\n\nincludes([3..4], 5)\n// false\n</code></pre>\n"
  }, {
    "name": "includes",
    "type": "function",
    "params": [{
      "name": "range1"
    }, {
      "name": "range2"
    }],
    "info": "<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">includes(range1: range, range2: range): boolean\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">includes([1..10], [4..6])\n// true\n\nincludes((5..8], [1..5))\n// false\n\nincludes([1..10], [1..5))\n// true\n</code></pre>\n"
  }, {
    "name": "during",
    "type": "function",
    "params": [{
      "name": "point"
    }, {
      "name": "range"
    }],
    "info": "<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">during(point: Any, range: range): boolean\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">during(5, [1..10])\n// true\n\nduring(12, [1..10])\n// false\n\nduring(1, (1..10])\n// false\n</code></pre>\n"
  }, {
    "name": "during",
    "type": "function",
    "params": [{
      "name": "range1"
    }, {
      "name": "range2"
    }],
    "info": "<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">during(range1: range, range2: range): boolean\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">during([4..6], [1..10))\n// true\n\nduring((1..5], (1..10])\n// true\n</code></pre>\n"
  }, {
    "name": "starts",
    "type": "function",
    "params": [{
      "name": "point"
    }, {
      "name": "range"
    }],
    "info": "<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">starts(point: Any, range: range): boolean\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">starts(1, [1..5])\n// true\n\nstarts(1, (1..8])\n// false\n</code></pre>\n"
  }, {
    "name": "starts",
    "type": "function",
    "params": [{
      "name": "range1"
    }, {
      "name": "range2"
    }],
    "info": "<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">starts(range1: range, range2: range): boolean\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">starts((1..5], [1..5])\n// false\n\nstarts([1..10], [1..5])\n// false\n\nstarts((1..5), (1..10))\n// true\n</code></pre>\n"
  }, {
    "name": "started by",
    "type": "function",
    "params": [{
      "name": "range"
    }, {
      "name": "point"
    }],
    "info": "<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">started by(range: range, point: Any): boolean\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">started by([1..10], 1)\n// true\n\nstarted by((1..10], 1)\n// false\n</code></pre>\n"
  }, {
    "name": "started by",
    "type": "function",
    "params": [{
      "name": "range1"
    }, {
      "name": "range2"
    }],
    "info": "<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">started by(range1: range, range2: range): boolean\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">started by([1..10], [1..5])\n// true\n\nstarted by((1..10], [1..5))\n// false\n\nstarted by([1..10], [1..10))\n// true\n</code></pre>\n"
  }, {
    "name": "coincides",
    "type": "function",
    "params": [{
      "name": "point1"
    }, {
      "name": "point2"
    }],
    "info": "<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">coincides(point1: Any, point2: Any): boolean\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">coincides(5, 5)\n// true\n\ncoincides(3, 4)\n// false\n</code></pre>\n"
  }, {
    "name": "coincides",
    "type": "function",
    "params": [{
      "name": "range1"
    }, {
      "name": "range2"
    }],
    "info": "<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">coincides(range1: range, range2: range): boolean\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">coincides([1..5], [1..5])\n// true\n\ncoincides((1..5], [1..5))\n// false\n\ncoincides([1..5], [2..6])\n// false\n</code></pre>\n"
  }, {
    "name": "substring",
    "type": "function",
    "params": [{
      "name": "string"
    }, {
      "name": "start position"
    }],
    "info": "<p>Returns a substring of the given value starting at <code>start position</code>.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">substring(string: string, start position: number): string\n</code></pre>\n<p>The <code>start position</code> starts at the index <code>1</code>. The last position is <code>-1</code>.</p>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">substring(&quot;foobar&quot;, 3)\n// &quot;obar&quot;\n\nsubstring(&quot;foobar&quot;, -2)\n// &quot;ar&quot;\n</code></pre>\n"
  }, {
    "name": "substring",
    "type": "function",
    "params": [{
      "name": "string"
    }, {
      "name": "start position"
    }, {
      "name": "length"
    }],
    "info": "<p>Returns a substring of the given value, starting at <code>start position</code> with the given <code>length</code>. If <code>length</code> is greater than\nthe remaining characters of the value, it returns all characters from <code>start position</code> until the end.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">substring(string: string, start position: number, length: number): string\n</code></pre>\n<p>The <code>start position</code> starts at the index <code>1</code>. The last position is <code>-1</code>.</p>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">substring(&quot;foobar&quot;, 3, 3)\n// &quot;oba&quot;\n\nsubstring(&quot;foobar&quot;, -3, 2)\n// &quot;ba&quot;\n\nsubstring(&quot;foobar&quot;, 3, 10)\n// &quot;obar&quot;\n</code></pre>\n"
  }, {
    "name": "string length",
    "type": "function",
    "params": [{
      "name": "string"
    }],
    "info": "<p>Returns the number of characters in the given value.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">string length(string: string): number\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">string length(&quot;foo&quot;)\n// 3\n</code></pre>\n"
  }, {
    "name": "upper case",
    "type": "function",
    "params": [{
      "name": "string"
    }],
    "info": "<p>Returns the given value with all characters are uppercase.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">upper case(string: string): string\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">upper case(&quot;aBc4&quot;)\n// &quot;ABC4&quot;\n</code></pre>\n"
  }, {
    "name": "lower case",
    "type": "function",
    "params": [{
      "name": "string"
    }],
    "info": "<p>Returns the given value with all characters are lowercase.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">lower case(string: string): string\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">lower case(&quot;aBc4&quot;)\n// &quot;abc4&quot;\n</code></pre>\n"
  }, {
    "name": "substring before",
    "type": "function",
    "params": [{
      "name": "string"
    }, {
      "name": "match"
    }],
    "info": "<p>Returns a substring of the given value that contains all characters before <code>match</code>.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">substring before(string: string, match: string): string\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">substring before(&quot;foobar&quot;, &quot;bar&quot;)\n// &quot;foo&quot;\n</code></pre>\n"
  }, {
    "name": "substring after",
    "type": "function",
    "params": [{
      "name": "string"
    }, {
      "name": "match"
    }],
    "info": "<p>Returns a substring of the given value that contains all characters after <code>match</code>.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">substring after(string: string, match: string): string\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">substring after(&quot;foobar&quot;, &quot;ob&quot;)\n// &quot;ar&quot;\n</code></pre>\n"
  }, {
    "name": "contains",
    "type": "function",
    "params": [{
      "name": "string"
    }, {
      "name": "match"
    }],
    "info": "<p>Returns <code>true</code> if the given value contains the substring <code>match</code>. Otherwise, returns <code>false</code>.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">contains(string: string, match: string): boolean\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">contains(&quot;foobar&quot;, &quot;of&quot;)\n// false\n</code></pre>\n"
  }, {
    "name": "starts with",
    "type": "function",
    "params": [{
      "name": "string"
    }, {
      "name": "match"
    }],
    "info": "<p>Returns <code>true</code> if the given value starts with the substring <code>match</code>. Otherwise, returns <code>false</code>.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">starts with(string: string, match: string): boolean\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">starts with(&quot;foobar&quot;, &quot;fo&quot;)\n// true\n</code></pre>\n"
  }, {
    "name": "ends with",
    "type": "function",
    "params": [{
      "name": "string"
    }, {
      "name": "match"
    }],
    "info": "<p>Returns <code>true</code> if the given value ends with the substring <code>match</code>. Otherwise, returns <code>false</code>.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">ends with(string: string, match: string): boolean\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">ends with(&quot;foobar&quot;, &quot;r&quot;)\n// true\n</code></pre>\n"
  }, {
    "name": "matches",
    "type": "function",
    "params": [{
      "name": "input"
    }, {
      "name": "pattern"
    }],
    "info": "<p>Returns <code>true</code> if the given value matches the <code>pattern</code>. Otherwise, returns <code>false</code>.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">matches(input: string, pattern: string): boolean\n</code></pre>\n<p>The <code>pattern</code> is a string that contains a regular expression.</p>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">matches(&quot;foobar&quot;, &quot;^fo*bar&quot;)\n// true\n</code></pre>\n"
  }, {
    "name": "matches",
    "type": "function",
    "params": [{
      "name": "input"
    }, {
      "name": "pattern"
    }, {
      "name": "flags"
    }],
    "info": "<p>Returns <code>true</code> if the given value matches the <code>pattern</code>. Otherwise, returns <code>false</code>.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">matches(input: string, pattern: string, flags: string): boolean\n</code></pre>\n<p>The <code>pattern</code> is a string that contains a regular expression.</p>\n<p>The <code>flags</code> can contain one or more of the following characters:</p>\n<ul>\n<li><code>s</code> (dot-all)</li>\n<li><code>m</code> (multi-line)</li>\n<li><code>i</code> (case insensitive)</li>\n<li><code>x</code> (comments)</li>\n</ul>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">matches(&quot;FooBar&quot;, &quot;foo&quot;, &quot;i&quot;)\n// true\n</code></pre>\n"
  }, {
    "name": "replace",
    "type": "function",
    "params": [{
      "name": "input"
    }, {
      "name": "pattern"
    }, {
      "name": "replacement"
    }],
    "info": "<p>Returns the resulting string after replacing all occurrences of <code>pattern</code> with <code>replacement</code>.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">replace(input: string, pattern: string, replacement: string): string\n</code></pre>\n<p>The <code>pattern</code> is a string that contains a regular expression.</p>\n<p>The <code>replacement</code> can access the match groups by using <code>$</code> and the number of the group, for example,\n<code>$1</code> to access the first group.</p>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">replace(&quot;abcd&quot;, &quot;(ab)|(a)&quot;, &quot;[1=$1][2=$2]&quot;)\n// &quot;[1=ab][2=]cd&quot;\n\nreplace(&quot;0123456789&quot;, &quot;(\\d{3})(\\d{3})(\\d{4})&quot;, &quot;($1) $2-$3&quot;)\n// &quot;(012) 345-6789&quot;\n</code></pre>\n"
  }, {
    "name": "replace",
    "type": "function",
    "params": [{
      "name": "input"
    }, {
      "name": "pattern"
    }, {
      "name": "replacement"
    }, {
      "name": "flags"
    }],
    "info": "<p>Returns the resulting string after replacing all occurrences of <code>pattern</code> with <code>replacement</code>.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">replace(input: string, pattern: string, replacement: string, flags: string): string\n</code></pre>\n<p>The <code>pattern</code> is a string that contains a regular expression.</p>\n<p>The <code>replacement</code> can access the match groups by using <code>$</code> and the number of the group, for example,\n<code>$1</code> to access the first group.</p>\n<p>The <code>flags</code> can contain one or more of the following characters:</p>\n<ul>\n<li><code>s</code> (dot-all)</li>\n<li><code>m</code> (multi-line)</li>\n<li><code>i</code> (case insensitive)</li>\n<li><code>x</code> (comments)</li>\n</ul>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">replace(&quot;How do you feel?&quot;, &quot;Feel&quot;, &quot;FEEL&quot;, &quot;i&quot;)\n// &quot;How do you FEEL?&quot;\n</code></pre>\n"
  }, {
    "name": "split",
    "type": "function",
    "params": [{
      "name": "string"
    }, {
      "name": "delimiter"
    }],
    "info": "<p>Splits the given value into a list of substrings, breaking at each occurrence of the <code>delimiter</code> pattern.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">split(string: string, delimiter: string): list&lt;string&gt;\n</code></pre>\n<p>The <code>delimiter</code> is a string that contains a regular expression.</p>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">split(&quot;John Doe&quot;, &quot;\\s&quot; )\n// [&quot;John&quot;, &quot;Doe&quot;]\n\nsplit(&quot;a;b;c;;&quot;, &quot;;&quot;)\n// [&quot;a&quot;, &quot;b&quot;, &quot;c&quot;, &quot;&quot;, &quot;&quot;]\n</code></pre>\n"
  }, {
    "name": "now",
    "type": "function",
    "params": [],
    "info": "<p>Returns the current date and time including the timezone.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">now(): date and time\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">now()\n// date and time(&quot;2020-07-31T14:27:30@Europe/Berlin&quot;)\n</code></pre>\n"
  }, {
    "name": "today",
    "type": "function",
    "params": [],
    "info": "<p>Returns the current date.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">today(): date\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">today()\n// date(&quot;2020-07-31&quot;)\n</code></pre>\n"
  }, {
    "name": "day of week",
    "type": "function",
    "params": [{
      "name": "date"
    }],
    "info": "<p>Returns the day of the week according to the Gregorian calendar. Note that it always returns the English name of the day.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">day of week(date: date): string\n</code></pre>\n<pre><code class=\"language-feel\">day of week(date: date and time): string\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">day of week(date(&quot;2019-09-17&quot;))\n// &quot;Tuesday&quot;\n\nday of week(date and time(&quot;2019-09-17T12:00:00&quot;))\n// &quot;Tuesday&quot;\n</code></pre>\n"
  }, {
    "name": "day of year",
    "type": "function",
    "params": [{
      "name": "date"
    }],
    "info": "<p>Returns the Gregorian number of the day within the year.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">day of year(date: date): number\n</code></pre>\n<pre><code class=\"language-feel\">day of year(date: date and time): number\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">day of year(date(&quot;2019-09-17&quot;))\n// 260\n\nday of year(date and time(&quot;2019-09-17T12:00:00&quot;))\n// 260\n</code></pre>\n"
  }, {
    "name": "week of year",
    "type": "function",
    "params": [{
      "name": "date"
    }],
    "info": "<p>Returns the Gregorian number of the week within the year, according to ISO 8601.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">week of year(date: date): number\n</code></pre>\n<pre><code class=\"language-feel\">week of year(date: date and time): number\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">week of year(date(&quot;2019-09-17&quot;))\n// 38\n\nweek of year(date and time(&quot;2019-09-17T12:00:00&quot;))\n// 38\n</code></pre>\n"
  }, {
    "name": "month of year",
    "type": "function",
    "params": [{
      "name": "date"
    }],
    "info": "<p>Returns the month of the year according to the Gregorian calendar. Note that it always returns the English name of the month.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">month of year(date: date): string\n</code></pre>\n<pre><code class=\"language-feel\">month of year(date: date and time): string\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">month of year(date(&quot;2019-09-17&quot;))\n// &quot;September&quot;\n\nmonth of year(date and time(&quot;2019-09-17T12:00:00&quot;))\n// &quot;September&quot;\n</code></pre>\n"
  }, {
    "name": "abs",
    "type": "function",
    "params": [{
      "name": "n"
    }],
    "info": "<p>Returns the absolute value of a given duration.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">abs(n: days and time duration): days and time duration\n</code></pre>\n<pre><code class=\"language-feel\">abs(n: years and months duration): years and months duration\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">abs(duration(&quot;-PT5H&quot;))\n// &quot;duration(&quot;PT5H&quot;)&quot;\n\nabs(duration(&quot;PT5H&quot;))\n// &quot;duration(&quot;PT5H&quot;)&quot;\n\nabs(duration(&quot;-P2M&quot;))\n// duration(&quot;P2M&quot;)\n</code></pre>\n"
  }];

  /**
   * List of FEEL camunda extensions.
   *
   * @type { Builtin[] }
   */
  const camundaExtensions = [{
    "name": "is defined",
    "type": "function",
    "params": [{
      "name": "value"
    }],
    "info": "<p><em>Camunda Extension</em></p>\n<p>Checks if a given value is not <code>null</code>. If the value is <code>null</code> then the function returns <code>false</code>.\nOtherwise, the function returns <code>true</code>.</p>\n<p>The function requires one argument. Calling <code>is defined()</code> without an argument is invalid.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">is defined(value: Any): boolean\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">is defined(1)\n// true\n\nis defined(null)\n// false\n\nis defined(x)\n// false - if no variable &quot;x&quot; exists\n\nis defined(x.y)\n// false - if no variable &quot;x&quot; exists or it doesn&#39;t have a property &quot;y&quot;\n\nis defined()\n// error - expected one argument\n</code></pre>\n<p>:::caution Breaking change</p>\n<p>This function worked differently in previous versions. It returned <code>true</code> if the value was <code>null</code>.\nSince this version, the function returns <code>false</code> if the value is <code>null</code>.</p>\n<p>:::</p>\n"
  }, {
    "name": "get or else",
    "type": "function",
    "params": [{
      "name": "value"
    }, {
      "name": "default"
    }],
    "info": "<p><em>Camunda Extension</em></p>\n<p>Return the provided value parameter if not <code>null</code>, otherwise return the default parameter</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">get or else(value: Any, default: Any): Any\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">get or else(&quot;this&quot;, &quot;default&quot;)\n// &quot;this&quot;\n\nget or else(null, &quot;default&quot;)\n// &quot;default&quot;\n\nget or else(null, null)\n// null\n</code></pre>\n",
    "engines": {
      "camunda": ">=8.3"
    }
  }, {
    "name": "assert",
    "type": "function",
    "params": [{
      "name": "value"
    }, {
      "name": "condition"
    }],
    "info": "<p><em>Camunda Extension</em></p>\n<p>Verify that the given condition is met. If the condition is <code>true</code>, the function returns the value.\nOtherwise, the evaluation fails with an error.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">assert(value: Any, condition: Any)\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">assert(x, x != null)\n// &quot;value&quot; - if x is &quot;value&quot;\n// error - if x is null or doesn&#39;t exist\n\nassert(x, x &gt;= 0)\n// 4 - if x is 4\n// error - if x is less than zero\n</code></pre>\n",
    "engines": {
      "camunda": ">=8.3"
    }
  }, {
    "name": "assert",
    "type": "function",
    "params": [{
      "name": "value"
    }, {
      "name": "condition"
    }, {
      "name": "cause"
    }],
    "info": "<p><em>Camunda Extension</em></p>\n<p>Verify that the given condition is met. If the condition is <code>true</code>, the function returns the value.\nOtherwise, the evaluation fails with an error containing the given message.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">assert(value: Any, condition: Any, cause: String)\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">assert(x, x != null, &quot;&#39;x&#39; should not be null&quot;)\n// &quot;value&quot; - if x is &quot;value&quot;\n// error(&#39;x&#39; should not be null) - if x is null or doesn&#39;t exist\n\nassert(x, x &gt;= 0, &quot;&#39;x&#39; should be positive&quot;)\n// 4 - if x is 4\n// error(&#39;x&#39; should be positive) - if x is less than zero\n</code></pre>\n",
    "engines": {
      "camunda": ">=8.3"
    }
  }, {
    "name": "get value",
    "type": "function",
    "params": [{
      "name": "context"
    }, {
      "name": "keys"
    }],
    "info": "<p><em>Camunda Extension</em></p>\n<p>Returns the value of the context entry for a context path defined by the given keys.</p>\n<p>If <code>keys</code> contains the keys <code>[k1, k2]</code> then it returns the value at the nested entry <code>k1.k2</code> of the context.</p>\n<p>If <code>keys</code> are empty or the nested entry defined by the keys doesn&#39;t exist in the context, it returns <code>null</code>.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">get value(context: context, keys: list&lt;string&gt;): Any\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">get value({x:1, y: {z:0}}, [&quot;y&quot;, &quot;z&quot;])\n// 0\n\nget value({x: {y: {z:0}}}, [&quot;x&quot;, &quot;y&quot;])\n// {z:0}\n\nget value({a: {b: 3}}, [&quot;b&quot;])\n// null\n</code></pre>\n"
  }, {
    "name": "context put",
    "type": "function",
    "params": [{
      "name": "context"
    }, {
      "name": "key"
    }, {
      "name": "value"
    }],
    "info": "<p>Adds a new entry with the given key and value to the context. Returns a new context that includes the entry.</p>\n<p>If an entry for the same key already exists in the context, it overrides the value.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">context put(context: context, key: string, value: Any): context\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">context put({x:1}, &quot;y&quot;, 2)\n// {x:1, y:2}\n</code></pre>\n<p>:::info\nThe function <code>context put()</code> replaced the previous function <code>put()</code> (Camunda Extension). The\nprevious function is deprecated and should not be used anymore.\n:::</p>\n"
  }, {
    "name": "context merge",
    "type": "function",
    "params": [{
      "name": "contexts"
    }],
    "info": "<p>Union the given contexts. Returns a new context that includes all entries of the given contexts.</p>\n<p>If an entry for the same key already exists in a context, it overrides the value. The entries are overridden in the same order as in the list of contexts.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">context merge(contexts: list&lt;context&gt;): context\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">context merge([{x:1}, {y:2}])\n// {x:1, y:2}\n\ncontext merge([{x:1, y: 0}, {y:2}])\n// {x:1, y:2}\n</code></pre>\n<p>:::info\nThe function <code>context merge()</code> replaced the previous function <code>put all()</code> (Camunda Extension). The\nprevious function is deprecated and should not be used anymore.\n:::</p>\n",
    "engines": {
      "camunda": ">=8.2"
    }
  }, {
    "name": "date and time",
    "type": "function",
    "params": [{
      "name": "date"
    }, {
      "name": "timezone"
    }],
    "info": "<p><em>Camunda Extension</em></p>\n<p>Returns the given date and time value at the given timezone.</p>\n<p>If <code>date</code> has a different timezone than <code>timezone</code> then it adjusts the time to match the local time of <code>timezone</code>.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">date and time(date: date and time, timezone: string): date and time\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">date and time(@&quot;2020-07-31T14:27:30@Europe/Berlin&quot;, &quot;America/Los_Angeles&quot;)\n// date and time(&quot;2020-07-31T05:27:30@America/Los_Angeles&quot;)\n\ndate and time(@&quot;2020-07-31T14:27:30&quot;, &quot;Z&quot;)\n// date and time(&quot;2020-07-31T12:27:30Z&quot;)\n</code></pre>\n"
  }, {
    "name": "duplicate values",
    "type": "function",
    "params": [{
      "name": "list"
    }],
    "info": "<p><em>Camunda Extension</em></p>\n<p>Returns all duplicate values of the given list.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">duplicate values(list: list): list\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">duplicate values([1,2,3,2,1])\n// [1,2]\n</code></pre>\n",
    "engines": {
      "camunda": ">=8.3"
    }
  }, {
    "name": "string join",
    "type": "function",
    "params": [{
      "name": "list"
    }, {
      "name": "delimiter"
    }, {
      "name": "prefix"
    }, {
      "name": "suffix"
    }],
    "info": "<p><em>Camunda Extension</em></p>\n<p>Joins a list of strings into a single string. This is similar to\nJava&#39;s <a href=\"https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/stream/Collectors.html#joining(java.lang.CharSequence,java.lang.CharSequence,java.lang.CharSequence)\">joining</a>\nfunction.</p>\n<p>If an item of the list is <code>null</code>, the item is ignored for the result string. If an item is\nneither a string nor <code>null</code>, the function returns <code>null</code> instead of a string.</p>\n<p>The resulting string starts with <code>prefix</code>, contains a <code>delimiter</code> between each element, and ends\nwith <code>suffix</code>.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">string join(list: list&lt;string&gt;, delimiter: string, prefix: string, suffix: string): string\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">string join([&quot;a&quot;,&quot;b&quot;,&quot;c&quot;], &quot;, &quot;, &quot;[&quot;, &quot;]&quot;)\n// &quot;[a, b, c]&quot;\n</code></pre>\n"
  }, {
    "name": "is empty",
    "type": "function",
    "params": [{
      "name": "list"
    }],
    "info": "<p><em>Camunda Extension</em></p>\n<p>Returns <code>true</code> if the given list is empty. Otherwise, returns <code>false</code>.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">is empty(list: list): boolean\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">is empty([])\n// true\n\nis empty([1,2,3])\n// false\n</code></pre>\n",
    "engines": {
      "camunda": ">=8.6"
    }
  }, {
    "name": "partition",
    "type": "function",
    "params": [{
      "name": "list"
    }, {
      "name": "size"
    }],
    "info": "<p><em>Camunda Extension</em></p>\n<p>Returns consecutive sublists of a list, each of the same size (the final list may be smaller).</p>\n<p>If <code>size</code> is less than <code>0</code>, it returns <code>null</code>.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">partition(list: list, size: number): list\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">partition([1,2,3,4,5], 2)\n// [[1,2], [3,4], [5]]\n\npartition([], 2)\n// []\n\npartition([1,2], 0)\n// null\n</code></pre>\n",
    "engines": {
      "camunda": ">=8.7"
    }
  }, {
    "name": "fromAi",
    "type": "function",
    "params": [{
      "name": "value"
    }],
    "info": "<p><em>Camunda Extension</em></p>\n<p>Returns the unmodified <code>value</code> parameter.</p>\n<ul>\n<li>The purpose of this function is solely to tag the value as being generated by an AI integration.</li>\n<li>The actual handling is not performed by the FEEL engine, but by a custom integration such as a connector or a job worker.</li>\n</ul>\n<p>The main use case of this function is for <a href=\"../../../connectors/out-of-the-box-connectors/agentic-ai-aiagent-tool-definitions.md\">tool definitions</a> used by the <a href=\"../../../connectors/out-of-the-box-connectors/agentic-ai-aiagent.md\">AI Agent connector</a>.</p>\n<p>See the following function overloads for additional function parameters.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">fromAi(value: Any): Any\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">fromAi(toolCall.searchQuery)\n// toolCall.searchQuery contents\n\nfromAi(toolCall.userId)\n// toolCall.userId contents\n</code></pre>\n",
    "engines": {
      "camunda": ">=8.8"
    }
  }, {
    "name": "fromAi",
    "type": "function",
    "params": [{
      "name": "value"
    }, {
      "name": "description"
    }],
    "info": "<p><em>Camunda Extension</em></p>\n<p>Returns the unmodified <code>value</code> parameter.</p>\n<p>In addition to the previous overload, it also accepts an optional <code>description</code> parameter to provide a textual description of the value. The description must be <code>null</code> or a string constant.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">fromAi(value: Any, description: string): Any\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">fromAi(toolCall.searchQuery, &quot;The search query used to find the best match.&quot;)\n// toolCall.searchQuery contents\n\nfromAi(toolCall.searchQuery, null)\n// toolCall.searchQuery contents\n</code></pre>\n",
    "engines": {
      "camunda": ">=8.8"
    }
  }, {
    "name": "fromAi",
    "type": "function",
    "params": [{
      "name": "value"
    }, {
      "name": "description"
    }, {
      "name": "type"
    }],
    "info": "<p><em>Camunda Extension</em></p>\n<p>Returns the unmodified <code>value</code> parameter.</p>\n<p>In addition to the previous overload, it also accepts an optional <code>type</code> parameter to provide type information about the value. The type must be <code>null</code> or a string constant.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">fromAi(value: Any, description: string, type: string): Any\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">fromAi(toolCall.searchQuery, &quot;The search query used to find the best match.&quot;, &quot;string&quot;)\n// toolCall.searchQuery contents\n\nfromAi(toolCall.userId, &quot;The user&#39;s ID&quot;, &quot;number&quot;)\n// toolCall.userId contents\n\nfromAi(toolCall.userId, null, &quot;number&quot;)\n// toolCall.userId contents\n\nfromAi(value: toolCall.userId, type: &quot;number&quot;)\n// toolCall.userId contents\n</code></pre>\n",
    "engines": {
      "camunda": ">=8.8"
    }
  }, {
    "name": "fromAi",
    "type": "function",
    "params": [{
      "name": "value"
    }, {
      "name": "description"
    }, {
      "name": "type"
    }, {
      "name": "schema"
    }],
    "info": "<p><em>Camunda Extension</em></p>\n<p>Returns the unmodified <code>value</code> parameter.</p>\n<p>In addition to the previous overload, it also accepts an optional <code>schema</code> parameter to provide a (partial) <a href=\"https://json-schema.org/\">JSON schema</a> for the value.</p>\n<ul>\n<li>The schema must be <code>null</code> or a context (map) containing only constant values. For example, function calls within the schema are not supported.</li>\n<li>The schema is not validated by the FEEL engine but might be by a custom integration consuming the information.</li>\n<li>From the engine side it is possible to specify both a <code>type</code> and a <code>schema</code>, and it depends on the integration as to which value takes precedence. The <a href=\"../../../connectors/out-of-the-box-connectors/agentic-ai-aiagent.md\">AI Agent connector</a> will override any type specified in the schema if the <code>type</code> parameter is also provided.</li>\n</ul>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">fromAi(value: Any, description: string, type: string, schema: context): Any\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">fromAi(toolCall.documentType, &quot;The document type to provide&quot;, &quot;string&quot;, {\n  enum: [&quot;invoice&quot;, &quot;receipt&quot;, &quot;contract&quot;]\n})\n// toolCall.documentType contents\n\nfromAi(value: toolCall.documentType, description: &quot;The document type to provide&quot;, schema: {\n  type: &quot;string&quot;,\n  enum: [&quot;invoice&quot;, &quot;receipt&quot;, &quot;contract&quot;]\n})\n// toolCall.documentType contents\n\nfromAi(toolCall.tags, &quot;Tags to apply to the blog post&quot;, &quot;array&quot;, {\n  items: {\n    type: &quot;string&quot;\n  }\n})\n// toolCall.tags contents\n</code></pre>\n",
    "engines": {
      "camunda": ">=8.8"
    }
  }, {
    "name": "fromAi",
    "type": "function",
    "params": [{
      "name": "value"
    }, {
      "name": "description"
    }, {
      "name": "type"
    }, {
      "name": "schema"
    }, {
      "name": "options"
    }],
    "info": "<p><em>Camunda Extension</em></p>\n<p>Returns the unmodified <code>value</code> parameter.</p>\n<p>In addition to the previous overload, it also accepts an optional <code>options</code> parameter to provide additional options for the integration handling the value definition.</p>\n<ul>\n<li>The options parameter must be <code>null</code> or a context (map) containing only constant values. For example, function calls within options are not supported.</li>\n</ul>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">fromAi(value: Any, description: string, type: string, schema: context, options: context): Any\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">fromAi(toolCall.documentType, &quot;The document type to provide&quot;, &quot;string&quot;, null, {\n  required: false\n})\n// toolCall.documentType contents\n\nfromAi(value: toolCall.documentType, options: {\n  required: false\n})\n// toolCall.documentType contents\n</code></pre>\n",
    "engines": {
      "camunda": ">=8.8"
    }
  }, {
    "name": "random number",
    "type": "function",
    "params": [],
    "info": "<p><em>Camunda Extension</em></p>\n<p>Returns a random number between <code>0</code> and <code>1</code>.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">random number(): number\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">random number()\n// 0.9701618132579795\n</code></pre>\n",
    "engines": {
      "camunda": ">=8.2"
    }
  }, {
    "name": "extract",
    "type": "function",
    "params": [{
      "name": "string"
    }, {
      "name": "pattern"
    }],
    "info": "<p><em>Camunda Extension</em></p>\n<p>Returns all matches of the pattern in the given string. Returns an empty list if the pattern doesn&#39;t\nmatch.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">extract(string: string, pattern: string): list&lt;string&gt;\n</code></pre>\n<p>The <code>pattern</code> is a string that contains a regular expression.</p>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">extract(&quot;references are 1234, 1256, 1378&quot;, &quot;12[0-9]*&quot;)\n// [&quot;1234&quot;,&quot;1256&quot;]\n</code></pre>\n"
  }, {
    "name": "trim",
    "type": "function",
    "params": [{
      "name": "string"
    }],
    "info": "<p><em>Camunda Extension</em></p>\n<p>Returns the given string without leading and trailing spaces.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">trim(string: string): string\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">trim(&quot;  hello world  &quot;)\n// &quot;hello world&quot;\n\ntrim(&quot;hello   world &quot;)\n// &quot;hello   world&quot;\n</code></pre>\n",
    "engines": {
      "camunda": ">=8.6"
    }
  }, {
    "name": "uuid",
    "type": "function",
    "params": [],
    "info": "<p><em>Camunda Extension</em></p>\n<p>Returns a UUID (Universally Unique Identifier) with 36 characters.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">uuid(): string\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">uuid()\n// &quot;7793aab1-d761-4d38-916b-b7270e309894&quot;\n</code></pre>\n",
    "engines": {
      "camunda": ">=8.6"
    }
  }, {
    "name": "to base64",
    "type": "function",
    "params": [{
      "name": "value"
    }],
    "info": "<p><em>Camunda Extension</em></p>\n<p>Returns the given string encoded in Base64 format.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">to base64(value: string): string\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">to base64(&quot;FEEL&quot;)\n// &quot;RkVFTA==&quot;\n</code></pre>\n",
    "engines": {
      "camunda": ">=8.6"
    }
  }, {
    "name": "from base64",
    "type": "function",
    "params": [{
      "name": "value"
    }],
    "info": "<p><em>Camunda Extension</em></p>\n<p>Returns the given Base64 encoded string decoded to a plain string.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">from base64(value: string): string\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">from base64(&quot;RkVFTA==&quot;)\n// &quot;FEEL&quot;\n</code></pre>\n"
  }, {
    "name": "is blank",
    "type": "function",
    "params": [{
      "name": "string"
    }],
    "info": "<p><em>Camunda Extension</em></p>\n<p>Returns <code>true</code> if the given string is blank (empty or contains only whitespaces).</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">is blank(string: string): boolean\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">is blank(&quot;&quot;)\n// true\n\nis blank(&quot; &quot;)\n// true\n\nis blank(&quot;hello world&quot;)\n// false\n</code></pre>\n",
    "engines": {
      "camunda": ">=8.8"
    }
  }, {
    "name": "last day of month",
    "type": "function",
    "params": [{
      "name": "date"
    }],
    "info": "<p><em>Camunda Extension</em></p>\n<p>Takes the month of the given date or date-time value and returns the last day of this month.</p>\n<p><strong>Function signature</strong></p>\n<pre><code class=\"language-feel\">last day of month(date: date): date\n</code></pre>\n<pre><code class=\"language-feel\">last day of month(date: date and time): date\n</code></pre>\n<p><strong>Examples</strong></p>\n<pre><code class=\"language-feel\">last day of month(date(&quot;2022-10-01&quot;))\n// date(&quot;2022-10-31&quot;))\n\nlast day of month(date and time(&quot;2022-10-16T12:00:00&quot;))\n// date(&quot;2022-10-31&quot;))\n</code></pre>\n",
    "engines": {
      "camunda": ">=8.2"
    }
  }];

  /**
   * Collection of builtins of camunda scala FEEL.
   *
   * @type { Builtin[] }
   */
  const camundaBuiltins = [...feelBuiltins, ...camundaExtensions];

  [linter(cmFeelLinter())];
  EditorView.theme({
    '& .cm-content': {
      padding: '0px'
    },
    '& .cm-line': {
      padding: '0px'
    },
    '&.cm-editor.cm-focused': {
      outline: 'none'
    },
    '& .cm-completionInfo': {
      whiteSpace: 'pre-wrap',
      overflow: 'hidden',
      textOverflow: 'ellipsis'
    },
    '&.cm-editor': {
      height: '100%'
    },
    // Don't wrap whitespace for custom HTML
    '& .cm-completionInfo > *': {
      whiteSpace: 'normal'
    },
    '& .cm-completionInfo ul': {
      margin: 0,
      paddingLeft: '15px'
    },
    '& .cm-completionInfo pre': {
      marginBottom: 0,
      whiteSpace: 'pre-wrap'
    },
    '& .cm-completionInfo p': {
      marginTop: 0
    },
    '& .cm-completionInfo p:not(:last-of-type)': {
      marginBottom: 0
    }
  });

  /**
   * @typedef { import('../language').Dialect } Dialect
   * @typedef { import('../language').ParserDialect } ParserDialect
   * @typedef { import('..').Variable } Variable
   */

  /**
   * @type {Facet<Variable[]>}
   */
  Facet.define();

  /**
   * @type {Facet<Variable[]>}
   */
  Facet.define();

  /**
   * @type {Facet<Dialect>}
   */
  Facet.define();

  /**
   * @type {Facet<ParserDialect>}
   */
  Facet.define();
  camundaBuiltins.map(builtin => ({
    ...builtin,
    info: () => domify(builtin.info)
  }));

  class LiteralExpressionEditor extends LiteralExpression {
    constructor(modeling) {
      super();
      this._modeling = modeling;
    }
    setText(literalExpression, value) {
      this._modeling.updateProperties(literalExpression, {
        text: value
      });
    }
  }
  LiteralExpressionEditor.$inject = ['modeling'];

  class InputSelect extends Component {
    constructor(props, context) {
      super(props, context);
      inject(this);
      const {
        value
      } = props;
      this.state = {
        value,
        optionsVisible: false
      };
      this._portalEl = null;
    }
    componentDidMount() {
      document.addEventListener('mousedown', this.onGlobalClick);
      document.addEventListener('focusin', this.onFocusChanged);
      this.keyboard.addListener(this.onKeyboard);
    }
    componentWillUnmount() {
      document.removeEventListener('focusin', this.onFocusChanged);
      document.removeEventListener('mousedown', this.onGlobalClick);
      this.keyboard.removeListener(this.onKeyboard);
      this.removePortalEl();
    }
    componentWillReceiveProps(props) {
      const {
        value
      } = props;
      this.setState({
        value
      });
    }
    componentWillUpdate(nextProps, nextState) {
      const {
        optionsVisible
      } = nextState;
      if (optionsVisible) {
        if (!this._portalEl) {
          this.addPortalEl();
        }
      } else {
        if (this._portalEl) {
          this.removePortalEl();
        }
      }
    }
    componentDidUpdate() {
      const {
        optionsVisible
      } = this.state;
      if (!optionsVisible || !this.inputNode) {
        return;
      }
      const optionsBounds = this.getOptionsBounds();
      assign$1(this._portalEl.style, optionsBounds);
    }
    getOptionsBounds() {
      const container = this.renderer.getContainer();
      const {
        top: containerTop,
        left: containerLeft,
        bottom: containerBottom
      } = container.getBoundingClientRect();
      const {
        top: inputTop,
        left: inputLeft,
        width,
        height,
        bottom: inputBottom
      } = this.inputNode.getBoundingClientRect();
      const top = inputTop + height - containerTop + container.scrollTop;
      const left = inputLeft - containerLeft + container.scrollLeft;
      const bounds = {
        top: `${top}px`,
        left: `${left}px`,
        width: `${width}px`,
        'max-height': `calc(100% - ${top}px)`
      };

      // open the options upwards when not even one option (=input height) fits
      if (containerBottom - inputBottom < height) {
        const bottom = containerBottom - inputTop;
        bounds.bottom = `${bottom}px`;
        bounds['max-height'] = `calc(100% - ${bottom})`;
        delete bounds.top;
      }
      return bounds;
    }
    addPortalEl() {
      this._portalEl = domify('<div class="dms-select-options"></div>');
      const container = this.renderer.getContainer();
      container.appendChild(this._portalEl);

      // suppress mousedown event propagation to handle click events inside the component
      this._portalEl.addEventListener('mousedown', stopPropagation);
    }
    removePortalEl() {
      if (this._portalEl) {
        this._portalEl.removeEventListener('mousedown', stopPropagation);
        remove$4(this._portalEl);
        this._portalEl = null;
      }
    }
    onChange = value => {
      this.setState({
        value
      });
      const {
        onChange
      } = this.props;
      if (typeof onChange !== 'function') {
        return;
      }
      onChange(value);
    };
    onInputClick = event => {
      event.preventDefault();
      event.stopPropagation();
      this.setOptionsVisible(!this.state.optionsVisible);
      this.focusInput();
    };
    onInput = event => {
      const {
        value
      } = event.target;
      this.onChange(value);
    };
    onOptionClick = (value, event) => {
      event.preventDefault();
      event.stopPropagation();
      this.setOptionsVisible(false);
      this.onChange(value);
      this.focusInput();
    };

    /**
     * Focus input node
     */
    focusInput() {
      const node = this.inputNode;
      node.focus();

      // move cursor to end of input
      if ('selectionStart' in node) {
        node.selectionStart = 100000;
      }
    }
    checkClose(focusTarget) {
      if (this._portalEl && !this._portalEl.contains(focusTarget) && !this.parentNode.contains(focusTarget)) {
        this.setOptionsVisible(false);
      }
    }
    onFocusChanged = evt => {
      this.checkClose(evt.target);
    };
    onGlobalClick = evt => {
      this.checkClose(evt.target);
    };
    select(direction) {
      const {
        options
      } = this.props;
      const {
        value
      } = this.state;
      if (!options) {
        return;
      }
      const option = options.filter(o => o.value === value)[0];
      const idx = option ? options.indexOf(option) : -1;
      const nextIdx = idx === -1 ? direction === 1 ? 0 : options.length - 1 : (idx + direction) % options.length;
      const nextOption = options[nextIdx < 0 ? options.length + nextIdx : nextIdx];
      this.onChange(nextOption.value);
    }
    setOptionsVisible(optionsVisible) {
      this.setState({
        optionsVisible
      });
    }
    onKeyDown = evt => {
      const {
        optionsVisible
      } = this.state;
      var code = evt.which;

      // DOWN or UP
      if (code === 40 || code === 38) {
        evt.stopPropagation();
        evt.preventDefault();
        if (!optionsVisible) {
          this.setOptionsVisible(true);
        } else {
          this.select(code === 40 ? 1 : -1);
        }
      }
      if (optionsVisible) {
        // ENTER
        // ESC
        if (code === 13 || code === 27) {
          evt.stopPropagation();
          evt.preventDefault();
          this.setOptionsVisible(false);
        }
      }
    };
    onKeyboard = keycode => {
      const {
        optionsVisible
      } = this.state;
      if (!optionsVisible) {
        return;
      }

      // close on ESC
      if (keycode === 27) {
        this.setOptionsVisible(false);
        return true;
      }
    };
    renderOptions(options, activeOption) {
      return createVNode(1, "div", "options", options.map(option => {
        return createVNode(1, "div", ['option', activeOption === option ? 'active' : ''].join(' '), option.label, 0, {
          "data-value": option.value,
          "onClick": e => this.onOptionClick(option.value, e)
        });
      }), 0);
    }
    render() {
      const {
        className,
        label: inputLabel,
        id,
        options,
        noInput,
        title
      } = this.props;
      const {
        optionsVisible,
        value
      } = this.state;
      const option = options ? options.filter(o => o.value === value)[0] : false;
      const label = option ? option.label : value;
      return createVNode(1, "div", [className || '', 'dms-input-select'].join(' '), [noInput ? createVNode(1, "div", "dms-input", label, 0, {
        "aria-label": inputLabel,
        "tabIndex": "0",
        "onKeyDown": this.onKeyDown
      }, null, node => this.inputNode = node) : createVNode(64, "input", "dms-input", null, 1, {
        "aria-label": inputLabel,
        "onInput": this.onInput,
        "onKeyDown": this.onKeyDown,
        "spellCheck": "false",
        "type": "text",
        "value": value,
        "id": id
      }, null, node => this.inputNode = node), createVNode(1, "span", ['dms-input-select-icon', optionsVisible ? 'dmn-icon-up' : 'dmn-icon-down'].join(' ')), optionsVisible && createPortal(this.renderOptions(options, option), this._portalEl)], 0, {
        "title": title,
        "onClick": this.onInputClick
      }, null, node => this.parentNode = node);
    }
  }
  InputSelect.$inject = ['keyboard', 'renderer'];

  // helper ////
  function stopPropagation(event) {
    event.stopPropagation();
  }

  /**
   * Does the definitions element contain graphical information?
   *
   * @param  {ModdleElement} definitions
   *
   * @return {boolean} true, if the definitions contains graphical information
   */
  function containsDi(definitions) {
    return definitions.dmnDI && definitions.dmnDI.diagrams && definitions.dmnDI.diagrams[0];
  }

  /**
   * The dmn viewer.
   */
  class Viewer extends Manager {
    _getViewProviders() {
      return [{
        id: 'drd',
        constructor: Viewer$5,
        opens(element) {
          return is(element, 'dmn:Definitions') && containsDi(element);
        }
      }, {
        id: 'decisionTable',
        constructor: Viewer$4,
        opens(element) {
          return is(element, 'dmn:Decision') && is(element.decisionLogic, 'dmn:DecisionTable');
        }
      }, {
        id: 'literalExpression',
        constructor: Viewer$2,
        opens(element) {
          return is(element, 'dmn:Decision') && is(element.decisionLogic, 'dmn:LiteralExpression');
        }
      }, {
        id: 'boxedExpression',
        constructor: Viewer$1,
        opens(element) {
          return is(element, 'dmn:BusinessKnowledgeModel') && getBoxedExpression(element);
        }
      }];
    }
  }

  return Viewer;

}));