(function(){'use strict';// ::- Persistent data structure representing an ordered mapping from
// strings to values, with some convenient update methods.
function OrderedMap(content) {
  this.content = content;
}

OrderedMap.prototype = {
  constructor: OrderedMap,

  find: function(key) {
    for (var i = 0; i < this.content.length; i += 2)
      { if (this.content[i] === key) { return i } }
    return -1
  },

  // :: (string) → ?any
  // Retrieve the value stored under `key`, or return undefined when
  // no such key exists.
  get: function(key) {
    var found = this.find(key);
    return found == -1 ? undefined : this.content[found + 1]
  },

  // :: (string, any, ?string) → OrderedMap
  // Create a new map by replacing the value of `key` with a new
  // value, or adding a binding to the end of the map. If `newKey` is
  // given, the key of the binding will be replaced with that key.
  update: function(key, value, newKey) {
    var self = newKey && newKey != key ? this.remove(newKey) : this;
    var found = self.find(key), content = self.content.slice();
    if (found == -1) {
      content.push(newKey || key, value);
    } else {
      content[found + 1] = value;
      if (newKey) { content[found] = newKey; }
    }
    return new OrderedMap(content)
  },

  // :: (string) → OrderedMap
  // Return a map with the given key removed, if it existed.
  remove: function(key) {
    var found = this.find(key);
    if (found == -1) { return this }
    var content = this.content.slice();
    content.splice(found, 2);
    return new OrderedMap(content)
  },

  // :: (string, any) → OrderedMap
  // Add a new key to the start of the map.
  addToStart: function(key, value) {
    return new OrderedMap([key, value].concat(this.remove(key).content))
  },

  // :: (string, any) → OrderedMap
  // Add a new key to the end of the map.
  addToEnd: function(key, value) {
    var content = this.remove(key).content.slice();
    content.push(key, value);
    return new OrderedMap(content)
  },

  // :: (string, string, any) → OrderedMap
  // Add a key after the given key. If `place` is not found, the new
  // key is added to the end.
  addBefore: function(place, key, value) {
    var without = this.remove(key), content = without.content.slice();
    var found = without.find(place);
    content.splice(found == -1 ? content.length : found, 0, key, value);
    return new OrderedMap(content)
  },

  // :: ((key: string, value: any))
  // Call the given function for each key/value pair in the map, in
  // order.
  forEach: function(f) {
    for (var i = 0; i < this.content.length; i += 2)
      { f(this.content[i], this.content[i + 1]); }
  },

  // :: (union<Object, OrderedMap>) → OrderedMap
  // Create a new map by prepending the keys in this map that don't
  // appear in `map` before the keys in `map`.
  prepend: function(map) {
    map = OrderedMap.from(map);
    if (!map.size) { return this }
    return new OrderedMap(map.content.concat(this.subtract(map).content))
  },

  // :: (union<Object, OrderedMap>) → OrderedMap
  // Create a new map by appending the keys in this map that don't
  // appear in `map` after the keys in `map`.
  append: function(map) {
    map = OrderedMap.from(map);
    if (!map.size) { return this }
    return new OrderedMap(this.subtract(map).content.concat(map.content))
  },

  // :: (union<Object, OrderedMap>) → OrderedMap
  // Create a map containing all the keys in this map that don't
  // appear in `map`.
  subtract: function(map) {
    var result = this;
    map = OrderedMap.from(map);
    for (var i = 0; i < map.content.length; i += 2)
      { result = result.remove(map.content[i]); }
    return result
  },

  // :: () → Object
  // Turn ordered map into a plain object.
  toObject: function() {
    var result = {};
    this.forEach(function(key, value) { result[key] = value; });
    return result
  },

  // :: number
  // The amount of keys in this map.
  get size() {
    return this.content.length >> 1
  }
};

// :: (?union<Object, OrderedMap>) → OrderedMap
// Return a map with the given content. If null, create an empty
// map. If given an ordered map, return that map itself. If given an
// object, create a map from the object's properties.
OrderedMap.from = function(value) {
  if (value instanceof OrderedMap) { return value }
  var content = [];
  if (value) { for (var prop in value) { content.push(prop, value[prop]); } }
  return new OrderedMap(content)
};function findDiffStart(a, b, pos) {
    for (var i = 0;; i++) {
        if (i == a.childCount || i == b.childCount)
            { return a.childCount == b.childCount ? null : pos; }
        var childA = a.child(i), childB = b.child(i);
        if (childA == childB) {
            pos += childA.nodeSize;
            continue;
        }
        if (!childA.sameMarkup(childB))
            { return pos; }
        if (childA.isText && childA.text != childB.text) {
            for (var j = 0; childA.text[j] == childB.text[j]; j++)
                { pos++; }
            return pos;
        }
        if (childA.content.size || childB.content.size) {
            var inner = findDiffStart(childA.content, childB.content, pos + 1);
            if (inner != null)
                { return inner; }
        }
        pos += childA.nodeSize;
    }
}
function findDiffEnd(a, b, posA, posB) {
    for (var iA = a.childCount, iB = b.childCount;;) {
        if (iA == 0 || iB == 0)
            { return iA == iB ? null : { a: posA, b: posB }; }
        var childA = a.child(--iA), childB = b.child(--iB), size = childA.nodeSize;
        if (childA == childB) {
            posA -= size;
            posB -= size;
            continue;
        }
        if (!childA.sameMarkup(childB))
            { return { a: posA, b: posB }; }
        if (childA.isText && childA.text != childB.text) {
            var same = 0, minSize = Math.min(childA.text.length, childB.text.length);
            while (same < minSize && childA.text[childA.text.length - same - 1] == childB.text[childB.text.length - same - 1]) {
                same++;
                posA--;
                posB--;
            }
            return { a: posA, b: posB };
        }
        if (childA.content.size || childB.content.size) {
            var inner = findDiffEnd(childA.content, childB.content, posA - 1, posB - 1);
            if (inner)
                { return inner; }
        }
        posA -= size;
        posB -= size;
    }
}

/**
A fragment represents a node's collection of child nodes.

Like nodes, fragments are persistent data structures, and you
should not mutate them or their content. Rather, you create new
instances whenever needed. The API tries to make this easy.
*/
var Fragment = function Fragment(
  /**
  @internal
  */
  content, size) {
      this.content = content;
      this.size = size || 0;
      if (size == null)
          { for (var i = 0; i < content.length; i++)
              { this.size += content[i].nodeSize; } }
  };

var prototypeAccessors$c = { firstChild: { configurable: true },lastChild: { configurable: true },childCount: { configurable: true } };
  /**
  Invoke a callback for all descendant nodes between the given two
  positions (relative to start of this fragment). Doesn't descend
  into a node when the callback returns `false`.
  */
  Fragment.prototype.nodesBetween = function nodesBetween (from, to, f, nodeStart, parent) {
        if ( nodeStart === void 0 ) nodeStart = 0;

      for (var i = 0, pos = 0; pos < to; i++) {
          var child = this.content[i], end = pos + child.nodeSize;
          if (end > from && f(child, nodeStart + pos, parent || null, i) !== false && child.content.size) {
              var start = pos + 1;
              child.nodesBetween(Math.max(0, from - start), Math.min(child.content.size, to - start), f, nodeStart + start);
          }
          pos = end;
      }
  };
  /**
  Call the given callback for every descendant node. `pos` will be
  relative to the start of the fragment. The callback may return
  `false` to prevent traversal of a given node's children.
  */
  Fragment.prototype.descendants = function descendants (f) {
      this.nodesBetween(0, this.size, f);
  };
  /**
  Extract the text between `from` and `to`. See the same method on
  [`Node`](https://prosemirror.net/docs/ref/#model.Node.textBetween).
  */
  Fragment.prototype.textBetween = function textBetween (from, to, blockSeparator, leafText) {
      var text = "", first = true;
      this.nodesBetween(from, to, function (node, pos) {
          var nodeText = node.isText ? node.text.slice(Math.max(from, pos) - pos, to - pos)
              : !node.isLeaf ? ""
                  : leafText ? (typeof leafText === "function" ? leafText(node) : leafText)
                      : node.type.spec.leafText ? node.type.spec.leafText(node)
                          : "";
          if (node.isBlock && (node.isLeaf && nodeText || node.isTextblock) && blockSeparator) {
              if (first)
                  { first = false; }
              else
                  { text += blockSeparator; }
          }
          text += nodeText;
      }, 0);
      return text;
  };
  /**
  Create a new fragment containing the combined content of this
  fragment and the other.
  */
  Fragment.prototype.append = function append (other) {
      if (!other.size)
          { return this; }
      if (!this.size)
          { return other; }
      var last = this.lastChild, first = other.firstChild, content = this.content.slice(), i = 0;
      if (last.isText && last.sameMarkup(first)) {
          content[content.length - 1] = last.withText(last.text + first.text);
          i = 1;
      }
      for (; i < other.content.length; i++)
          { content.push(other.content[i]); }
      return new Fragment(content, this.size + other.size);
  };
  /**
  Cut out the sub-fragment between the two given positions.
  */
  Fragment.prototype.cut = function cut (from, to) {
        if ( to === void 0 ) to = this.size;

      if (from == 0 && to == this.size)
          { return this; }
      var result = [], size = 0;
      if (to > from)
          { for (var i = 0, pos = 0; pos < to; i++) {
              var child = this.content[i], end = pos + child.nodeSize;
              if (end > from) {
                  if (pos < from || end > to) {
                      if (child.isText)
                          { child = child.cut(Math.max(0, from - pos), Math.min(child.text.length, to - pos)); }
                      else
                          { child = child.cut(Math.max(0, from - pos - 1), Math.min(child.content.size, to - pos - 1)); }
                  }
                  result.push(child);
                  size += child.nodeSize;
              }
              pos = end;
          } }
      return new Fragment(result, size);
  };
  /**
  @internal
  */
  Fragment.prototype.cutByIndex = function cutByIndex (from, to) {
      if (from == to)
          { return Fragment.empty; }
      if (from == 0 && to == this.content.length)
          { return this; }
      return new Fragment(this.content.slice(from, to));
  };
  /**
  Create a new fragment in which the node at the given index is
  replaced by the given node.
  */
  Fragment.prototype.replaceChild = function replaceChild (index, node) {
      var current = this.content[index];
      if (current == node)
          { return this; }
      var copy = this.content.slice();
      var size = this.size + node.nodeSize - current.nodeSize;
      copy[index] = node;
      return new Fragment(copy, size);
  };
  /**
  Create a new fragment by prepending the given node to this
  fragment.
  */
  Fragment.prototype.addToStart = function addToStart (node) {
      return new Fragment([node].concat(this.content), this.size + node.nodeSize);
  };
  /**
  Create a new fragment by appending the given node to this
  fragment.
  */
  Fragment.prototype.addToEnd = function addToEnd (node) {
      return new Fragment(this.content.concat(node), this.size + node.nodeSize);
  };
  /**
  Compare this fragment to another one.
  */
  Fragment.prototype.eq = function eq (other) {
      if (this.content.length != other.content.length)
          { return false; }
      for (var i = 0; i < this.content.length; i++)
          { if (!this.content[i].eq(other.content[i]))
              { return false; } }
      return true;
  };
  /**
  The first child of the fragment, or `null` if it is empty.
  */
  prototypeAccessors$c.firstChild.get = function () { return this.content.length ? this.content[0] : null; };
  /**
  The last child of the fragment, or `null` if it is empty.
  */
  prototypeAccessors$c.lastChild.get = function () { return this.content.length ? this.content[this.content.length - 1] : null; };
  /**
  The number of child nodes in this fragment.
  */
  prototypeAccessors$c.childCount.get = function () { return this.content.length; };
  /**
  Get the child node at the given index. Raise an error when the
  index is out of range.
  */
  Fragment.prototype.child = function child (index) {
      var found = this.content[index];
      if (!found)
          { throw new RangeError("Index " + index + " out of range for " + this); }
      return found;
  };
  /**
  Get the child node at the given index, if it exists.
  */
  Fragment.prototype.maybeChild = function maybeChild (index) {
      return this.content[index] || null;
  };
  /**
  Call `f` for every child node, passing the node, its offset
  into this parent node, and its index.
  */
  Fragment.prototype.forEach = function forEach (f) {
      for (var i = 0, p = 0; i < this.content.length; i++) {
          var child = this.content[i];
          f(child, p, i);
          p += child.nodeSize;
      }
  };
  /**
  Find the first position at which this fragment and another
  fragment differ, or `null` if they are the same.
  */
  Fragment.prototype.findDiffStart = function findDiffStart$1 (other, pos) {
        if ( pos === void 0 ) pos = 0;

      return findDiffStart(this, other, pos);
  };
  /**
  Find the first position, searching from the end, at which this
  fragment and the given fragment differ, or `null` if they are
  the same. Since this position will not be the same in both
  nodes, an object with two separate positions is returned.
  */
  Fragment.prototype.findDiffEnd = function findDiffEnd$1 (other, pos, otherPos) {
        if ( pos === void 0 ) pos = this.size;
        if ( otherPos === void 0 ) otherPos = other.size;

      return findDiffEnd(this, other, pos, otherPos);
  };
  /**
  Find the index and inner offset corresponding to a given relative
  position in this fragment. The result object will be reused
  (overwritten) the next time the function is called. @internal
  */
  Fragment.prototype.findIndex = function findIndex (pos, round) {
        if ( round === void 0 ) round = -1;

      if (pos == 0)
          { return retIndex(0, pos); }
      if (pos == this.size)
          { return retIndex(this.content.length, pos); }
      if (pos > this.size || pos < 0)
          { throw new RangeError(("Position " + pos + " outside of fragment (" + (this) + ")")); }
      for (var i = 0, curPos = 0;; i++) {
          var cur = this.child(i), end = curPos + cur.nodeSize;
          if (end >= pos) {
              if (end == pos || round > 0)
                  { return retIndex(i + 1, end); }
              return retIndex(i, curPos);
          }
          curPos = end;
      }
  };
  /**
  Return a debugging string that describes this fragment.
  */
  Fragment.prototype.toString = function toString () { return "<" + this.toStringInner() + ">"; };
  /**
  @internal
  */
  Fragment.prototype.toStringInner = function toStringInner () { return this.content.join(", "); };
  /**
  Create a JSON-serializeable representation of this fragment.
  */
  Fragment.prototype.toJSON = function toJSON () {
      return this.content.length ? this.content.map(function (n) { return n.toJSON(); }) : null;
  };
  /**
  Deserialize a fragment from its JSON representation.
  */
  Fragment.fromJSON = function fromJSON (schema, value) {
      if (!value)
          { return Fragment.empty; }
      if (!Array.isArray(value))
          { throw new RangeError("Invalid input for Fragment.fromJSON"); }
      return new Fragment(value.map(schema.nodeFromJSON));
  };
  /**
  Build a fragment from an array of nodes. Ensures that adjacent
  text nodes with the same marks are joined together.
  */
  Fragment.fromArray = function fromArray (array) {
      if (!array.length)
          { return Fragment.empty; }
      var joined, size = 0;
      for (var i = 0; i < array.length; i++) {
          var node = array[i];
          size += node.nodeSize;
          if (i && node.isText && array[i - 1].sameMarkup(node)) {
              if (!joined)
                  { joined = array.slice(0, i); }
              joined[joined.length - 1] = node
                  .withText(joined[joined.length - 1].text + node.text);
          }
          else if (joined) {
              joined.push(node);
          }
      }
      return new Fragment(joined || array, size);
  };
  /**
  Create a fragment from something that can be interpreted as a
  set of nodes. For `null`, it returns the empty fragment. For a
  fragment, the fragment itself. For a node or array of nodes, a
  fragment containing those nodes.
  */
  Fragment.from = function from (nodes) {
      if (!nodes)
          { return Fragment.empty; }
      if (nodes instanceof Fragment)
          { return nodes; }
      if (Array.isArray(nodes))
          { return this.fromArray(nodes); }
      if (nodes.attrs)
          { return new Fragment([nodes], nodes.nodeSize); }
      throw new RangeError("Can not convert " + nodes + " to a Fragment" +
          (nodes.nodesBetween ? " (looks like multiple versions of prosemirror-model were loaded)" : ""));
  };

Object.defineProperties( Fragment.prototype, prototypeAccessors$c );
/**
An empty fragment. Intended to be reused whenever a node doesn't
contain anything (rather than allocating a new empty fragment for
each leaf node).
*/
Fragment.empty = new Fragment([], 0);
var found = { index: 0, offset: 0 };
function retIndex(index, offset) {
    found.index = index;
    found.offset = offset;
    return found;
}

function compareDeep(a, b) {
    if (a === b)
        { return true; }
    if (!(a && typeof a == "object") ||
        !(b && typeof b == "object"))
        { return false; }
    var array = Array.isArray(a);
    if (Array.isArray(b) != array)
        { return false; }
    if (array) {
        if (a.length != b.length)
            { return false; }
        for (var i = 0; i < a.length; i++)
            { if (!compareDeep(a[i], b[i]))
                { return false; } }
    }
    else {
        for (var p in a)
            { if (!(p in b) || !compareDeep(a[p], b[p]))
                { return false; } }
        for (var p$1 in b)
            { if (!(p$1 in a))
                { return false; } }
    }
    return true;
}

/**
A mark is a piece of information that can be attached to a node,
such as it being emphasized, in code font, or a link. It has a
type and optionally a set of attributes that provide further
information (such as the target of the link). Marks are created
through a `Schema`, which controls which types exist and which
attributes they have.
*/
var Mark = function Mark(
  /**
  The type of this mark.
  */
  type, 
  /**
  The attributes associated with this mark.
  */
  attrs) {
      this.type = type;
      this.attrs = attrs;
  };
  /**
  Given a set of marks, create a new set which contains this one as
  well, in the right position. If this mark is already in the set,
  the set itself is returned. If any marks that are set to be
  [exclusive](https://prosemirror.net/docs/ref/#model.MarkSpec.excludes) with this mark are present,
  those are replaced by this one.
  */
  Mark.prototype.addToSet = function addToSet (set) {
      var copy, placed = false;
      for (var i = 0; i < set.length; i++) {
          var other = set[i];
          if (this.eq(other))
              { return set; }
          if (this.type.excludes(other.type)) {
              if (!copy)
                  { copy = set.slice(0, i); }
          }
          else if (other.type.excludes(this.type)) {
              return set;
          }
          else {
              if (!placed && other.type.rank > this.type.rank) {
                  if (!copy)
                      { copy = set.slice(0, i); }
                  copy.push(this);
                  placed = true;
              }
              if (copy)
                  { copy.push(other); }
          }
      }
      if (!copy)
          { copy = set.slice(); }
      if (!placed)
          { copy.push(this); }
      return copy;
  };
  /**
  Remove this mark from the given set, returning a new set. If this
  mark is not in the set, the set itself is returned.
  */
  Mark.prototype.removeFromSet = function removeFromSet (set) {
      for (var i = 0; i < set.length; i++)
          { if (this.eq(set[i]))
              { return set.slice(0, i).concat(set.slice(i + 1)); } }
      return set;
  };
  /**
  Test whether this mark is in the given set of marks.
  */
  Mark.prototype.isInSet = function isInSet (set) {
      for (var i = 0; i < set.length; i++)
          { if (this.eq(set[i]))
              { return true; } }
      return false;
  };
  /**
  Test whether this mark has the same type and attributes as
  another mark.
  */
  Mark.prototype.eq = function eq (other) {
      return this == other ||
          (this.type == other.type && compareDeep(this.attrs, other.attrs));
  };
  /**
  Convert this mark to a JSON-serializeable representation.
  */
  Mark.prototype.toJSON = function toJSON () {
      var obj = { type: this.type.name };
      for (var _ in this.attrs) {
          obj.attrs = this.attrs;
          break;
      }
      return obj;
  };
  /**
  Deserialize a mark from JSON.
  */
  Mark.fromJSON = function fromJSON (schema, json) {
      if (!json)
          { throw new RangeError("Invalid input for Mark.fromJSON"); }
      var type = schema.marks[json.type];
      if (!type)
          { throw new RangeError(("There is no mark type " + (json.type) + " in this schema")); }
      var mark = type.create(json.attrs);
      type.checkAttrs(mark.attrs);
      return mark;
  };
  /**
  Test whether two sets of marks are identical.
  */
  Mark.sameSet = function sameSet (a, b) {
      if (a == b)
          { return true; }
      if (a.length != b.length)
          { return false; }
      for (var i = 0; i < a.length; i++)
          { if (!a[i].eq(b[i]))
              { return false; } }
      return true;
  };
  /**
  Create a properly sorted mark set from null, a single mark, or an
  unsorted array of marks.
  */
  Mark.setFrom = function setFrom (marks) {
      if (!marks || Array.isArray(marks) && marks.length == 0)
          { return Mark.none; }
      if (marks instanceof Mark)
          { return [marks]; }
      var copy = marks.slice();
      copy.sort(function (a, b) { return a.type.rank - b.type.rank; });
      return copy;
  };
/**
The empty set of marks.
*/
Mark.none = [];

/**
Error type raised by [`Node.replace`](https://prosemirror.net/docs/ref/#model.Node.replace) when
given an invalid replacement.
*/
var ReplaceError = /*@__PURE__*/(function (Error) {
  function ReplaceError () {
    Error.apply(this, arguments);
  }if ( Error ) ReplaceError.__proto__ = Error;
  ReplaceError.prototype = Object.create( Error && Error.prototype );
  ReplaceError.prototype.constructor = ReplaceError;

  

  return ReplaceError;
}(Error));
/*
ReplaceError = function(this: any, message: string) {
  let err = Error.call(this, message)
  ;(err as any).__proto__ = ReplaceError.prototype
  return err
} as any

ReplaceError.prototype = Object.create(Error.prototype)
ReplaceError.prototype.constructor = ReplaceError
ReplaceError.prototype.name = "ReplaceError"
*/
/**
A slice represents a piece cut out of a larger document. It
stores not only a fragment, but also the depth up to which nodes on
both side are ‘open’ (cut through).
*/
var Slice = function Slice(
  /**
  The slice's content.
  */
  content, 
  /**
  The open depth at the start of the fragment.
  */
  openStart, 
  /**
  The open depth at the end.
  */
  openEnd) {
      this.content = content;
      this.openStart = openStart;
      this.openEnd = openEnd;
  };

var prototypeAccessors$1$3 = { size: { configurable: true } };
  /**
  The size this slice would add when inserted into a document.
  */
  prototypeAccessors$1$3.size.get = function () {
      return this.content.size - this.openStart - this.openEnd;
  };
  /**
  @internal
  */
  Slice.prototype.insertAt = function insertAt (pos, fragment) {
      var content = insertInto(this.content, pos + this.openStart, fragment);
      return content && new Slice(content, this.openStart, this.openEnd);
  };
  /**
  @internal
  */
  Slice.prototype.removeBetween = function removeBetween (from, to) {
      return new Slice(removeRange(this.content, from + this.openStart, to + this.openStart), this.openStart, this.openEnd);
  };
  /**
  Tests whether this slice is equal to another slice.
  */
  Slice.prototype.eq = function eq (other) {
      return this.content.eq(other.content) && this.openStart == other.openStart && this.openEnd == other.openEnd;
  };
  /**
  @internal
  */
  Slice.prototype.toString = function toString () {
      return this.content + "(" + this.openStart + "," + this.openEnd + ")";
  };
  /**
  Convert a slice to a JSON-serializable representation.
  */
  Slice.prototype.toJSON = function toJSON () {
      if (!this.content.size)
          { return null; }
      var json = { content: this.content.toJSON() };
      if (this.openStart > 0)
          { json.openStart = this.openStart; }
      if (this.openEnd > 0)
          { json.openEnd = this.openEnd; }
      return json;
  };
  /**
  Deserialize a slice from its JSON representation.
  */
  Slice.fromJSON = function fromJSON (schema, json) {
      if (!json)
          { return Slice.empty; }
      var openStart = json.openStart || 0, openEnd = json.openEnd || 0;
      if (typeof openStart != "number" || typeof openEnd != "number")
          { throw new RangeError("Invalid input for Slice.fromJSON"); }
      return new Slice(Fragment.fromJSON(schema, json.content), openStart, openEnd);
  };
  /**
  Create a slice from a fragment by taking the maximum possible
  open value on both side of the fragment.
  */
  Slice.maxOpen = function maxOpen (fragment, openIsolating) {
        if ( openIsolating === void 0 ) openIsolating = true;

      var openStart = 0, openEnd = 0;
      for (var n = fragment.firstChild; n && !n.isLeaf && (openIsolating || !n.type.spec.isolating); n = n.firstChild)
          { openStart++; }
      for (var n$1 = fragment.lastChild; n$1 && !n$1.isLeaf && (openIsolating || !n$1.type.spec.isolating); n$1 = n$1.lastChild)
          { openEnd++; }
      return new Slice(fragment, openStart, openEnd);
  };

Object.defineProperties( Slice.prototype, prototypeAccessors$1$3 );
/**
The empty slice.
*/
Slice.empty = new Slice(Fragment.empty, 0, 0);
function removeRange(content, from, to) {
    var ref = content.findIndex(from);
    var index = ref.index;
    var offset = ref.offset;
    var child = content.maybeChild(index);
    var ref$1 = content.findIndex(to);
    var indexTo = ref$1.index;
    var offsetTo = ref$1.offset;
    if (offset == from || child.isText) {
        if (offsetTo != to && !content.child(indexTo).isText)
            { throw new RangeError("Removing non-flat range"); }
        return content.cut(0, from).append(content.cut(to));
    }
    if (index != indexTo)
        { throw new RangeError("Removing non-flat range"); }
    return content.replaceChild(index, child.copy(removeRange(child.content, from - offset - 1, to - offset - 1)));
}
function insertInto(content, dist, insert, parent) {
    var ref = content.findIndex(dist);
    var index = ref.index;
    var offset = ref.offset;
    var child = content.maybeChild(index);
    if (offset == dist || child.isText) {
        if (parent && !parent.canReplace(index, index, insert))
            { return null; }
        return content.cut(0, dist).append(insert).append(content.cut(dist));
    }
    var inner = insertInto(child.content, dist - offset - 1, insert);
    return inner && content.replaceChild(index, child.copy(inner));
}
function replace$3($from, $to, slice) {
    if (slice.openStart > $from.depth)
        { throw new ReplaceError("Inserted content deeper than insertion position"); }
    if ($from.depth - slice.openStart != $to.depth - slice.openEnd)
        { throw new ReplaceError("Inconsistent open depths"); }
    return replaceOuter($from, $to, slice, 0);
}
function replaceOuter($from, $to, slice, depth) {
    var index = $from.index(depth), node = $from.node(depth);
    if (index == $to.index(depth) && depth < $from.depth - slice.openStart) {
        var inner = replaceOuter($from, $to, slice, depth + 1);
        return node.copy(node.content.replaceChild(index, inner));
    }
    else if (!slice.content.size) {
        return close(node, replaceTwoWay($from, $to, depth));
    }
    else if (!slice.openStart && !slice.openEnd && $from.depth == depth && $to.depth == depth) { // Simple, flat case
        var parent = $from.parent, content = parent.content;
        return close(parent, content.cut(0, $from.parentOffset).append(slice.content).append(content.cut($to.parentOffset)));
    }
    else {
        var ref = prepareSliceForReplace(slice, $from);
        var start = ref.start;
        var end = ref.end;
        return close(node, replaceThreeWay($from, start, end, $to, depth));
    }
}
function checkJoin(main, sub) {
    if (!sub.type.compatibleContent(main.type))
        { throw new ReplaceError("Cannot join " + sub.type.name + " onto " + main.type.name); }
}
function joinable$1($before, $after, depth) {
    var node = $before.node(depth);
    checkJoin(node, $after.node(depth));
    return node;
}
function addNode(child, target) {
    var last = target.length - 1;
    if (last >= 0 && child.isText && child.sameMarkup(target[last]))
        { target[last] = child.withText(target[last].text + child.text); }
    else
        { target.push(child); }
}
function addRange$1($start, $end, depth, target) {
    var node = ($end || $start).node(depth);
    var startIndex = 0, endIndex = $end ? $end.index(depth) : node.childCount;
    if ($start) {
        startIndex = $start.index(depth);
        if ($start.depth > depth) {
            startIndex++;
        }
        else if ($start.textOffset) {
            addNode($start.nodeAfter, target);
            startIndex++;
        }
    }
    for (var i = startIndex; i < endIndex; i++)
        { addNode(node.child(i), target); }
    if ($end && $end.depth == depth && $end.textOffset)
        { addNode($end.nodeBefore, target); }
}
function close(node, content) {
    node.type.checkContent(content);
    return node.copy(content);
}
function replaceThreeWay($from, $start, $end, $to, depth) {
    var openStart = $from.depth > depth && joinable$1($from, $start, depth + 1);
    var openEnd = $to.depth > depth && joinable$1($end, $to, depth + 1);
    var content = [];
    addRange$1(null, $from, depth, content);
    if (openStart && openEnd && $start.index(depth) == $end.index(depth)) {
        checkJoin(openStart, openEnd);
        addNode(close(openStart, replaceThreeWay($from, $start, $end, $to, depth + 1)), content);
    }
    else {
        if (openStart)
            { addNode(close(openStart, replaceTwoWay($from, $start, depth + 1)), content); }
        addRange$1($start, $end, depth, content);
        if (openEnd)
            { addNode(close(openEnd, replaceTwoWay($end, $to, depth + 1)), content); }
    }
    addRange$1($to, null, depth, content);
    return new Fragment(content);
}
function replaceTwoWay($from, $to, depth) {
    var content = [];
    addRange$1(null, $from, depth, content);
    if ($from.depth > depth) {
        var type = joinable$1($from, $to, depth + 1);
        addNode(close(type, replaceTwoWay($from, $to, depth + 1)), content);
    }
    addRange$1($to, null, depth, content);
    return new Fragment(content);
}
function prepareSliceForReplace(slice, $along) {
    var extra = $along.depth - slice.openStart, parent = $along.node(extra);
    var node = parent.copy(slice.content);
    for (var i = extra - 1; i >= 0; i--)
        { node = $along.node(i).copy(Fragment.from(node)); }
    return { start: node.resolveNoCache(slice.openStart + extra),
        end: node.resolveNoCache(node.content.size - slice.openEnd - extra) };
}

/**
You can [_resolve_](https://prosemirror.net/docs/ref/#model.Node.resolve) a position to get more
information about it. Objects of this class represent such a
resolved position, providing various pieces of context
information, and some helper methods.

Throughout this interface, methods that take an optional `depth`
parameter will interpret undefined as `this.depth` and negative
numbers as `this.depth + value`.
*/
var ResolvedPos = function ResolvedPos(
  /**
  The position that was resolved.
  */
  pos, 
  /**
  @internal
  */
  path, 
  /**
  The offset this position has into its parent node.
  */
  parentOffset) {
      this.pos = pos;
      this.path = path;
      this.parentOffset = parentOffset;
      this.depth = path.length / 3 - 1;
  };

var prototypeAccessors$2$4 = { parent: { configurable: true },doc: { configurable: true },textOffset: { configurable: true },nodeAfter: { configurable: true },nodeBefore: { configurable: true } };
  /**
  @internal
  */
  ResolvedPos.prototype.resolveDepth = function resolveDepth (val) {
      if (val == null)
          { return this.depth; }
      if (val < 0)
          { return this.depth + val; }
      return val;
  };
  /**
  The parent node that the position points into. Note that even if
  a position points into a text node, that node is not considered
  the parent—text nodes are ‘flat’ in this model, and have no content.
  */
  prototypeAccessors$2$4.parent.get = function () { return this.node(this.depth); };
  /**
  The root node in which the position was resolved.
  */
  prototypeAccessors$2$4.doc.get = function () { return this.node(0); };
  /**
  The ancestor node at the given level. `p.node(p.depth)` is the
  same as `p.parent`.
  */
  ResolvedPos.prototype.node = function node (depth) { return this.path[this.resolveDepth(depth) * 3]; };
  /**
  The index into the ancestor at the given level. If this points
  at the 3rd node in the 2nd paragraph on the top level, for
  example, `p.index(0)` is 1 and `p.index(1)` is 2.
  */
  ResolvedPos.prototype.index = function index (depth) { return this.path[this.resolveDepth(depth) * 3 + 1]; };
  /**
  The index pointing after this position into the ancestor at the
  given level.
  */
  ResolvedPos.prototype.indexAfter = function indexAfter (depth) {
      depth = this.resolveDepth(depth);
      return this.index(depth) + (depth == this.depth && !this.textOffset ? 0 : 1);
  };
  /**
  The (absolute) position at the start of the node at the given
  level.
  */
  ResolvedPos.prototype.start = function start (depth) {
      depth = this.resolveDepth(depth);
      return depth == 0 ? 0 : this.path[depth * 3 - 1] + 1;
  };
  /**
  The (absolute) position at the end of the node at the given
  level.
  */
  ResolvedPos.prototype.end = function end (depth) {
      depth = this.resolveDepth(depth);
      return this.start(depth) + this.node(depth).content.size;
  };
  /**
  The (absolute) position directly before the wrapping node at the
  given level, or, when `depth` is `this.depth + 1`, the original
  position.
  */
  ResolvedPos.prototype.before = function before (depth) {
      depth = this.resolveDepth(depth);
      if (!depth)
          { throw new RangeError("There is no position before the top-level node"); }
      return depth == this.depth + 1 ? this.pos : this.path[depth * 3 - 1];
  };
  /**
  The (absolute) position directly after the wrapping node at the
  given level, or the original position when `depth` is `this.depth + 1`.
  */
  ResolvedPos.prototype.after = function after (depth) {
      depth = this.resolveDepth(depth);
      if (!depth)
          { throw new RangeError("There is no position after the top-level node"); }
      return depth == this.depth + 1 ? this.pos : this.path[depth * 3 - 1] + this.path[depth * 3].nodeSize;
  };
  /**
  When this position points into a text node, this returns the
  distance between the position and the start of the text node.
  Will be zero for positions that point between nodes.
  */
  prototypeAccessors$2$4.textOffset.get = function () { return this.pos - this.path[this.path.length - 1]; };
  /**
  Get the node directly after the position, if any. If the position
  points into a text node, only the part of that node after the
  position is returned.
  */
  prototypeAccessors$2$4.nodeAfter.get = function () {
      var parent = this.parent, index = this.index(this.depth);
      if (index == parent.childCount)
          { return null; }
      var dOff = this.pos - this.path[this.path.length - 1], child = parent.child(index);
      return dOff ? parent.child(index).cut(dOff) : child;
  };
  /**
  Get the node directly before the position, if any. If the
  position points into a text node, only the part of that node
  before the position is returned.
  */
  prototypeAccessors$2$4.nodeBefore.get = function () {
      var index = this.index(this.depth);
      var dOff = this.pos - this.path[this.path.length - 1];
      if (dOff)
          { return this.parent.child(index).cut(0, dOff); }
      return index == 0 ? null : this.parent.child(index - 1);
  };
  /**
  Get the position at the given index in the parent node at the
  given depth (which defaults to `this.depth`).
  */
  ResolvedPos.prototype.posAtIndex = function posAtIndex (index, depth) {
      depth = this.resolveDepth(depth);
      var node = this.path[depth * 3], pos = depth == 0 ? 0 : this.path[depth * 3 - 1] + 1;
      for (var i = 0; i < index; i++)
          { pos += node.child(i).nodeSize; }
      return pos;
  };
  /**
  Get the marks at this position, factoring in the surrounding
  marks' [`inclusive`](https://prosemirror.net/docs/ref/#model.MarkSpec.inclusive) property. If the
  position is at the start of a non-empty node, the marks of the
  node after it (if any) are returned.
  */
  ResolvedPos.prototype.marks = function marks () {
      var parent = this.parent, index = this.index();
      // In an empty parent, return the empty array
      if (parent.content.size == 0)
          { return Mark.none; }
      // When inside a text node, just return the text node's marks
      if (this.textOffset)
          { return parent.child(index).marks; }
      var main = parent.maybeChild(index - 1), other = parent.maybeChild(index);
      // If the `after` flag is true of there is no node before, make
      // the node after this position the main reference.
      if (!main) {
          var tmp = main;
          main = other;
          other = tmp;
      }
      // Use all marks in the main node, except those that have
      // `inclusive` set to false and are not present in the other node.
      var marks = main.marks;
      for (var i = 0; i < marks.length; i++)
          { if (marks[i].type.spec.inclusive === false && (!other || !marks[i].isInSet(other.marks)))
              { marks = marks[i--].removeFromSet(marks); } }
      return marks;
  };
  /**
  Get the marks after the current position, if any, except those
  that are non-inclusive and not present at position `$end`. This
  is mostly useful for getting the set of marks to preserve after a
  deletion. Will return `null` if this position is at the end of
  its parent node or its parent node isn't a textblock (in which
  case no marks should be preserved).
  */
  ResolvedPos.prototype.marksAcross = function marksAcross ($end) {
      var after = this.parent.maybeChild(this.index());
      if (!after || !after.isInline)
          { return null; }
      var marks = after.marks, next = $end.parent.maybeChild($end.index());
      for (var i = 0; i < marks.length; i++)
          { if (marks[i].type.spec.inclusive === false && (!next || !marks[i].isInSet(next.marks)))
              { marks = marks[i--].removeFromSet(marks); } }
      return marks;
  };
  /**
  The depth up to which this position and the given (non-resolved)
  position share the same parent nodes.
  */
  ResolvedPos.prototype.sharedDepth = function sharedDepth (pos) {
      for (var depth = this.depth; depth > 0; depth--)
          { if (this.start(depth) <= pos && this.end(depth) >= pos)
              { return depth; } }
      return 0;
  };
  /**
  Returns a range based on the place where this position and the
  given position diverge around block content. If both point into
  the same textblock, for example, a range around that textblock
  will be returned. If they point into different blocks, the range
  around those blocks in their shared ancestor is returned. You can
  pass in an optional predicate that will be called with a parent
  node to see if a range into that parent is acceptable.
  */
  ResolvedPos.prototype.blockRange = function blockRange (other, pred) {
        if ( other === void 0 ) other = this;

      if (other.pos < this.pos)
          { return other.blockRange(this); }
      for (var d = this.depth - (this.parent.inlineContent || this.pos == other.pos ? 1 : 0); d >= 0; d--)
          { if (other.pos <= this.end(d) && (!pred || pred(this.node(d))))
              { return new NodeRange(this, other, d); } }
      return null;
  };
  /**
  Query whether the given position shares the same parent node.
  */
  ResolvedPos.prototype.sameParent = function sameParent (other) {
      return this.pos - this.parentOffset == other.pos - other.parentOffset;
  };
  /**
  Return the greater of this and the given position.
  */
  ResolvedPos.prototype.max = function max (other) {
      return other.pos > this.pos ? other : this;
  };
  /**
  Return the smaller of this and the given position.
  */
  ResolvedPos.prototype.min = function min (other) {
      return other.pos < this.pos ? other : this;
  };
  /**
  @internal
  */
  ResolvedPos.prototype.toString = function toString () {
      var str = "";
      for (var i = 1; i <= this.depth; i++)
          { str += (str ? "/" : "") + this.node(i).type.name + "_" + this.index(i - 1); }
      return str + ":" + this.parentOffset;
  };
  /**
  @internal
  */
  ResolvedPos.resolve = function resolve (doc, pos) {
      if (!(pos >= 0 && pos <= doc.content.size))
          { throw new RangeError("Position " + pos + " out of range"); }
      var path = [];
      var start = 0, parentOffset = pos;
      for (var node = doc;;) {
          var ref = node.content.findIndex(parentOffset);
            var index = ref.index;
            var offset = ref.offset;
          var rem = parentOffset - offset;
          path.push(node, index, start + offset);
          if (!rem)
              { break; }
          node = node.child(index);
          if (node.isText)
              { break; }
          parentOffset = rem - 1;
          start += offset + 1;
      }
      return new ResolvedPos(pos, path, parentOffset);
  };
  /**
  @internal
  */
  ResolvedPos.resolveCached = function resolveCached (doc, pos) {
      var cache = resolveCache.get(doc);
      if (cache) {
          for (var i = 0; i < cache.elts.length; i++) {
              var elt = cache.elts[i];
              if (elt.pos == pos)
                  { return elt; }
          }
      }
      else {
          resolveCache.set(doc, cache = new ResolveCache);
      }
      var result = cache.elts[cache.i] = ResolvedPos.resolve(doc, pos);
      cache.i = (cache.i + 1) % resolveCacheSize;
      return result;
  };

Object.defineProperties( ResolvedPos.prototype, prototypeAccessors$2$4 );
var ResolveCache = function ResolveCache() {
      this.elts = [];
      this.i = 0;
  };
var resolveCacheSize = 12, resolveCache = new WeakMap();
/**
Represents a flat range of content, i.e. one that starts and
ends in the same node.
*/
var NodeRange = function NodeRange(
  /**
  A resolved position along the start of the content. May have a
  `depth` greater than this object's `depth` property, since
  these are the positions that were used to compute the range,
  not re-resolved positions directly at its boundaries.
  */
  $from, 
  /**
  A position along the end of the content. See
  caveat for [`$from`](https://prosemirror.net/docs/ref/#model.NodeRange.$from).
  */
  $to, 
  /**
  The depth of the node that this range points into.
  */
  depth) {
      this.$from = $from;
      this.$to = $to;
      this.depth = depth;
  };

var prototypeAccessors$3$3 = { start: { configurable: true },end: { configurable: true },parent: { configurable: true },startIndex: { configurable: true },endIndex: { configurable: true } };
  /**
  The position at the start of the range.
  */
  prototypeAccessors$3$3.start.get = function () { return this.$from.before(this.depth + 1); };
  /**
  The position at the end of the range.
  */
  prototypeAccessors$3$3.end.get = function () { return this.$to.after(this.depth + 1); };
  /**
  The parent node that the range points into.
  */
  prototypeAccessors$3$3.parent.get = function () { return this.$from.node(this.depth); };
  /**
  The start index of the range in the parent node.
  */
  prototypeAccessors$3$3.startIndex.get = function () { return this.$from.index(this.depth); };
  /**
  The end index of the range in the parent node.
  */
  prototypeAccessors$3$3.endIndex.get = function () { return this.$to.indexAfter(this.depth); };

Object.defineProperties( NodeRange.prototype, prototypeAccessors$3$3 );

var emptyAttrs = Object.create(null);
/**
This class represents a node in the tree that makes up a
ProseMirror document. So a document is an instance of `Node`, with
children that are also instances of `Node`.

Nodes are persistent data structures. Instead of changing them, you
create new ones with the content you want. Old ones keep pointing
at the old document shape. This is made cheaper by sharing
structure between the old and new data as much as possible, which a
tree shape like this (without back pointers) makes easy.

**Do not** directly mutate the properties of a `Node` object. See
[the guide](/docs/guide/#doc) for more information.
*/
var Node$1 = function Node(
  /**
  The type of node that this is.
  */
  type, 
  /**
  An object mapping attribute names to values. The kind of
  attributes allowed and required are
  [determined](https://prosemirror.net/docs/ref/#model.NodeSpec.attrs) by the node type.
  */
  attrs, 
  // A fragment holding the node's children.
  content, 
  /**
  The marks (things like whether it is emphasized or part of a
  link) applied to this node.
  */
  marks) {
      if ( marks === void 0 ) marks = Mark.none;

      this.type = type;
      this.attrs = attrs;
      this.marks = marks;
      this.content = content || Fragment.empty;
  };

var prototypeAccessors$4$3 = { nodeSize: { configurable: true },childCount: { configurable: true },textContent: { configurable: true },firstChild: { configurable: true },lastChild: { configurable: true },isBlock: { configurable: true },isTextblock: { configurable: true },inlineContent: { configurable: true },isInline: { configurable: true },isText: { configurable: true },isLeaf: { configurable: true },isAtom: { configurable: true } };
  /**
  The size of this node, as defined by the integer-based [indexing
  scheme](/docs/guide/#doc.indexing). For text nodes, this is the
  amount of characters. For other leaf nodes, it is one. For
  non-leaf nodes, it is the size of the content plus two (the
  start and end token).
  */
  prototypeAccessors$4$3.nodeSize.get = function () { return this.isLeaf ? 1 : 2 + this.content.size; };
  /**
  The number of children that the node has.
  */
  prototypeAccessors$4$3.childCount.get = function () { return this.content.childCount; };
  /**
  Get the child node at the given index. Raises an error when the
  index is out of range.
  */
  Node$1.prototype.child = function child (index) { return this.content.child(index); };
  /**
  Get the child node at the given index, if it exists.
  */
  Node$1.prototype.maybeChild = function maybeChild (index) { return this.content.maybeChild(index); };
  /**
  Call `f` for every child node, passing the node, its offset
  into this parent node, and its index.
  */
  Node$1.prototype.forEach = function forEach (f) { this.content.forEach(f); };
  /**
  Invoke a callback for all descendant nodes recursively between
  the given two positions that are relative to start of this
  node's content. The callback is invoked with the node, its
  position relative to the original node (method receiver),
  its parent node, and its child index. When the callback returns
  false for a given node, that node's children will not be
  recursed over. The last parameter can be used to specify a
  starting position to count from.
  */
  Node$1.prototype.nodesBetween = function nodesBetween (from, to, f, startPos) {
        if ( startPos === void 0 ) startPos = 0;

      this.content.nodesBetween(from, to, f, startPos, this);
  };
  /**
  Call the given callback for every descendant node. Doesn't
  descend into a node when the callback returns `false`.
  */
  Node$1.prototype.descendants = function descendants (f) {
      this.nodesBetween(0, this.content.size, f);
  };
  /**
  Concatenates all the text nodes found in this fragment and its
  children.
  */
  prototypeAccessors$4$3.textContent.get = function () {
      return (this.isLeaf && this.type.spec.leafText)
          ? this.type.spec.leafText(this)
          : this.textBetween(0, this.content.size, "");
  };
  /**
  Get all text between positions `from` and `to`. When
  `blockSeparator` is given, it will be inserted to separate text
  from different block nodes. If `leafText` is given, it'll be
  inserted for every non-text leaf node encountered, otherwise
  [`leafText`](https://prosemirror.net/docs/ref/#model.NodeSpec^leafText) will be used.
  */
  Node$1.prototype.textBetween = function textBetween (from, to, blockSeparator, leafText) {
      return this.content.textBetween(from, to, blockSeparator, leafText);
  };
  /**
  Returns this node's first child, or `null` if there are no
  children.
  */
  prototypeAccessors$4$3.firstChild.get = function () { return this.content.firstChild; };
  /**
  Returns this node's last child, or `null` if there are no
  children.
  */
  prototypeAccessors$4$3.lastChild.get = function () { return this.content.lastChild; };
  /**
  Test whether two nodes represent the same piece of document.
  */
  Node$1.prototype.eq = function eq (other) {
      return this == other || (this.sameMarkup(other) && this.content.eq(other.content));
  };
  /**
  Compare the markup (type, attributes, and marks) of this node to
  those of another. Returns `true` if both have the same markup.
  */
  Node$1.prototype.sameMarkup = function sameMarkup (other) {
      return this.hasMarkup(other.type, other.attrs, other.marks);
  };
  /**
  Check whether this node's markup correspond to the given type,
  attributes, and marks.
  */
  Node$1.prototype.hasMarkup = function hasMarkup (type, attrs, marks) {
      return this.type == type &&
          compareDeep(this.attrs, attrs || type.defaultAttrs || emptyAttrs) &&
          Mark.sameSet(this.marks, marks || Mark.none);
  };
  /**
  Create a new node with the same markup as this node, containing
  the given content (or empty, if no content is given).
  */
  Node$1.prototype.copy = function copy (content) {
        if ( content === void 0 ) content = null;

      if (content == this.content)
          { return this; }
      return new Node$1(this.type, this.attrs, content, this.marks);
  };
  /**
  Create a copy of this node, with the given set of marks instead
  of the node's own marks.
  */
  Node$1.prototype.mark = function mark (marks) {
      return marks == this.marks ? this : new Node$1(this.type, this.attrs, this.content, marks);
  };
  /**
  Create a copy of this node with only the content between the
  given positions. If `to` is not given, it defaults to the end of
  the node.
  */
  Node$1.prototype.cut = function cut (from, to) {
        if ( to === void 0 ) to = this.content.size;

      if (from == 0 && to == this.content.size)
          { return this; }
      return this.copy(this.content.cut(from, to));
  };
  /**
  Cut out the part of the document between the given positions, and
  return it as a `Slice` object.
  */
  Node$1.prototype.slice = function slice (from, to, includeParents) {
        if ( to === void 0 ) to = this.content.size;
        if ( includeParents === void 0 ) includeParents = false;

      if (from == to)
          { return Slice.empty; }
      var $from = this.resolve(from), $to = this.resolve(to);
      var depth = includeParents ? 0 : $from.sharedDepth(to);
      var start = $from.start(depth), node = $from.node(depth);
      var content = node.content.cut($from.pos - start, $to.pos - start);
      return new Slice(content, $from.depth - depth, $to.depth - depth);
  };
  /**
  Replace the part of the document between the given positions with
  the given slice. The slice must 'fit', meaning its open sides
  must be able to connect to the surrounding content, and its
  content nodes must be valid children for the node they are placed
  into. If any of this is violated, an error of type
  [`ReplaceError`](https://prosemirror.net/docs/ref/#model.ReplaceError) is thrown.
  */
  Node$1.prototype.replace = function replace$1 (from, to, slice) {
      return replace$3(this.resolve(from), this.resolve(to), slice);
  };
  /**
  Find the node directly after the given position.
  */
  Node$1.prototype.nodeAt = function nodeAt (pos) {
      for (var node = this;;) {
          var ref = node.content.findIndex(pos);
            var index = ref.index;
            var offset = ref.offset;
          node = node.maybeChild(index);
          if (!node)
              { return null; }
          if (offset == pos || node.isText)
              { return node; }
          pos -= offset + 1;
      }
  };
  /**
  Find the (direct) child node after the given offset, if any,
  and return it along with its index and offset relative to this
  node.
  */
  Node$1.prototype.childAfter = function childAfter (pos) {
      var ref = this.content.findIndex(pos);
        var index = ref.index;
        var offset = ref.offset;
      return { node: this.content.maybeChild(index), index: index, offset: offset };
  };
  /**
  Find the (direct) child node before the given offset, if any,
  and return it along with its index and offset relative to this
  node.
  */
  Node$1.prototype.childBefore = function childBefore (pos) {
      if (pos == 0)
          { return { node: null, index: 0, offset: 0 }; }
      var ref = this.content.findIndex(pos);
        var index = ref.index;
        var offset = ref.offset;
      if (offset < pos)
          { return { node: this.content.child(index), index: index, offset: offset }; }
      var node = this.content.child(index - 1);
      return { node: node, index: index - 1, offset: offset - node.nodeSize };
  };
  /**
  Resolve the given position in the document, returning an
  [object](https://prosemirror.net/docs/ref/#model.ResolvedPos) with information about its context.
  */
  Node$1.prototype.resolve = function resolve (pos) { return ResolvedPos.resolveCached(this, pos); };
  /**
  @internal
  */
  Node$1.prototype.resolveNoCache = function resolveNoCache (pos) { return ResolvedPos.resolve(this, pos); };
  /**
  Test whether a given mark or mark type occurs in this document
  between the two given positions.
  */
  Node$1.prototype.rangeHasMark = function rangeHasMark (from, to, type) {
      var found = false;
      if (to > from)
          { this.nodesBetween(from, to, function (node) {
              if (type.isInSet(node.marks))
                  { found = true; }
              return !found;
          }); }
      return found;
  };
  /**
  True when this is a block (non-inline node)
  */
  prototypeAccessors$4$3.isBlock.get = function () { return this.type.isBlock; };
  /**
  True when this is a textblock node, a block node with inline
  content.
  */
  prototypeAccessors$4$3.isTextblock.get = function () { return this.type.isTextblock; };
  /**
  True when this node allows inline content.
  */
  prototypeAccessors$4$3.inlineContent.get = function () { return this.type.inlineContent; };
  /**
  True when this is an inline node (a text node or a node that can
  appear among text).
  */
  prototypeAccessors$4$3.isInline.get = function () { return this.type.isInline; };
  /**
  True when this is a text node.
  */
  prototypeAccessors$4$3.isText.get = function () { return this.type.isText; };
  /**
  True when this is a leaf node.
  */
  prototypeAccessors$4$3.isLeaf.get = function () { return this.type.isLeaf; };
  /**
  True when this is an atom, i.e. when it does not have directly
  editable content. This is usually the same as `isLeaf`, but can
  be configured with the [`atom` property](https://prosemirror.net/docs/ref/#model.NodeSpec.atom)
  on a node's spec (typically used when the node is displayed as
  an uneditable [node view](https://prosemirror.net/docs/ref/#view.NodeView)).
  */
  prototypeAccessors$4$3.isAtom.get = function () { return this.type.isAtom; };
  /**
  Return a string representation of this node for debugging
  purposes.
  */
  Node$1.prototype.toString = function toString () {
      if (this.type.spec.toDebugString)
          { return this.type.spec.toDebugString(this); }
      var name = this.type.name;
      if (this.content.size)
          { name += "(" + this.content.toStringInner() + ")"; }
      return wrapMarks$1(this.marks, name);
  };
  /**
  Get the content match in this node at the given index.
  */
  Node$1.prototype.contentMatchAt = function contentMatchAt (index) {
      var match = this.type.contentMatch.matchFragment(this.content, 0, index);
      if (!match)
          { throw new Error("Called contentMatchAt on a node with invalid content"); }
      return match;
  };
  /**
  Test whether replacing the range between `from` and `to` (by
  child index) with the given replacement fragment (which defaults
  to the empty fragment) would leave the node's content valid. You
  can optionally pass `start` and `end` indices into the
  replacement fragment.
  */
  Node$1.prototype.canReplace = function canReplace (from, to, replacement, start, end) {
        if ( replacement === void 0 ) replacement = Fragment.empty;
        if ( start === void 0 ) start = 0;
        if ( end === void 0 ) end = replacement.childCount;

      var one = this.contentMatchAt(from).matchFragment(replacement, start, end);
      var two = one && one.matchFragment(this.content, to);
      if (!two || !two.validEnd)
          { return false; }
      for (var i = start; i < end; i++)
          { if (!this.type.allowsMarks(replacement.child(i).marks))
              { return false; } }
      return true;
  };
  /**
  Test whether replacing the range `from` to `to` (by index) with
  a node of the given type would leave the node's content valid.
  */
  Node$1.prototype.canReplaceWith = function canReplaceWith (from, to, type, marks) {
      if (marks && !this.type.allowsMarks(marks))
          { return false; }
      var start = this.contentMatchAt(from).matchType(type);
      var end = start && start.matchFragment(this.content, to);
      return end ? end.validEnd : false;
  };
  /**
  Test whether the given node's content could be appended to this
  node. If that node is empty, this will only return true if there
  is at least one node type that can appear in both nodes (to avoid
  merging completely incompatible nodes).
  */
  Node$1.prototype.canAppend = function canAppend (other) {
      if (other.content.size)
          { return this.canReplace(this.childCount, this.childCount, other.content); }
      else
          { return this.type.compatibleContent(other.type); }
  };
  /**
  Check whether this node and its descendants conform to the
  schema, and raise an exception when they do not.
  */
  Node$1.prototype.check = function check () {
      this.type.checkContent(this.content);
      this.type.checkAttrs(this.attrs);
      var copy = Mark.none;
      for (var i = 0; i < this.marks.length; i++) {
          var mark = this.marks[i];
          mark.type.checkAttrs(mark.attrs);
          copy = mark.addToSet(copy);
      }
      if (!Mark.sameSet(copy, this.marks))
          { throw new RangeError(("Invalid collection of marks for node " + (this.type.name) + ": " + (this.marks.map(function (m) { return m.type.name; })))); }
      this.content.forEach(function (node) { return node.check(); });
  };
  /**
  Return a JSON-serializeable representation of this node.
  */
  Node$1.prototype.toJSON = function toJSON () {
      var obj = { type: this.type.name };
      for (var _ in this.attrs) {
          obj.attrs = this.attrs;
          break;
      }
      if (this.content.size)
          { obj.content = this.content.toJSON(); }
      if (this.marks.length)
          { obj.marks = this.marks.map(function (n) { return n.toJSON(); }); }
      return obj;
  };
  /**
  Deserialize a node from its JSON representation.
  */
  Node$1.fromJSON = function fromJSON (schema, json) {
      if (!json)
          { throw new RangeError("Invalid input for Node.fromJSON"); }
      var marks = undefined;
      if (json.marks) {
          if (!Array.isArray(json.marks))
              { throw new RangeError("Invalid mark data for Node.fromJSON"); }
          marks = json.marks.map(schema.markFromJSON);
      }
      if (json.type == "text") {
          if (typeof json.text != "string")
              { throw new RangeError("Invalid text node in JSON"); }
          return schema.text(json.text, marks);
      }
      var content = Fragment.fromJSON(schema, json.content);
      var node = schema.nodeType(json.type).create(json.attrs, content, marks);
      node.type.checkAttrs(node.attrs);
      return node;
  };

Object.defineProperties( Node$1.prototype, prototypeAccessors$4$3 );
Node$1.prototype.text = undefined;
var TextNode$1 = /*@__PURE__*/(function (Node) {
  function TextNode(type, attrs, content, marks) {
        Node.call(this, type, attrs, null, marks);
        if (!content)
            { throw new RangeError("Empty text nodes are not allowed"); }
        this.text = content;
    }

  if ( Node ) TextNode.__proto__ = Node;
  TextNode.prototype = Object.create( Node && Node.prototype );
  TextNode.prototype.constructor = TextNode;

  var prototypeAccessors$5 = { textContent: { configurable: true },nodeSize: { configurable: true } };
    TextNode.prototype.toString = function toString () {
        if (this.type.spec.toDebugString)
            { return this.type.spec.toDebugString(this); }
        return wrapMarks$1(this.marks, JSON.stringify(this.text));
    };
    prototypeAccessors$5.textContent.get = function () { return this.text; };
    TextNode.prototype.textBetween = function textBetween (from, to) { return this.text.slice(from, to); };
    prototypeAccessors$5.nodeSize.get = function () { return this.text.length; };
    TextNode.prototype.mark = function mark (marks) {
        return marks == this.marks ? this : new TextNode(this.type, this.attrs, this.text, marks);
    };
    TextNode.prototype.withText = function withText (text) {
        if (text == this.text)
            { return this; }
        return new TextNode(this.type, this.attrs, text, this.marks);
    };
    TextNode.prototype.cut = function cut (from, to) {
        if ( from === void 0 ) from = 0;
        if ( to === void 0 ) to = this.text.length;

        if (from == 0 && to == this.text.length)
            { return this; }
        return this.withText(this.text.slice(from, to));
    };
    TextNode.prototype.eq = function eq (other) {
        return this.sameMarkup(other) && this.text == other.text;
    };
    TextNode.prototype.toJSON = function toJSON () {
        var base = Node.prototype.toJSON.call(this);
        base.text = this.text;
        return base;
    };

  Object.defineProperties( TextNode.prototype, prototypeAccessors$5 );

  return TextNode;
}(Node$1));
function wrapMarks$1(marks, str) {
    for (var i = marks.length - 1; i >= 0; i--)
        { str = marks[i].type.name + "(" + str + ")"; }
    return str;
}

/**
Instances of this class represent a match state of a node type's
[content expression](https://prosemirror.net/docs/ref/#model.NodeSpec.content), and can be used to
find out whether further content matches here, and whether a given
position is a valid end of the node.
*/
var ContentMatch = function ContentMatch(
  /**
  True when this match state represents a valid end of the node.
  */
  validEnd) {
      this.validEnd = validEnd;
      /**
      @internal
      */
      this.next = [];
      /**
      @internal
      */
      this.wrapCache = [];
  };

var prototypeAccessors$6$2 = { inlineContent: { configurable: true },defaultType: { configurable: true },edgeCount: { configurable: true } };
  /**
  @internal
  */
  ContentMatch.parse = function parse (string, nodeTypes) {
      var stream = new TokenStream(string, nodeTypes);
      if (stream.next == null)
          { return ContentMatch.empty; }
      var expr = parseExpr(stream);
      if (stream.next)
          { stream.err("Unexpected trailing text"); }
      var match = dfa(nfa(expr));
      checkForDeadEnds(match, stream);
      return match;
  };
  /**
  Match a node type, returning a match after that node if
  successful.
  */
  ContentMatch.prototype.matchType = function matchType (type) {
      for (var i = 0; i < this.next.length; i++)
          { if (this.next[i].type == type)
              { return this.next[i].next; } }
      return null;
  };
  /**
  Try to match a fragment. Returns the resulting match when
  successful.
  */
  ContentMatch.prototype.matchFragment = function matchFragment (frag, start, end) {
        if ( start === void 0 ) start = 0;
        if ( end === void 0 ) end = frag.childCount;

      var cur = this;
      for (var i = start; cur && i < end; i++)
          { cur = cur.matchType(frag.child(i).type); }
      return cur;
  };
  /**
  @internal
  */
  prototypeAccessors$6$2.inlineContent.get = function () {
      return this.next.length != 0 && this.next[0].type.isInline;
  };
  /**
  Get the first matching node type at this match position that can
  be generated.
  */
  prototypeAccessors$6$2.defaultType.get = function () {
      for (var i = 0; i < this.next.length; i++) {
          var ref = this.next[i];
            var type = ref.type;
          if (!(type.isText || type.hasRequiredAttrs()))
              { return type; }
      }
      return null;
  };
  /**
  @internal
  */
  ContentMatch.prototype.compatible = function compatible (other) {
      for (var i = 0; i < this.next.length; i++)
          { for (var j = 0; j < other.next.length; j++)
              { if (this.next[i].type == other.next[j].type)
                  { return true; } } }
      return false;
  };
  /**
  Try to match the given fragment, and if that fails, see if it can
  be made to match by inserting nodes in front of it. When
  successful, return a fragment of inserted nodes (which may be
  empty if nothing had to be inserted). When `toEnd` is true, only
  return a fragment if the resulting match goes to the end of the
  content expression.
  */
  ContentMatch.prototype.fillBefore = function fillBefore (after, toEnd, startIndex) {
        if ( toEnd === void 0 ) toEnd = false;
        if ( startIndex === void 0 ) startIndex = 0;

      var seen = [this];
      function search(match, types) {
          var finished = match.matchFragment(after, startIndex);
          if (finished && (!toEnd || finished.validEnd))
              { return Fragment.from(types.map(function (tp) { return tp.createAndFill(); })); }
          for (var i = 0; i < match.next.length; i++) {
              var ref = match.next[i];
                var type = ref.type;
                var next = ref.next;
              if (!(type.isText || type.hasRequiredAttrs()) && seen.indexOf(next) == -1) {
                  seen.push(next);
                  var found = search(next, types.concat(type));
                  if (found)
                      { return found; }
              }
          }
          return null;
      }
      return search(this, []);
  };
  /**
  Find a set of wrapping node types that would allow a node of the
  given type to appear at this position. The result may be empty
  (when it fits directly) and will be null when no such wrapping
  exists.
  */
  ContentMatch.prototype.findWrapping = function findWrapping (target) {
      for (var i = 0; i < this.wrapCache.length; i += 2)
          { if (this.wrapCache[i] == target)
              { return this.wrapCache[i + 1]; } }
      var computed = this.computeWrapping(target);
      this.wrapCache.push(target, computed);
      return computed;
  };
  /**
  @internal
  */
  ContentMatch.prototype.computeWrapping = function computeWrapping (target) {
      var seen = Object.create(null), active = [{ match: this, type: null, via: null }];
      while (active.length) {
          var current = active.shift(), match = current.match;
          if (match.matchType(target)) {
              var result = [];
              for (var obj = current; obj.type; obj = obj.via)
                  { result.push(obj.type); }
              return result.reverse();
          }
          for (var i = 0; i < match.next.length; i++) {
              var ref = match.next[i];
                var type = ref.type;
                var next = ref.next;
              if (!type.isLeaf && !type.hasRequiredAttrs() && !(type.name in seen) && (!current.type || next.validEnd)) {
                  active.push({ match: type.contentMatch, type: type, via: current });
                  seen[type.name] = true;
              }
          }
      }
      return null;
  };
  /**
  The number of outgoing edges this node has in the finite
  automaton that describes the content expression.
  */
  prototypeAccessors$6$2.edgeCount.get = function () {
      return this.next.length;
  };
  /**
  Get the _n_​th outgoing edge from this node in the finite
  automaton that describes the content expression.
  */
  ContentMatch.prototype.edge = function edge (n) {
      if (n >= this.next.length)
          { throw new RangeError(("There's no " + n + "th edge in this content match")); }
      return this.next[n];
  };
  /**
  @internal
  */
  ContentMatch.prototype.toString = function toString () {
      var seen = [];
      function scan(m) {
          seen.push(m);
          for (var i = 0; i < m.next.length; i++)
              { if (seen.indexOf(m.next[i].next) == -1)
                  { scan(m.next[i].next); } }
      }
      scan(this);
      return seen.map(function (m, i) {
          var out = i + (m.validEnd ? "*" : " ") + " ";
          for (var i$1 = 0; i$1 < m.next.length; i$1++)
              { out += (i$1 ? ", " : "") + m.next[i$1].type.name + "->" + seen.indexOf(m.next[i$1].next); }
          return out;
      }).join("\n");
  };

Object.defineProperties( ContentMatch.prototype, prototypeAccessors$6$2 );
/**
@internal
*/
ContentMatch.empty = new ContentMatch(true);
var TokenStream = function TokenStream(string, nodeTypes) {
      this.string = string;
      this.nodeTypes = nodeTypes;
      this.inline = null;
      this.pos = 0;
      this.tokens = string.split(/\s*(?=\b|\W|$)/);
      if (this.tokens[this.tokens.length - 1] == "")
          { this.tokens.pop(); }
      if (this.tokens[0] == "")
          { this.tokens.shift(); }
  };

var prototypeAccessors$7$2 = { next: { configurable: true } };
  prototypeAccessors$7$2.next.get = function () { return this.tokens[this.pos]; };
  TokenStream.prototype.eat = function eat (tok) { return this.next == tok && (this.pos++ || true); };
  TokenStream.prototype.err = function err (str) { throw new SyntaxError(str + " (in content expression '" + this.string + "')"); };

Object.defineProperties( TokenStream.prototype, prototypeAccessors$7$2 );
function parseExpr(stream) {
    var exprs = [];
    do {
        exprs.push(parseExprSeq(stream));
    } while (stream.eat("|"));
    return exprs.length == 1 ? exprs[0] : { type: "choice", exprs: exprs };
}
function parseExprSeq(stream) {
    var exprs = [];
    do {
        exprs.push(parseExprSubscript(stream));
    } while (stream.next && stream.next != ")" && stream.next != "|");
    return exprs.length == 1 ? exprs[0] : { type: "seq", exprs: exprs };
}
function parseExprSubscript(stream) {
    var expr = parseExprAtom(stream);
    for (;;) {
        if (stream.eat("+"))
            { expr = { type: "plus", expr: expr }; }
        else if (stream.eat("*"))
            { expr = { type: "star", expr: expr }; }
        else if (stream.eat("?"))
            { expr = { type: "opt", expr: expr }; }
        else if (stream.eat("{"))
            { expr = parseExprRange(stream, expr); }
        else
            { break; }
    }
    return expr;
}
function parseNum(stream) {
    if (/\D/.test(stream.next))
        { stream.err("Expected number, got '" + stream.next + "'"); }
    var result = Number(stream.next);
    stream.pos++;
    return result;
}
function parseExprRange(stream, expr) {
    var min = parseNum(stream), max = min;
    if (stream.eat(",")) {
        if (stream.next != "}")
            { max = parseNum(stream); }
        else
            { max = -1; }
    }
    if (!stream.eat("}"))
        { stream.err("Unclosed braced range"); }
    return { type: "range", min: min, max: max, expr: expr };
}
function resolveName(stream, name) {
    var types = stream.nodeTypes, type = types[name];
    if (type)
        { return [type]; }
    var result = [];
    for (var typeName in types) {
        var type$1 = types[typeName];
        if (type$1.groups.indexOf(name) > -1)
            { result.push(type$1); }
    }
    if (result.length == 0)
        { stream.err("No node type or group '" + name + "' found"); }
    return result;
}
function parseExprAtom(stream) {
    if (stream.eat("(")) {
        var expr = parseExpr(stream);
        if (!stream.eat(")"))
            { stream.err("Missing closing paren"); }
        return expr;
    }
    else if (!/\W/.test(stream.next)) {
        var exprs = resolveName(stream, stream.next).map(function (type) {
            if (stream.inline == null)
                { stream.inline = type.isInline; }
            else if (stream.inline != type.isInline)
                { stream.err("Mixing inline and block content"); }
            return { type: "name", value: type };
        });
        stream.pos++;
        return exprs.length == 1 ? exprs[0] : { type: "choice", exprs: exprs };
    }
    else {
        stream.err("Unexpected token '" + stream.next + "'");
    }
}
/**
Construct an NFA from an expression as returned by the parser. The
NFA is represented as an array of states, which are themselves
arrays of edges, which are `{term, to}` objects. The first state is
the entry state and the last node is the success state.

Note that unlike typical NFAs, the edge ordering in this one is
significant, in that it is used to contruct filler content when
necessary.
*/
function nfa(expr) {
    var nfa = [[]];
    connect(compile(expr, 0), node());
    return nfa;
    function node() { return nfa.push([]) - 1; }
    function edge(from, to, term) {
        var edge = { term: term, to: to };
        nfa[from].push(edge);
        return edge;
    }
    function connect(edges, to) {
        edges.forEach(function (edge) { return edge.to = to; });
    }
    function compile(expr, from) {
        if (expr.type == "choice") {
            return expr.exprs.reduce(function (out, expr) { return out.concat(compile(expr, from)); }, []);
        }
        else if (expr.type == "seq") {
            for (var i = 0;; i++) {
                var next = compile(expr.exprs[i], from);
                if (i == expr.exprs.length - 1)
                    { return next; }
                connect(next, from = node());
            }
        }
        else if (expr.type == "star") {
            var loop = node();
            edge(from, loop);
            connect(compile(expr.expr, loop), loop);
            return [edge(loop)];
        }
        else if (expr.type == "plus") {
            var loop$1 = node();
            connect(compile(expr.expr, from), loop$1);
            connect(compile(expr.expr, loop$1), loop$1);
            return [edge(loop$1)];
        }
        else if (expr.type == "opt") {
            return [edge(from)].concat(compile(expr.expr, from));
        }
        else if (expr.type == "range") {
            var cur = from;
            for (var i$1 = 0; i$1 < expr.min; i$1++) {
                var next$1 = node();
                connect(compile(expr.expr, cur), next$1);
                cur = next$1;
            }
            if (expr.max == -1) {
                connect(compile(expr.expr, cur), cur);
            }
            else {
                for (var i$2 = expr.min; i$2 < expr.max; i$2++) {
                    var next$2 = node();
                    edge(cur, next$2);
                    connect(compile(expr.expr, cur), next$2);
                    cur = next$2;
                }
            }
            return [edge(cur)];
        }
        else if (expr.type == "name") {
            return [edge(from, undefined, expr.value)];
        }
        else {
            throw new Error("Unknown expr type");
        }
    }
}
function cmp(a, b) { return b - a; }
// Get the set of nodes reachable by null edges from `node`. Omit
// nodes with only a single null-out-edge, since they may lead to
// needless duplicated nodes.
function nullFrom(nfa, node) {
    var result = [];
    scan(node);
    return result.sort(cmp);
    function scan(node) {
        var edges = nfa[node];
        if (edges.length == 1 && !edges[0].term)
            { return scan(edges[0].to); }
        result.push(node);
        for (var i = 0; i < edges.length; i++) {
            var ref = edges[i];
            var term = ref.term;
            var to = ref.to;
            if (!term && result.indexOf(to) == -1)
                { scan(to); }
        }
    }
}
// Compiles an NFA as produced by `nfa` into a DFA, modeled as a set
// of state objects (`ContentMatch` instances) with transitions
// between them.
function dfa(nfa) {
    var labeled = Object.create(null);
    return explore(nullFrom(nfa, 0));
    function explore(states) {
        var out = [];
        states.forEach(function (node) {
            nfa[node].forEach(function (ref) {
                var term = ref.term;
                var to = ref.to;

                if (!term)
                    { return; }
                var set;
                for (var i = 0; i < out.length; i++)
                    { if (out[i][0] == term)
                        { set = out[i][1]; } }
                nullFrom(nfa, to).forEach(function (node) {
                    if (!set)
                        { out.push([term, set = []]); }
                    if (set.indexOf(node) == -1)
                        { set.push(node); }
                });
            });
        });
        var state = labeled[states.join(",")] = new ContentMatch(states.indexOf(nfa.length - 1) > -1);
        for (var i = 0; i < out.length; i++) {
            var states$1 = out[i][1].sort(cmp);
            state.next.push({ type: out[i][0], next: labeled[states$1.join(",")] || explore(states$1) });
        }
        return state;
    }
}
function checkForDeadEnds(match, stream) {
    for (var i = 0, work = [match]; i < work.length; i++) {
        var state = work[i], dead = !state.validEnd, nodes = [];
        for (var j = 0; j < state.next.length; j++) {
            var ref = state.next[j];
            var type = ref.type;
            var next = ref.next;
            nodes.push(type.name);
            if (dead && !(type.isText || type.hasRequiredAttrs()))
                { dead = false; }
            if (work.indexOf(next) == -1)
                { work.push(next); }
        }
        if (dead)
            { stream.err("Only non-generatable nodes (" + nodes.join(", ") + ") in a required position (see https://prosemirror.net/docs/guide/#generatable)"); }
    }
}

// For node types where all attrs have a default value (or which don't
// have any attributes), build up a single reusable default attribute
// object, and use it for all nodes that don't specify specific
// attributes.
function defaultAttrs(attrs) {
    var defaults = Object.create(null);
    for (var attrName in attrs) {
        var attr = attrs[attrName];
        if (!attr.hasDefault)
            { return null; }
        defaults[attrName] = attr.default;
    }
    return defaults;
}
function computeAttrs(attrs, value) {
    var built = Object.create(null);
    for (var name in attrs) {
        var given = value && value[name];
        if (given === undefined) {
            var attr = attrs[name];
            if (attr.hasDefault)
                { given = attr.default; }
            else
                { throw new RangeError("No value supplied for attribute " + name); }
        }
        built[name] = given;
    }
    return built;
}
function checkAttrs(attrs, values, type, name) {
    for (var name$1 in values)
        { if (!(name$1 in attrs))
            { throw new RangeError(("Unsupported attribute " + name$1 + " for " + type + " of type " + name$1)); } }
    for (var name$2 in attrs) {
        var attr = attrs[name$2];
        if (attr.validate)
            { attr.validate(values[name$2]); }
    }
}
function initAttrs(typeName, attrs) {
    var result = Object.create(null);
    if (attrs)
        { for (var name in attrs)
            { result[name] = new Attribute(typeName, name, attrs[name]); } }
    return result;
}
/**
Node types are objects allocated once per `Schema` and used to
[tag](https://prosemirror.net/docs/ref/#model.Node.type) `Node` instances. They contain information
about the node type, such as its name and what kind of node it
represents.
*/
var NodeType$2 = function NodeType(
  /**
  The name the node type has in this schema.
  */
  name, 
  /**
  A link back to the `Schema` the node type belongs to.
  */
  schema, 
  /**
  The spec that this type is based on
  */
  spec) {
      this.name = name;
      this.schema = schema;
      this.spec = spec;
      /**
      The set of marks allowed in this node. `null` means all marks
      are allowed.
      */
      this.markSet = null;
      this.groups = spec.group ? spec.group.split(" ") : [];
      this.attrs = initAttrs(name, spec.attrs);
      this.defaultAttrs = defaultAttrs(this.attrs);
      this.contentMatch = null;
      this.inlineContent = null;
      this.isBlock = !(spec.inline || name == "text");
      this.isText = name == "text";
  };

var prototypeAccessors$8$1 = { isInline: { configurable: true },isTextblock: { configurable: true },isLeaf: { configurable: true },isAtom: { configurable: true },whitespace: { configurable: true } };
  /**
  True if this is an inline type.
  */
  prototypeAccessors$8$1.isInline.get = function () { return !this.isBlock; };
  /**
  True if this is a textblock type, a block that contains inline
  content.
  */
  prototypeAccessors$8$1.isTextblock.get = function () { return this.isBlock && this.inlineContent; };
  /**
  True for node types that allow no content.
  */
  prototypeAccessors$8$1.isLeaf.get = function () { return this.contentMatch == ContentMatch.empty; };
  /**
  True when this node is an atom, i.e. when it does not have
  directly editable content.
  */
  prototypeAccessors$8$1.isAtom.get = function () { return this.isLeaf || !!this.spec.atom; };
  /**
  The node type's [whitespace](https://prosemirror.net/docs/ref/#model.NodeSpec.whitespace) option.
  */
  prototypeAccessors$8$1.whitespace.get = function () {
      return this.spec.whitespace || (this.spec.code ? "pre" : "normal");
  };
  /**
  Tells you whether this node type has any required attributes.
  */
  NodeType$2.prototype.hasRequiredAttrs = function hasRequiredAttrs () {
      for (var n in this.attrs)
          { if (this.attrs[n].isRequired)
              { return true; } }
      return false;
  };
  /**
  Indicates whether this node allows some of the same content as
  the given node type.
  */
  NodeType$2.prototype.compatibleContent = function compatibleContent (other) {
      return this == other || this.contentMatch.compatible(other.contentMatch);
  };
  /**
  @internal
  */
  NodeType$2.prototype.computeAttrs = function computeAttrs$1 (attrs) {
      if (!attrs && this.defaultAttrs)
          { return this.defaultAttrs; }
      else
          { return computeAttrs(this.attrs, attrs); }
  };
  /**
  Create a `Node` of this type. The given attributes are
  checked and defaulted (you can pass `null` to use the type's
  defaults entirely, if no required attributes exist). `content`
  may be a `Fragment`, a node, an array of nodes, or
  `null`. Similarly `marks` may be `null` to default to the empty
  set of marks.
  */
  NodeType$2.prototype.create = function create (attrs, content, marks) {
        if ( attrs === void 0 ) attrs = null;

      if (this.isText)
          { throw new Error("NodeType.create can't construct text nodes"); }
      return new Node$1(this, this.computeAttrs(attrs), Fragment.from(content), Mark.setFrom(marks));
  };
  /**
  Like [`create`](https://prosemirror.net/docs/ref/#model.NodeType.create), but check the given content
  against the node type's content restrictions, and throw an error
  if it doesn't match.
  */
  NodeType$2.prototype.createChecked = function createChecked (attrs, content, marks) {
        if ( attrs === void 0 ) attrs = null;

      content = Fragment.from(content);
      this.checkContent(content);
      return new Node$1(this, this.computeAttrs(attrs), content, Mark.setFrom(marks));
  };
  /**
  Like [`create`](https://prosemirror.net/docs/ref/#model.NodeType.create), but see if it is
  necessary to add nodes to the start or end of the given fragment
  to make it fit the node. If no fitting wrapping can be found,
  return null. Note that, due to the fact that required nodes can
  always be created, this will always succeed if you pass null or
  `Fragment.empty` as content.
  */
  NodeType$2.prototype.createAndFill = function createAndFill (attrs, content, marks) {
        if ( attrs === void 0 ) attrs = null;

      attrs = this.computeAttrs(attrs);
      content = Fragment.from(content);
      if (content.size) {
          var before = this.contentMatch.fillBefore(content);
          if (!before)
              { return null; }
          content = before.append(content);
      }
      var matched = this.contentMatch.matchFragment(content);
      var after = matched && matched.fillBefore(Fragment.empty, true);
      if (!after)
          { return null; }
      return new Node$1(this, attrs, content.append(after), Mark.setFrom(marks));
  };
  /**
  Returns true if the given fragment is valid content for this node
  type.
  */
  NodeType$2.prototype.validContent = function validContent (content) {
      var result = this.contentMatch.matchFragment(content);
      if (!result || !result.validEnd)
          { return false; }
      for (var i = 0; i < content.childCount; i++)
          { if (!this.allowsMarks(content.child(i).marks))
              { return false; } }
      return true;
  };
  /**
  Throws a RangeError if the given fragment is not valid content for this
  node type.
  @internal
  */
  NodeType$2.prototype.checkContent = function checkContent (content) {
      if (!this.validContent(content))
          { throw new RangeError(("Invalid content for node " + (this.name) + ": " + (content.toString().slice(0, 50)))); }
  };
  /**
  @internal
  */
  NodeType$2.prototype.checkAttrs = function checkAttrs$1 (attrs) {
      checkAttrs(this.attrs, attrs, "node", this.name);
  };
  /**
  Check whether the given mark type is allowed in this node.
  */
  NodeType$2.prototype.allowsMarkType = function allowsMarkType (markType) {
      return this.markSet == null || this.markSet.indexOf(markType) > -1;
  };
  /**
  Test whether the given set of marks are allowed in this node.
  */
  NodeType$2.prototype.allowsMarks = function allowsMarks (marks) {
      if (this.markSet == null)
          { return true; }
      for (var i = 0; i < marks.length; i++)
          { if (!this.allowsMarkType(marks[i].type))
              { return false; } }
      return true;
  };
  /**
  Removes the marks that are not allowed in this node from the given set.
  */
  NodeType$2.prototype.allowedMarks = function allowedMarks (marks) {
      if (this.markSet == null)
          { return marks; }
      var copy;
      for (var i = 0; i < marks.length; i++) {
          if (!this.allowsMarkType(marks[i].type)) {
              if (!copy)
                  { copy = marks.slice(0, i); }
          }
          else if (copy) {
              copy.push(marks[i]);
          }
      }
      return !copy ? marks : copy.length ? copy : Mark.none;
  };
  /**
  @internal
  */
  NodeType$2.compile = function compile (nodes, schema) {
      var result = Object.create(null);
      nodes.forEach(function (name, spec) { return result[name] = new NodeType$2(name, schema, spec); });
      var topType = schema.spec.topNode || "doc";
      if (!result[topType])
          { throw new RangeError("Schema is missing its top node type ('" + topType + "')"); }
      if (!result.text)
          { throw new RangeError("Every schema needs a 'text' type"); }
      for (var _ in result.text.attrs)
          { throw new RangeError("The text node type should not have attributes"); }
      return result;
  };

Object.defineProperties( NodeType$2.prototype, prototypeAccessors$8$1 );
function validateType(typeName, attrName, type) {
    var types = type.split("|");
    return function (value) {
        var name = value === null ? "null" : typeof value;
        if (types.indexOf(name) < 0)
            { throw new RangeError(("Expected value of type " + types + " for attribute " + attrName + " on type " + typeName + ", got " + name)); }
    };
}
// Attribute descriptors
var Attribute = function Attribute(typeName, attrName, options) {
      this.hasDefault = Object.prototype.hasOwnProperty.call(options, "default");
      this.default = options.default;
      this.validate = typeof options.validate == "string" ? validateType(typeName, attrName, options.validate) : options.validate;
  };

var prototypeAccessors$9$1 = { isRequired: { configurable: true } };
  prototypeAccessors$9$1.isRequired.get = function () {
      return !this.hasDefault;
  };

Object.defineProperties( Attribute.prototype, prototypeAccessors$9$1 );
// Marks
/**
Like nodes, marks (which are associated with nodes to signify
things like emphasis or being part of a link) are
[tagged](https://prosemirror.net/docs/ref/#model.Mark.type) with type objects, which are
instantiated once per `Schema`.
*/
var MarkType = function MarkType(
  /**
  The name of the mark type.
  */
  name, 
  /**
  @internal
  */
  rank, 
  /**
  The schema that this mark type instance is part of.
  */
  schema, 
  /**
  The spec on which the type is based.
  */
  spec) {
      this.name = name;
      this.rank = rank;
      this.schema = schema;
      this.spec = spec;
      this.attrs = initAttrs(name, spec.attrs);
      this.excluded = null;
      var defaults = defaultAttrs(this.attrs);
      this.instance = defaults ? new Mark(this, defaults) : null;
  };
  /**
  Create a mark of this type. `attrs` may be `null` or an object
  containing only some of the mark's attributes. The others, if
  they have defaults, will be added.
  */
  MarkType.prototype.create = function create (attrs) {
        if ( attrs === void 0 ) attrs = null;

      if (!attrs && this.instance)
          { return this.instance; }
      return new Mark(this, computeAttrs(this.attrs, attrs));
  };
  /**
  @internal
  */
  MarkType.compile = function compile (marks, schema) {
      var result = Object.create(null), rank = 0;
      marks.forEach(function (name, spec) { return result[name] = new MarkType(name, rank++, schema, spec); });
      return result;
  };
  /**
  When there is a mark of this type in the given set, a new set
  without it is returned. Otherwise, the input set is returned.
  */
  MarkType.prototype.removeFromSet = function removeFromSet (set) {
      for (var i = 0; i < set.length; i++)
          { if (set[i].type == this) {
              set = set.slice(0, i).concat(set.slice(i + 1));
              i--;
          } }
      return set;
  };
  /**
  Tests whether there is a mark of this type in the given set.
  */
  MarkType.prototype.isInSet = function isInSet (set) {
      for (var i = 0; i < set.length; i++)
          { if (set[i].type == this)
              { return set[i]; } }
  };
  /**
  @internal
  */
  MarkType.prototype.checkAttrs = function checkAttrs$2 (attrs) {
      checkAttrs(this.attrs, attrs, "mark", this.name);
  };
  /**
  Queries whether a given mark type is
  [excluded](https://prosemirror.net/docs/ref/#model.MarkSpec.excludes) by this one.
  */
  MarkType.prototype.excludes = function excludes (other) {
      return this.excluded.indexOf(other) > -1;
  };
/**
A document schema. Holds [node](https://prosemirror.net/docs/ref/#model.NodeType) and [mark
type](https://prosemirror.net/docs/ref/#model.MarkType) objects for the nodes and marks that may
occur in conforming documents, and provides functionality for
creating and deserializing such documents.

When given, the type parameters provide the names of the nodes and
marks in this schema.
*/
var Schema = function Schema(spec) {
      /**
      The [linebreak
      replacement](https://prosemirror.net/docs/ref/#model.NodeSpec.linebreakReplacement) node defined
      in this schema, if any.
      */
      this.linebreakReplacement = null;
      /**
      An object for storing whatever values modules may want to
      compute and cache per schema. (If you want to store something
      in it, try to use property names unlikely to clash.)
      */
      this.cached = Object.create(null);
      var instanceSpec = this.spec = {};
      for (var prop in spec)
          { instanceSpec[prop] = spec[prop]; }
      instanceSpec.nodes = OrderedMap.from(spec.nodes),
          instanceSpec.marks = OrderedMap.from(spec.marks || {}),
          this.nodes = NodeType$2.compile(this.spec.nodes, this);
      this.marks = MarkType.compile(this.spec.marks, this);
      var contentExprCache = Object.create(null);
      for (var prop$1 in this.nodes) {
          if (prop$1 in this.marks)
              { throw new RangeError(prop$1 + " can not be both a node and a mark"); }
          var type = this.nodes[prop$1], contentExpr = type.spec.content || "", markExpr = type.spec.marks;
          type.contentMatch = contentExprCache[contentExpr] ||
              (contentExprCache[contentExpr] = ContentMatch.parse(contentExpr, this.nodes));
          type.inlineContent = type.contentMatch.inlineContent;
          if (type.spec.linebreakReplacement) {
              if (this.linebreakReplacement)
                  { throw new RangeError("Multiple linebreak nodes defined"); }
              if (!type.isInline || !type.isLeaf)
                  { throw new RangeError("Linebreak replacement nodes must be inline leaf nodes"); }
              this.linebreakReplacement = type;
          }
          type.markSet = markExpr == "_" ? null :
              markExpr ? gatherMarks(this, markExpr.split(" ")) :
                  markExpr == "" || !type.inlineContent ? [] : null;
      }
      for (var prop$2 in this.marks) {
          var type$1 = this.marks[prop$2], excl = type$1.spec.excludes;
          type$1.excluded = excl == null ? [type$1] : excl == "" ? [] : gatherMarks(this, excl.split(" "));
      }
      this.nodeFromJSON = this.nodeFromJSON.bind(this);
      this.markFromJSON = this.markFromJSON.bind(this);
      this.topNodeType = this.nodes[this.spec.topNode || "doc"];
      this.cached.wrappings = Object.create(null);
  };
  /**
  Create a node in this schema. The `type` may be a string or a
  `NodeType` instance. Attributes will be extended with defaults,
  `content` may be a `Fragment`, `null`, a `Node`, or an array of
  nodes.
  */
  Schema.prototype.node = function node (type, attrs, content, marks) {
        if ( attrs === void 0 ) attrs = null;

      if (typeof type == "string")
          { type = this.nodeType(type); }
      else if (!(type instanceof NodeType$2))
          { throw new RangeError("Invalid node type: " + type); }
      else if (type.schema != this)
          { throw new RangeError("Node type from different schema used (" + type.name + ")"); }
      return type.createChecked(attrs, content, marks);
  };
  /**
  Create a text node in the schema. Empty text nodes are not
  allowed.
  */
  Schema.prototype.text = function text (text$1, marks) {
      var type = this.nodes.text;
      return new TextNode$1(type, type.defaultAttrs, text$1, Mark.setFrom(marks));
  };
  /**
  Create a mark with the given type and attributes.
  */
  Schema.prototype.mark = function mark (type, attrs) {
      if (typeof type == "string")
          { type = this.marks[type]; }
      return type.create(attrs);
  };
  /**
  Deserialize a node from its JSON representation. This method is
  bound.
  */
  Schema.prototype.nodeFromJSON = function nodeFromJSON (json) {
      return Node$1.fromJSON(this, json);
  };
  /**
  Deserialize a mark from its JSON representation. This method is
  bound.
  */
  Schema.prototype.markFromJSON = function markFromJSON (json) {
      return Mark.fromJSON(this, json);
  };
  /**
  @internal
  */
  Schema.prototype.nodeType = function nodeType (name) {
      var found = this.nodes[name];
      if (!found)
          { throw new RangeError("Unknown node type: " + name); }
      return found;
  };
function gatherMarks(schema, marks) {
    var found = [];
    for (var i = 0; i < marks.length; i++) {
        var name = marks[i], mark = schema.marks[name], ok = mark;
        if (mark) {
            found.push(mark);
        }
        else {
            for (var prop in schema.marks) {
                var mark$1 = schema.marks[prop];
                if (name == "_" || (mark$1.spec.group && mark$1.spec.group.split(" ").indexOf(name) > -1))
                    { found.push(ok = mark$1); }
            }
        }
        if (!ok)
            { throw new SyntaxError("Unknown mark type: '" + marks[i] + "'"); }
    }
    return found;
}

function isTagRule(rule) { return rule.tag != null; }
function isStyleRule(rule) { return rule.style != null; }
/**
A DOM parser represents a strategy for parsing DOM content into a
ProseMirror document conforming to a given schema. Its behavior is
defined by an array of [rules](https://prosemirror.net/docs/ref/#model.ParseRule).
*/
var DOMParser = function DOMParser(
  /**
  The schema into which the parser parses.
  */
  schema, 
  /**
  The set of [parse rules](https://prosemirror.net/docs/ref/#model.ParseRule) that the parser
  uses, in order of precedence.
  */
  rules) {
      var this$1$1 = this;

      this.schema = schema;
      this.rules = rules;
      /**
      @internal
      */
      this.tags = [];
      /**
      @internal
      */
      this.styles = [];
      var matchedStyles = this.matchedStyles = [];
      rules.forEach(function (rule) {
          if (isTagRule(rule)) {
              this$1$1.tags.push(rule);
          }
          else if (isStyleRule(rule)) {
              var prop = /[^=]*/.exec(rule.style)[0];
              if (matchedStyles.indexOf(prop) < 0)
                  { matchedStyles.push(prop); }
              this$1$1.styles.push(rule);
          }
      });
      // Only normalize list elements when lists in the schema can't directly contain themselves
      this.normalizeLists = !this.tags.some(function (r) {
          if (!/^(ul|ol)\b/.test(r.tag) || !r.node)
              { return false; }
          var node = schema.nodes[r.node];
          return node.contentMatch.matchType(node);
      });
  };
  /**
  Parse a document from the content of a DOM node.
  */
  DOMParser.prototype.parse = function parse (dom, options) {
        if ( options === void 0 ) options = {};

      var context = new ParseContext$1(this, options, false);
      context.addAll(dom, Mark.none, options.from, options.to);
      return context.finish();
  };
  /**
  Parses the content of the given DOM node, like
  [`parse`](https://prosemirror.net/docs/ref/#model.DOMParser.parse), and takes the same set of
  options. But unlike that method, which produces a whole node,
  this one returns a slice that is open at the sides, meaning that
  the schema constraints aren't applied to the start of nodes to
  the left of the input and the end of nodes at the end.
  */
  DOMParser.prototype.parseSlice = function parseSlice (dom, options) {
        if ( options === void 0 ) options = {};

      var context = new ParseContext$1(this, options, true);
      context.addAll(dom, Mark.none, options.from, options.to);
      return Slice.maxOpen(context.finish());
  };
  /**
  @internal
  */
  DOMParser.prototype.matchTag = function matchTag (dom, context, after) {
      for (var i = after ? this.tags.indexOf(after) + 1 : 0; i < this.tags.length; i++) {
          var rule = this.tags[i];
          if (matches(dom, rule.tag) &&
              (rule.namespace === undefined || dom.namespaceURI == rule.namespace) &&
              (!rule.context || context.matchesContext(rule.context))) {
              if (rule.getAttrs) {
                  var result = rule.getAttrs(dom);
                  if (result === false)
                      { continue; }
                  rule.attrs = result || undefined;
              }
              return rule;
          }
      }
  };
  /**
  @internal
  */
  DOMParser.prototype.matchStyle = function matchStyle (prop, value, context, after) {
      for (var i = after ? this.styles.indexOf(after) + 1 : 0; i < this.styles.length; i++) {
          var rule = this.styles[i], style = rule.style;
          if (style.indexOf(prop) != 0 ||
              rule.context && !context.matchesContext(rule.context) ||
              // Test that the style string either precisely matches the prop,
              // or has an '=' sign after the prop, followed by the given
              // value.
              style.length > prop.length &&
                  (style.charCodeAt(prop.length) != 61 || style.slice(prop.length + 1) != value))
              { continue; }
          if (rule.getAttrs) {
              var result = rule.getAttrs(value);
              if (result === false)
                  { continue; }
              rule.attrs = result || undefined;
          }
          return rule;
      }
  };
  /**
  @internal
  */
  DOMParser.schemaRules = function schemaRules (schema) {
      var result = [];
      function insert(rule) {
          var priority = rule.priority == null ? 50 : rule.priority, i = 0;
          for (; i < result.length; i++) {
              var next = result[i], nextPriority = next.priority == null ? 50 : next.priority;
              if (nextPriority < priority)
                  { break; }
          }
          result.splice(i, 0, rule);
      }
      var loop = function ( name ) {
          var rules = schema.marks[name].spec.parseDOM;
          if (rules)
              { rules.forEach(function (rule) {
                  insert(rule = copy$1(rule));
                  if (!(rule.mark || rule.ignore || rule.clearMark))
                      { rule.mark = name; }
              }); }
      };

        for (var name in schema.marks) loop( name );
      var loop$1 = function ( name ) {
          var rules$1 = schema.nodes[name$1].spec.parseDOM;
          if (rules$1)
              { rules$1.forEach(function (rule) {
                  insert(rule = copy$1(rule));
                  if (!(rule.node || rule.ignore || rule.mark))
                      { rule.node = name$1; }
              }); }
      };

        for (var name$1 in schema.nodes) loop$1();
      return result;
  };
  /**
  Construct a DOM parser using the parsing rules listed in a
  schema's [node specs](https://prosemirror.net/docs/ref/#model.NodeSpec.parseDOM), reordered by
  [priority](https://prosemirror.net/docs/ref/#model.ParseRule.priority).
  */
  DOMParser.fromSchema = function fromSchema (schema) {
      return schema.cached.domParser ||
          (schema.cached.domParser = new DOMParser(schema, DOMParser.schemaRules(schema)));
  };
var blockTags = {
    address: true, article: true, aside: true, blockquote: true, canvas: true,
    dd: true, div: true, dl: true, fieldset: true, figcaption: true, figure: true,
    footer: true, form: true, h1: true, h2: true, h3: true, h4: true, h5: true,
    h6: true, header: true, hgroup: true, hr: true, li: true, noscript: true, ol: true,
    output: true, p: true, pre: true, section: true, table: true, tfoot: true, ul: true
};
var ignoreTags = {
    head: true, noscript: true, object: true, script: true, style: true, title: true
};
var listTags = { ol: true, ul: true };
// Using a bitfield for node context options
var OPT_PRESERVE_WS = 1, OPT_PRESERVE_WS_FULL = 2, OPT_OPEN_LEFT = 4;
function wsOptionsFor(type, preserveWhitespace, base) {
    if (preserveWhitespace != null)
        { return (preserveWhitespace ? OPT_PRESERVE_WS : 0) |
            (preserveWhitespace === "full" ? OPT_PRESERVE_WS_FULL : 0); }
    return type && type.whitespace == "pre" ? OPT_PRESERVE_WS | OPT_PRESERVE_WS_FULL : base & ~OPT_OPEN_LEFT;
}
var NodeContext = function NodeContext(type, attrs, marks, solid, match, options) {
      this.type = type;
      this.attrs = attrs;
      this.marks = marks;
      this.solid = solid;
      this.options = options;
      this.content = [];
      // Marks applied to the node's children
      this.activeMarks = Mark.none;
      this.match = match || (options & OPT_OPEN_LEFT ? null : type.contentMatch);
  };
  NodeContext.prototype.findWrapping = function findWrapping (node) {
      if (!this.match) {
          if (!this.type)
              { return []; }
          var fill = this.type.contentMatch.fillBefore(Fragment.from(node));
          if (fill) {
              this.match = this.type.contentMatch.matchFragment(fill);
          }
          else {
              var start = this.type.contentMatch, wrap;
              if (wrap = start.findWrapping(node.type)) {
                  this.match = start;
                  return wrap;
              }
              else {
                  return null;
              }
          }
      }
      return this.match.findWrapping(node.type);
  };
  NodeContext.prototype.finish = function finish (openEnd) {
      if (!(this.options & OPT_PRESERVE_WS)) { // Strip trailing whitespace
          var last = this.content[this.content.length - 1], m;
          if (last && last.isText && (m = /[ \t\r\n\u000c]+$/.exec(last.text))) {
              var text = last;
              if (last.text.length == m[0].length)
                  { this.content.pop(); }
              else
                  { this.content[this.content.length - 1] = text.withText(text.text.slice(0, text.text.length - m[0].length)); }
          }
      }
      var content = Fragment.from(this.content);
      if (!openEnd && this.match)
          { content = content.append(this.match.fillBefore(Fragment.empty, true)); }
      return this.type ? this.type.create(this.attrs, content, this.marks) : content;
  };
  NodeContext.prototype.inlineContext = function inlineContext (node) {
      if (this.type)
          { return this.type.inlineContent; }
      if (this.content.length)
          { return this.content[0].isInline; }
      return node.parentNode && !blockTags.hasOwnProperty(node.parentNode.nodeName.toLowerCase());
  };
var ParseContext$1 = function ParseContext(
  // The parser we are using.
  parser, 
  // The options passed to this parse.
  options, isOpen) {
      this.parser = parser;
      this.options = options;
      this.isOpen = isOpen;
      this.open = 0;
      var topNode = options.topNode, topContext;
      var topOptions = wsOptionsFor(null, options.preserveWhitespace, 0) | (isOpen ? OPT_OPEN_LEFT : 0);
      if (topNode)
          { topContext = new NodeContext(topNode.type, topNode.attrs, Mark.none, true, options.topMatch || topNode.type.contentMatch, topOptions); }
      else if (isOpen)
          { topContext = new NodeContext(null, null, Mark.none, true, null, topOptions); }
      else
          { topContext = new NodeContext(parser.schema.topNodeType, null, Mark.none, true, null, topOptions); }
      this.nodes = [topContext];
      this.find = options.findPositions;
      this.needsBlock = false;
  };

var prototypeAccessors$10$2 = { top: { configurable: true },currentPos: { configurable: true } };
  prototypeAccessors$10$2.top.get = function () {
      return this.nodes[this.open];
  };
  // Add a DOM node to the content. Text is inserted as text node,
  // otherwise, the node is passed to `addElement` or, if it has a
  // `style` attribute, `addElementWithStyles`.
  ParseContext$1.prototype.addDOM = function addDOM (dom, marks) {
      if (dom.nodeType == 3)
          { this.addTextNode(dom, marks); }
      else if (dom.nodeType == 1)
          { this.addElement(dom, marks); }
  };
  ParseContext$1.prototype.addTextNode = function addTextNode (dom, marks) {
      var value = dom.nodeValue;
      var top = this.top;
      if (top.options & OPT_PRESERVE_WS_FULL ||
          top.inlineContext(dom) ||
          /[^ \t\r\n\u000c]/.test(value)) {
          if (!(top.options & OPT_PRESERVE_WS)) {
              value = value.replace(/[ \t\r\n\u000c]+/g, " ");
              // If this starts with whitespace, and there is no node before it, or
              // a hard break, or a text node that ends with whitespace, strip the
              // leading space.
              if (/^[ \t\r\n\u000c]/.test(value) && this.open == this.nodes.length - 1) {
                  var nodeBefore = top.content[top.content.length - 1];
                  var domNodeBefore = dom.previousSibling;
                  if (!nodeBefore ||
                      (domNodeBefore && domNodeBefore.nodeName == 'BR') ||
                      (nodeBefore.isText && /[ \t\r\n\u000c]$/.test(nodeBefore.text)))
                      { value = value.slice(1); }
              }
          }
          else if (!(top.options & OPT_PRESERVE_WS_FULL)) {
              value = value.replace(/\r?\n|\r/g, " ");
          }
          else {
              value = value.replace(/\r\n?/g, "\n");
          }
          if (value)
              { this.insertNode(this.parser.schema.text(value), marks); }
          this.findInText(dom);
      }
      else {
          this.findInside(dom);
      }
  };
  // Try to find a handler for the given tag and use that to parse. If
  // none is found, the element's content nodes are added directly.
  ParseContext$1.prototype.addElement = function addElement (dom, marks, matchAfter) {
      var name = dom.nodeName.toLowerCase(), ruleID;
      if (listTags.hasOwnProperty(name) && this.parser.normalizeLists)
          { normalizeList(dom); }
      var rule = (this.options.ruleFromNode && this.options.ruleFromNode(dom)) ||
          (ruleID = this.parser.matchTag(dom, this, matchAfter));
      if (rule ? rule.ignore : ignoreTags.hasOwnProperty(name)) {
          this.findInside(dom);
          this.ignoreFallback(dom, marks);
      }
      else if (!rule || rule.skip || rule.closeParent) {
          if (rule && rule.closeParent)
              { this.open = Math.max(0, this.open - 1); }
          else if (rule && rule.skip.nodeType)
              { dom = rule.skip; }
          var sync, top = this.top, oldNeedsBlock = this.needsBlock;
          if (blockTags.hasOwnProperty(name)) {
              if (top.content.length && top.content[0].isInline && this.open) {
                  this.open--;
                  top = this.top;
              }
              sync = true;
              if (!top.type)
                  { this.needsBlock = true; }
          }
          else if (!dom.firstChild) {
              this.leafFallback(dom, marks);
              return;
          }
          var innerMarks = rule && rule.skip ? marks : this.readStyles(dom, marks);
          if (innerMarks)
              { this.addAll(dom, innerMarks); }
          if (sync)
              { this.sync(top); }
          this.needsBlock = oldNeedsBlock;
      }
      else {
          var innerMarks$1 = this.readStyles(dom, marks);
          if (innerMarks$1)
              { this.addElementByRule(dom, rule, innerMarks$1, rule.consuming === false ? ruleID : undefined); }
      }
  };
  // Called for leaf DOM nodes that would otherwise be ignored
  ParseContext$1.prototype.leafFallback = function leafFallback (dom, marks) {
      if (dom.nodeName == "BR" && this.top.type && this.top.type.inlineContent)
          { this.addTextNode(dom.ownerDocument.createTextNode("\n"), marks); }
  };
  // Called for ignored nodes
  ParseContext$1.prototype.ignoreFallback = function ignoreFallback (dom, marks) {
      // Ignored BR nodes should at least create an inline context
      if (dom.nodeName == "BR" && (!this.top.type || !this.top.type.inlineContent))
          { this.findPlace(this.parser.schema.text("-"), marks); }
  };
  // Run any style parser associated with the node's styles. Either
  // return an updated array of marks, or null to indicate some of the
  // styles had a rule with `ignore` set.
  ParseContext$1.prototype.readStyles = function readStyles (dom, marks) {
        var this$1$1 = this;

      var styles = dom.style;
      // Because many properties will only show up in 'normalized' form
      // in `style.item` (i.e. text-decoration becomes
      // text-decoration-line, text-decoration-color, etc), we directly
      // query the styles mentioned in our rules instead of iterating
      // over the items.
      if (styles && styles.length)
          { for (var i = 0; i < this.parser.matchedStyles.length; i++) {
              var name = this.parser.matchedStyles[i], value = styles.getPropertyValue(name);
              if (value)
                  { var loop = function ( after$1 ) {
                      var rule = this$1$1.parser.matchStyle(name, value, this$1$1, after$1);
                      if (!rule)
                          { return 'break'; }
                      if (rule.ignore)
                          { return { v: null }; }
                      if (rule.clearMark)
                          { marks = marks.filter(function (m) { return !rule.clearMark(m); }); }
                      else
                          { marks = marks.concat(this$1$1.parser.schema.marks[rule.mark].create(rule.attrs)); }
                      if (rule.consuming === false)
                          { after$1 = rule; }
                      else
                          { return 'break';
 }
                  };

                      for (var after = undefined;;) {
                        var returned = loop( after );

                        if ( returned === 'break' ) break;
                        if ( returned ) return returned.v;
                      } }
          } }
      return marks;
  };
  // Look up a handler for the given node. If none are found, return
  // false. Otherwise, apply it, use its return value to drive the way
  // the node's content is wrapped, and return true.
  ParseContext$1.prototype.addElementByRule = function addElementByRule (dom, rule, marks, continueAfter) {
        var this$1$1 = this;

      var sync, nodeType;
      if (rule.node) {
          nodeType = this.parser.schema.nodes[rule.node];
          if (!nodeType.isLeaf) {
              var inner = this.enter(nodeType, rule.attrs || null, marks, rule.preserveWhitespace);
              if (inner) {
                  sync = true;
                  marks = inner;
              }
          }
          else if (!this.insertNode(nodeType.create(rule.attrs), marks)) {
              this.leafFallback(dom, marks);
          }
      }
      else {
          var markType = this.parser.schema.marks[rule.mark];
          marks = marks.concat(markType.create(rule.attrs));
      }
      var startIn = this.top;
      if (nodeType && nodeType.isLeaf) {
          this.findInside(dom);
      }
      else if (continueAfter) {
          this.addElement(dom, marks, continueAfter);
      }
      else if (rule.getContent) {
          this.findInside(dom);
          rule.getContent(dom, this.parser.schema).forEach(function (node) { return this$1$1.insertNode(node, marks); });
      }
      else {
          var contentDOM = dom;
          if (typeof rule.contentElement == "string")
              { contentDOM = dom.querySelector(rule.contentElement); }
          else if (typeof rule.contentElement == "function")
              { contentDOM = rule.contentElement(dom); }
          else if (rule.contentElement)
              { contentDOM = rule.contentElement; }
          this.findAround(dom, contentDOM, true);
          this.addAll(contentDOM, marks);
      }
      if (sync && this.sync(startIn))
          { this.open--; }
  };
  // Add all child nodes between `startIndex` and `endIndex` (or the
  // whole node, if not given). If `sync` is passed, use it to
  // synchronize after every block element.
  ParseContext$1.prototype.addAll = function addAll (parent, marks, startIndex, endIndex) {
      var index = startIndex || 0;
      for (var dom = startIndex ? parent.childNodes[startIndex] : parent.firstChild, end = endIndex == null ? null : parent.childNodes[endIndex]; dom != end; dom = dom.nextSibling, ++index) {
          this.findAtPoint(parent, index);
          this.addDOM(dom, marks);
      }
      this.findAtPoint(parent, index);
  };
  // Try to find a way to fit the given node type into the current
  // context. May add intermediate wrappers and/or leave non-solid
  // nodes that we're in.
  ParseContext$1.prototype.findPlace = function findPlace (node, marks) {
      var route, sync;
      for (var depth = this.open; depth >= 0; depth--) {
          var cx = this.nodes[depth];
          var found = cx.findWrapping(node);
          if (found && (!route || route.length > found.length)) {
              route = found;
              sync = cx;
              if (!found.length)
                  { break; }
          }
          if (cx.solid)
              { break; }
      }
      if (!route)
          { return null; }
      this.sync(sync);
      for (var i = 0; i < route.length; i++)
          { marks = this.enterInner(route[i], null, marks, false); }
      return marks;
  };
  // Try to insert the given node, adjusting the context when needed.
  ParseContext$1.prototype.insertNode = function insertNode (node, marks) {
      if (node.isInline && this.needsBlock && !this.top.type) {
          var block = this.textblockFromContext();
          if (block)
              { marks = this.enterInner(block, null, marks); }
      }
      var innerMarks = this.findPlace(node, marks);
      if (innerMarks) {
          this.closeExtra();
          var top = this.top;
          if (top.match)
              { top.match = top.match.matchType(node.type); }
          var nodeMarks = Mark.none;
          for (var m of innerMarks.concat(node.marks))
              if (top.type ? top.type.allowsMarkType(m.type) : markMayApply(m.type, node.type))
                  { nodeMarks = m.addToSet(nodeMarks); }
          top.content.push(node.mark(nodeMarks));
          return true;
      }
      return false;
  };
  // Try to start a node of the given type, adjusting the context when
  // necessary.
  ParseContext$1.prototype.enter = function enter (type, attrs, marks, preserveWS) {
      var innerMarks = this.findPlace(type.create(attrs), marks);
      if (innerMarks)
          { innerMarks = this.enterInner(type, attrs, marks, true, preserveWS); }
      return innerMarks;
  };
  // Open a node of the given type
  ParseContext$1.prototype.enterInner = function enterInner (type, attrs, marks, solid, preserveWS) {
        if ( solid === void 0 ) solid = false;

      this.closeExtra();
      var top = this.top;
      top.match = top.match && top.match.matchType(type);
      var options = wsOptionsFor(type, preserveWS, top.options);
      if ((top.options & OPT_OPEN_LEFT) && top.content.length == 0)
          { options |= OPT_OPEN_LEFT; }
      var applyMarks = Mark.none;
      marks = marks.filter(function (m) {
          if (top.type ? top.type.allowsMarkType(m.type) : markMayApply(m.type, type)) {
              applyMarks = m.addToSet(applyMarks);
              return false;
          }
          return true;
      });
      this.nodes.push(new NodeContext(type, attrs, applyMarks, solid, null, options));
      this.open++;
      return marks;
  };
  // Make sure all nodes above this.open are finished and added to
  // their parents
  ParseContext$1.prototype.closeExtra = function closeExtra (openEnd) {
        if ( openEnd === void 0 ) openEnd = false;

      var i = this.nodes.length - 1;
      if (i > this.open) {
          for (; i > this.open; i--)
              { this.nodes[i - 1].content.push(this.nodes[i].finish(openEnd)); }
          this.nodes.length = this.open + 1;
      }
  };
  ParseContext$1.prototype.finish = function finish () {
      this.open = 0;
      this.closeExtra(this.isOpen);
      return this.nodes[0].finish(this.isOpen || this.options.topOpen);
  };
  ParseContext$1.prototype.sync = function sync (to) {
      for (var i = this.open; i >= 0; i--)
          { if (this.nodes[i] == to) {
              this.open = i;
              return true;
          } }
      return false;
  };
  prototypeAccessors$10$2.currentPos.get = function () {
      this.closeExtra();
      var pos = 0;
      for (var i = this.open; i >= 0; i--) {
          var content = this.nodes[i].content;
          for (var j = content.length - 1; j >= 0; j--)
              { pos += content[j].nodeSize; }
          if (i)
              { pos++; }
      }
      return pos;
  };
  ParseContext$1.prototype.findAtPoint = function findAtPoint (parent, offset) {
      if (this.find)
          { for (var i = 0; i < this.find.length; i++) {
              if (this.find[i].node == parent && this.find[i].offset == offset)
                  { this.find[i].pos = this.currentPos; }
          } }
  };
  ParseContext$1.prototype.findInside = function findInside (parent) {
      if (this.find)
          { for (var i = 0; i < this.find.length; i++) {
              if (this.find[i].pos == null && parent.nodeType == 1 && parent.contains(this.find[i].node))
                  { this.find[i].pos = this.currentPos; }
          } }
  };
  ParseContext$1.prototype.findAround = function findAround (parent, content, before) {
      if (parent != content && this.find)
          { for (var i = 0; i < this.find.length; i++) {
              if (this.find[i].pos == null && parent.nodeType == 1 && parent.contains(this.find[i].node)) {
                  var pos = content.compareDocumentPosition(this.find[i].node);
                  if (pos & (before ? 2 : 4))
                      { this.find[i].pos = this.currentPos; }
              }
          } }
  };
  ParseContext$1.prototype.findInText = function findInText (textNode) {
      if (this.find)
          { for (var i = 0; i < this.find.length; i++) {
              if (this.find[i].node == textNode)
                  { this.find[i].pos = this.currentPos - (textNode.nodeValue.length - this.find[i].offset); }
          } }
  };
  // Determines whether the given context string matches this context.
  ParseContext$1.prototype.matchesContext = function matchesContext (context) {
        var this$1$1 = this;

      if (context.indexOf("|") > -1)
          { return context.split(/\s*\|\s*/).some(this.matchesContext, this); }
      var parts = context.split("/");
      var option = this.options.context;
      var useRoot = !this.isOpen && (!option || option.parent.type == this.nodes[0].type);
      var minDepth = -(option ? option.depth + 1 : 0) + (useRoot ? 0 : 1);
      var match = function (i, depth) {
          for (; i >= 0; i--) {
              var part = parts[i];
              if (part == "") {
                  if (i == parts.length - 1 || i == 0)
                      { continue; }
                  for (; depth >= minDepth; depth--)
                      { if (match(i - 1, depth))
                          { return true; } }
                  return false;
              }
              else {
                  var next = depth > 0 || (depth == 0 && useRoot) ? this$1$1.nodes[depth].type
                      : option && depth >= minDepth ? option.node(depth - minDepth).type
                          : null;
                  if (!next || (next.name != part && next.groups.indexOf(part) == -1))
                      { return false; }
                  depth--;
              }
          }
          return true;
      };
      return match(parts.length - 1, this.open);
  };
  ParseContext$1.prototype.textblockFromContext = function textblockFromContext () {
      var $context = this.options.context;
      if ($context)
          { for (var d = $context.depth; d >= 0; d--) {
              var deflt = $context.node(d).contentMatchAt($context.indexAfter(d)).defaultType;
              if (deflt && deflt.isTextblock && deflt.defaultAttrs)
                  { return deflt; }
          } }
      for (var name in this.parser.schema.nodes) {
          var type = this.parser.schema.nodes[name];
          if (type.isTextblock && type.defaultAttrs)
              { return type; }
      }
  };

Object.defineProperties( ParseContext$1.prototype, prototypeAccessors$10$2 );
// Kludge to work around directly nested list nodes produced by some
// tools and allowed by browsers to mean that the nested list is
// actually part of the list item above it.
function normalizeList(dom) {
    for (var child = dom.firstChild, prevItem = null; child; child = child.nextSibling) {
        var name = child.nodeType == 1 ? child.nodeName.toLowerCase() : null;
        if (name && listTags.hasOwnProperty(name) && prevItem) {
            prevItem.appendChild(child);
            child = prevItem;
        }
        else if (name == "li") {
            prevItem = child;
        }
        else if (name) {
            prevItem = null;
        }
    }
}
// Apply a CSS selector.
function matches(dom, selector) {
    return (dom.matches || dom.msMatchesSelector || dom.webkitMatchesSelector || dom.mozMatchesSelector).call(dom, selector);
}
function copy$1(obj) {
    var copy = {};
    for (var prop in obj)
        { copy[prop] = obj[prop]; }
    return copy;
}
// Used when finding a mark at the top level of a fragment parse.
// Checks whether it would be reasonable to apply a given mark type to
// a given node, by looking at the way the mark occurs in the schema.
function markMayApply(markType, nodeType) {
    var nodes = nodeType.schema.nodes;
    var loop = function ( name ) {
        var parent = nodes[name];
        if (!parent.allowsMarkType(markType))
            { return; }
        var seen = [], scan = function (match) {
            seen.push(match);
            for (var i = 0; i < match.edgeCount; i++) {
                var ref = match.edge(i);
                var type = ref.type;
                var next = ref.next;
                if (type == nodeType)
                    { return true; }
                if (seen.indexOf(next) < 0 && scan(next))
                    { return true; }
            }
        };
        if (scan(parent.contentMatch))
            { return { v: true }; }
    };

    for (var name in nodes) {
      var returned = loop( name );

      if ( returned ) return returned.v;
    }
}

/**
A DOM serializer knows how to convert ProseMirror nodes and
marks of various types to DOM nodes.
*/
var DOMSerializer = function DOMSerializer(
  /**
  The node serialization functions.
  */
  nodes, 
  /**
  The mark serialization functions.
  */
  marks) {
      this.nodes = nodes;
      this.marks = marks;
  };
  /**
  Serialize the content of this fragment to a DOM fragment. When
  not in the browser, the `document` option, containing a DOM
  document, should be passed so that the serializer can create
  nodes.
  */
  DOMSerializer.prototype.serializeFragment = function serializeFragment (fragment, options, target) {
        var this$1$1 = this;
        if ( options === void 0 ) options = {};

      if (!target)
          { target = doc$3(options).createDocumentFragment(); }
      var top = target, active = [];
      fragment.forEach(function (node) {
          if (active.length || node.marks.length) {
              var keep = 0, rendered = 0;
              while (keep < active.length && rendered < node.marks.length) {
                  var next = node.marks[rendered];
                  if (!this$1$1.marks[next.type.name]) {
                      rendered++;
                      continue;
                  }
                  if (!next.eq(active[keep][0]) || next.type.spec.spanning === false)
                      { break; }
                  keep++;
                  rendered++;
              }
              while (keep < active.length)
                  { top = active.pop()[1]; }
              while (rendered < node.marks.length) {
                  var add = node.marks[rendered++];
                  var markDOM = this$1$1.serializeMark(add, node.isInline, options);
                  if (markDOM) {
                      active.push([add, top]);
                      top.appendChild(markDOM.dom);
                      top = markDOM.contentDOM || markDOM.dom;
                  }
              }
          }
          top.appendChild(this$1$1.serializeNodeInner(node, options));
      });
      return target;
  };
  /**
  @internal
  */
  DOMSerializer.prototype.serializeNodeInner = function serializeNodeInner (node, options) {
      var ref = renderSpec(doc$3(options), this.nodes[node.type.name](node), null, node.attrs);
        var dom = ref.dom;
        var contentDOM = ref.contentDOM;
      if (contentDOM) {
          if (node.isLeaf)
              { throw new RangeError("Content hole not allowed in a leaf node spec"); }
          this.serializeFragment(node.content, options, contentDOM);
      }
      return dom;
  };
  /**
  Serialize this node to a DOM node. This can be useful when you
  need to serialize a part of a document, as opposed to the whole
  document. To serialize a whole document, use
  [`serializeFragment`](https://prosemirror.net/docs/ref/#model.DOMSerializer.serializeFragment) on
  its [content](https://prosemirror.net/docs/ref/#model.Node.content).
  */
  DOMSerializer.prototype.serializeNode = function serializeNode (node, options) {
        if ( options === void 0 ) options = {};

      var dom = this.serializeNodeInner(node, options);
      for (var i = node.marks.length - 1; i >= 0; i--) {
          var wrap = this.serializeMark(node.marks[i], node.isInline, options);
          if (wrap) {
              (wrap.contentDOM || wrap.dom).appendChild(dom);
              dom = wrap.dom;
          }
      }
      return dom;
  };
  /**
  @internal
  */
  DOMSerializer.prototype.serializeMark = function serializeMark (mark, inline, options) {
        if ( options === void 0 ) options = {};

      var toDOM = this.marks[mark.type.name];
      return toDOM && renderSpec(doc$3(options), toDOM(mark, inline), null, mark.attrs);
  };
  DOMSerializer.renderSpec = function renderSpec$1 (doc, structure, xmlNS, blockArraysIn) {
        if ( xmlNS === void 0 ) xmlNS = null;

      return renderSpec(doc, structure, xmlNS, blockArraysIn);
  };
  /**
  Build a serializer using the [`toDOM`](https://prosemirror.net/docs/ref/#model.NodeSpec.toDOM)
  properties in a schema's node and mark specs.
  */
  DOMSerializer.fromSchema = function fromSchema (schema) {
      return schema.cached.domSerializer ||
          (schema.cached.domSerializer = new DOMSerializer(this.nodesFromSchema(schema), this.marksFromSchema(schema)));
  };
  /**
  Gather the serializers in a schema's node specs into an object.
  This can be useful as a base to build a custom serializer from.
  */
  DOMSerializer.nodesFromSchema = function nodesFromSchema (schema) {
      var result = gatherToDOM(schema.nodes);
      if (!result.text)
          { result.text = function (node) { return node.text; }; }
      return result;
  };
  /**
  Gather the serializers in a schema's mark specs into an object.
  */
  DOMSerializer.marksFromSchema = function marksFromSchema (schema) {
      return gatherToDOM(schema.marks);
  };
function gatherToDOM(obj) {
    var result = {};
    for (var name in obj) {
        var toDOM = obj[name].spec.toDOM;
        if (toDOM)
            { result[name] = toDOM; }
    }
    return result;
}
function doc$3(options) {
    return options.document || window.document;
}
var suspiciousAttributeCache = new WeakMap();
function suspiciousAttributes(attrs) {
    var value = suspiciousAttributeCache.get(attrs);
    if (value === undefined)
        { suspiciousAttributeCache.set(attrs, value = suspiciousAttributesInner(attrs)); }
    return value;
}
function suspiciousAttributesInner(attrs) {
    var result = null;
    function scan(value) {
        if (value && typeof value == "object") {
            if (Array.isArray(value)) {
                if (typeof value[0] == "string") {
                    if (!result)
                        { result = []; }
                    result.push(value);
                }
                else {
                    for (var i = 0; i < value.length; i++)
                        { scan(value[i]); }
                }
            }
            else {
                for (var prop in value)
                    { scan(value[prop]); }
            }
        }
    }
    scan(attrs);
    return result;
}
function renderSpec(doc, structure, xmlNS, blockArraysIn) {
    if (typeof structure == "string")
        { return { dom: doc.createTextNode(structure) }; }
    if (structure.nodeType != null)
        { return { dom: structure }; }
    if (structure.dom && structure.dom.nodeType != null)
        { return structure; }
    var tagName = structure[0], suspicious;
    if (typeof tagName != "string")
        { throw new RangeError("Invalid array passed to renderSpec"); }
    if (blockArraysIn && (suspicious = suspiciousAttributes(blockArraysIn)) &&
        suspicious.indexOf(structure) > -1)
        { throw new RangeError("Using an array from an attribute object as a DOM spec. This may be an attempted cross site scripting attack."); }
    var space = tagName.indexOf(" ");
    if (space > 0) {
        xmlNS = tagName.slice(0, space);
        tagName = tagName.slice(space + 1);
    }
    var contentDOM;
    var dom = (xmlNS ? doc.createElementNS(xmlNS, tagName) : doc.createElement(tagName));
    var attrs = structure[1], start = 1;
    if (attrs && typeof attrs == "object" && attrs.nodeType == null && !Array.isArray(attrs)) {
        start = 2;
        for (var name in attrs)
            { if (attrs[name] != null) {
                var space$1 = name.indexOf(" ");
                if (space$1 > 0)
                    { dom.setAttributeNS(name.slice(0, space$1), name.slice(space$1 + 1), attrs[name]); }
                else
                    { dom.setAttribute(name, attrs[name]); }
            } }
    }
    for (var i = start; i < structure.length; i++) {
        var child = structure[i];
        if (child === 0) {
            if (i < structure.length - 1 || i > start)
                { throw new RangeError("Content hole must be the only child of its parent node"); }
            return { dom: dom, contentDOM: dom };
        }
        else {
            var ref = renderSpec(doc, child, xmlNS, blockArraysIn);
            var inner = ref.dom;
            var innerContent = ref.contentDOM;
            dom.appendChild(inner);
            if (innerContent) {
                if (contentDOM)
                    { throw new RangeError("Multiple content holes"); }
                contentDOM = innerContent;
            }
        }
    }
    return { dom: dom, contentDOM: contentDOM };
}var model=/*#__PURE__*/Object.freeze({__proto__:null,ContentMatch:ContentMatch,DOMParser:DOMParser,DOMSerializer:DOMSerializer,Fragment:Fragment,Mark:Mark,MarkType:MarkType,Node:Node$1,NodeRange:NodeRange,NodeType:NodeType$2,ReplaceError:ReplaceError,ResolvedPos:ResolvedPos,Schema:Schema,Slice:Slice});// Recovery values encode a range index and an offset. They are
// represented as numbers, because tons of them will be created when
// mapping, for example, a large number of decorations. The number's
// lower 16 bits provide the index, the remaining bits the offset.
//
// Note: We intentionally don't use bit shift operators to en- and
// decode these, since those clip to 32 bits, which we might in rare
// cases want to overflow. A 64-bit float can represent 48-bit
// integers precisely.
var lower16 = 0xffff;
var factor16 = Math.pow(2, 16);
function makeRecover(index, offset) { return index + offset * factor16; }
function recoverIndex(value) { return value & lower16; }
function recoverOffset(value) { return (value - (value & lower16)) / factor16; }
var DEL_BEFORE = 1, DEL_AFTER = 2, DEL_ACROSS = 4, DEL_SIDE = 8;
/**
An object representing a mapped position with extra
information.
*/
var MapResult = function MapResult(
/**
The mapped version of the position.
*/
pos, 
/**
@internal
*/
delInfo, 
/**
@internal
*/
recover) {
    this.pos = pos;
    this.delInfo = delInfo;
    this.recover = recover;
};

var prototypeAccessors$b = { deleted: { configurable: true },deletedBefore: { configurable: true },deletedAfter: { configurable: true },deletedAcross: { configurable: true } };
/**
Tells you whether the position was deleted, that is, whether the
step removed the token on the side queried (via the `assoc`)
argument from the document.
*/
prototypeAccessors$b.deleted.get = function () { return (this.delInfo & DEL_SIDE) > 0; };
/**
Tells you whether the token before the mapped position was deleted.
*/
prototypeAccessors$b.deletedBefore.get = function () { return (this.delInfo & (DEL_BEFORE | DEL_ACROSS)) > 0; };
/**
True when the token after the mapped position was deleted.
*/
prototypeAccessors$b.deletedAfter.get = function () { return (this.delInfo & (DEL_AFTER | DEL_ACROSS)) > 0; };
/**
Tells whether any of the steps mapped through deletes across the
position (including both the token before and after the
position).
*/
prototypeAccessors$b.deletedAcross.get = function () { return (this.delInfo & DEL_ACROSS) > 0; };

Object.defineProperties( MapResult.prototype, prototypeAccessors$b );
/**
A map describing the deletions and insertions made by a step, which
can be used to find the correspondence between positions in the
pre-step version of a document and the same position in the
post-step version.
*/
var StepMap = function StepMap(
/**
@internal
*/
ranges, 
/**
@internal
*/
inverted) {
    if ( inverted === void 0 ) inverted = false;

    this.ranges = ranges;
    this.inverted = inverted;
    if (!ranges.length && StepMap.empty)
        { return StepMap.empty; }
};
/**
@internal
*/
StepMap.prototype.recover = function recover (value) {
    var diff = 0, index = recoverIndex(value);
    if (!this.inverted)
        { for (var i = 0; i < index; i++)
            { diff += this.ranges[i * 3 + 2] - this.ranges[i * 3 + 1]; } }
    return this.ranges[index * 3] + diff + recoverOffset(value);
};
StepMap.prototype.mapResult = function mapResult (pos, assoc) {
    if ( assoc === void 0 ) assoc = 1;
 return this._map(pos, assoc, false); };
StepMap.prototype.map = function map (pos, assoc) {
    if ( assoc === void 0 ) assoc = 1;
 return this._map(pos, assoc, true); };
/**
@internal
*/
StepMap.prototype._map = function _map (pos, assoc, simple) {
    var diff = 0, oldIndex = this.inverted ? 2 : 1, newIndex = this.inverted ? 1 : 2;
    for (var i = 0; i < this.ranges.length; i += 3) {
        var start = this.ranges[i] - (this.inverted ? diff : 0);
        if (start > pos)
            { break; }
        var oldSize = this.ranges[i + oldIndex], newSize = this.ranges[i + newIndex], end = start + oldSize;
        if (pos <= end) {
            var side = !oldSize ? assoc : pos == start ? -1 : pos == end ? 1 : assoc;
            var result = start + diff + (side < 0 ? 0 : newSize);
            if (simple)
                { return result; }
            var recover = pos == (assoc < 0 ? start : end) ? null : makeRecover(i / 3, pos - start);
            var del = pos == start ? DEL_AFTER : pos == end ? DEL_BEFORE : DEL_ACROSS;
            if (assoc < 0 ? pos != start : pos != end)
                { del |= DEL_SIDE; }
            return new MapResult(result, del, recover);
        }
        diff += newSize - oldSize;
    }
    return simple ? pos + diff : new MapResult(pos + diff, 0, null);
};
/**
@internal
*/
StepMap.prototype.touches = function touches (pos, recover) {
    var diff = 0, index = recoverIndex(recover);
    var oldIndex = this.inverted ? 2 : 1, newIndex = this.inverted ? 1 : 2;
    for (var i = 0; i < this.ranges.length; i += 3) {
        var start = this.ranges[i] - (this.inverted ? diff : 0);
        if (start > pos)
            { break; }
        var oldSize = this.ranges[i + oldIndex], end = start + oldSize;
        if (pos <= end && i == index * 3)
            { return true; }
        diff += this.ranges[i + newIndex] - oldSize;
    }
    return false;
};
/**
Calls the given function on each of the changed ranges included in
this map.
*/
StepMap.prototype.forEach = function forEach (f) {
    var oldIndex = this.inverted ? 2 : 1, newIndex = this.inverted ? 1 : 2;
    for (var i = 0, diff = 0; i < this.ranges.length; i += 3) {
        var start = this.ranges[i], oldStart = start - (this.inverted ? diff : 0), newStart = start + (this.inverted ? 0 : diff);
        var oldSize = this.ranges[i + oldIndex], newSize = this.ranges[i + newIndex];
        f(oldStart, oldStart + oldSize, newStart, newStart + newSize);
        diff += newSize - oldSize;
    }
};
/**
Create an inverted version of this map. The result can be used to
map positions in the post-step document to the pre-step document.
*/
StepMap.prototype.invert = function invert () {
    return new StepMap(this.ranges, !this.inverted);
};
/**
@internal
*/
StepMap.prototype.toString = function toString () {
    return (this.inverted ? "-" : "") + JSON.stringify(this.ranges);
};
/**
Create a map that moves all positions by offset `n` (which may be
negative). This can be useful when applying steps meant for a
sub-document to a larger document, or vice-versa.
*/
StepMap.offset = function offset (n) {
    return n == 0 ? StepMap.empty : new StepMap(n < 0 ? [0, -n, 0] : [0, 0, n]);
};
/**
A StepMap that contains no changed ranges.
*/
StepMap.empty = new StepMap([]);
/**
A mapping represents a pipeline of zero or more [step
maps](https://prosemirror.net/docs/ref/#transform.StepMap). It has special provisions for losslessly
handling mapping positions through a series of steps in which some
steps are inverted versions of earlier steps. (This comes up when
‘[rebasing](/docs/guide/#transform.rebasing)’ steps for
collaboration or history management.)
*/
var Mapping = function Mapping(
/**
The step maps in this mapping.
*/
maps, 
/**
@internal
*/
mirror, 
/**
The starting position in the `maps` array, used when `map` or
`mapResult` is called.
*/
from, 
/**
The end position in the `maps` array.
*/
to) {
    if ( maps === void 0 ) maps = [];
    if ( from === void 0 ) from = 0;
    if ( to === void 0 ) to = maps.length;

    this.maps = maps;
    this.mirror = mirror;
    this.from = from;
    this.to = to;
};
/**
Create a mapping that maps only through a part of this one.
*/
Mapping.prototype.slice = function slice (from, to) {
        if ( from === void 0 ) from = 0;
        if ( to === void 0 ) to = this.maps.length;

    return new Mapping(this.maps, this.mirror, from, to);
};
/**
@internal
*/
Mapping.prototype.copy = function copy () {
    return new Mapping(this.maps.slice(), this.mirror && this.mirror.slice(), this.from, this.to);
};
/**
Add a step map to the end of this mapping. If `mirrors` is
given, it should be the index of the step map that is the mirror
image of this one.
*/
Mapping.prototype.appendMap = function appendMap (map, mirrors) {
    this.to = this.maps.push(map);
    if (mirrors != null)
        { this.setMirror(this.maps.length - 1, mirrors); }
};
/**
Add all the step maps in a given mapping to this one (preserving
mirroring information).
*/
Mapping.prototype.appendMapping = function appendMapping (mapping) {
    for (var i = 0, startSize = this.maps.length; i < mapping.maps.length; i++) {
        var mirr = mapping.getMirror(i);
        this.appendMap(mapping.maps[i], mirr != null && mirr < i ? startSize + mirr : undefined);
    }
};
/**
Finds the offset of the step map that mirrors the map at the
given offset, in this mapping (as per the second argument to
`appendMap`).
*/
Mapping.prototype.getMirror = function getMirror (n) {
    if (this.mirror)
        { for (var i = 0; i < this.mirror.length; i++)
            { if (this.mirror[i] == n)
                { return this.mirror[i + (i % 2 ? -1 : 1)]; } } }
};
/**
@internal
*/
Mapping.prototype.setMirror = function setMirror (n, m) {
    if (!this.mirror)
        { this.mirror = []; }
    this.mirror.push(n, m);
};
/**
Append the inverse of the given mapping to this one.
*/
Mapping.prototype.appendMappingInverted = function appendMappingInverted (mapping) {
    for (var i = mapping.maps.length - 1, totalSize = this.maps.length + mapping.maps.length; i >= 0; i--) {
        var mirr = mapping.getMirror(i);
        this.appendMap(mapping.maps[i].invert(), mirr != null && mirr > i ? totalSize - mirr - 1 : undefined);
    }
};
/**
Create an inverted version of this mapping.
*/
Mapping.prototype.invert = function invert () {
    var inverse = new Mapping;
    inverse.appendMappingInverted(this);
    return inverse;
};
/**
Map a position through this mapping.
*/
Mapping.prototype.map = function map (pos, assoc) {
        if ( assoc === void 0 ) assoc = 1;

    if (this.mirror)
        { return this._map(pos, assoc, true); }
    for (var i = this.from; i < this.to; i++)
        { pos = this.maps[i].map(pos, assoc); }
    return pos;
};
/**
Map a position through this mapping, returning a mapping
result.
*/
Mapping.prototype.mapResult = function mapResult (pos, assoc) {
    if ( assoc === void 0 ) assoc = 1;
 return this._map(pos, assoc, false); };
/**
@internal
*/
Mapping.prototype._map = function _map (pos, assoc, simple) {
    var delInfo = 0;
    for (var i = this.from; i < this.to; i++) {
        var map = this.maps[i], result = map.mapResult(pos, assoc);
        if (result.recover != null) {
            var corr = this.getMirror(i);
            if (corr != null && corr > i && corr < this.to) {
                i = corr;
                pos = this.maps[corr].recover(result.recover);
                continue;
            }
        }
        delInfo |= result.delInfo;
        pos = result.pos;
    }
    return simple ? pos : new MapResult(pos, delInfo, null);
};

var stepsByID = Object.create(null);
/**
A step object represents an atomic change. It generally applies
only to the document it was created for, since the positions
stored in it will only make sense for that document.

New steps are defined by creating classes that extend `Step`,
overriding the `apply`, `invert`, `map`, `getMap` and `fromJSON`
methods, and registering your class with a unique
JSON-serialization identifier using
[`Step.jsonID`](https://prosemirror.net/docs/ref/#transform.Step^jsonID).
*/
var Step = function Step () {};

Step.prototype.getMap = function getMap () { return StepMap.empty; };
/**
Try to merge this step with another one, to be applied directly
after it. Returns the merged step when possible, null if the
steps can't be merged.
*/
Step.prototype.merge = function merge (other) { return null; };
/**
Deserialize a step from its JSON representation. Will call
through to the step class' own implementation of this method.
*/
Step.fromJSON = function fromJSON (schema, json) {
    if (!json || !json.stepType)
        { throw new RangeError("Invalid input for Step.fromJSON"); }
    var type = stepsByID[json.stepType];
    if (!type)
        { throw new RangeError(("No step type " + (json.stepType) + " defined")); }
    return type.fromJSON(schema, json);
};
/**
To be able to serialize steps to JSON, each step needs a string
ID to attach to its JSON representation. Use this method to
register an ID for your step classes. Try to pick something
that's unlikely to clash with steps from other modules.
*/
Step.jsonID = function jsonID (id, stepClass) {
    if (id in stepsByID)
        { throw new RangeError("Duplicate use of step JSON ID " + id); }
    stepsByID[id] = stepClass;
    stepClass.prototype.jsonID = id;
    return stepClass;
};
/**
The result of [applying](https://prosemirror.net/docs/ref/#transform.Step.apply) a step. Contains either a
new document or a failure value.
*/
var StepResult = function StepResult(
/**
The transformed document, if successful.
*/
doc, 
/**
The failure message, if unsuccessful.
*/
failed) {
    this.doc = doc;
    this.failed = failed;
};
/**
Create a successful step result.
*/
StepResult.ok = function ok (doc) { return new StepResult(doc, null); };
/**
Create a failed step result.
*/
StepResult.fail = function fail (message) { return new StepResult(null, message); };
/**
Call [`Node.replace`](https://prosemirror.net/docs/ref/#model.Node.replace) with the given
arguments. Create a successful result if it succeeds, and a
failed one if it throws a `ReplaceError`.
*/
StepResult.fromReplace = function fromReplace (doc, from, to, slice) {
    try {
        return StepResult.ok(doc.replace(from, to, slice));
    }
    catch (e) {
        if (e instanceof ReplaceError)
            { return StepResult.fail(e.message); }
        throw e;
    }
};

function mapFragment(fragment, f, parent) {
    var mapped = [];
    for (var i = 0; i < fragment.childCount; i++) {
        var child = fragment.child(i);
        if (child.content.size)
            { child = child.copy(mapFragment(child.content, f, child)); }
        if (child.isInline)
            { child = f(child, parent, i); }
        mapped.push(child);
    }
    return Fragment.fromArray(mapped);
}
/**
Add a mark to all inline content between two positions.
*/
var AddMarkStep = /*@__PURE__*/(function (Step) {
    function AddMarkStep(
    /**
    The start of the marked range.
    */
    from, 
    /**
    The end of the marked range.
    */
    to, 
    /**
    The mark to add.
    */
    mark) {
        Step.call(this);
        this.from = from;
        this.to = to;
        this.mark = mark;
    }

    if ( Step ) AddMarkStep.__proto__ = Step;
    AddMarkStep.prototype = Object.create( Step && Step.prototype );
    AddMarkStep.prototype.constructor = AddMarkStep;
    AddMarkStep.prototype.apply = function apply (doc) {
        var this$1$1 = this;

        var oldSlice = doc.slice(this.from, this.to), $from = doc.resolve(this.from);
        var parent = $from.node($from.sharedDepth(this.to));
        var slice = new Slice(mapFragment(oldSlice.content, function (node, parent) {
            if (!node.isAtom || !parent.type.allowsMarkType(this$1$1.mark.type))
                { return node; }
            return node.mark(this$1$1.mark.addToSet(node.marks));
        }, parent), oldSlice.openStart, oldSlice.openEnd);
        return StepResult.fromReplace(doc, this.from, this.to, slice);
    };
    AddMarkStep.prototype.invert = function invert () {
        return new RemoveMarkStep(this.from, this.to, this.mark);
    };
    AddMarkStep.prototype.map = function map (mapping) {
        var from = mapping.mapResult(this.from, 1), to = mapping.mapResult(this.to, -1);
        if (from.deleted && to.deleted || from.pos >= to.pos)
            { return null; }
        return new AddMarkStep(from.pos, to.pos, this.mark);
    };
    AddMarkStep.prototype.merge = function merge (other) {
        if (other instanceof AddMarkStep &&
            other.mark.eq(this.mark) &&
            this.from <= other.to && this.to >= other.from)
            { return new AddMarkStep(Math.min(this.from, other.from), Math.max(this.to, other.to), this.mark); }
        return null;
    };
    AddMarkStep.prototype.toJSON = function toJSON () {
        return { stepType: "addMark", mark: this.mark.toJSON(),
            from: this.from, to: this.to };
    };
    /**
    @internal
    */
    AddMarkStep.fromJSON = function fromJSON (schema, json) {
        if (typeof json.from != "number" || typeof json.to != "number")
            { throw new RangeError("Invalid input for AddMarkStep.fromJSON"); }
        return new AddMarkStep(json.from, json.to, schema.markFromJSON(json.mark));
    };

    return AddMarkStep;
}(Step));
Step.jsonID("addMark", AddMarkStep);
/**
Remove a mark from all inline content between two positions.
*/
var RemoveMarkStep = /*@__PURE__*/(function (Step) {
    function RemoveMarkStep(
    /**
    The start of the unmarked range.
    */
    from, 
    /**
    The end of the unmarked range.
    */
    to, 
    /**
    The mark to remove.
    */
    mark) {
        Step.call(this);
        this.from = from;
        this.to = to;
        this.mark = mark;
    }

    if ( Step ) RemoveMarkStep.__proto__ = Step;
    RemoveMarkStep.prototype = Object.create( Step && Step.prototype );
    RemoveMarkStep.prototype.constructor = RemoveMarkStep;
    RemoveMarkStep.prototype.apply = function apply (doc) {
        var this$1$1 = this;

        var oldSlice = doc.slice(this.from, this.to);
        var slice = new Slice(mapFragment(oldSlice.content, function (node) {
            return node.mark(this$1$1.mark.removeFromSet(node.marks));
        }, doc), oldSlice.openStart, oldSlice.openEnd);
        return StepResult.fromReplace(doc, this.from, this.to, slice);
    };
    RemoveMarkStep.prototype.invert = function invert () {
        return new AddMarkStep(this.from, this.to, this.mark);
    };
    RemoveMarkStep.prototype.map = function map (mapping) {
        var from = mapping.mapResult(this.from, 1), to = mapping.mapResult(this.to, -1);
        if (from.deleted && to.deleted || from.pos >= to.pos)
            { return null; }
        return new RemoveMarkStep(from.pos, to.pos, this.mark);
    };
    RemoveMarkStep.prototype.merge = function merge (other) {
        if (other instanceof RemoveMarkStep &&
            other.mark.eq(this.mark) &&
            this.from <= other.to && this.to >= other.from)
            { return new RemoveMarkStep(Math.min(this.from, other.from), Math.max(this.to, other.to), this.mark); }
        return null;
    };
    RemoveMarkStep.prototype.toJSON = function toJSON () {
        return { stepType: "removeMark", mark: this.mark.toJSON(),
            from: this.from, to: this.to };
    };
    /**
    @internal
    */
    RemoveMarkStep.fromJSON = function fromJSON (schema, json) {
        if (typeof json.from != "number" || typeof json.to != "number")
            { throw new RangeError("Invalid input for RemoveMarkStep.fromJSON"); }
        return new RemoveMarkStep(json.from, json.to, schema.markFromJSON(json.mark));
    };

    return RemoveMarkStep;
}(Step));
Step.jsonID("removeMark", RemoveMarkStep);
/**
Add a mark to a specific node.
*/
var AddNodeMarkStep = /*@__PURE__*/(function (Step) {
    function AddNodeMarkStep(
    /**
    The position of the target node.
    */
    pos, 
    /**
    The mark to add.
    */
    mark) {
        Step.call(this);
        this.pos = pos;
        this.mark = mark;
    }

    if ( Step ) AddNodeMarkStep.__proto__ = Step;
    AddNodeMarkStep.prototype = Object.create( Step && Step.prototype );
    AddNodeMarkStep.prototype.constructor = AddNodeMarkStep;
    AddNodeMarkStep.prototype.apply = function apply (doc) {
        var node = doc.nodeAt(this.pos);
        if (!node)
            { return StepResult.fail("No node at mark step's position"); }
        var updated = node.type.create(node.attrs, null, this.mark.addToSet(node.marks));
        return StepResult.fromReplace(doc, this.pos, this.pos + 1, new Slice(Fragment.from(updated), 0, node.isLeaf ? 0 : 1));
    };
    AddNodeMarkStep.prototype.invert = function invert (doc) {
        var node = doc.nodeAt(this.pos);
        if (node) {
            var newSet = this.mark.addToSet(node.marks);
            if (newSet.length == node.marks.length) {
                for (var i = 0; i < node.marks.length; i++)
                    { if (!node.marks[i].isInSet(newSet))
                        { return new AddNodeMarkStep(this.pos, node.marks[i]); } }
                return new AddNodeMarkStep(this.pos, this.mark);
            }
        }
        return new RemoveNodeMarkStep(this.pos, this.mark);
    };
    AddNodeMarkStep.prototype.map = function map (mapping) {
        var pos = mapping.mapResult(this.pos, 1);
        return pos.deletedAfter ? null : new AddNodeMarkStep(pos.pos, this.mark);
    };
    AddNodeMarkStep.prototype.toJSON = function toJSON () {
        return { stepType: "addNodeMark", pos: this.pos, mark: this.mark.toJSON() };
    };
    /**
    @internal
    */
    AddNodeMarkStep.fromJSON = function fromJSON (schema, json) {
        if (typeof json.pos != "number")
            { throw new RangeError("Invalid input for AddNodeMarkStep.fromJSON"); }
        return new AddNodeMarkStep(json.pos, schema.markFromJSON(json.mark));
    };

    return AddNodeMarkStep;
}(Step));
Step.jsonID("addNodeMark", AddNodeMarkStep);
/**
Remove a mark from a specific node.
*/
var RemoveNodeMarkStep = /*@__PURE__*/(function (Step) {
    function RemoveNodeMarkStep(
    /**
    The position of the target node.
    */
    pos, 
    /**
    The mark to remove.
    */
    mark) {
        Step.call(this);
        this.pos = pos;
        this.mark = mark;
    }

    if ( Step ) RemoveNodeMarkStep.__proto__ = Step;
    RemoveNodeMarkStep.prototype = Object.create( Step && Step.prototype );
    RemoveNodeMarkStep.prototype.constructor = RemoveNodeMarkStep;
    RemoveNodeMarkStep.prototype.apply = function apply (doc) {
        var node = doc.nodeAt(this.pos);
        if (!node)
            { return StepResult.fail("No node at mark step's position"); }
        var updated = node.type.create(node.attrs, null, this.mark.removeFromSet(node.marks));
        return StepResult.fromReplace(doc, this.pos, this.pos + 1, new Slice(Fragment.from(updated), 0, node.isLeaf ? 0 : 1));
    };
    RemoveNodeMarkStep.prototype.invert = function invert (doc) {
        var node = doc.nodeAt(this.pos);
        if (!node || !this.mark.isInSet(node.marks))
            { return this; }
        return new AddNodeMarkStep(this.pos, this.mark);
    };
    RemoveNodeMarkStep.prototype.map = function map (mapping) {
        var pos = mapping.mapResult(this.pos, 1);
        return pos.deletedAfter ? null : new RemoveNodeMarkStep(pos.pos, this.mark);
    };
    RemoveNodeMarkStep.prototype.toJSON = function toJSON () {
        return { stepType: "removeNodeMark", pos: this.pos, mark: this.mark.toJSON() };
    };
    /**
    @internal
    */
    RemoveNodeMarkStep.fromJSON = function fromJSON (schema, json) {
        if (typeof json.pos != "number")
            { throw new RangeError("Invalid input for RemoveNodeMarkStep.fromJSON"); }
        return new RemoveNodeMarkStep(json.pos, schema.markFromJSON(json.mark));
    };

    return RemoveNodeMarkStep;
}(Step));
Step.jsonID("removeNodeMark", RemoveNodeMarkStep);

/**
Replace a part of the document with a slice of new content.
*/
var ReplaceStep = /*@__PURE__*/(function (Step) {
    function ReplaceStep(
    /**
    The start position of the replaced range.
    */
    from, 
    /**
    The end position of the replaced range.
    */
    to, 
    /**
    The slice to insert.
    */
    slice, 
    /**
    @internal
    */
    structure) {
        if ( structure === void 0 ) structure = false;

        Step.call(this);
        this.from = from;
        this.to = to;
        this.slice = slice;
        this.structure = structure;
    }

    if ( Step ) ReplaceStep.__proto__ = Step;
    ReplaceStep.prototype = Object.create( Step && Step.prototype );
    ReplaceStep.prototype.constructor = ReplaceStep;
    ReplaceStep.prototype.apply = function apply (doc) {
        if (this.structure && contentBetween(doc, this.from, this.to))
            { return StepResult.fail("Structure replace would overwrite content"); }
        return StepResult.fromReplace(doc, this.from, this.to, this.slice);
    };
    ReplaceStep.prototype.getMap = function getMap () {
        return new StepMap([this.from, this.to - this.from, this.slice.size]);
    };
    ReplaceStep.prototype.invert = function invert (doc) {
        return new ReplaceStep(this.from, this.from + this.slice.size, doc.slice(this.from, this.to));
    };
    ReplaceStep.prototype.map = function map (mapping) {
        var from = mapping.mapResult(this.from, 1), to = mapping.mapResult(this.to, -1);
        if (from.deletedAcross && to.deletedAcross)
            { return null; }
        return new ReplaceStep(from.pos, Math.max(from.pos, to.pos), this.slice);
    };
    ReplaceStep.prototype.merge = function merge (other) {
        if (!(other instanceof ReplaceStep) || other.structure || this.structure)
            { return null; }
        if (this.from + this.slice.size == other.from && !this.slice.openEnd && !other.slice.openStart) {
            var slice = this.slice.size + other.slice.size == 0 ? Slice.empty
                : new Slice(this.slice.content.append(other.slice.content), this.slice.openStart, other.slice.openEnd);
            return new ReplaceStep(this.from, this.to + (other.to - other.from), slice, this.structure);
        }
        else if (other.to == this.from && !this.slice.openStart && !other.slice.openEnd) {
            var slice$1 = this.slice.size + other.slice.size == 0 ? Slice.empty
                : new Slice(other.slice.content.append(this.slice.content), other.slice.openStart, this.slice.openEnd);
            return new ReplaceStep(other.from, this.to, slice$1, this.structure);
        }
        else {
            return null;
        }
    };
    ReplaceStep.prototype.toJSON = function toJSON () {
        var json = { stepType: "replace", from: this.from, to: this.to };
        if (this.slice.size)
            { json.slice = this.slice.toJSON(); }
        if (this.structure)
            { json.structure = true; }
        return json;
    };
    /**
    @internal
    */
    ReplaceStep.fromJSON = function fromJSON (schema, json) {
        if (typeof json.from != "number" || typeof json.to != "number")
            { throw new RangeError("Invalid input for ReplaceStep.fromJSON"); }
        return new ReplaceStep(json.from, json.to, Slice.fromJSON(schema, json.slice), !!json.structure);
    };

    return ReplaceStep;
}(Step));
Step.jsonID("replace", ReplaceStep);
/**
Replace a part of the document with a slice of content, but
preserve a range of the replaced content by moving it into the
slice.
*/
var ReplaceAroundStep = /*@__PURE__*/(function (Step) {
    function ReplaceAroundStep(
    /**
    The start position of the replaced range.
    */
    from, 
    /**
    The end position of the replaced range.
    */
    to, 
    /**
    The start of preserved range.
    */
    gapFrom, 
    /**
    The end of preserved range.
    */
    gapTo, 
    /**
    The slice to insert.
    */
    slice, 
    /**
    The position in the slice where the preserved range should be
    inserted.
    */
    insert, 
    /**
    @internal
    */
    structure) {
        if ( structure === void 0 ) structure = false;

        Step.call(this);
        this.from = from;
        this.to = to;
        this.gapFrom = gapFrom;
        this.gapTo = gapTo;
        this.slice = slice;
        this.insert = insert;
        this.structure = structure;
    }

    if ( Step ) ReplaceAroundStep.__proto__ = Step;
    ReplaceAroundStep.prototype = Object.create( Step && Step.prototype );
    ReplaceAroundStep.prototype.constructor = ReplaceAroundStep;
    ReplaceAroundStep.prototype.apply = function apply (doc) {
        if (this.structure && (contentBetween(doc, this.from, this.gapFrom) ||
            contentBetween(doc, this.gapTo, this.to)))
            { return StepResult.fail("Structure gap-replace would overwrite content"); }
        var gap = doc.slice(this.gapFrom, this.gapTo);
        if (gap.openStart || gap.openEnd)
            { return StepResult.fail("Gap is not a flat range"); }
        var inserted = this.slice.insertAt(this.insert, gap.content);
        if (!inserted)
            { return StepResult.fail("Content does not fit in gap"); }
        return StepResult.fromReplace(doc, this.from, this.to, inserted);
    };
    ReplaceAroundStep.prototype.getMap = function getMap () {
        return new StepMap([this.from, this.gapFrom - this.from, this.insert,
            this.gapTo, this.to - this.gapTo, this.slice.size - this.insert]);
    };
    ReplaceAroundStep.prototype.invert = function invert (doc) {
        var gap = this.gapTo - this.gapFrom;
        return new ReplaceAroundStep(this.from, this.from + this.slice.size + gap, this.from + this.insert, this.from + this.insert + gap, doc.slice(this.from, this.to).removeBetween(this.gapFrom - this.from, this.gapTo - this.from), this.gapFrom - this.from, this.structure);
    };
    ReplaceAroundStep.prototype.map = function map (mapping) {
        var from = mapping.mapResult(this.from, 1), to = mapping.mapResult(this.to, -1);
        var gapFrom = this.from == this.gapFrom ? from.pos : mapping.map(this.gapFrom, -1);
        var gapTo = this.to == this.gapTo ? to.pos : mapping.map(this.gapTo, 1);
        if ((from.deletedAcross && to.deletedAcross) || gapFrom < from.pos || gapTo > to.pos)
            { return null; }
        return new ReplaceAroundStep(from.pos, to.pos, gapFrom, gapTo, this.slice, this.insert, this.structure);
    };
    ReplaceAroundStep.prototype.toJSON = function toJSON () {
        var json = { stepType: "replaceAround", from: this.from, to: this.to,
            gapFrom: this.gapFrom, gapTo: this.gapTo, insert: this.insert };
        if (this.slice.size)
            { json.slice = this.slice.toJSON(); }
        if (this.structure)
            { json.structure = true; }
        return json;
    };
    /**
    @internal
    */
    ReplaceAroundStep.fromJSON = function fromJSON (schema, json) {
        if (typeof json.from != "number" || typeof json.to != "number" ||
            typeof json.gapFrom != "number" || typeof json.gapTo != "number" || typeof json.insert != "number")
            { throw new RangeError("Invalid input for ReplaceAroundStep.fromJSON"); }
        return new ReplaceAroundStep(json.from, json.to, json.gapFrom, json.gapTo, Slice.fromJSON(schema, json.slice), json.insert, !!json.structure);
    };

    return ReplaceAroundStep;
}(Step));
Step.jsonID("replaceAround", ReplaceAroundStep);
function contentBetween(doc, from, to) {
    var $from = doc.resolve(from), dist = to - from, depth = $from.depth;
    while (dist > 0 && depth > 0 && $from.indexAfter(depth) == $from.node(depth).childCount) {
        depth--;
        dist--;
    }
    if (dist > 0) {
        var next = $from.node(depth).maybeChild($from.indexAfter(depth));
        while (dist > 0) {
            if (!next || next.isLeaf)
                { return true; }
            next = next.firstChild;
            dist--;
        }
    }
    return false;
}

function addMark(tr, from, to, mark) {
    var removed = [], added = [];
    var removing, adding;
    tr.doc.nodesBetween(from, to, function (node, pos, parent) {
        if (!node.isInline)
            { return; }
        var marks = node.marks;
        if (!mark.isInSet(marks) && parent.type.allowsMarkType(mark.type)) {
            var start = Math.max(pos, from), end = Math.min(pos + node.nodeSize, to);
            var newSet = mark.addToSet(marks);
            for (var i = 0; i < marks.length; i++) {
                if (!marks[i].isInSet(newSet)) {
                    if (removing && removing.to == start && removing.mark.eq(marks[i]))
                        { removing.to = end; }
                    else
                        { removed.push(removing = new RemoveMarkStep(start, end, marks[i])); }
                }
            }
            if (adding && adding.to == start)
                { adding.to = end; }
            else
                { added.push(adding = new AddMarkStep(start, end, mark)); }
        }
    });
    removed.forEach(function (s) { return tr.step(s); });
    added.forEach(function (s) { return tr.step(s); });
}
function removeMark$1(tr, from, to, mark) {
    var matched = [], step = 0;
    tr.doc.nodesBetween(from, to, function (node, pos) {
        if (!node.isInline)
            { return; }
        step++;
        var toRemove = null;
        if (mark instanceof MarkType) {
            var set = node.marks, found;
            while (found = mark.isInSet(set)) {
                (toRemove || (toRemove = [])).push(found);
                set = found.removeFromSet(set);
            }
        }
        else if (mark) {
            if (mark.isInSet(node.marks))
                { toRemove = [mark]; }
        }
        else {
            toRemove = node.marks;
        }
        if (toRemove && toRemove.length) {
            var end = Math.min(pos + node.nodeSize, to);
            for (var i = 0; i < toRemove.length; i++) {
                var style = toRemove[i], found$1 = (void 0);
                for (var j = 0; j < matched.length; j++) {
                    var m = matched[j];
                    if (m.step == step - 1 && style.eq(matched[j].style))
                        { found$1 = m; }
                }
                if (found$1) {
                    found$1.to = end;
                    found$1.step = step;
                }
                else {
                    matched.push({ style: style, from: Math.max(pos, from), to: end, step: step });
                }
            }
        }
    });
    matched.forEach(function (m) { return tr.step(new RemoveMarkStep(m.from, m.to, m.style)); });
}
function clearIncompatible(tr, pos, parentType, match, clearNewlines) {
    if ( match === void 0 ) match = parentType.contentMatch;
    if ( clearNewlines === void 0 ) clearNewlines = true;

    var node = tr.doc.nodeAt(pos);
    var replSteps = [], cur = pos + 1;
    for (var i = 0; i < node.childCount; i++) {
        var child = node.child(i), end = cur + child.nodeSize;
        var allowed = match.matchType(child.type);
        if (!allowed) {
            replSteps.push(new ReplaceStep(cur, end, Slice.empty));
        }
        else {
            match = allowed;
            for (var j = 0; j < child.marks.length; j++)
                { if (!parentType.allowsMarkType(child.marks[j].type))
                    { tr.step(new RemoveMarkStep(cur, end, child.marks[j])); } }
            if (clearNewlines && child.isText && parentType.whitespace != "pre") {
                var m = (void 0), newline = /\r?\n|\r/g, slice = (void 0);
                while (m = newline.exec(child.text)) {
                    if (!slice)
                        { slice = new Slice(Fragment.from(parentType.schema.text(" ", parentType.allowedMarks(child.marks))), 0, 0); }
                    replSteps.push(new ReplaceStep(cur + m.index, cur + m.index + m[0].length, slice));
                }
            }
        }
        cur = end;
    }
    if (!match.validEnd) {
        var fill = match.fillBefore(Fragment.empty, true);
        tr.replace(cur, cur, new Slice(fill, 0, 0));
    }
    for (var i$1 = replSteps.length - 1; i$1 >= 0; i$1--)
        { tr.step(replSteps[i$1]); }
}

function canCut(node, start, end) {
    return (start == 0 || node.canReplace(start, node.childCount)) &&
        (end == node.childCount || node.canReplace(0, end));
}
/**
Try to find a target depth to which the content in the given range
can be lifted. Will not go across
[isolating](https://prosemirror.net/docs/ref/#model.NodeSpec.isolating) parent nodes.
*/
function liftTarget(range) {
    var parent = range.parent;
    var content = parent.content.cutByIndex(range.startIndex, range.endIndex);
    for (var depth = range.depth;; --depth) {
        var node = range.$from.node(depth);
        var index = range.$from.index(depth), endIndex = range.$to.indexAfter(depth);
        if (depth < range.depth && node.canReplace(index, endIndex, content))
            { return depth; }
        if (depth == 0 || node.type.spec.isolating || !canCut(node, index, endIndex))
            { break; }
    }
    return null;
}
function lift$2(tr, range, target) {
    var $from = range.$from;
    var $to = range.$to;
    var depth = range.depth;
    var gapStart = $from.before(depth + 1), gapEnd = $to.after(depth + 1);
    var start = gapStart, end = gapEnd;
    var before = Fragment.empty, openStart = 0;
    for (var d = depth, splitting = false; d > target; d--)
        { if (splitting || $from.index(d) > 0) {
            splitting = true;
            before = Fragment.from($from.node(d).copy(before));
            openStart++;
        }
        else {
            start--;
        } }
    var after = Fragment.empty, openEnd = 0;
    for (var d$1 = depth, splitting$1 = false; d$1 > target; d$1--)
        { if (splitting$1 || $to.after(d$1 + 1) < $to.end(d$1)) {
            splitting$1 = true;
            after = Fragment.from($to.node(d$1).copy(after));
            openEnd++;
        }
        else {
            end++;
        } }
    tr.step(new ReplaceAroundStep(start, end, gapStart, gapEnd, new Slice(before.append(after), openStart, openEnd), before.size - openStart, true));
}
/**
Try to find a valid way to wrap the content in the given range in a
node of the given type. May introduce extra nodes around and inside
the wrapper node, if necessary. Returns null if no valid wrapping
could be found. When `innerRange` is given, that range's content is
used as the content to fit into the wrapping, instead of the
content of `range`.
*/
function findWrapping(range, nodeType, attrs, innerRange) {
    if ( attrs === void 0 ) attrs = null;
    if ( innerRange === void 0 ) innerRange = range;

    var around = findWrappingOutside(range, nodeType);
    var inner = around && findWrappingInside(innerRange, nodeType);
    if (!inner)
        { return null; }
    return around.map(withAttrs)
        .concat({ type: nodeType, attrs: attrs }).concat(inner.map(withAttrs));
}
function withAttrs(type) { return { type: type, attrs: null }; }
function findWrappingOutside(range, type) {
    var parent = range.parent;
    var startIndex = range.startIndex;
    var endIndex = range.endIndex;
    var around = parent.contentMatchAt(startIndex).findWrapping(type);
    if (!around)
        { return null; }
    var outer = around.length ? around[0] : type;
    return parent.canReplaceWith(startIndex, endIndex, outer) ? around : null;
}
function findWrappingInside(range, type) {
    var parent = range.parent;
    var startIndex = range.startIndex;
    var endIndex = range.endIndex;
    var inner = parent.child(startIndex);
    var inside = type.contentMatch.findWrapping(inner.type);
    if (!inside)
        { return null; }
    var lastType = inside.length ? inside[inside.length - 1] : type;
    var innerMatch = lastType.contentMatch;
    for (var i = startIndex; innerMatch && i < endIndex; i++)
        { innerMatch = innerMatch.matchType(parent.child(i).type); }
    if (!innerMatch || !innerMatch.validEnd)
        { return null; }
    return inside;
}
function wrap(tr, range, wrappers) {
    var content = Fragment.empty;
    for (var i = wrappers.length - 1; i >= 0; i--) {
        if (content.size) {
            var match = wrappers[i].type.contentMatch.matchFragment(content);
            if (!match || !match.validEnd)
                { throw new RangeError("Wrapper type given to Transform.wrap does not form valid content of its parent wrapper"); }
        }
        content = Fragment.from(wrappers[i].type.create(wrappers[i].attrs, content));
    }
    var start = range.start, end = range.end;
    tr.step(new ReplaceAroundStep(start, end, start, end, new Slice(content, 0, 0), wrappers.length, true));
}
function setBlockType$1(tr, from, to, type, attrs) {
    if (!type.isTextblock)
        { throw new RangeError("Type given to setBlockType should be a textblock"); }
    var mapFrom = tr.steps.length;
    tr.doc.nodesBetween(from, to, function (node, pos) {
        var attrsHere = typeof attrs == "function" ? attrs(node) : attrs;
        if (node.isTextblock && !node.hasMarkup(type, attrsHere) &&
            canChangeType(tr.doc, tr.mapping.slice(mapFrom).map(pos), type)) {
            var convertNewlines = null;
            if (type.schema.linebreakReplacement) {
                var pre = type.whitespace == "pre", supportLinebreak = !!type.contentMatch.matchType(type.schema.linebreakReplacement);
                if (pre && !supportLinebreak)
                    { convertNewlines = false; }
                else if (!pre && supportLinebreak)
                    { convertNewlines = true; }
            }
            // Ensure all markup that isn't allowed in the new node type is cleared
            if (convertNewlines === false)
                { replaceLinebreaks(tr, node, pos, mapFrom); }
            clearIncompatible(tr, tr.mapping.slice(mapFrom).map(pos, 1), type, undefined, convertNewlines === null);
            var mapping = tr.mapping.slice(mapFrom);
            var startM = mapping.map(pos, 1), endM = mapping.map(pos + node.nodeSize, 1);
            tr.step(new ReplaceAroundStep(startM, endM, startM + 1, endM - 1, new Slice(Fragment.from(type.create(attrsHere, null, node.marks)), 0, 0), 1, true));
            if (convertNewlines === true)
                { replaceNewlines(tr, node, pos, mapFrom); }
            return false;
        }
    });
}
function replaceNewlines(tr, node, pos, mapFrom) {
    node.forEach(function (child, offset) {
        if (child.isText) {
            var m, newline = /\r?\n|\r/g;
            while (m = newline.exec(child.text)) {
                var start = tr.mapping.slice(mapFrom).map(pos + 1 + offset + m.index);
                tr.replaceWith(start, start + 1, node.type.schema.linebreakReplacement.create());
            }
        }
    });
}
function replaceLinebreaks(tr, node, pos, mapFrom) {
    node.forEach(function (child, offset) {
        if (child.type == child.type.schema.linebreakReplacement) {
            var start = tr.mapping.slice(mapFrom).map(pos + 1 + offset);
            tr.replaceWith(start, start + 1, node.type.schema.text("\n"));
        }
    });
}
function canChangeType(doc, pos, type) {
    var $pos = doc.resolve(pos), index = $pos.index();
    return $pos.parent.canReplaceWith(index, index + 1, type);
}
/**
Change the type, attributes, and/or marks of the node at `pos`.
When `type` isn't given, the existing node type is preserved,
*/
function setNodeMarkup(tr, pos, type, attrs, marks) {
    var node = tr.doc.nodeAt(pos);
    if (!node)
        { throw new RangeError("No node at given position"); }
    if (!type)
        { type = node.type; }
    var newNode = type.create(attrs, null, marks || node.marks);
    if (node.isLeaf)
        { return tr.replaceWith(pos, pos + node.nodeSize, newNode); }
    if (!type.validContent(node.content))
        { throw new RangeError("Invalid content for node type " + type.name); }
    tr.step(new ReplaceAroundStep(pos, pos + node.nodeSize, pos + 1, pos + node.nodeSize - 1, new Slice(Fragment.from(newNode), 0, 0), 1, true));
}
/**
Check whether splitting at the given position is allowed.
*/
function canSplit(doc, pos, depth, typesAfter) {
    if ( depth === void 0 ) depth = 1;

    var $pos = doc.resolve(pos), base = $pos.depth - depth;
    var innerType = (typesAfter && typesAfter[typesAfter.length - 1]) || $pos.parent;
    if (base < 0 || $pos.parent.type.spec.isolating ||
        !$pos.parent.canReplace($pos.index(), $pos.parent.childCount) ||
        !innerType.type.validContent($pos.parent.content.cutByIndex($pos.index(), $pos.parent.childCount)))
        { return false; }
    for (var d = $pos.depth - 1, i = depth - 2; d > base; d--, i--) {
        var node = $pos.node(d), index$1 = $pos.index(d);
        if (node.type.spec.isolating)
            { return false; }
        var rest = node.content.cutByIndex(index$1, node.childCount);
        var overrideChild = typesAfter && typesAfter[i + 1];
        if (overrideChild)
            { rest = rest.replaceChild(0, overrideChild.type.create(overrideChild.attrs)); }
        var after = (typesAfter && typesAfter[i]) || node;
        if (!node.canReplace(index$1 + 1, node.childCount) || !after.type.validContent(rest))
            { return false; }
    }
    var index = $pos.indexAfter(base);
    var baseType = typesAfter && typesAfter[0];
    return $pos.node(base).canReplaceWith(index, index, baseType ? baseType.type : $pos.node(base + 1).type);
}
function split(tr, pos, depth, typesAfter) {
    if ( depth === void 0 ) depth = 1;

    var $pos = tr.doc.resolve(pos), before = Fragment.empty, after = Fragment.empty;
    for (var d = $pos.depth, e = $pos.depth - depth, i = depth - 1; d > e; d--, i--) {
        before = Fragment.from($pos.node(d).copy(before));
        var typeAfter = typesAfter && typesAfter[i];
        after = Fragment.from(typeAfter ? typeAfter.type.create(typeAfter.attrs, after) : $pos.node(d).copy(after));
    }
    tr.step(new ReplaceStep(pos, pos, new Slice(before.append(after), depth, depth), true));
}
/**
Test whether the blocks before and after a given position can be
joined.
*/
function canJoin(doc, pos) {
    var $pos = doc.resolve(pos), index = $pos.index();
    return joinable($pos.nodeBefore, $pos.nodeAfter) &&
        $pos.parent.canReplace(index, index + 1);
}
function joinable(a, b) {
    return !!(a && b && !a.isLeaf && a.canAppend(b));
}
/**
Find an ancestor of the given position that can be joined to the
block before (or after if `dir` is positive). Returns the joinable
point, if any.
*/
function joinPoint(doc, pos, dir) {
    if ( dir === void 0 ) dir = -1;

    var $pos = doc.resolve(pos);
    for (var d = $pos.depth;; d--) {
        var before = (void 0), after = (void 0), index = $pos.index(d);
        if (d == $pos.depth) {
            before = $pos.nodeBefore;
            after = $pos.nodeAfter;
        }
        else if (dir > 0) {
            before = $pos.node(d + 1);
            index++;
            after = $pos.node(d).maybeChild(index);
        }
        else {
            before = $pos.node(d).maybeChild(index - 1);
            after = $pos.node(d + 1);
        }
        if (before && !before.isTextblock && joinable(before, after) &&
            $pos.node(d).canReplace(index, index + 1))
            { return pos; }
        if (d == 0)
            { break; }
        pos = dir < 0 ? $pos.before(d) : $pos.after(d);
    }
}
function join(tr, pos, depth) {
    var step = new ReplaceStep(pos - depth, pos + depth, Slice.empty, true);
    tr.step(step);
}
/**
Try to find a point where a node of the given type can be inserted
near `pos`, by searching up the node hierarchy when `pos` itself
isn't a valid place but is at the start or end of a node. Return
null if no position was found.
*/
function insertPoint(doc, pos, nodeType) {
    var $pos = doc.resolve(pos);
    if ($pos.parent.canReplaceWith($pos.index(), $pos.index(), nodeType))
        { return pos; }
    if ($pos.parentOffset == 0)
        { for (var d = $pos.depth - 1; d >= 0; d--) {
            var index = $pos.index(d);
            if ($pos.node(d).canReplaceWith(index, index, nodeType))
                { return $pos.before(d + 1); }
            if (index > 0)
                { return null; }
        } }
    if ($pos.parentOffset == $pos.parent.content.size)
        { for (var d$1 = $pos.depth - 1; d$1 >= 0; d$1--) {
            var index$1 = $pos.indexAfter(d$1);
            if ($pos.node(d$1).canReplaceWith(index$1, index$1, nodeType))
                { return $pos.after(d$1 + 1); }
            if (index$1 < $pos.node(d$1).childCount)
                { return null; }
        } }
    return null;
}
/**
Finds a position at or around the given position where the given
slice can be inserted. Will look at parent nodes' nearest boundary
and try there, even if the original position wasn't directly at the
start or end of that node. Returns null when no position was found.
*/
function dropPoint(doc, pos, slice) {
    var $pos = doc.resolve(pos);
    if (!slice.content.size)
        { return pos; }
    var content = slice.content;
    for (var i = 0; i < slice.openStart; i++)
        { content = content.firstChild.content; }
    for (var pass = 1; pass <= (slice.openStart == 0 && slice.size ? 2 : 1); pass++) {
        for (var d = $pos.depth; d >= 0; d--) {
            var bias = d == $pos.depth ? 0 : $pos.pos <= ($pos.start(d + 1) + $pos.end(d + 1)) / 2 ? -1 : 1;
            var insertPos = $pos.index(d) + (bias > 0 ? 1 : 0);
            var parent = $pos.node(d), fits = false;
            if (pass == 1) {
                fits = parent.canReplace(insertPos, insertPos, content);
            }
            else {
                var wrapping = parent.contentMatchAt(insertPos).findWrapping(content.firstChild.type);
                fits = wrapping && parent.canReplaceWith(insertPos, insertPos, wrapping[0]);
            }
            if (fits)
                { return bias == 0 ? $pos.pos : bias < 0 ? $pos.before(d + 1) : $pos.after(d + 1); }
        }
    }
    return null;
}

/**
‘Fit’ a slice into a given position in the document, producing a
[step](https://prosemirror.net/docs/ref/#transform.Step) that inserts it. Will return null if
there's no meaningful way to insert the slice here, or inserting it
would be a no-op (an empty slice over an empty range).
*/
function replaceStep(doc, from, to, slice) {
    if ( to === void 0 ) to = from;
    if ( slice === void 0 ) slice = Slice.empty;

    if (from == to && !slice.size)
        { return null; }
    var $from = doc.resolve(from), $to = doc.resolve(to);
    // Optimization -- avoid work if it's obvious that it's not needed.
    if (fitsTrivially($from, $to, slice))
        { return new ReplaceStep(from, to, slice); }
    return new Fitter($from, $to, slice).fit();
}
function fitsTrivially($from, $to, slice) {
    return !slice.openStart && !slice.openEnd && $from.start() == $to.start() &&
        $from.parent.canReplace($from.index(), $to.index(), slice.content);
}
// Algorithm for 'placing' the elements of a slice into a gap:
//
// We consider the content of each node that is open to the left to be
// independently placeable. I.e. in <p("foo"), p("bar")>, when the
// paragraph on the left is open, "foo" can be placed (somewhere on
// the left side of the replacement gap) independently from p("bar").
//
// This class tracks the state of the placement progress in the
// following properties:
//
//  - `frontier` holds a stack of `{type, match}` objects that
//    represent the open side of the replacement. It starts at
//    `$from`, then moves forward as content is placed, and is finally
//    reconciled with `$to`.
//
//  - `unplaced` is a slice that represents the content that hasn't
//    been placed yet.
//
//  - `placed` is a fragment of placed content. Its open-start value
//    is implicit in `$from`, and its open-end value in `frontier`.
var Fitter = function Fitter($from, $to, unplaced) {
    this.$from = $from;
    this.$to = $to;
    this.unplaced = unplaced;
    this.frontier = [];
    this.placed = Fragment.empty;
    for (var i = 0; i <= $from.depth; i++) {
        var node = $from.node(i);
        this.frontier.push({
            type: node.type,
            match: node.contentMatchAt($from.indexAfter(i))
        });
    }
    for (var i$1 = $from.depth; i$1 > 0; i$1--)
        { this.placed = Fragment.from($from.node(i$1).copy(this.placed)); }
};

var prototypeAccessors$1$2 = { depth: { configurable: true } };
prototypeAccessors$1$2.depth.get = function () { return this.frontier.length - 1; };
Fitter.prototype.fit = function fit () {
    // As long as there's unplaced content, try to place some of it.
    // If that fails, either increase the open score of the unplaced
    // slice, or drop nodes from it, and then try again.
    while (this.unplaced.size) {
        var fit = this.findFittable();
        if (fit)
            { this.placeNodes(fit); }
        else
            { this.openMore() || this.dropNode(); }
    }
    // When there's inline content directly after the frontier _and_
    // directly after `this.$to`, we must generate a `ReplaceAround`
    // step that pulls that content into the node after the frontier.
    // That means the fitting must be done to the end of the textblock
    // node after `this.$to`, not `this.$to` itself.
    var moveInline = this.mustMoveInline(), placedSize = this.placed.size - this.depth - this.$from.depth;
    var $from = this.$from, $to = this.close(moveInline < 0 ? this.$to : $from.doc.resolve(moveInline));
    if (!$to)
        { return null; }
    // If closing to `$to` succeeded, create a step
    var content = this.placed, openStart = $from.depth, openEnd = $to.depth;
    while (openStart && openEnd && content.childCount == 1) { // Normalize by dropping open parent nodes
        content = content.firstChild.content;
        openStart--;
        openEnd--;
    }
    var slice = new Slice(content, openStart, openEnd);
    if (moveInline > -1)
        { return new ReplaceAroundStep($from.pos, moveInline, this.$to.pos, this.$to.end(), slice, placedSize); }
    if (slice.size || $from.pos != this.$to.pos) // Don't generate no-op steps
        { return new ReplaceStep($from.pos, $to.pos, slice); }
    return null;
};
// Find a position on the start spine of `this.unplaced` that has
// content that can be moved somewhere on the frontier. Returns two
// depths, one for the slice and one for the frontier.
Fitter.prototype.findFittable = function findFittable () {
    var startDepth = this.unplaced.openStart;
    for (var cur = this.unplaced.content, d = 0, openEnd = this.unplaced.openEnd; d < startDepth; d++) {
        var node = cur.firstChild;
        if (cur.childCount > 1)
            { openEnd = 0; }
        if (node.type.spec.isolating && openEnd <= d) {
            startDepth = d;
            break;
        }
        cur = node.content;
    }
    // Only try wrapping nodes (pass 2) after finding a place without
    // wrapping failed.
    for (var pass = 1; pass <= 2; pass++) {
        for (var sliceDepth = pass == 1 ? startDepth : this.unplaced.openStart; sliceDepth >= 0; sliceDepth--) {
            var fragment = (void 0), parent = null;
            if (sliceDepth) {
                parent = contentAt(this.unplaced.content, sliceDepth - 1).firstChild;
                fragment = parent.content;
            }
            else {
                fragment = this.unplaced.content;
            }
            var first = fragment.firstChild;
            for (var frontierDepth = this.depth; frontierDepth >= 0; frontierDepth--) {
                var ref = this.frontier[frontierDepth];
                    var type = ref.type;
                    var match = ref.match;
                    var wrap = (void 0), inject = null;
                // In pass 1, if the next node matches, or there is no next
                // node but the parents look compatible, we've found a
                // place.
                if (pass == 1 && (first ? match.matchType(first.type) || (inject = match.fillBefore(Fragment.from(first), false))
                    : parent && type.compatibleContent(parent.type)))
                    { return { sliceDepth: sliceDepth, frontierDepth: frontierDepth, parent: parent, inject: inject }; }
                // In pass 2, look for a set of wrapping nodes that make
                // `first` fit here.
                else if (pass == 2 && first && (wrap = match.findWrapping(first.type)))
                    { return { sliceDepth: sliceDepth, frontierDepth: frontierDepth, parent: parent, wrap: wrap }; }
                // Don't continue looking further up if the parent node
                // would fit here.
                if (parent && match.matchType(parent.type))
                    { break; }
            }
        }
    }
};
Fitter.prototype.openMore = function openMore () {
    var ref = this.unplaced;
        var content = ref.content;
        var openStart = ref.openStart;
        var openEnd = ref.openEnd;
    var inner = contentAt(content, openStart);
    if (!inner.childCount || inner.firstChild.isLeaf)
        { return false; }
    this.unplaced = new Slice(content, openStart + 1, Math.max(openEnd, inner.size + openStart >= content.size - openEnd ? openStart + 1 : 0));
    return true;
};
Fitter.prototype.dropNode = function dropNode () {
    var ref = this.unplaced;
        var content = ref.content;
        var openStart = ref.openStart;
        var openEnd = ref.openEnd;
    var inner = contentAt(content, openStart);
    if (inner.childCount <= 1 && openStart > 0) {
        var openAtEnd = content.size - openStart <= openStart + inner.size;
        this.unplaced = new Slice(dropFromFragment(content, openStart - 1, 1), openStart - 1, openAtEnd ? openStart - 1 : openEnd);
    }
    else {
        this.unplaced = new Slice(dropFromFragment(content, openStart, 1), openStart, openEnd);
    }
};
// Move content from the unplaced slice at `sliceDepth` to the
// frontier node at `frontierDepth`. Close that frontier node when
// applicable.
Fitter.prototype.placeNodes = function placeNodes (ref) {
        var sliceDepth = ref.sliceDepth;
        var frontierDepth = ref.frontierDepth;
        var parent = ref.parent;
        var inject = ref.inject;
        var wrap = ref.wrap;

    while (this.depth > frontierDepth)
        { this.closeFrontierNode(); }
    if (wrap)
        { for (var i = 0; i < wrap.length; i++)
            { this.openFrontierNode(wrap[i]); } }
    var slice = this.unplaced, fragment = parent ? parent.content : slice.content;
    var openStart = slice.openStart - sliceDepth;
    var taken = 0, add = [];
    var ref$1 = this.frontier[frontierDepth];
        var match = ref$1.match;
        var type = ref$1.type;
    if (inject) {
        for (var i$1 = 0; i$1 < inject.childCount; i$1++)
            { add.push(inject.child(i$1)); }
        match = match.matchFragment(inject);
    }
    // Computes the amount of (end) open nodes at the end of the
    // fragment. When 0, the parent is open, but no more. When
    // negative, nothing is open.
    var openEndCount = (fragment.size + sliceDepth) - (slice.content.size - slice.openEnd);
    // Scan over the fragment, fitting as many child nodes as
    // possible.
    while (taken < fragment.childCount) {
        var next = fragment.child(taken), matches = match.matchType(next.type);
        if (!matches)
            { break; }
        taken++;
        if (taken > 1 || openStart == 0 || next.content.size) { // Drop empty open nodes
            match = matches;
            add.push(closeNodeStart(next.mark(type.allowedMarks(next.marks)), taken == 1 ? openStart : 0, taken == fragment.childCount ? openEndCount : -1));
        }
    }
    var toEnd = taken == fragment.childCount;
    if (!toEnd)
        { openEndCount = -1; }
    this.placed = addToFragment(this.placed, frontierDepth, Fragment.from(add));
    this.frontier[frontierDepth].match = match;
    // If the parent types match, and the entire node was moved, and
    // it's not open, close this frontier node right away.
    if (toEnd && openEndCount < 0 && parent && parent.type == this.frontier[this.depth].type && this.frontier.length > 1)
        { this.closeFrontierNode(); }
    // Add new frontier nodes for any open nodes at the end.
    for (var i$2 = 0, cur = fragment; i$2 < openEndCount; i$2++) {
        var node = cur.lastChild;
        this.frontier.push({ type: node.type, match: node.contentMatchAt(node.childCount) });
        cur = node.content;
    }
    // Update `this.unplaced`. Drop the entire node from which we
    // placed it we got to its end, otherwise just drop the placed
    // nodes.
    this.unplaced = !toEnd ? new Slice(dropFromFragment(slice.content, sliceDepth, taken), slice.openStart, slice.openEnd)
        : sliceDepth == 0 ? Slice.empty
            : new Slice(dropFromFragment(slice.content, sliceDepth - 1, 1), sliceDepth - 1, openEndCount < 0 ? slice.openEnd : sliceDepth - 1);
};
Fitter.prototype.mustMoveInline = function mustMoveInline () {
    if (!this.$to.parent.isTextblock)
        { return -1; }
    var top = this.frontier[this.depth], level;
    if (!top.type.isTextblock || !contentAfterFits(this.$to, this.$to.depth, top.type, top.match, false) ||
        (this.$to.depth == this.depth && (level = this.findCloseLevel(this.$to)) && level.depth == this.depth))
        { return -1; }
    var ref = this.$to;
        var depth = ref.depth;
        var after = this.$to.after(depth);
    while (depth > 1 && after == this.$to.end(--depth))
        { ++after; }
    return after;
};
Fitter.prototype.findCloseLevel = function findCloseLevel ($to) {
    scan: for (var i = Math.min(this.depth, $to.depth); i >= 0; i--) {
        var ref = this.frontier[i];
            var match = ref.match;
            var type = ref.type;
        var dropInner = i < $to.depth && $to.end(i + 1) == $to.pos + ($to.depth - (i + 1));
        var fit = contentAfterFits($to, i, type, match, dropInner);
        if (!fit)
            { continue; }
        for (var d = i - 1; d >= 0; d--) {
            var ref$1 = this.frontier[d];
                var match$1 = ref$1.match;
                var type$1 = ref$1.type;
            var matches = contentAfterFits($to, d, type$1, match$1, true);
            if (!matches || matches.childCount)
                { continue scan; }
        }
        return { depth: i, fit: fit, move: dropInner ? $to.doc.resolve($to.after(i + 1)) : $to };
    }
};
Fitter.prototype.close = function close ($to) {
    var close = this.findCloseLevel($to);
    if (!close)
        { return null; }
    while (this.depth > close.depth)
        { this.closeFrontierNode(); }
    if (close.fit.childCount)
        { this.placed = addToFragment(this.placed, close.depth, close.fit); }
    $to = close.move;
    for (var d = close.depth + 1; d <= $to.depth; d++) {
        var node = $to.node(d), add = node.type.contentMatch.fillBefore(node.content, true, $to.index(d));
        this.openFrontierNode(node.type, node.attrs, add);
    }
    return $to;
};
Fitter.prototype.openFrontierNode = function openFrontierNode (type, attrs, content) {
        if ( attrs === void 0 ) attrs = null;

    var top = this.frontier[this.depth];
    top.match = top.match.matchType(type);
    this.placed = addToFragment(this.placed, this.depth, Fragment.from(type.create(attrs, content)));
    this.frontier.push({ type: type, match: type.contentMatch });
};
Fitter.prototype.closeFrontierNode = function closeFrontierNode () {
    var open = this.frontier.pop();
    var add = open.match.fillBefore(Fragment.empty, true);
    if (add.childCount)
        { this.placed = addToFragment(this.placed, this.frontier.length, add); }
};

Object.defineProperties( Fitter.prototype, prototypeAccessors$1$2 );
function dropFromFragment(fragment, depth, count) {
    if (depth == 0)
        { return fragment.cutByIndex(count, fragment.childCount); }
    return fragment.replaceChild(0, fragment.firstChild.copy(dropFromFragment(fragment.firstChild.content, depth - 1, count)));
}
function addToFragment(fragment, depth, content) {
    if (depth == 0)
        { return fragment.append(content); }
    return fragment.replaceChild(fragment.childCount - 1, fragment.lastChild.copy(addToFragment(fragment.lastChild.content, depth - 1, content)));
}
function contentAt(fragment, depth) {
    for (var i = 0; i < depth; i++)
        { fragment = fragment.firstChild.content; }
    return fragment;
}
function closeNodeStart(node, openStart, openEnd) {
    if (openStart <= 0)
        { return node; }
    var frag = node.content;
    if (openStart > 1)
        { frag = frag.replaceChild(0, closeNodeStart(frag.firstChild, openStart - 1, frag.childCount == 1 ? openEnd - 1 : 0)); }
    if (openStart > 0) {
        frag = node.type.contentMatch.fillBefore(frag).append(frag);
        if (openEnd <= 0)
            { frag = frag.append(node.type.contentMatch.matchFragment(frag).fillBefore(Fragment.empty, true)); }
    }
    return node.copy(frag);
}
function contentAfterFits($to, depth, type, match, open) {
    var node = $to.node(depth), index = open ? $to.indexAfter(depth) : $to.index(depth);
    if (index == node.childCount && !type.compatibleContent(node.type))
        { return null; }
    var fit = match.fillBefore(node.content, true, index);
    return fit && !invalidMarks(type, node.content, index) ? fit : null;
}
function invalidMarks(type, fragment, start) {
    for (var i = start; i < fragment.childCount; i++)
        { if (!type.allowsMarks(fragment.child(i).marks))
            { return true; } }
    return false;
}
function definesContent(type) {
    return type.spec.defining || type.spec.definingForContent;
}
function replaceRange$1(tr, from, to, slice) {
    if (!slice.size)
        { return tr.deleteRange(from, to); }
    var $from = tr.doc.resolve(from), $to = tr.doc.resolve(to);
    if (fitsTrivially($from, $to, slice))
        { return tr.step(new ReplaceStep(from, to, slice)); }
    var targetDepths = coveredDepths($from, tr.doc.resolve(to));
    // Can't replace the whole document, so remove 0 if it's present
    if (targetDepths[targetDepths.length - 1] == 0)
        { targetDepths.pop(); }
    // Negative numbers represent not expansion over the whole node at
    // that depth, but replacing from $from.before(-D) to $to.pos.
    var preferredTarget = -($from.depth + 1);
    targetDepths.unshift(preferredTarget);
    // This loop picks a preferred target depth, if one of the covering
    // depths is not outside of a defining node, and adds negative
    // depths for any depth that has $from at its start and does not
    // cross a defining node.
    for (var d = $from.depth, pos = $from.pos - 1; d > 0; d--, pos--) {
        var spec = $from.node(d).type.spec;
        if (spec.defining || spec.definingAsContext || spec.isolating)
            { break; }
        if (targetDepths.indexOf(d) > -1)
            { preferredTarget = d; }
        else if ($from.before(d) == pos)
            { targetDepths.splice(1, 0, -d); }
    }
    // Try to fit each possible depth of the slice into each possible
    // target depth, starting with the preferred depths.
    var preferredTargetIndex = targetDepths.indexOf(preferredTarget);
    var leftNodes = [], preferredDepth = slice.openStart;
    for (var content = slice.content, i = 0;; i++) {
        var node = content.firstChild;
        leftNodes.push(node);
        if (i == slice.openStart)
            { break; }
        content = node.content;
    }
    // Back up preferredDepth to cover defining textblocks directly
    // above it, possibly skipping a non-defining textblock.
    for (var d$1 = preferredDepth - 1; d$1 >= 0; d$1--) {
        var leftNode = leftNodes[d$1], def = definesContent(leftNode.type);
        if (def && !leftNode.sameMarkup($from.node(Math.abs(preferredTarget) - 1)))
            { preferredDepth = d$1; }
        else if (def || !leftNode.type.isTextblock)
            { break; }
    }
    for (var j = slice.openStart; j >= 0; j--) {
        var openDepth = (j + preferredDepth + 1) % (slice.openStart + 1);
        var insert = leftNodes[openDepth];
        if (!insert)
            { continue; }
        for (var i$1 = 0; i$1 < targetDepths.length; i$1++) {
            // Loop over possible expansion levels, starting with the
            // preferred one
            var targetDepth = targetDepths[(i$1 + preferredTargetIndex) % targetDepths.length], expand = true;
            if (targetDepth < 0) {
                expand = false;
                targetDepth = -targetDepth;
            }
            var parent = $from.node(targetDepth - 1), index = $from.index(targetDepth - 1);
            if (parent.canReplaceWith(index, index, insert.type, insert.marks))
                { return tr.replace($from.before(targetDepth), expand ? $to.after(targetDepth) : to, new Slice(closeFragment(slice.content, 0, slice.openStart, openDepth), openDepth, slice.openEnd)); }
        }
    }
    var startSteps = tr.steps.length;
    for (var i$2 = targetDepths.length - 1; i$2 >= 0; i$2--) {
        tr.replace(from, to, slice);
        if (tr.steps.length > startSteps)
            { break; }
        var depth = targetDepths[i$2];
        if (depth < 0)
            { continue; }
        from = $from.before(depth);
        to = $to.after(depth);
    }
}
function closeFragment(fragment, depth, oldOpen, newOpen, parent) {
    if (depth < oldOpen) {
        var first = fragment.firstChild;
        fragment = fragment.replaceChild(0, first.copy(closeFragment(first.content, depth + 1, oldOpen, newOpen, first)));
    }
    if (depth > newOpen) {
        var match = parent.contentMatchAt(0);
        var start = match.fillBefore(fragment).append(fragment);
        fragment = start.append(match.matchFragment(start).fillBefore(Fragment.empty, true));
    }
    return fragment;
}
function replaceRangeWith(tr, from, to, node) {
    if (!node.isInline && from == to && tr.doc.resolve(from).parent.content.size) {
        var point = insertPoint(tr.doc, from, node.type);
        if (point != null)
            { from = to = point; }
    }
    tr.replaceRange(from, to, new Slice(Fragment.from(node), 0, 0));
}
function deleteRange(tr, from, to) {
    var $from = tr.doc.resolve(from), $to = tr.doc.resolve(to);
    var covered = coveredDepths($from, $to);
    for (var i = 0; i < covered.length; i++) {
        var depth = covered[i], last = i == covered.length - 1;
        if ((last && depth == 0) || $from.node(depth).type.contentMatch.validEnd)
            { return tr.delete($from.start(depth), $to.end(depth)); }
        if (depth > 0 && (last || $from.node(depth - 1).canReplace($from.index(depth - 1), $to.indexAfter(depth - 1))))
            { return tr.delete($from.before(depth), $to.after(depth)); }
    }
    for (var d = 1; d <= $from.depth && d <= $to.depth; d++) {
        if (from - $from.start(d) == $from.depth - d && to > $from.end(d) && $to.end(d) - to != $to.depth - d)
            { return tr.delete($from.before(d), to); }
    }
    tr.delete(from, to);
}
// Returns an array of all depths for which $from - $to spans the
// whole content of the nodes at that depth.
function coveredDepths($from, $to) {
    var result = [], minDepth = Math.min($from.depth, $to.depth);
    for (var d = minDepth; d >= 0; d--) {
        var start = $from.start(d);
        if (start < $from.pos - ($from.depth - d) ||
            $to.end(d) > $to.pos + ($to.depth - d) ||
            $from.node(d).type.spec.isolating ||
            $to.node(d).type.spec.isolating)
            { break; }
        if (start == $to.start(d) ||
            (d == $from.depth && d == $to.depth && $from.parent.inlineContent && $to.parent.inlineContent &&
                d && $to.start(d - 1) == start - 1))
            { result.push(d); }
    }
    return result;
}

/**
Update an attribute in a specific node.
*/
var AttrStep = /*@__PURE__*/(function (Step) {
    function AttrStep(
    /**
    The position of the target node.
    */
    pos, 
    /**
    The attribute to set.
    */
    attr, 
    // The attribute's new value.
    value) {
        Step.call(this);
        this.pos = pos;
        this.attr = attr;
        this.value = value;
    }

    if ( Step ) AttrStep.__proto__ = Step;
    AttrStep.prototype = Object.create( Step && Step.prototype );
    AttrStep.prototype.constructor = AttrStep;
    AttrStep.prototype.apply = function apply (doc) {
        var node = doc.nodeAt(this.pos);
        if (!node)
            { return StepResult.fail("No node at attribute step's position"); }
        var attrs = Object.create(null);
        for (var name in node.attrs)
            { attrs[name] = node.attrs[name]; }
        attrs[this.attr] = this.value;
        var updated = node.type.create(attrs, null, node.marks);
        return StepResult.fromReplace(doc, this.pos, this.pos + 1, new Slice(Fragment.from(updated), 0, node.isLeaf ? 0 : 1));
    };
    AttrStep.prototype.getMap = function getMap () {
        return StepMap.empty;
    };
    AttrStep.prototype.invert = function invert (doc) {
        return new AttrStep(this.pos, this.attr, doc.nodeAt(this.pos).attrs[this.attr]);
    };
    AttrStep.prototype.map = function map (mapping) {
        var pos = mapping.mapResult(this.pos, 1);
        return pos.deletedAfter ? null : new AttrStep(pos.pos, this.attr, this.value);
    };
    AttrStep.prototype.toJSON = function toJSON () {
        return { stepType: "attr", pos: this.pos, attr: this.attr, value: this.value };
    };
    AttrStep.fromJSON = function fromJSON (schema, json) {
        if (typeof json.pos != "number" || typeof json.attr != "string")
            { throw new RangeError("Invalid input for AttrStep.fromJSON"); }
        return new AttrStep(json.pos, json.attr, json.value);
    };

    return AttrStep;
}(Step));
Step.jsonID("attr", AttrStep);
/**
Update an attribute in the doc node.
*/
var DocAttrStep = /*@__PURE__*/(function (Step) {
    function DocAttrStep(
    /**
    The attribute to set.
    */
    attr, 
    // The attribute's new value.
    value) {
        Step.call(this);
        this.attr = attr;
        this.value = value;
    }

    if ( Step ) DocAttrStep.__proto__ = Step;
    DocAttrStep.prototype = Object.create( Step && Step.prototype );
    DocAttrStep.prototype.constructor = DocAttrStep;
    DocAttrStep.prototype.apply = function apply (doc) {
        var attrs = Object.create(null);
        for (var name in doc.attrs)
            { attrs[name] = doc.attrs[name]; }
        attrs[this.attr] = this.value;
        var updated = doc.type.create(attrs, doc.content, doc.marks);
        return StepResult.ok(updated);
    };
    DocAttrStep.prototype.getMap = function getMap () {
        return StepMap.empty;
    };
    DocAttrStep.prototype.invert = function invert (doc) {
        return new DocAttrStep(this.attr, doc.attrs[this.attr]);
    };
    DocAttrStep.prototype.map = function map (mapping) {
        return this;
    };
    DocAttrStep.prototype.toJSON = function toJSON () {
        return { stepType: "docAttr", attr: this.attr, value: this.value };
    };
    DocAttrStep.fromJSON = function fromJSON (schema, json) {
        if (typeof json.attr != "string")
            { throw new RangeError("Invalid input for DocAttrStep.fromJSON"); }
        return new DocAttrStep(json.attr, json.value);
    };

    return DocAttrStep;
}(Step));
Step.jsonID("docAttr", DocAttrStep);

/**
@internal
*/
var TransformError = /*@__PURE__*/(function (Error) {
    function TransformError () {
        Error.apply(this, arguments);
    }if ( Error ) TransformError.__proto__ = Error;
    TransformError.prototype = Object.create( Error && Error.prototype );
    TransformError.prototype.constructor = TransformError;

    

    return TransformError;
}(Error));
TransformError = function TransformError(message) {
    var err = Error.call(this, message);
    err.__proto__ = TransformError.prototype;
    return err;
};
TransformError.prototype = Object.create(Error.prototype);
TransformError.prototype.constructor = TransformError;
TransformError.prototype.name = "TransformError";
/**
Abstraction to build up and track an array of
[steps](https://prosemirror.net/docs/ref/#transform.Step) representing a document transformation.

Most transforming methods return the `Transform` object itself, so
that they can be chained.
*/
var Transform = function Transform(
/**
The current document (the result of applying the steps in the
transform).
*/
doc) {
    this.doc = doc;
    /**
    The steps in this transform.
    */
    this.steps = [];
    /**
    The documents before each of the steps.
    */
    this.docs = [];
    /**
    A mapping with the maps for each of the steps in this transform.
    */
    this.mapping = new Mapping;
};

var prototypeAccessors$2$3 = { before: { configurable: true },docChanged: { configurable: true } };
/**
The starting document.
*/
prototypeAccessors$2$3.before.get = function () { return this.docs.length ? this.docs[0] : this.doc; };
/**
Apply a new step in this transform, saving the result. Throws an
error when the step fails.
*/
Transform.prototype.step = function step (step$1) {
    var result = this.maybeStep(step$1);
    if (result.failed)
        { throw new TransformError(result.failed); }
    return this;
};
/**
Try to apply a step in this transformation, ignoring it if it
fails. Returns the step result.
*/
Transform.prototype.maybeStep = function maybeStep (step) {
    var result = step.apply(this.doc);
    if (!result.failed)
        { this.addStep(step, result.doc); }
    return result;
};
/**
True when the document has been changed (when there are any
steps).
*/
prototypeAccessors$2$3.docChanged.get = function () {
    return this.steps.length > 0;
};
/**
@internal
*/
Transform.prototype.addStep = function addStep (step, doc) {
    this.docs.push(this.doc);
    this.steps.push(step);
    this.mapping.appendMap(step.getMap());
    this.doc = doc;
};
/**
Replace the part of the document between `from` and `to` with the
given `slice`.
*/
Transform.prototype.replace = function replace (from, to, slice) {
        if ( to === void 0 ) to = from;
        if ( slice === void 0 ) slice = Slice.empty;

    var step = replaceStep(this.doc, from, to, slice);
    if (step)
        { this.step(step); }
    return this;
};
/**
Replace the given range with the given content, which may be a
fragment, node, or array of nodes.
*/
Transform.prototype.replaceWith = function replaceWith (from, to, content) {
    return this.replace(from, to, new Slice(Fragment.from(content), 0, 0));
};
/**
Delete the content between the given positions.
*/
Transform.prototype.delete = function delete$1 (from, to) {
    return this.replace(from, to, Slice.empty);
};
/**
Insert the given content at the given position.
*/
Transform.prototype.insert = function insert (pos, content) {
    return this.replaceWith(pos, pos, content);
};
/**
Replace a range of the document with a given slice, using
`from`, `to`, and the slice's
[`openStart`](https://prosemirror.net/docs/ref/#model.Slice.openStart) property as hints, rather
than fixed start and end points. This method may grow the
replaced area or close open nodes in the slice in order to get a
fit that is more in line with WYSIWYG expectations, by dropping
fully covered parent nodes of the replaced region when they are
marked [non-defining as
context](https://prosemirror.net/docs/ref/#model.NodeSpec.definingAsContext), or including an
open parent node from the slice that _is_ marked as [defining
its content](https://prosemirror.net/docs/ref/#model.NodeSpec.definingForContent).
    
This is the method, for example, to handle paste. The similar
[`replace`](https://prosemirror.net/docs/ref/#transform.Transform.replace) method is a more
primitive tool which will _not_ move the start and end of its given
range, and is useful in situations where you need more precise
control over what happens.
*/
Transform.prototype.replaceRange = function replaceRange$1$1 (from, to, slice) {
    replaceRange$1(this, from, to, slice);
    return this;
};
/**
Replace the given range with a node, but use `from` and `to` as
hints, rather than precise positions. When from and to are the same
and are at the start or end of a parent node in which the given
node doesn't fit, this method may _move_ them out towards a parent
that does allow the given node to be placed. When the given range
completely covers a parent node, this method may completely replace
that parent node.
*/
Transform.prototype.replaceRangeWith = function replaceRangeWith$1 (from, to, node) {
    replaceRangeWith(this, from, to, node);
    return this;
};
/**
Delete the given range, expanding it to cover fully covered
parent nodes until a valid replace is found.
*/
Transform.prototype.deleteRange = function deleteRange$1 (from, to) {
    deleteRange(this, from, to);
    return this;
};
/**
Split the content in the given range off from its parent, if there
is sibling content before or after it, and move it up the tree to
the depth specified by `target`. You'll probably want to use
[`liftTarget`](https://prosemirror.net/docs/ref/#transform.liftTarget) to compute `target`, to make
sure the lift is valid.
*/
Transform.prototype.lift = function lift$1 (range, target) {
    lift$2(this, range, target);
    return this;
};
/**
Join the blocks around the given position. If depth is 2, their
last and first siblings are also joined, and so on.
*/
Transform.prototype.join = function join$1 (pos, depth) {
        if ( depth === void 0 ) depth = 1;

    join(this, pos, depth);
    return this;
};
/**
Wrap the given [range](https://prosemirror.net/docs/ref/#model.NodeRange) in the given set of wrappers.
The wrappers are assumed to be valid in this position, and should
probably be computed with [`findWrapping`](https://prosemirror.net/docs/ref/#transform.findWrapping).
*/
Transform.prototype.wrap = function wrap$1 (range, wrappers) {
    wrap(this, range, wrappers);
    return this;
};
/**
Set the type of all textblocks (partly) between `from` and `to` to
the given node type with the given attributes.
*/
Transform.prototype.setBlockType = function setBlockType$1$1 (from, to, type, attrs) {
        if ( to === void 0 ) to = from;
        if ( attrs === void 0 ) attrs = null;

    setBlockType$1(this, from, to, type, attrs);
    return this;
};
/**
Change the type, attributes, and/or marks of the node at `pos`.
When `type` isn't given, the existing node type is preserved,
*/
Transform.prototype.setNodeMarkup = function setNodeMarkup$1 (pos, type, attrs, marks) {
        if ( attrs === void 0 ) attrs = null;

    setNodeMarkup(this, pos, type, attrs, marks);
    return this;
};
/**
Set a single attribute on a given node to a new value.
The `pos` addresses the document content. Use `setDocAttribute`
to set attributes on the document itself.
*/
Transform.prototype.setNodeAttribute = function setNodeAttribute (pos, attr, value) {
    this.step(new AttrStep(pos, attr, value));
    return this;
};
/**
Set a single attribute on the document to a new value.
*/
Transform.prototype.setDocAttribute = function setDocAttribute (attr, value) {
    this.step(new DocAttrStep(attr, value));
    return this;
};
/**
Add a mark to the node at position `pos`.
*/
Transform.prototype.addNodeMark = function addNodeMark (pos, mark) {
    this.step(new AddNodeMarkStep(pos, mark));
    return this;
};
/**
Remove a mark (or a mark of the given type) from the node at
position `pos`.
*/
Transform.prototype.removeNodeMark = function removeNodeMark (pos, mark) {
    if (!(mark instanceof Mark)) {
        var node = this.doc.nodeAt(pos);
        if (!node)
            { throw new RangeError("No node at position " + pos); }
        mark = mark.isInSet(node.marks);
        if (!mark)
            { return this; }
    }
    this.step(new RemoveNodeMarkStep(pos, mark));
    return this;
};
/**
Split the node at the given position, and optionally, if `depth` is
greater than one, any number of nodes above that. By default, the
parts split off will inherit the node type of the original node.
This can be changed by passing an array of types and attributes to
use after the split.
*/
Transform.prototype.split = function split$1 (pos, depth, typesAfter) {
        if ( depth === void 0 ) depth = 1;

    split(this, pos, depth, typesAfter);
    return this;
};
/**
Add the given mark to the inline content between `from` and `to`.
*/
Transform.prototype.addMark = function addMark$1 (from, to, mark) {
    addMark(this, from, to, mark);
    return this;
};
/**
Remove marks from inline nodes between `from` and `to`. When
`mark` is a single mark, remove precisely that mark. When it is
a mark type, remove all marks of that type. When it is null,
remove all marks of any type.
*/
Transform.prototype.removeMark = function removeMark$1$1 (from, to, mark) {
    removeMark$1(this, from, to, mark);
    return this;
};
/**
Removes all marks and nodes from the content of the node at
`pos` that don't match the given new parent node type. Accepts
an optional starting [content match](https://prosemirror.net/docs/ref/#model.ContentMatch) as
third argument.
*/
Transform.prototype.clearIncompatible = function clearIncompatible$1 (pos, parentType, match) {
    clearIncompatible(this, pos, parentType, match);
    return this;
};

Object.defineProperties( Transform.prototype, prototypeAccessors$2$3 );var transform=/*#__PURE__*/Object.freeze({__proto__:null,AddMarkStep:AddMarkStep,AddNodeMarkStep:AddNodeMarkStep,AttrStep:AttrStep,DocAttrStep:DocAttrStep,MapResult:MapResult,Mapping:Mapping,RemoveMarkStep:RemoveMarkStep,RemoveNodeMarkStep:RemoveNodeMarkStep,ReplaceAroundStep:ReplaceAroundStep,ReplaceStep:ReplaceStep,Step:Step,StepMap:StepMap,StepResult:StepResult,Transform:Transform,get TransformError(){return TransformError},canJoin:canJoin,canSplit:canSplit,dropPoint:dropPoint,findWrapping:findWrapping,insertPoint:insertPoint,joinPoint:joinPoint,liftTarget:liftTarget,replaceStep:replaceStep});var classesById = Object.create(null);
/**
Superclass for editor selections. Every selection type should
extend this. Should not be instantiated directly.
*/
var Selection = function Selection(
/**
The resolved anchor of the selection (the side that stays in
place when the selection is modified).
*/
$anchor, 
/**
The resolved head of the selection (the side that moves when
the selection is modified).
*/
$head, ranges) {
    this.$anchor = $anchor;
    this.$head = $head;
    this.ranges = ranges || [new SelectionRange$1($anchor.min($head), $anchor.max($head))];
};

var prototypeAccessors$a = { anchor: { configurable: true },head: { configurable: true },from: { configurable: true },to: { configurable: true },$from: { configurable: true },$to: { configurable: true },empty: { configurable: true } };
/**
The selection's anchor, as an unresolved position.
*/
prototypeAccessors$a.anchor.get = function () { return this.$anchor.pos; };
/**
The selection's head.
*/
prototypeAccessors$a.head.get = function () { return this.$head.pos; };
/**
The lower bound of the selection's main range.
*/
prototypeAccessors$a.from.get = function () { return this.$from.pos; };
/**
The upper bound of the selection's main range.
*/
prototypeAccessors$a.to.get = function () { return this.$to.pos; };
/**
The resolved lower  bound of the selection's main range.
*/
prototypeAccessors$a.$from.get = function () {
    return this.ranges[0].$from;
};
/**
The resolved upper bound of the selection's main range.
*/
prototypeAccessors$a.$to.get = function () {
    return this.ranges[0].$to;
};
/**
Indicates whether the selection contains any content.
*/
prototypeAccessors$a.empty.get = function () {
    var ranges = this.ranges;
    for (var i = 0; i < ranges.length; i++)
        { if (ranges[i].$from.pos != ranges[i].$to.pos)
            { return false; } }
    return true;
};
/**
Get the content of this selection as a slice.
*/
Selection.prototype.content = function content () {
    return this.$from.doc.slice(this.from, this.to, true);
};
/**
Replace the selection with a slice or, if no slice is given,
delete the selection. Will append to the given transaction.
*/
Selection.prototype.replace = function replace (tr, content) {
        if ( content === void 0 ) content = Slice.empty;

    // Put the new selection at the position after the inserted
    // content. When that ended in an inline node, search backwards,
    // to get the position after that node. If not, search forward.
    var lastNode = content.content.lastChild, lastParent = null;
    for (var i = 0; i < content.openEnd; i++) {
        lastParent = lastNode;
        lastNode = lastNode.lastChild;
    }
    var mapFrom = tr.steps.length, ranges = this.ranges;
    for (var i$1 = 0; i$1 < ranges.length; i$1++) {
        var ref = ranges[i$1];
            var $from = ref.$from;
            var $to = ref.$to;
            var mapping = tr.mapping.slice(mapFrom);
        tr.replaceRange(mapping.map($from.pos), mapping.map($to.pos), i$1 ? Slice.empty : content);
        if (i$1 == 0)
            { selectionToInsertionEnd(tr, mapFrom, (lastNode ? lastNode.isInline : lastParent && lastParent.isTextblock) ? -1 : 1); }
    }
};
/**
Replace the selection with the given node, appending the changes
to the given transaction.
*/
Selection.prototype.replaceWith = function replaceWith (tr, node) {
    var mapFrom = tr.steps.length, ranges = this.ranges;
    for (var i = 0; i < ranges.length; i++) {
        var ref = ranges[i];
            var $from = ref.$from;
            var $to = ref.$to;
            var mapping = tr.mapping.slice(mapFrom);
        var from = mapping.map($from.pos), to = mapping.map($to.pos);
        if (i) {
            tr.deleteRange(from, to);
        }
        else {
            tr.replaceRangeWith(from, to, node);
            selectionToInsertionEnd(tr, mapFrom, node.isInline ? -1 : 1);
        }
    }
};
/**
Find a valid cursor or leaf node selection starting at the given
position and searching back if `dir` is negative, and forward if
positive. When `textOnly` is true, only consider cursor
selections. Will return null when no valid selection position is
found.
*/
Selection.findFrom = function findFrom ($pos, dir, textOnly) {
        if ( textOnly === void 0 ) textOnly = false;

    var inner = $pos.parent.inlineContent ? new TextSelection($pos)
        : findSelectionIn($pos.node(0), $pos.parent, $pos.pos, $pos.index(), dir, textOnly);
    if (inner)
        { return inner; }
    for (var depth = $pos.depth - 1; depth >= 0; depth--) {
        var found = dir < 0
            ? findSelectionIn($pos.node(0), $pos.node(depth), $pos.before(depth + 1), $pos.index(depth), dir, textOnly)
            : findSelectionIn($pos.node(0), $pos.node(depth), $pos.after(depth + 1), $pos.index(depth) + 1, dir, textOnly);
        if (found)
            { return found; }
    }
    return null;
};
/**
Find a valid cursor or leaf node selection near the given
position. Searches forward first by default, but if `bias` is
negative, it will search backwards first.
*/
Selection.near = function near ($pos, bias) {
        if ( bias === void 0 ) bias = 1;

    return this.findFrom($pos, bias) || this.findFrom($pos, -bias) || new AllSelection($pos.node(0));
};
/**
Find the cursor or leaf node selection closest to the start of
the given document. Will return an
[`AllSelection`](https://prosemirror.net/docs/ref/#state.AllSelection) if no valid position
exists.
*/
Selection.atStart = function atStart (doc) {
    return findSelectionIn(doc, doc, 0, 0, 1) || new AllSelection(doc);
};
/**
Find the cursor or leaf node selection closest to the end of the
given document.
*/
Selection.atEnd = function atEnd (doc) {
    return findSelectionIn(doc, doc, doc.content.size, doc.childCount, -1) || new AllSelection(doc);
};
/**
Deserialize the JSON representation of a selection. Must be
implemented for custom classes (as a static class method).
*/
Selection.fromJSON = function fromJSON (doc, json) {
    if (!json || !json.type)
        { throw new RangeError("Invalid input for Selection.fromJSON"); }
    var cls = classesById[json.type];
    if (!cls)
        { throw new RangeError(("No selection type " + (json.type) + " defined")); }
    return cls.fromJSON(doc, json);
};
/**
To be able to deserialize selections from JSON, custom selection
classes must register themselves with an ID string, so that they
can be disambiguated. Try to pick something that's unlikely to
clash with classes from other modules.
*/
Selection.jsonID = function jsonID (id, selectionClass) {
    if (id in classesById)
        { throw new RangeError("Duplicate use of selection JSON ID " + id); }
    classesById[id] = selectionClass;
    selectionClass.prototype.jsonID = id;
    return selectionClass;
};
/**
Get a [bookmark](https://prosemirror.net/docs/ref/#state.SelectionBookmark) for this selection,
which is a value that can be mapped without having access to a
current document, and later resolved to a real selection for a
given document again. (This is used mostly by the history to
track and restore old selections.) The default implementation of
this method just converts the selection to a text selection and
returns the bookmark for that.
*/
Selection.prototype.getBookmark = function getBookmark () {
    return TextSelection.between(this.$anchor, this.$head).getBookmark();
};

Object.defineProperties( Selection.prototype, prototypeAccessors$a );
Selection.prototype.visible = true;
/**
Represents a selected range in a document.
*/
var SelectionRange$1 = function SelectionRange(
/**
The lower bound of the range.
*/
$from, 
/**
The upper bound of the range.
*/
$to) {
    this.$from = $from;
    this.$to = $to;
};
var warnedAboutTextSelection = false;
function checkTextSelection($pos) {
    if (!warnedAboutTextSelection && !$pos.parent.inlineContent) {
        warnedAboutTextSelection = true;
        console["warn"]("TextSelection endpoint not pointing into a node with inline content (" + $pos.parent.type.name + ")");
    }
}
/**
A text selection represents a classical editor selection, with a
head (the moving side) and anchor (immobile side), both of which
point into textblock nodes. It can be empty (a regular cursor
position).
*/
var TextSelection = /*@__PURE__*/(function (Selection) {
    function TextSelection($anchor, $head) {
        if ( $head === void 0 ) $head = $anchor;

        checkTextSelection($anchor);
        checkTextSelection($head);
        Selection.call(this, $anchor, $head);
    }

    if ( Selection ) TextSelection.__proto__ = Selection;
    TextSelection.prototype = Object.create( Selection && Selection.prototype );
    TextSelection.prototype.constructor = TextSelection;

    var prototypeAccessors$1 = { $cursor: { configurable: true } };
    /**
    Returns a resolved position if this is a cursor selection (an
    empty text selection), and null otherwise.
    */
    prototypeAccessors$1.$cursor.get = function () { return this.$anchor.pos == this.$head.pos ? this.$head : null; };
    TextSelection.prototype.map = function map (doc, mapping) {
        var $head = doc.resolve(mapping.map(this.head));
        if (!$head.parent.inlineContent)
            { return Selection.near($head); }
        var $anchor = doc.resolve(mapping.map(this.anchor));
        return new TextSelection($anchor.parent.inlineContent ? $anchor : $head, $head);
    };
    TextSelection.prototype.replace = function replace (tr, content) {
        if ( content === void 0 ) content = Slice.empty;

        Selection.prototype.replace.call(this, tr, content);
        if (content == Slice.empty) {
            var marks = this.$from.marksAcross(this.$to);
            if (marks)
                { tr.ensureMarks(marks); }
        }
    };
    TextSelection.prototype.eq = function eq (other) {
        return other instanceof TextSelection && other.anchor == this.anchor && other.head == this.head;
    };
    TextSelection.prototype.getBookmark = function getBookmark () {
        return new TextBookmark(this.anchor, this.head);
    };
    TextSelection.prototype.toJSON = function toJSON () {
        return { type: "text", anchor: this.anchor, head: this.head };
    };
    /**
    @internal
    */
    TextSelection.fromJSON = function fromJSON (doc, json) {
        if (typeof json.anchor != "number" || typeof json.head != "number")
            { throw new RangeError("Invalid input for TextSelection.fromJSON"); }
        return new TextSelection(doc.resolve(json.anchor), doc.resolve(json.head));
    };
    /**
    Create a text selection from non-resolved positions.
    */
    TextSelection.create = function create (doc, anchor, head) {
        if ( head === void 0 ) head = anchor;

        var $anchor = doc.resolve(anchor);
        return new this($anchor, head == anchor ? $anchor : doc.resolve(head));
    };
    /**
    Return a text selection that spans the given positions or, if
    they aren't text positions, find a text selection near them.
    `bias` determines whether the method searches forward (default)
    or backwards (negative number) first. Will fall back to calling
    [`Selection.near`](https://prosemirror.net/docs/ref/#state.Selection^near) when the document
    doesn't contain a valid text position.
    */
    TextSelection.between = function between ($anchor, $head, bias) {
        var dPos = $anchor.pos - $head.pos;
        if (!bias || dPos)
            { bias = dPos >= 0 ? 1 : -1; }
        if (!$head.parent.inlineContent) {
            var found = Selection.findFrom($head, bias, true) || Selection.findFrom($head, -bias, true);
            if (found)
                { $head = found.$head; }
            else
                { return Selection.near($head, bias); }
        }
        if (!$anchor.parent.inlineContent) {
            if (dPos == 0) {
                $anchor = $head;
            }
            else {
                $anchor = (Selection.findFrom($anchor, -bias, true) || Selection.findFrom($anchor, bias, true)).$anchor;
                if (($anchor.pos < $head.pos) != (dPos < 0))
                    { $anchor = $head; }
            }
        }
        return new TextSelection($anchor, $head);
    };

    Object.defineProperties( TextSelection.prototype, prototypeAccessors$1 );

    return TextSelection;
}(Selection));
Selection.jsonID("text", TextSelection);
var TextBookmark = function TextBookmark(anchor, head) {
    this.anchor = anchor;
    this.head = head;
};
TextBookmark.prototype.map = function map (mapping) {
    return new TextBookmark(mapping.map(this.anchor), mapping.map(this.head));
};
TextBookmark.prototype.resolve = function resolve (doc) {
    return TextSelection.between(doc.resolve(this.anchor), doc.resolve(this.head));
};
/**
A node selection is a selection that points at a single node. All
nodes marked [selectable](https://prosemirror.net/docs/ref/#model.NodeSpec.selectable) can be the
target of a node selection. In such a selection, `from` and `to`
point directly before and after the selected node, `anchor` equals
`from`, and `head` equals `to`..
*/
var NodeSelection = /*@__PURE__*/(function (Selection) {
    function NodeSelection($pos) {
        var node = $pos.nodeAfter;
        var $end = $pos.node(0).resolve($pos.pos + node.nodeSize);
        Selection.call(this, $pos, $end);
        this.node = node;
    }

    if ( Selection ) NodeSelection.__proto__ = Selection;
    NodeSelection.prototype = Object.create( Selection && Selection.prototype );
    NodeSelection.prototype.constructor = NodeSelection;
    NodeSelection.prototype.map = function map (doc, mapping) {
        var ref = mapping.mapResult(this.anchor);
        var deleted = ref.deleted;
        var pos = ref.pos;
        var $pos = doc.resolve(pos);
        if (deleted)
            { return Selection.near($pos); }
        return new NodeSelection($pos);
    };
    NodeSelection.prototype.content = function content () {
        return new Slice(Fragment.from(this.node), 0, 0);
    };
    NodeSelection.prototype.eq = function eq (other) {
        return other instanceof NodeSelection && other.anchor == this.anchor;
    };
    NodeSelection.prototype.toJSON = function toJSON () {
        return { type: "node", anchor: this.anchor };
    };
    NodeSelection.prototype.getBookmark = function getBookmark () { return new NodeBookmark(this.anchor); };
    /**
    @internal
    */
    NodeSelection.fromJSON = function fromJSON (doc, json) {
        if (typeof json.anchor != "number")
            { throw new RangeError("Invalid input for NodeSelection.fromJSON"); }
        return new NodeSelection(doc.resolve(json.anchor));
    };
    /**
    Create a node selection from non-resolved positions.
    */
    NodeSelection.create = function create (doc, from) {
        return new NodeSelection(doc.resolve(from));
    };
    /**
    Determines whether the given node may be selected as a node
    selection.
    */
    NodeSelection.isSelectable = function isSelectable (node) {
        return !node.isText && node.type.spec.selectable !== false;
    };

    return NodeSelection;
}(Selection));
NodeSelection.prototype.visible = false;
Selection.jsonID("node", NodeSelection);
var NodeBookmark = function NodeBookmark(anchor) {
    this.anchor = anchor;
};
NodeBookmark.prototype.map = function map (mapping) {
    var ref = mapping.mapResult(this.anchor);
        var deleted = ref.deleted;
        var pos = ref.pos;
    return deleted ? new TextBookmark(pos, pos) : new NodeBookmark(pos);
};
NodeBookmark.prototype.resolve = function resolve (doc) {
    var $pos = doc.resolve(this.anchor), node = $pos.nodeAfter;
    if (node && NodeSelection.isSelectable(node))
        { return new NodeSelection($pos); }
    return Selection.near($pos);
};
/**
A selection type that represents selecting the whole document
(which can not necessarily be expressed with a text selection, when
there are for example leaf block nodes at the start or end of the
document).
*/
var AllSelection = /*@__PURE__*/(function (Selection) {
    function AllSelection(doc) {
        Selection.call(this, doc.resolve(0), doc.resolve(doc.content.size));
    }

    if ( Selection ) AllSelection.__proto__ = Selection;
    AllSelection.prototype = Object.create( Selection && Selection.prototype );
    AllSelection.prototype.constructor = AllSelection;
    AllSelection.prototype.replace = function replace (tr, content) {
        if ( content === void 0 ) content = Slice.empty;

        if (content == Slice.empty) {
            tr.delete(0, tr.doc.content.size);
            var sel = Selection.atStart(tr.doc);
            if (!sel.eq(tr.selection))
                { tr.setSelection(sel); }
        }
        else {
            Selection.prototype.replace.call(this, tr, content);
        }
    };
    AllSelection.prototype.toJSON = function toJSON () { return { type: "all" }; };
    /**
    @internal
    */
    AllSelection.fromJSON = function fromJSON (doc) { return new AllSelection(doc); };
    AllSelection.prototype.map = function map (doc) { return new AllSelection(doc); };
    AllSelection.prototype.eq = function eq (other) { return other instanceof AllSelection; };
    AllSelection.prototype.getBookmark = function getBookmark () { return AllBookmark; };

    return AllSelection;
}(Selection));
Selection.jsonID("all", AllSelection);
var AllBookmark = {
    map: function map() { return this; },
    resolve: function resolve(doc) { return new AllSelection(doc); }
};
// FIXME we'll need some awareness of text direction when scanning for selections
// Try to find a selection inside the given node. `pos` points at the
// position where the search starts. When `text` is true, only return
// text selections.
function findSelectionIn(doc, node, pos, index, dir, text) {
    if ( text === void 0 ) text = false;

    if (node.inlineContent)
        { return TextSelection.create(doc, pos); }
    for (var i = index - (dir > 0 ? 0 : 1); dir > 0 ? i < node.childCount : i >= 0; i += dir) {
        var child = node.child(i);
        if (!child.isAtom) {
            var inner = findSelectionIn(doc, child, pos + dir, dir < 0 ? child.childCount : 0, dir, text);
            if (inner)
                { return inner; }
        }
        else if (!text && NodeSelection.isSelectable(child)) {
            return NodeSelection.create(doc, pos - (dir < 0 ? child.nodeSize : 0));
        }
        pos += child.nodeSize * dir;
    }
    return null;
}
function selectionToInsertionEnd(tr, startLen, bias) {
    var last = tr.steps.length - 1;
    if (last < startLen)
        { return; }
    var step = tr.steps[last];
    if (!(step instanceof ReplaceStep || step instanceof ReplaceAroundStep))
        { return; }
    var map = tr.mapping.maps[last], end;
    map.forEach(function (_from, _to, _newFrom, newTo) { if (end == null)
        { end = newTo; } });
    tr.setSelection(Selection.near(tr.doc.resolve(end), bias));
}

var UPDATED_SEL = 1, UPDATED_MARKS = 2, UPDATED_SCROLL = 4;
/**
An editor state transaction, which can be applied to a state to
create an updated state. Use
[`EditorState.tr`](https://prosemirror.net/docs/ref/#state.EditorState.tr) to create an instance.

Transactions track changes to the document (they are a subclass of
[`Transform`](https://prosemirror.net/docs/ref/#transform.Transform)), but also other state changes,
like selection updates and adjustments of the set of [stored
marks](https://prosemirror.net/docs/ref/#state.EditorState.storedMarks). In addition, you can store
metadata properties in a transaction, which are extra pieces of
information that client code or plugins can use to describe what a
transaction represents, so that they can update their [own
state](https://prosemirror.net/docs/ref/#state.StateField) accordingly.

The [editor view](https://prosemirror.net/docs/ref/#view.EditorView) uses a few metadata
properties: it will attach a property `"pointer"` with the value
`true` to selection transactions directly caused by mouse or touch
input, a `"composition"` property holding an ID identifying the
composition that caused it to transactions caused by composed DOM
input, and a `"uiEvent"` property of that may be `"paste"`,
`"cut"`, or `"drop"`.
*/
var Transaction$1 = /*@__PURE__*/(function (Transform) {
    function Transaction(state) {
        Transform.call(this, state.doc);
        // The step count for which the current selection is valid.
        this.curSelectionFor = 0;
        // Bitfield to track which aspects of the state were updated by
        // this transaction.
        this.updated = 0;
        // Object used to store metadata properties for the transaction.
        this.meta = Object.create(null);
        this.time = Date.now();
        this.curSelection = state.selection;
        this.storedMarks = state.storedMarks;
    }

    if ( Transform ) Transaction.__proto__ = Transform;
    Transaction.prototype = Object.create( Transform && Transform.prototype );
    Transaction.prototype.constructor = Transaction;

    var prototypeAccessors$2 = { selection: { configurable: true },selectionSet: { configurable: true },storedMarksSet: { configurable: true },isGeneric: { configurable: true },scrolledIntoView: { configurable: true } };
    /**
    The transaction's current selection. This defaults to the editor
    selection [mapped](https://prosemirror.net/docs/ref/#state.Selection.map) through the steps in the
    transaction, but can be overwritten with
    [`setSelection`](https://prosemirror.net/docs/ref/#state.Transaction.setSelection).
    */
    prototypeAccessors$2.selection.get = function () {
        if (this.curSelectionFor < this.steps.length) {
            this.curSelection = this.curSelection.map(this.doc, this.mapping.slice(this.curSelectionFor));
            this.curSelectionFor = this.steps.length;
        }
        return this.curSelection;
    };
    /**
    Update the transaction's current selection. Will determine the
    selection that the editor gets when the transaction is applied.
    */
    Transaction.prototype.setSelection = function setSelection (selection) {
        if (selection.$from.doc != this.doc)
            { throw new RangeError("Selection passed to setSelection must point at the current document"); }
        this.curSelection = selection;
        this.curSelectionFor = this.steps.length;
        this.updated = (this.updated | UPDATED_SEL) & ~UPDATED_MARKS;
        this.storedMarks = null;
        return this;
    };
    /**
    Whether the selection was explicitly updated by this transaction.
    */
    prototypeAccessors$2.selectionSet.get = function () {
        return (this.updated & UPDATED_SEL) > 0;
    };
    /**
    Set the current stored marks.
    */
    Transaction.prototype.setStoredMarks = function setStoredMarks (marks) {
        this.storedMarks = marks;
        this.updated |= UPDATED_MARKS;
        return this;
    };
    /**
    Make sure the current stored marks or, if that is null, the marks
    at the selection, match the given set of marks. Does nothing if
    this is already the case.
    */
    Transaction.prototype.ensureMarks = function ensureMarks (marks) {
        if (!Mark.sameSet(this.storedMarks || this.selection.$from.marks(), marks))
            { this.setStoredMarks(marks); }
        return this;
    };
    /**
    Add a mark to the set of stored marks.
    */
    Transaction.prototype.addStoredMark = function addStoredMark (mark) {
        return this.ensureMarks(mark.addToSet(this.storedMarks || this.selection.$head.marks()));
    };
    /**
    Remove a mark or mark type from the set of stored marks.
    */
    Transaction.prototype.removeStoredMark = function removeStoredMark (mark) {
        return this.ensureMarks(mark.removeFromSet(this.storedMarks || this.selection.$head.marks()));
    };
    /**
    Whether the stored marks were explicitly set for this transaction.
    */
    prototypeAccessors$2.storedMarksSet.get = function () {
        return (this.updated & UPDATED_MARKS) > 0;
    };
    /**
    @internal
    */
    Transaction.prototype.addStep = function addStep (step, doc) {
        Transform.prototype.addStep.call(this, step, doc);
        this.updated = this.updated & ~UPDATED_MARKS;
        this.storedMarks = null;
    };
    /**
    Update the timestamp for the transaction.
    */
    Transaction.prototype.setTime = function setTime (time) {
        this.time = time;
        return this;
    };
    /**
    Replace the current selection with the given slice.
    */
    Transaction.prototype.replaceSelection = function replaceSelection (slice) {
        this.selection.replace(this, slice);
        return this;
    };
    /**
    Replace the selection with the given node. When `inheritMarks` is
    true and the content is inline, it inherits the marks from the
    place where it is inserted.
    */
    Transaction.prototype.replaceSelectionWith = function replaceSelectionWith (node, inheritMarks) {
        if ( inheritMarks === void 0 ) inheritMarks = true;

        var selection = this.selection;
        if (inheritMarks)
            { node = node.mark(this.storedMarks || (selection.empty ? selection.$from.marks() : (selection.$from.marksAcross(selection.$to) || Mark.none))); }
        selection.replaceWith(this, node);
        return this;
    };
    /**
    Delete the selection.
    */
    Transaction.prototype.deleteSelection = function deleteSelection () {
        this.selection.replace(this);
        return this;
    };
    /**
    Replace the given range, or the selection if no range is given,
    with a text node containing the given string.
    */
    Transaction.prototype.insertText = function insertText (text, from, to) {
        var schema = this.doc.type.schema;
        if (from == null) {
            if (!text)
                { return this.deleteSelection(); }
            return this.replaceSelectionWith(schema.text(text), true);
        }
        else {
            if (to == null)
                { to = from; }
            to = to == null ? from : to;
            if (!text)
                { return this.deleteRange(from, to); }
            var marks = this.storedMarks;
            if (!marks) {
                var $from = this.doc.resolve(from);
                marks = to == from ? $from.marks() : $from.marksAcross(this.doc.resolve(to));
            }
            this.replaceRangeWith(from, to, schema.text(text, marks));
            if (!this.selection.empty)
                { this.setSelection(Selection.near(this.selection.$to)); }
            return this;
        }
    };
    /**
    Store a metadata property in this transaction, keyed either by
    name or by plugin.
    */
    Transaction.prototype.setMeta = function setMeta (key, value) {
        this.meta[typeof key == "string" ? key : key.key] = value;
        return this;
    };
    /**
    Retrieve a metadata property for a given name or plugin.
    */
    Transaction.prototype.getMeta = function getMeta (key) {
        return this.meta[typeof key == "string" ? key : key.key];
    };
    /**
    Returns true if this transaction doesn't contain any metadata,
    and can thus safely be extended.
    */
    prototypeAccessors$2.isGeneric.get = function () {
        for (var _ in this.meta)
            { return false; }
        return true;
    };
    /**
    Indicate that the editor should scroll the selection into view
    when updated to the state produced by this transaction.
    */
    Transaction.prototype.scrollIntoView = function scrollIntoView () {
        this.updated |= UPDATED_SCROLL;
        return this;
    };
    /**
    True when this transaction has had `scrollIntoView` called on it.
    */
    prototypeAccessors$2.scrolledIntoView.get = function () {
        return (this.updated & UPDATED_SCROLL) > 0;
    };

    Object.defineProperties( Transaction.prototype, prototypeAccessors$2 );

    return Transaction;
}(Transform));

function bind(f, self) {
    return !self || !f ? f : f.bind(self);
}
var FieldDesc = function FieldDesc(name, desc, self) {
    this.name = name;
    this.init = bind(desc.init, self);
    this.apply = bind(desc.apply, self);
};
var baseFields = [
    new FieldDesc("doc", {
        init: function init(config) { return config.doc || config.schema.topNodeType.createAndFill(); },
        apply: function apply(tr) { return tr.doc; }
    }),
    new FieldDesc("selection", {
        init: function init(config, instance) { return config.selection || Selection.atStart(instance.doc); },
        apply: function apply(tr) { return tr.selection; }
    }),
    new FieldDesc("storedMarks", {
        init: function init(config) { return config.storedMarks || null; },
        apply: function apply(tr, _marks, _old, state) { return state.selection.$cursor ? tr.storedMarks : null; }
    }),
    new FieldDesc("scrollToSelection", {
        init: function init() { return 0; },
        apply: function apply(tr, prev) { return tr.scrolledIntoView ? prev + 1 : prev; }
    })
];
// Object wrapping the part of a state object that stays the same
// across transactions. Stored in the state's `config` property.
var Configuration$1 = function Configuration(schema, plugins) {
    var this$1$1 = this;

    this.schema = schema;
    this.plugins = [];
    this.pluginsByKey = Object.create(null);
    this.fields = baseFields.slice();
    if (plugins)
        { plugins.forEach(function (plugin) {
            if (this$1$1.pluginsByKey[plugin.key])
                { throw new RangeError("Adding different instances of a keyed plugin (" + plugin.key + ")"); }
            this$1$1.plugins.push(plugin);
            this$1$1.pluginsByKey[plugin.key] = plugin;
            if (plugin.spec.state)
                { this$1$1.fields.push(new FieldDesc(plugin.key, plugin.spec.state, plugin)); }
        }); }
};
/**
The state of a ProseMirror editor is represented by an object of
this type. A state is a persistent data structure—it isn't
updated, but rather a new state value is computed from an old one
using the [`apply`](https://prosemirror.net/docs/ref/#state.EditorState.apply) method.

A state holds a number of built-in fields, and plugins can
[define](https://prosemirror.net/docs/ref/#state.PluginSpec.state) additional fields.
*/
var EditorState$1 = function EditorState(
/**
@internal
*/
config) {
    this.config = config;
};

var prototypeAccessors$3$2 = { schema: { configurable: true },plugins: { configurable: true },tr: { configurable: true } };
/**
The schema of the state's document.
*/
prototypeAccessors$3$2.schema.get = function () {
    return this.config.schema;
};
/**
The plugins that are active in this state.
*/
prototypeAccessors$3$2.plugins.get = function () {
    return this.config.plugins;
};
/**
Apply the given transaction to produce a new state.
*/
EditorState$1.prototype.apply = function apply (tr) {
    return this.applyTransaction(tr).state;
};
/**
@internal
*/
EditorState$1.prototype.filterTransaction = function filterTransaction (tr, ignore) {
        if ( ignore === void 0 ) ignore = -1;

    for (var i = 0; i < this.config.plugins.length; i++)
        { if (i != ignore) {
            var plugin = this.config.plugins[i];
            if (plugin.spec.filterTransaction && !plugin.spec.filterTransaction.call(plugin, tr, this))
                { return false; }
        } }
    return true;
};
/**
Verbose variant of [`apply`](https://prosemirror.net/docs/ref/#state.EditorState.apply) that
returns the precise transactions that were applied (which might
be influenced by the [transaction
hooks](https://prosemirror.net/docs/ref/#state.PluginSpec.filterTransaction) of
plugins) along with the new state.
*/
EditorState$1.prototype.applyTransaction = function applyTransaction (rootTr) {
    if (!this.filterTransaction(rootTr))
        { return { state: this, transactions: [] }; }
    var trs = [rootTr], newState = this.applyInner(rootTr), seen = null;
    // This loop repeatedly gives plugins a chance to respond to
    // transactions as new transactions are added, making sure to only
    // pass the transactions the plugin did not see before.
    for (;;) {
        var haveNew = false;
        for (var i = 0; i < this.config.plugins.length; i++) {
            var plugin = this.config.plugins[i];
            if (plugin.spec.appendTransaction) {
                var n = seen ? seen[i].n : 0, oldState = seen ? seen[i].state : this;
                var tr = n < trs.length &&
                    plugin.spec.appendTransaction.call(plugin, n ? trs.slice(n) : trs, oldState, newState);
                if (tr && newState.filterTransaction(tr, i)) {
                    tr.setMeta("appendedTransaction", rootTr);
                    if (!seen) {
                        seen = [];
                        for (var j = 0; j < this.config.plugins.length; j++)
                            { seen.push(j < i ? { state: newState, n: trs.length } : { state: this, n: 0 }); }
                    }
                    trs.push(tr);
                    newState = newState.applyInner(tr);
                    haveNew = true;
                }
                if (seen)
                    { seen[i] = { state: newState, n: trs.length }; }
            }
        }
        if (!haveNew)
            { return { state: newState, transactions: trs }; }
    }
};
/**
@internal
*/
EditorState$1.prototype.applyInner = function applyInner (tr) {
    if (!tr.before.eq(this.doc))
        { throw new RangeError("Applying a mismatched transaction"); }
    var newInstance = new EditorState$1(this.config), fields = this.config.fields;
    for (var i = 0; i < fields.length; i++) {
        var field = fields[i];
        newInstance[field.name] = field.apply(tr, this[field.name], this, newInstance);
    }
    return newInstance;
};
/**
Start a [transaction](https://prosemirror.net/docs/ref/#state.Transaction) from this state.
*/
prototypeAccessors$3$2.tr.get = function () { return new Transaction$1(this); };
/**
Create a new state.
*/
EditorState$1.create = function create (config) {
    var $config = new Configuration$1(config.doc ? config.doc.type.schema : config.schema, config.plugins);
    var instance = new EditorState$1($config);
    for (var i = 0; i < $config.fields.length; i++)
        { instance[$config.fields[i].name] = $config.fields[i].init(config, instance); }
    return instance;
};
/**
Create a new state based on this one, but with an adjusted set
of active plugins. State fields that exist in both sets of
plugins are kept unchanged. Those that no longer exist are
dropped, and those that are new are initialized using their
[`init`](https://prosemirror.net/docs/ref/#state.StateField.init) method, passing in the new
configuration object..
*/
EditorState$1.prototype.reconfigure = function reconfigure (config) {
    var $config = new Configuration$1(this.schema, config.plugins);
    var fields = $config.fields, instance = new EditorState$1($config);
    for (var i = 0; i < fields.length; i++) {
        var name = fields[i].name;
        instance[name] = this.hasOwnProperty(name) ? this[name] : fields[i].init(config, instance);
    }
    return instance;
};
/**
Serialize this state to JSON. If you want to serialize the state
of plugins, pass an object mapping property names to use in the
resulting JSON object to plugin objects. The argument may also be
a string or number, in which case it is ignored, to support the
way `JSON.stringify` calls `toString` methods.
*/
EditorState$1.prototype.toJSON = function toJSON (pluginFields) {
    var result = { doc: this.doc.toJSON(), selection: this.selection.toJSON() };
    if (this.storedMarks)
        { result.storedMarks = this.storedMarks.map(function (m) { return m.toJSON(); }); }
    if (pluginFields && typeof pluginFields == 'object')
        { for (var prop in pluginFields) {
            if (prop == "doc" || prop == "selection")
                { throw new RangeError("The JSON fields `doc` and `selection` are reserved"); }
            var plugin = pluginFields[prop], state = plugin.spec.state;
            if (state && state.toJSON)
                { result[prop] = state.toJSON.call(plugin, this[plugin.key]); }
        } }
    return result;
};
/**
Deserialize a JSON representation of a state. `config` should
have at least a `schema` field, and should contain array of
plugins to initialize the state with. `pluginFields` can be used
to deserialize the state of plugins, by associating plugin
instances with the property names they use in the JSON object.
*/
EditorState$1.fromJSON = function fromJSON (config, json, pluginFields) {
    if (!json)
        { throw new RangeError("Invalid input for EditorState.fromJSON"); }
    if (!config.schema)
        { throw new RangeError("Required config field 'schema' missing"); }
    var $config = new Configuration$1(config.schema, config.plugins);
    var instance = new EditorState$1($config);
    $config.fields.forEach(function (field) {
        if (field.name == "doc") {
            instance.doc = Node$1.fromJSON(config.schema, json.doc);
        }
        else if (field.name == "selection") {
            instance.selection = Selection.fromJSON(instance.doc, json.selection);
        }
        else if (field.name == "storedMarks") {
            if (json.storedMarks)
                { instance.storedMarks = json.storedMarks.map(config.schema.markFromJSON); }
        }
        else {
            if (pluginFields)
                { for (var prop in pluginFields) {
                    var plugin = pluginFields[prop], state = plugin.spec.state;
                    if (plugin.key == field.name && state && state.fromJSON &&
                        Object.prototype.hasOwnProperty.call(json, prop)) {
                        instance[field.name] = state.fromJSON.call(plugin, config, json[prop], instance);
                        return;
                    }
                } }
            instance[field.name] = field.init(config, instance);
        }
    });
    return instance;
};

Object.defineProperties( EditorState$1.prototype, prototypeAccessors$3$2 );

function bindProps(obj, self, target) {
    for (var prop in obj) {
        var val = obj[prop];
        if (val instanceof Function)
            { val = val.bind(self); }
        else if (prop == "handleDOMEvents")
            { val = bindProps(val, self, {}); }
        target[prop] = val;
    }
    return target;
}
/**
Plugins bundle functionality that can be added to an editor.
They are part of the [editor state](https://prosemirror.net/docs/ref/#state.EditorState) and
may influence that state and the view that contains it.
*/
var Plugin = function Plugin(
/**
The plugin's [spec object](https://prosemirror.net/docs/ref/#state.PluginSpec).
*/
spec) {
    this.spec = spec;
    /**
    The [props](https://prosemirror.net/docs/ref/#view.EditorProps) exported by this plugin.
    */
    this.props = {};
    if (spec.props)
        { bindProps(spec.props, this, this.props); }
    this.key = spec.key ? spec.key.key : createKey("plugin");
};
/**
Extract the plugin's state field from an editor state.
*/
Plugin.prototype.getState = function getState (state) { return state[this.key]; };
var keys = Object.create(null);
function createKey(name) {
    if (name in keys)
        { return name + "$" + ++keys[name]; }
    keys[name] = 0;
    return name + "$";
}
/**
A key is used to [tag](https://prosemirror.net/docs/ref/#state.PluginSpec.key) plugins in a way
that makes it possible to find them, given an editor state.
Assigning a key does mean only one plugin of that type can be
active in a state.
*/
var PluginKey = function PluginKey(name) {
if ( name === void 0 ) name = "key";
 this.key = createKey(name); };
/**
Get the active plugin with this key, if any, from an editor
state.
*/
PluginKey.prototype.get = function get (state) { return state.config.pluginsByKey[this.key]; };
/**
Get the plugin's state from an editor state.
*/
PluginKey.prototype.getState = function getState (state) { return state[this.key]; };var state=/*#__PURE__*/Object.freeze({__proto__:null,AllSelection:AllSelection,EditorState:EditorState$1,NodeSelection:NodeSelection,Plugin:Plugin,PluginKey:PluginKey,Selection:Selection,SelectionRange:SelectionRange$1,TextSelection:TextSelection,Transaction:Transaction$1});var domIndex$1 = function (node) {
    for (var index = 0;; index++) {
        node = node.previousSibling;
        if (!node)
            { return index; }
    }
};
var parentNode = function (node) {
    var parent = node.assignedSlot || node.parentNode;
    return parent && parent.nodeType == 11 ? parent.host : parent;
};
var reusedRange = null;
// Note that this will always return the same range, because DOM range
// objects are every expensive, and keep slowing down subsequent DOM
// updates, for some reason.
var textRange$1 = function (node, from, to) {
    var range = reusedRange || (reusedRange = document.createRange());
    range.setEnd(node, to == null ? node.nodeValue.length : to);
    range.setStart(node, from || 0);
    return range;
};
var clearReusedRange = function () {
    reusedRange = null;
};
// 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)
var isEquivalentPosition$1 = function (node, off, targetNode, targetOff) {
    return targetNode && (scanFor$1(node, off, targetNode, targetOff, -1) ||
        scanFor$1(node, off, targetNode, targetOff, 1));
};
var atomElements = /^(img|br|input|textarea|hr)$/i;
function scanFor$1(node, off, targetNode, targetOff, dir) {
    for (;;) {
        if (node == targetNode && off == targetOff)
            { return true; }
        if (off == (dir < 0 ? 0 : nodeSize$1(node))) {
            var parent = node.parentNode;
            if (!parent || parent.nodeType != 1 || hasBlockDesc(node) || atomElements.test(node.nodeName) ||
                node.contentEditable == "false")
                { return false; }
            off = domIndex$1(node) + (dir < 0 ? 0 : 1);
            node = parent;
        }
        else if (node.nodeType == 1) {
            node = node.childNodes[off + (dir < 0 ? -1 : 0)];
            if (node.contentEditable == "false")
                { return false; }
            off = dir < 0 ? nodeSize$1(node) : 0;
        }
        else {
            return false;
        }
    }
}
function nodeSize$1(node) {
    return node.nodeType == 3 ? node.nodeValue.length : node.childNodes.length;
}
function textNodeBefore$1(node, offset) {
    for (;;) {
        if (node.nodeType == 3 && offset)
            { return node; }
        if (node.nodeType == 1 && offset > 0) {
            if (node.contentEditable == "false")
                { return null; }
            node = node.childNodes[offset - 1];
            offset = nodeSize$1(node);
        }
        else if (node.parentNode && !hasBlockDesc(node)) {
            offset = domIndex$1(node);
            node = node.parentNode;
        }
        else {
            return null;
        }
    }
}
function textNodeAfter$1(node, offset) {
    for (;;) {
        if (node.nodeType == 3 && offset < node.nodeValue.length)
            { return node; }
        if (node.nodeType == 1 && offset < node.childNodes.length) {
            if (node.contentEditable == "false")
                { return null; }
            node = node.childNodes[offset];
            offset = 0;
        }
        else if (node.parentNode && !hasBlockDesc(node)) {
            offset = domIndex$1(node) + 1;
            node = node.parentNode;
        }
        else {
            return null;
        }
    }
}
function isOnEdge(node, offset, parent) {
    for (var atStart = offset == 0, atEnd = offset == nodeSize$1(node); atStart || atEnd;) {
        if (node == parent)
            { return true; }
        var index = domIndex$1(node);
        node = node.parentNode;
        if (!node)
            { return false; }
        atStart = atStart && index == 0;
        atEnd = atEnd && index == nodeSize$1(node);
    }
}
function hasBlockDesc(dom) {
    var desc;
    for (var cur = dom; cur; cur = cur.parentNode)
        { if (desc = cur.pmViewDesc)
            { break; } }
    return desc && desc.node && desc.node.isBlock && (desc.dom == dom || desc.contentDOM == dom);
}
// Work around Chrome issue https://bugs.chromium.org/p/chromium/issues/detail?id=447523
// (isCollapsed inappropriately returns true in shadow dom)
var selectionCollapsed = function (domSel) {
    return domSel.focusNode && isEquivalentPosition$1(domSel.focusNode, domSel.focusOffset, domSel.anchorNode, domSel.anchorOffset);
};
function keyEvent(keyCode, key) {
    var event = document.createEvent("Event");
    event.initEvent("keydown", true, true);
    event.keyCode = keyCode;
    event.key = event.code = key;
    return event;
}
function deepActiveElement(doc) {
    var elt = doc.activeElement;
    while (elt && elt.shadowRoot)
        { elt = elt.shadowRoot.activeElement; }
    return elt;
}
function caretFromPoint(doc, x, y) {
    if (doc.caretPositionFromPoint) {
        try { // Firefox throws for this call in hard-to-predict circumstances (#994)
            var pos = doc.caretPositionFromPoint(x, y);
            // Clip the offset, because Chrome will return a text offset
            // into <input> nodes, which can't be treated as a regular DOM
            // offset
            if (pos)
                { return { node: pos.offsetNode, offset: Math.min(nodeSize$1(pos.offsetNode), pos.offset) }; }
        }
        catch (_) { }
    }
    if (doc.caretRangeFromPoint) {
        var range = doc.caretRangeFromPoint(x, y);
        if (range)
            { return { node: range.startContainer, offset: Math.min(nodeSize$1(range.startContainer), range.startOffset) }; }
    }
}

var nav$1 = typeof navigator != "undefined" ? navigator : null;
var doc$2 = typeof document != "undefined" ? document : null;
var agent = (nav$1 && nav$1.userAgent) || "";
var ie_edge$1 = /Edge\/(\d+)/.exec(agent);
var ie_upto10$1 = /MSIE \d/.exec(agent);
var ie_11up$1 = /Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(agent);
var ie$2 = !!(ie_upto10$1 || ie_11up$1 || ie_edge$1);
var ie_version = ie_upto10$1 ? document.documentMode : ie_11up$1 ? +ie_11up$1[1] : ie_edge$1 ? +ie_edge$1[1] : 0;
var gecko$1 = !ie$2 && /gecko\/(\d+)/i.test(agent);
gecko$1 && +(/Firefox\/(\d+)/.exec(agent) || [0, 0])[1];
var _chrome = !ie$2 && /Chrome\/(\d+)/.exec(agent);
var chrome$1 = !!_chrome;
var chrome_version = _chrome ? +_chrome[1] : 0;
var safari$1 = !ie$2 && !!nav$1 && /Apple Computer/.test(nav$1.vendor);
// Is true for both iOS and iPadOS for convenience
var ios$1 = safari$1 && (/Mobile\/\w+/.test(agent) || !!nav$1 && nav$1.maxTouchPoints > 2);
var mac$4 = ios$1 || (nav$1 ? /Mac/.test(nav$1.platform) : false);
var windows = nav$1 ? /Win/.test(nav$1.platform) : false;
var android$1 = /Android \d/.test(agent);
var webkit$1 = !!doc$2 && "webkitFontSmoothing" in doc$2.documentElement.style;
var webkit_version = webkit$1 ? +(/\bAppleWebKit\/(\d+)/.exec(navigator.userAgent) || [0, 0])[1] : 0;

function windowRect$1(doc) {
    var vp = doc.defaultView && doc.defaultView.visualViewport;
    if (vp)
        { return {
            left: 0, right: vp.width,
            top: 0, bottom: vp.height
        }; }
    return { left: 0, right: doc.documentElement.clientWidth,
        top: 0, bottom: doc.documentElement.clientHeight };
}
function getSide(value, side) {
    return typeof value == "number" ? value : value[side];
}
function clientRect(node) {
    var rect = node.getBoundingClientRect();
    // Adjust for elements with style "transform: scale()"
    var scaleX = (rect.width / node.offsetWidth) || 1;
    var scaleY = (rect.height / node.offsetHeight) || 1;
    // Make sure scrollbar width isn't included in the rectangle
    return { left: rect.left, right: rect.left + node.clientWidth * scaleX,
        top: rect.top, bottom: rect.top + node.clientHeight * scaleY };
}
function scrollRectIntoView$1(view, rect, startDOM) {
    var scrollThreshold = view.someProp("scrollThreshold") || 0, scrollMargin = view.someProp("scrollMargin") || 5;
    var doc = view.dom.ownerDocument;
    for (var parent = startDOM || view.dom;; parent = parentNode(parent)) {
        if (!parent)
            { break; }
        if (parent.nodeType != 1)
            { continue; }
        var elt = parent;
        var atTop = elt == doc.body;
        var bounding = atTop ? windowRect$1(doc) : clientRect(elt);
        var moveX = 0, moveY = 0;
        if (rect.top < bounding.top + getSide(scrollThreshold, "top"))
            { moveY = -(bounding.top - rect.top + getSide(scrollMargin, "top")); }
        else if (rect.bottom > bounding.bottom - getSide(scrollThreshold, "bottom"))
            { moveY = rect.bottom - rect.top > bounding.bottom - bounding.top
                ? rect.top + getSide(scrollMargin, "top") - bounding.top
                : rect.bottom - bounding.bottom + getSide(scrollMargin, "bottom"); }
        if (rect.left < bounding.left + getSide(scrollThreshold, "left"))
            { moveX = -(bounding.left - rect.left + getSide(scrollMargin, "left")); }
        else if (rect.right > bounding.right - getSide(scrollThreshold, "right"))
            { moveX = rect.right - bounding.right + getSide(scrollMargin, "right"); }
        if (moveX || moveY) {
            if (atTop) {
                doc.defaultView.scrollBy(moveX, moveY);
            }
            else {
                var startX = elt.scrollLeft, startY = elt.scrollTop;
                if (moveY)
                    { elt.scrollTop += moveY; }
                if (moveX)
                    { elt.scrollLeft += moveX; }
                var dX = elt.scrollLeft - startX, dY = elt.scrollTop - startY;
                rect = { left: rect.left - dX, top: rect.top - dY, right: rect.right - dX, bottom: rect.bottom - dY };
            }
        }
        if (atTop || /^(fixed|sticky)$/.test(getComputedStyle(parent).position))
            { break; }
    }
}
// Store the scroll position of the editor's parent nodes, along with
// the top position of an element near the top of the editor, which
// will be used to make sure the visible viewport remains stable even
// when the size of the content above changes.
function storeScrollPos(view) {
    var rect = view.dom.getBoundingClientRect(), startY = Math.max(0, rect.top);
    var refDOM, refTop;
    for (var x = (rect.left + rect.right) / 2, y = startY + 1; y < Math.min(innerHeight, rect.bottom); y += 5) {
        var dom = view.root.elementFromPoint(x, y);
        if (!dom || dom == view.dom || !view.dom.contains(dom))
            { continue; }
        var localRect = dom.getBoundingClientRect();
        if (localRect.top >= startY - 20) {
            refDOM = dom;
            refTop = localRect.top;
            break;
        }
    }
    return { refDOM: refDOM, refTop: refTop, stack: scrollStack(view.dom) };
}
function scrollStack(dom) {
    var stack = [], doc = dom.ownerDocument;
    for (var cur = dom; cur; cur = parentNode(cur)) {
        stack.push({ dom: cur, top: cur.scrollTop, left: cur.scrollLeft });
        if (dom == doc)
            { break; }
    }
    return stack;
}
// Reset the scroll position of the editor's parent nodes to that what
// it was before, when storeScrollPos was called.
function resetScrollPos(ref) {
    var refDOM = ref.refDOM;
    var refTop = ref.refTop;
    var stack = ref.stack;

    var newRefTop = refDOM ? refDOM.getBoundingClientRect().top : 0;
    restoreScrollStack(stack, newRefTop == 0 ? 0 : newRefTop - refTop);
}
function restoreScrollStack(stack, dTop) {
    for (var i = 0; i < stack.length; i++) {
        var ref = stack[i];
        var dom = ref.dom;
        var top = ref.top;
        var left = ref.left;
        if (dom.scrollTop != top + dTop)
            { dom.scrollTop = top + dTop; }
        if (dom.scrollLeft != left)
            { dom.scrollLeft = left; }
    }
}
var preventScrollSupported$1 = null;
// Feature-detects support for .focus({preventScroll: true}), and uses
// a fallback kludge when not supported.
function focusPreventScroll$1(dom) {
    if (dom.setActive)
        { return dom.setActive(); } // in IE
    if (preventScrollSupported$1)
        { return dom.focus(preventScrollSupported$1); }
    var stored = scrollStack(dom);
    dom.focus(preventScrollSupported$1 == null ? {
        get preventScroll() {
            preventScrollSupported$1 = { preventScroll: true };
            return true;
        }
    } : undefined);
    if (!preventScrollSupported$1) {
        preventScrollSupported$1 = false;
        restoreScrollStack(stored, 0);
    }
}
function findOffsetInNode(node, coords) {
    var closest, dxClosest = 2e8, coordsClosest, offset = 0;
    var rowBot = coords.top, rowTop = coords.top;
    var firstBelow, coordsBelow;
    for (var child = node.firstChild, childIndex = 0; child; child = child.nextSibling, childIndex++) {
        var rects = (void 0);
        if (child.nodeType == 1)
            { rects = child.getClientRects(); }
        else if (child.nodeType == 3)
            { rects = textRange$1(child).getClientRects(); }
        else
            { continue; }
        for (var i = 0; i < rects.length; i++) {
            var rect = rects[i];
            if (rect.top <= rowBot && rect.bottom >= rowTop) {
                rowBot = Math.max(rect.bottom, rowBot);
                rowTop = Math.min(rect.top, rowTop);
                var dx = rect.left > coords.left ? rect.left - coords.left
                    : rect.right < coords.left ? coords.left - rect.right : 0;
                if (dx < dxClosest) {
                    closest = child;
                    dxClosest = dx;
                    coordsClosest = dx && closest.nodeType == 3 ? {
                        left: rect.right < coords.left ? rect.right : rect.left,
                        top: coords.top
                    } : coords;
                    if (child.nodeType == 1 && dx)
                        { offset = childIndex + (coords.left >= (rect.left + rect.right) / 2 ? 1 : 0); }
                    continue;
                }
            }
            else if (rect.top > coords.top && !firstBelow && rect.left <= coords.left && rect.right >= coords.left) {
                firstBelow = child;
                coordsBelow = { left: Math.max(rect.left, Math.min(rect.right, coords.left)), top: rect.top };
            }
            if (!closest && (coords.left >= rect.right && coords.top >= rect.top ||
                coords.left >= rect.left && coords.top >= rect.bottom))
                { offset = childIndex + 1; }
        }
    }
    if (!closest && firstBelow) {
        closest = firstBelow;
        coordsClosest = coordsBelow;
        dxClosest = 0;
    }
    if (closest && closest.nodeType == 3)
        { return findOffsetInText(closest, coordsClosest); }
    if (!closest || (dxClosest && closest.nodeType == 1))
        { return { node: node, offset: offset }; }
    return findOffsetInNode(closest, coordsClosest);
}
function findOffsetInText(node, coords) {
    var len = node.nodeValue.length;
    var range = document.createRange();
    for (var i = 0; i < len; i++) {
        range.setEnd(node, i + 1);
        range.setStart(node, i);
        var rect = singleRect(range, 1);
        if (rect.top == rect.bottom)
            { continue; }
        if (inRect(coords, rect))
            { return { node: node, offset: i + (coords.left >= (rect.left + rect.right) / 2 ? 1 : 0) }; }
    }
    return { node: node, offset: 0 };
}
function inRect(coords, rect) {
    return coords.left >= rect.left - 1 && coords.left <= rect.right + 1 &&
        coords.top >= rect.top - 1 && coords.top <= rect.bottom + 1;
}
function targetKludge(dom, coords) {
    var parent = dom.parentNode;
    if (parent && /^li$/i.test(parent.nodeName) && coords.left < dom.getBoundingClientRect().left)
        { return parent; }
    return dom;
}
function posFromElement(view, elt, coords) {
    var ref = findOffsetInNode(elt, coords);
    var node = ref.node;
    var offset = ref.offset;
    var bias = -1;
    if (node.nodeType == 1 && !node.firstChild) {
        var rect = node.getBoundingClientRect();
        bias = rect.left != rect.right && coords.left > (rect.left + rect.right) / 2 ? 1 : -1;
    }
    return view.docView.posFromDOM(node, offset, bias);
}
function posFromCaret(view, node, offset, coords) {
    // Browser (in caretPosition/RangeFromPoint) will agressively
    // normalize towards nearby inline nodes. Since we are interested in
    // positions between block nodes too, we first walk up the hierarchy
    // of nodes to see if there are block nodes that the coordinates
    // fall outside of. If so, we take the position before/after that
    // block. If not, we call `posFromDOM` on the raw node/offset.
    var outsideBlock = -1;
    for (var cur = node, sawBlock = false;;) {
        if (cur == view.dom)
            { break; }
        var desc = view.docView.nearestDesc(cur, true);
        if (!desc)
            { return null; }
        if (desc.dom.nodeType == 1 && (desc.node.isBlock && desc.parent || !desc.contentDOM)) {
            var rect = desc.dom.getBoundingClientRect();
            if (desc.node.isBlock && desc.parent) {
                // Only apply the horizontal test to the innermost block. Vertical for any parent.
                if (!sawBlock && rect.left > coords.left || rect.top > coords.top)
                    { outsideBlock = desc.posBefore; }
                else if (!sawBlock && rect.right < coords.left || rect.bottom < coords.top)
                    { outsideBlock = desc.posAfter; }
                sawBlock = true;
            }
            if (!desc.contentDOM && outsideBlock < 0 && !desc.node.isText) {
                // If we are inside a leaf, return the side of the leaf closer to the coords
                var before = desc.node.isBlock ? coords.top < (rect.top + rect.bottom) / 2
                    : coords.left < (rect.left + rect.right) / 2;
                return before ? desc.posBefore : desc.posAfter;
            }
        }
        cur = desc.dom.parentNode;
    }
    return outsideBlock > -1 ? outsideBlock : view.docView.posFromDOM(node, offset, -1);
}
function elementFromPoint(element, coords, box) {
    var len = element.childNodes.length;
    if (len && box.top < box.bottom) {
        for (var startI = Math.max(0, Math.min(len - 1, Math.floor(len * (coords.top - box.top) / (box.bottom - box.top)) - 2)), i = startI;;) {
            var child = element.childNodes[i];
            if (child.nodeType == 1) {
                var rects = child.getClientRects();
                for (var j = 0; j < rects.length; j++) {
                    var rect = rects[j];
                    if (inRect(coords, rect))
                        { return elementFromPoint(child, coords, rect); }
                }
            }
            if ((i = (i + 1) % len) == startI)
                { break; }
        }
    }
    return element;
}
// Given an x,y position on the editor, get the position in the document.
function posAtCoords$1(view, coords) {
    var assign;

    var doc = view.dom.ownerDocument, node, offset = 0;
    var caret = caretFromPoint(doc, coords.left, coords.top);
    if (caret)
        { ((assign = caret, node = assign.node, offset = assign.offset)); }
    var elt = (view.root.elementFromPoint ? view.root : doc)
        .elementFromPoint(coords.left, coords.top);
    var pos;
    if (!elt || !view.dom.contains(elt.nodeType != 1 ? elt.parentNode : elt)) {
        var box = view.dom.getBoundingClientRect();
        if (!inRect(coords, box))
            { return null; }
        elt = elementFromPoint(view.dom, coords, box);
        if (!elt)
            { return null; }
    }
    // Safari's caretRangeFromPoint returns nonsense when on a draggable element
    if (safari$1) {
        for (var p = elt; node && p; p = parentNode(p))
            { if (p.draggable)
                { node = undefined; } }
    }
    elt = targetKludge(elt, coords);
    if (node) {
        if (gecko$1 && node.nodeType == 1) {
            // Firefox will sometimes return offsets into <input> nodes, which
            // have no actual children, from caretPositionFromPoint (#953)
            offset = Math.min(offset, node.childNodes.length);
            // It'll also move the returned position before image nodes,
            // even if those are behind it.
            if (offset < node.childNodes.length) {
                var next = node.childNodes[offset], box$1;
                if (next.nodeName == "IMG" && (box$1 = next.getBoundingClientRect()).right <= coords.left &&
                    box$1.bottom > coords.top)
                    { offset++; }
            }
        }
        var prev;
        // When clicking above the right side of an uneditable node, Chrome will report a cursor position after that node.
        if (webkit$1 && offset && node.nodeType == 1 && (prev = node.childNodes[offset - 1]).nodeType == 1 &&
            prev.contentEditable == "false" && prev.getBoundingClientRect().top >= coords.top)
            { offset--; }
        // Suspiciously specific kludge to work around caret*FromPoint
        // never returning a position at the end of the document
        if (node == view.dom && offset == node.childNodes.length - 1 && node.lastChild.nodeType == 1 &&
            coords.top > node.lastChild.getBoundingClientRect().bottom)
            { pos = view.state.doc.content.size; }
        // Ignore positions directly after a BR, since caret*FromPoint
        // 'round up' positions that would be more accurately placed
        // before the BR node.
        else if (offset == 0 || node.nodeType != 1 || node.childNodes[offset - 1].nodeName != "BR")
            { pos = posFromCaret(view, node, offset, coords); }
    }
    if (pos == null)
        { pos = posFromElement(view, elt, coords); }
    var desc = view.docView.nearestDesc(elt, true);
    return { pos: pos, inside: desc ? desc.posAtStart - desc.border : -1 };
}
function nonZero(rect) {
    return rect.top < rect.bottom || rect.left < rect.right;
}
function singleRect(target, bias) {
    var rects = target.getClientRects();
    if (rects.length) {
        var first = rects[bias < 0 ? 0 : rects.length - 1];
        if (nonZero(first))
            { return first; }
    }
    return Array.prototype.find.call(rects, nonZero) || target.getBoundingClientRect();
}
var BIDI = /[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/;
// Given a position in the document model, get a bounding box of the
// character at that position, relative to the window.
function coordsAtPos(view, pos, side) {
    var ref = view.docView.domFromPos(pos, side < 0 ? -1 : 1);
    var node = ref.node;
    var offset = ref.offset;
    var atom = ref.atom;
    var supportEmptyRange = webkit$1 || gecko$1;
    if (node.nodeType == 3) {
        // These browsers support querying empty text ranges. Prefer that in
        // bidi context or when at the end of a node.
        if (supportEmptyRange && (BIDI.test(node.nodeValue) || (side < 0 ? !offset : offset == node.nodeValue.length))) {
            var rect = singleRect(textRange$1(node, offset, offset), side);
            // Firefox returns bad results (the position before the space)
            // when querying a position directly after line-broken
            // whitespace. Detect this situation and and kludge around it
            if (gecko$1 && offset && /\s/.test(node.nodeValue[offset - 1]) && offset < node.nodeValue.length) {
                var rectBefore = singleRect(textRange$1(node, offset - 1, offset - 1), -1);
                if (rectBefore.top == rect.top) {
                    var rectAfter = singleRect(textRange$1(node, offset, offset + 1), -1);
                    if (rectAfter.top != rect.top)
                        { return flattenV(rectAfter, rectAfter.left < rectBefore.left); }
                }
            }
            return rect;
        }
        else {
            var from = offset, to = offset, takeSide = side < 0 ? 1 : -1;
            if (side < 0 && !offset) {
                to++;
                takeSide = -1;
            }
            else if (side >= 0 && offset == node.nodeValue.length) {
                from--;
                takeSide = 1;
            }
            else if (side < 0) {
                from--;
            }
            else {
                to++;
            }
            return flattenV(singleRect(textRange$1(node, from, to), takeSide), takeSide < 0);
        }
    }
    var $dom = view.state.doc.resolve(pos - (atom || 0));
    // Return a horizontal line in block context
    if (!$dom.parent.inlineContent) {
        if (atom == null && offset && (side < 0 || offset == nodeSize$1(node))) {
            var before = node.childNodes[offset - 1];
            if (before.nodeType == 1)
                { return flattenH(before.getBoundingClientRect(), false); }
        }
        if (atom == null && offset < nodeSize$1(node)) {
            var after = node.childNodes[offset];
            if (after.nodeType == 1)
                { return flattenH(after.getBoundingClientRect(), true); }
        }
        return flattenH(node.getBoundingClientRect(), side >= 0);
    }
    // Inline, not in text node (this is not Bidi-safe)
    if (atom == null && offset && (side < 0 || offset == nodeSize$1(node))) {
        var before$1 = node.childNodes[offset - 1];
        var target = before$1.nodeType == 3 ? textRange$1(before$1, nodeSize$1(before$1) - (supportEmptyRange ? 0 : 1))
            // BR nodes tend to only return the rectangle before them.
            // Only use them if they are the last element in their parent
            : before$1.nodeType == 1 && (before$1.nodeName != "BR" || !before$1.nextSibling) ? before$1 : null;
        if (target)
            { return flattenV(singleRect(target, 1), false); }
    }
    if (atom == null && offset < nodeSize$1(node)) {
        var after$1 = node.childNodes[offset];
        while (after$1.pmViewDesc && after$1.pmViewDesc.ignoreForCoords)
            { after$1 = after$1.nextSibling; }
        var target$1 = !after$1 ? null : after$1.nodeType == 3 ? textRange$1(after$1, 0, (supportEmptyRange ? 0 : 1))
            : after$1.nodeType == 1 ? after$1 : null;
        if (target$1)
            { return flattenV(singleRect(target$1, -1), true); }
    }
    // All else failed, just try to get a rectangle for the target node
    return flattenV(singleRect(node.nodeType == 3 ? textRange$1(node) : node, -side), side >= 0);
}
function flattenV(rect, left) {
    if (rect.width == 0)
        { return rect; }
    var x = left ? rect.left : rect.right;
    return { top: rect.top, bottom: rect.bottom, left: x, right: x };
}
function flattenH(rect, top) {
    if (rect.height == 0)
        { return rect; }
    var y = top ? rect.top : rect.bottom;
    return { top: y, bottom: y, left: rect.left, right: rect.right };
}
function withFlushedState(view, state, f) {
    var viewState = view.state, active = view.root.activeElement;
    if (viewState != state)
        { view.updateState(state); }
    if (active != view.dom)
        { view.focus(); }
    try {
        return f();
    }
    finally {
        if (viewState != state)
            { view.updateState(viewState); }
        if (active != view.dom && active)
            { active.focus(); }
    }
}
// Whether vertical position motion in a given direction
// from a position would leave a text block.
function endOfTextblockVertical(view, state, dir) {
    var sel = state.selection;
    var $pos = dir == "up" ? sel.$from : sel.$to;
    return withFlushedState(view, state, function () {
        var ref = view.docView.domFromPos($pos.pos, dir == "up" ? -1 : 1);
        var dom = ref.node;
        for (;;) {
            var nearest = view.docView.nearestDesc(dom, true);
            if (!nearest)
                { break; }
            if (nearest.node.isBlock) {
                dom = nearest.contentDOM || nearest.dom;
                break;
            }
            dom = nearest.dom.parentNode;
        }
        var coords = coordsAtPos(view, $pos.pos, 1);
        for (var child = dom.firstChild; child; child = child.nextSibling) {
            var boxes = (void 0);
            if (child.nodeType == 1)
                { boxes = child.getClientRects(); }
            else if (child.nodeType == 3)
                { boxes = textRange$1(child, 0, child.nodeValue.length).getClientRects(); }
            else
                { continue; }
            for (var i = 0; i < boxes.length; i++) {
                var box = boxes[i];
                if (box.bottom > box.top + 1 &&
                    (dir == "up" ? coords.top - box.top > (box.bottom - coords.top) * 2
                        : box.bottom - coords.bottom > (coords.bottom - box.top) * 2))
                    { return false; }
            }
        }
        return true;
    });
}
var maybeRTL = /[\u0590-\u08ac]/;
function endOfTextblockHorizontal(view, state, dir) {
    var ref = state.selection;
    var $head = ref.$head;
    if (!$head.parent.isTextblock)
        { return false; }
    var offset = $head.parentOffset, atStart = !offset, atEnd = offset == $head.parent.content.size;
    var sel = view.domSelection();
    if (!sel)
        { return $head.pos == $head.start() || $head.pos == $head.end(); }
    // If the textblock is all LTR, or the browser doesn't support
    // Selection.modify (Edge), fall back to a primitive approach
    if (!maybeRTL.test($head.parent.textContent) || !sel.modify)
        { return dir == "left" || dir == "backward" ? atStart : atEnd; }
    return withFlushedState(view, state, function () {
        // This is a huge hack, but appears to be the best we can
        // currently do: use `Selection.modify` to move the selection by
        // one character, and see if that moves the cursor out of the
        // textblock (or doesn't move it at all, when at the start/end of
        // the document).
        var ref = view.domSelectionRange();
        var oldNode = ref.focusNode;
        var oldOff = ref.focusOffset;
        var anchorNode = ref.anchorNode;
        var anchorOffset = ref.anchorOffset;
        var oldBidiLevel = sel.caretBidiLevel // Only for Firefox
        ;
        sel.modify("move", dir, "character");
        var parentDOM = $head.depth ? view.docView.domAfterPos($head.before()) : view.dom;
        var ref$1 = view.domSelectionRange();
        var newNode = ref$1.focusNode;
        var newOff = ref$1.focusOffset;
        var result = newNode && !parentDOM.contains(newNode.nodeType == 1 ? newNode : newNode.parentNode) ||
            (oldNode == newNode && oldOff == newOff);
        // Restore the previous selection
        try {
            sel.collapse(anchorNode, anchorOffset);
            if (oldNode && (oldNode != anchorNode || oldOff != anchorOffset) && sel.extend)
                { sel.extend(oldNode, oldOff); }
        }
        catch (_) { }
        if (oldBidiLevel != null)
            { sel.caretBidiLevel = oldBidiLevel; }
        return result;
    });
}
var cachedState = null;
var cachedDir = null;
var cachedResult = false;
function endOfTextblock(view, state, dir) {
    if (cachedState == state && cachedDir == dir)
        { return cachedResult; }
    cachedState = state;
    cachedDir = dir;
    return cachedResult = dir == "up" || dir == "down"
        ? endOfTextblockVertical(view, state, dir)
        : endOfTextblockHorizontal(view, state, dir);
}

// View descriptions are data structures that describe the DOM that is
// used to represent the editor's content. They are used for:
//
// - Incremental redrawing when the document changes
//
// - Figuring out what part of the document a given DOM position
//   corresponds to
//
// - Wiring in custom implementations of the editing interface for a
//   given node
//
// They form a doubly-linked mutable tree, starting at `view.docView`.
var NOT_DIRTY = 0, CHILD_DIRTY = 1, CONTENT_DIRTY = 2, NODE_DIRTY = 3;
// Superclass for the various kinds of descriptions. Defines their
// basic structure and shared methods.
var ViewDesc = function ViewDesc(parent, children, dom, 
// This is the node that holds the child views. It may be null for
// descs that don't have children.
contentDOM) {
    this.parent = parent;
    this.children = children;
    this.dom = dom;
    this.contentDOM = contentDOM;
    this.dirty = NOT_DIRTY;
    // An expando property on the DOM node provides a link back to its
    // description.
    dom.pmViewDesc = this;
};

var prototypeAccessors$5 = { size: { configurable: true },border: { configurable: true },posBefore: { configurable: true },posAtStart: { configurable: true },posAfter: { configurable: true },posAtEnd: { configurable: true },contentLost: { configurable: true },domAtom: { configurable: true },ignoreForCoords: { configurable: true } };
// Used to check whether a given description corresponds to a
// widget/mark/node.
ViewDesc.prototype.matchesWidget = function matchesWidget (widget) { return false; };
ViewDesc.prototype.matchesMark = function matchesMark (mark) { return false; };
ViewDesc.prototype.matchesNode = function matchesNode (node, outerDeco, innerDeco) { return false; };
ViewDesc.prototype.matchesHack = function matchesHack (nodeName) { return false; };
// When parsing in-editor content (in domchange.js), we allow
// descriptions to determine the parse rules that should be used to
// parse them.
ViewDesc.prototype.parseRule = function parseRule () { return null; };
// Used by the editor's event handler to ignore events that come
// from certain descs.
ViewDesc.prototype.stopEvent = function stopEvent (event) { return false; };
// The size of the content represented by this desc.
prototypeAccessors$5.size.get = function () {
    var size = 0;
    for (var i = 0; i < this.children.length; i++)
        { size += this.children[i].size; }
    return size;
};
// For block nodes, this represents the space taken up by their
// start/end tokens.
prototypeAccessors$5.border.get = function () { return 0; };
ViewDesc.prototype.destroy = function destroy () {
    this.parent = undefined;
    if (this.dom.pmViewDesc == this)
        { this.dom.pmViewDesc = undefined; }
    for (var i = 0; i < this.children.length; i++)
        { this.children[i].destroy(); }
};
ViewDesc.prototype.posBeforeChild = function posBeforeChild (child) {
    for (var i = 0, pos = this.posAtStart;; i++) {
        var cur = this.children[i];
        if (cur == child)
            { return pos; }
        pos += cur.size;
    }
};
prototypeAccessors$5.posBefore.get = function () {
    return this.parent.posBeforeChild(this);
};
prototypeAccessors$5.posAtStart.get = function () {
    return this.parent ? this.parent.posBeforeChild(this) + this.border : 0;
};
prototypeAccessors$5.posAfter.get = function () {
    return this.posBefore + this.size;
};
prototypeAccessors$5.posAtEnd.get = function () {
    return this.posAtStart + this.size - 2 * this.border;
};
ViewDesc.prototype.localPosFromDOM = function localPosFromDOM (dom, offset, bias) {
    // If the DOM position is in the content, use the child desc after
    // it to figure out a position.
    if (this.contentDOM && this.contentDOM.contains(dom.nodeType == 1 ? dom : dom.parentNode)) {
        if (bias < 0) {
            var domBefore, desc;
            if (dom == this.contentDOM) {
                domBefore = dom.childNodes[offset - 1];
            }
            else {
                while (dom.parentNode != this.contentDOM)
                    { dom = dom.parentNode; }
                domBefore = dom.previousSibling;
            }
            while (domBefore && !((desc = domBefore.pmViewDesc) && desc.parent == this))
                { domBefore = domBefore.previousSibling; }
            return domBefore ? this.posBeforeChild(desc) + desc.size : this.posAtStart;
        }
        else {
            var domAfter, desc$1;
            if (dom == this.contentDOM) {
                domAfter = dom.childNodes[offset];
            }
            else {
                while (dom.parentNode != this.contentDOM)
                    { dom = dom.parentNode; }
                domAfter = dom.nextSibling;
            }
            while (domAfter && !((desc$1 = domAfter.pmViewDesc) && desc$1.parent == this))
                { domAfter = domAfter.nextSibling; }
            return domAfter ? this.posBeforeChild(desc$1) : this.posAtEnd;
        }
    }
    // Otherwise, use various heuristics, falling back on the bias
    // parameter, to determine whether to return the position at the
    // start or at the end of this view desc.
    var atEnd;
    if (dom == this.dom && this.contentDOM) {
        atEnd = offset > domIndex$1(this.contentDOM);
    }
    else if (this.contentDOM && this.contentDOM != this.dom && this.dom.contains(this.contentDOM)) {
        atEnd = dom.compareDocumentPosition(this.contentDOM) & 2;
    }
    else if (this.dom.firstChild) {
        if (offset == 0)
            { for (var search = dom;; search = search.parentNode) {
                if (search == this.dom) {
                    atEnd = false;
                    break;
                }
                if (search.previousSibling)
                    { break; }
            } }
        if (atEnd == null && offset == dom.childNodes.length)
            { for (var search$1 = dom;; search$1 = search$1.parentNode) {
                if (search$1 == this.dom) {
                    atEnd = true;
                    break;
                }
                if (search$1.nextSibling)
                    { break; }
            } }
    }
    return (atEnd == null ? bias > 0 : atEnd) ? this.posAtEnd : this.posAtStart;
};
ViewDesc.prototype.nearestDesc = function nearestDesc (dom, onlyNodes) {
        if ( onlyNodes === void 0 ) onlyNodes = false;

    for (var first = true, cur = dom; cur; cur = cur.parentNode) {
        var desc = this.getDesc(cur), nodeDOM = (void 0);
        if (desc && (!onlyNodes || desc.node)) {
            // If dom is outside of this desc's nodeDOM, don't count it.
            if (first && (nodeDOM = desc.nodeDOM) &&
                !(nodeDOM.nodeType == 1 ? nodeDOM.contains(dom.nodeType == 1 ? dom : dom.parentNode) : nodeDOM == dom))
                { first = false; }
            else
                { return desc; }
        }
    }
};
ViewDesc.prototype.getDesc = function getDesc (dom) {
    var desc = dom.pmViewDesc;
    for (var cur = desc; cur; cur = cur.parent)
        { if (cur == this)
            { return desc; } }
};
ViewDesc.prototype.posFromDOM = function posFromDOM (dom, offset, bias) {
    for (var scan = dom; scan; scan = scan.parentNode) {
        var desc = this.getDesc(scan);
        if (desc)
            { return desc.localPosFromDOM(dom, offset, bias); }
    }
    return -1;
};
// Find the desc for the node after the given pos, if any. (When a
// parent node overrode rendering, there might not be one.)
ViewDesc.prototype.descAt = function descAt (pos) {
    for (var i = 0, offset = 0; i < this.children.length; i++) {
        var child = this.children[i], end = offset + child.size;
        if (offset == pos && end != offset) {
            while (!child.border && child.children.length)
                { child = child.children[0]; }
            return child;
        }
        if (pos < end)
            { return child.descAt(pos - offset - child.border); }
        offset = end;
    }
};
ViewDesc.prototype.domFromPos = function domFromPos (pos, side) {
    if (!this.contentDOM)
        { return { node: this.dom, offset: 0, atom: pos + 1 }; }
    // First find the position in the child array
    var i = 0, offset = 0;
    for (var curPos = 0; i < this.children.length; i++) {
        var child = this.children[i], end = curPos + child.size;
        if (end > pos || child instanceof TrailingHackViewDesc) {
            offset = pos - curPos;
            break;
        }
        curPos = end;
    }
    // If this points into the middle of a child, call through
    if (offset)
        { return this.children[i].domFromPos(offset - this.children[i].border, side); }
    // Go back if there were any zero-length widgets with side >= 0 before this point
    for (var prev = (void 0); i && !(prev = this.children[i - 1]).size && prev instanceof WidgetViewDesc && prev.side >= 0; i--) { }
    // Scan towards the first useable node
    if (side <= 0) {
        var prev$1, enter = true;
        for (;; i--, enter = false) {
            prev$1 = i ? this.children[i - 1] : null;
            if (!prev$1 || prev$1.dom.parentNode == this.contentDOM)
                { break; }
        }
        if (prev$1 && side && enter && !prev$1.border && !prev$1.domAtom)
            { return prev$1.domFromPos(prev$1.size, side); }
        return { node: this.contentDOM, offset: prev$1 ? domIndex$1(prev$1.dom) + 1 : 0 };
    }
    else {
        var next, enter$1 = true;
        for (;; i++, enter$1 = false) {
            next = i < this.children.length ? this.children[i] : null;
            if (!next || next.dom.parentNode == this.contentDOM)
                { break; }
        }
        if (next && enter$1 && !next.border && !next.domAtom)
            { return next.domFromPos(0, side); }
        return { node: this.contentDOM, offset: next ? domIndex$1(next.dom) : this.contentDOM.childNodes.length };
    }
};
// Used to find a DOM range in a single parent for a given changed
// range.
ViewDesc.prototype.parseRange = function parseRange (from, to, base) {
        if ( base === void 0 ) base = 0;

    if (this.children.length == 0)
        { return { node: this.contentDOM, from: from, to: to, fromOffset: 0, toOffset: this.contentDOM.childNodes.length }; }
    var fromOffset = -1, toOffset = -1;
    for (var offset = base, i = 0;; i++) {
        var child = this.children[i], end = offset + child.size;
        if (fromOffset == -1 && from <= end) {
            var childBase = offset + child.border;
            // FIXME maybe descend mark views to parse a narrower range?
            if (from >= childBase && to <= end - child.border && child.node &&
                child.contentDOM && this.contentDOM.contains(child.contentDOM))
                { return child.parseRange(from, to, childBase); }
            from = offset;
            for (var j = i; j > 0; j--) {
                var prev = this.children[j - 1];
                if (prev.size && prev.dom.parentNode == this.contentDOM && !prev.emptyChildAt(1)) {
                    fromOffset = domIndex$1(prev.dom) + 1;
                    break;
                }
                from -= prev.size;
            }
            if (fromOffset == -1)
                { fromOffset = 0; }
        }
        if (fromOffset > -1 && (end > to || i == this.children.length - 1)) {
            to = end;
            for (var j$1 = i + 1; j$1 < this.children.length; j$1++) {
                var next = this.children[j$1];
                if (next.size && next.dom.parentNode == this.contentDOM && !next.emptyChildAt(-1)) {
                    toOffset = domIndex$1(next.dom);
                    break;
                }
                to += next.size;
            }
            if (toOffset == -1)
                { toOffset = this.contentDOM.childNodes.length; }
            break;
        }
        offset = end;
    }
    return { node: this.contentDOM, from: from, to: to, fromOffset: fromOffset, toOffset: toOffset };
};
ViewDesc.prototype.emptyChildAt = function emptyChildAt (side) {
    if (this.border || !this.contentDOM || !this.children.length)
        { return false; }
    var child = this.children[side < 0 ? 0 : this.children.length - 1];
    return child.size == 0 || child.emptyChildAt(side);
};
ViewDesc.prototype.domAfterPos = function domAfterPos (pos) {
    var ref = this.domFromPos(pos, 0);
        var node = ref.node;
        var offset = ref.offset;
    if (node.nodeType != 1 || offset == node.childNodes.length)
        { throw new RangeError("No node after pos " + pos); }
    return node.childNodes[offset];
};
// View descs are responsible for setting any selection that falls
// entirely inside of them, so that custom implementations can do
// custom things with the selection. Note that this falls apart when
// a selection starts in such a node and ends in another, in which
// case we just use whatever domFromPos produces as a best effort.
ViewDesc.prototype.setSelection = function setSelection (anchor, head, root, force) {
        if ( force === void 0 ) force = false;

    // If the selection falls entirely in a child, give it to that child
    var from = Math.min(anchor, head), to = Math.max(anchor, head);
    for (var i = 0, offset = 0; i < this.children.length; i++) {
        var child = this.children[i], end = offset + child.size;
        if (from > offset && to < end)
            { return child.setSelection(anchor - offset - child.border, head - offset - child.border, root, force); }
        offset = end;
    }
    var anchorDOM = this.domFromPos(anchor, anchor ? -1 : 1);
    var headDOM = head == anchor ? anchorDOM : this.domFromPos(head, head ? -1 : 1);
    var domSel = root.getSelection();
    var brKludge = false;
    // On Firefox, using Selection.collapse to put the cursor after a
    // BR node for some reason doesn't always work (#1073). On Safari,
    // the cursor sometimes inexplicable visually lags behind its
    // reported position in such situations (#1092).
    if ((gecko$1 || safari$1) && anchor == head) {
        var node = anchorDOM.node;
            var offset$1 = anchorDOM.offset;
        if (node.nodeType == 3) {
            brKludge = !!(offset$1 && node.nodeValue[offset$1 - 1] == "\n");
            // Issue #1128
            if (brKludge && offset$1 == node.nodeValue.length) {
                for (var scan = node, after = (void 0); scan; scan = scan.parentNode) {
                    if (after = scan.nextSibling) {
                        if (after.nodeName == "BR")
                            { anchorDOM = headDOM = { node: after.parentNode, offset: domIndex$1(after) + 1 }; }
                        break;
                    }
                    var desc = scan.pmViewDesc;
                    if (desc && desc.node && desc.node.isBlock)
                        { break; }
                }
            }
        }
        else {
            var prev = node.childNodes[offset$1 - 1];
            brKludge = prev && (prev.nodeName == "BR" || prev.contentEditable == "false");
        }
    }
    // Firefox can act strangely when the selection is in front of an
    // uneditable node. See #1163 and https://bugzilla.mozilla.org/show_bug.cgi?id=1709536
    if (gecko$1 && domSel.focusNode && domSel.focusNode != headDOM.node && domSel.focusNode.nodeType == 1) {
        var after$1 = domSel.focusNode.childNodes[domSel.focusOffset];
        if (after$1 && after$1.contentEditable == "false")
            { force = true; }
    }
    if (!(force || brKludge && safari$1) &&
        isEquivalentPosition$1(anchorDOM.node, anchorDOM.offset, domSel.anchorNode, domSel.anchorOffset) &&
        isEquivalentPosition$1(headDOM.node, headDOM.offset, domSel.focusNode, domSel.focusOffset))
        { return; }
    // 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.
    var domSelExtended = false;
    if ((domSel.extend || anchor == head) && !brKludge) {
        domSel.collapse(anchorDOM.node, anchorDOM.offset);
        try {
            if (anchor != head)
                { domSel.extend(headDOM.node, headDOM.offset); }
            domSelExtended = true;
        }
        catch (_) {
            // In some cases with Chrome the selection is empty after calling
            // collapse, even when it should be valid. This appears to be a bug, but
            // it is difficult to isolate. If this happens fallback to the old path
            // without using extend.
            // Similarly, this could crash on Safari if the editor is hidden, and
            // there was no selection.
        }
    }
    if (!domSelExtended) {
        if (anchor > head) {
            var tmp = anchorDOM;
            anchorDOM = headDOM;
            headDOM = tmp;
        }
        var range = document.createRange();
        range.setEnd(headDOM.node, headDOM.offset);
        range.setStart(anchorDOM.node, anchorDOM.offset);
        domSel.removeAllRanges();
        domSel.addRange(range);
    }
};
ViewDesc.prototype.ignoreMutation = function ignoreMutation (mutation) {
    return !this.contentDOM && mutation.type != "selection";
};
prototypeAccessors$5.contentLost.get = function () {
    return this.contentDOM && this.contentDOM != this.dom && !this.dom.contains(this.contentDOM);
};
// Remove a subtree of the element tree that has been touched
// by a DOM change, so that the next update will redraw it.
ViewDesc.prototype.markDirty = function markDirty (from, to) {
    for (var offset = 0, i = 0; i < this.children.length; i++) {
        var child = this.children[i], end = offset + child.size;
        if (offset == end ? from <= end && to >= offset : from < end && to > offset) {
            var startInside = offset + child.border, endInside = end - child.border;
            if (from >= startInside && to <= endInside) {
                this.dirty = from == offset || to == end ? CONTENT_DIRTY : CHILD_DIRTY;
                if (from == startInside && to == endInside &&
                    (child.contentLost || child.dom.parentNode != this.contentDOM))
                    { child.dirty = NODE_DIRTY; }
                else
                    { child.markDirty(from - startInside, to - startInside); }
                return;
            }
            else {
                child.dirty = child.dom == child.contentDOM && child.dom.parentNode == this.contentDOM && !child.children.length
                    ? CONTENT_DIRTY : NODE_DIRTY;
            }
        }
        offset = end;
    }
    this.dirty = CONTENT_DIRTY;
};
ViewDesc.prototype.markParentsDirty = function markParentsDirty () {
    var level = 1;
    for (var node = this.parent; node; node = node.parent, level++) {
        var dirty = level == 1 ? CONTENT_DIRTY : CHILD_DIRTY;
        if (node.dirty < dirty)
            { node.dirty = dirty; }
    }
};
prototypeAccessors$5.domAtom.get = function () { return false; };
prototypeAccessors$5.ignoreForCoords.get = function () { return false; };
ViewDesc.prototype.isText = function isText (text) { return false; };

Object.defineProperties( ViewDesc.prototype, prototypeAccessors$5 );
// A widget desc represents a widget decoration, which is a DOM node
// drawn between the document nodes.
var WidgetViewDesc = /*@__PURE__*/(function (ViewDesc) {
    function WidgetViewDesc(parent, widget, view, pos) {
        var self, dom = widget.type.toDOM;
        if (typeof dom == "function")
            { dom = dom(view, function () {
                if (!self)
                    { return pos; }
                if (self.parent)
                    { return self.parent.posBeforeChild(self); }
            }); }
        if (!widget.type.spec.raw) {
            if (dom.nodeType != 1) {
                var wrap = document.createElement("span");
                wrap.appendChild(dom);
                dom = wrap;
            }
            dom.contentEditable = "false";
            dom.classList.add("ProseMirror-widget");
        }
        ViewDesc.call(this, parent, [], dom, null);
        this.widget = widget;
        this.widget = widget;
        self = this;
    }

    if ( ViewDesc ) WidgetViewDesc.__proto__ = ViewDesc;
    WidgetViewDesc.prototype = Object.create( ViewDesc && ViewDesc.prototype );
    WidgetViewDesc.prototype.constructor = WidgetViewDesc;

    var prototypeAccessors$1 = { domAtom: { configurable: true },side: { configurable: true } };
    WidgetViewDesc.prototype.matchesWidget = function matchesWidget (widget) {
        return this.dirty == NOT_DIRTY && widget.type.eq(this.widget.type);
    };
    WidgetViewDesc.prototype.parseRule = function parseRule () { return { ignore: true }; };
    WidgetViewDesc.prototype.stopEvent = function stopEvent (event) {
        var stop = this.widget.spec.stopEvent;
        return stop ? stop(event) : false;
    };
    WidgetViewDesc.prototype.ignoreMutation = function ignoreMutation (mutation) {
        return mutation.type != "selection" || this.widget.spec.ignoreSelection;
    };
    WidgetViewDesc.prototype.destroy = function destroy () {
        this.widget.type.destroy(this.dom);
        ViewDesc.prototype.destroy.call(this);
    };
    prototypeAccessors$1.domAtom.get = function () { return true; };
    prototypeAccessors$1.side.get = function () { return this.widget.type.side; };

    Object.defineProperties( WidgetViewDesc.prototype, prototypeAccessors$1 );

    return WidgetViewDesc;
}(ViewDesc));
var CompositionViewDesc = /*@__PURE__*/(function (ViewDesc) {
    function CompositionViewDesc(parent, dom, textDOM, text) {
        ViewDesc.call(this, parent, [], dom, null);
        this.textDOM = textDOM;
        this.text = text;
    }

    if ( ViewDesc ) CompositionViewDesc.__proto__ = ViewDesc;
    CompositionViewDesc.prototype = Object.create( ViewDesc && ViewDesc.prototype );
    CompositionViewDesc.prototype.constructor = CompositionViewDesc;

    var prototypeAccessors$2 = { size: { configurable: true } };
    prototypeAccessors$2.size.get = function () { return this.text.length; };
    CompositionViewDesc.prototype.localPosFromDOM = function localPosFromDOM (dom, offset) {
        if (dom != this.textDOM)
            { return this.posAtStart + (offset ? this.size : 0); }
        return this.posAtStart + offset;
    };
    CompositionViewDesc.prototype.domFromPos = function domFromPos (pos) {
        return { node: this.textDOM, offset: pos };
    };
    CompositionViewDesc.prototype.ignoreMutation = function ignoreMutation (mut) {
        return mut.type === 'characterData' && mut.target.nodeValue == mut.oldValue;
    };

    Object.defineProperties( CompositionViewDesc.prototype, prototypeAccessors$2 );

    return CompositionViewDesc;
}(ViewDesc));
// A mark desc represents a mark. May have multiple children,
// depending on how the mark is split. Note that marks are drawn using
// a fixed nesting order, for simplicity and predictability, so in
// some cases they will be split more often than would appear
// necessary.
var MarkViewDesc = /*@__PURE__*/(function (ViewDesc) {
    function MarkViewDesc(parent, mark, dom, contentDOM) {
        ViewDesc.call(this, parent, [], dom, contentDOM);
        this.mark = mark;
    }

    if ( ViewDesc ) MarkViewDesc.__proto__ = ViewDesc;
    MarkViewDesc.prototype = Object.create( ViewDesc && ViewDesc.prototype );
    MarkViewDesc.prototype.constructor = MarkViewDesc;
    MarkViewDesc.create = function create (parent, mark, inline, view) {
        var custom = view.nodeViews[mark.type.name];
        var spec = custom && custom(mark, view, inline);
        if (!spec || !spec.dom)
            { spec = DOMSerializer.renderSpec(document, mark.type.spec.toDOM(mark, inline), null, mark.attrs); }
        return new MarkViewDesc(parent, mark, spec.dom, spec.contentDOM || spec.dom);
    };
    MarkViewDesc.prototype.parseRule = function parseRule () {
        if ((this.dirty & NODE_DIRTY) || this.mark.type.spec.reparseInView)
            { return null; }
        return { mark: this.mark.type.name, attrs: this.mark.attrs, contentElement: this.contentDOM };
    };
    MarkViewDesc.prototype.matchesMark = function matchesMark (mark) { return this.dirty != NODE_DIRTY && this.mark.eq(mark); };
    MarkViewDesc.prototype.markDirty = function markDirty (from, to) {
        ViewDesc.prototype.markDirty.call(this, from, to);
        // Move dirty info to nearest node view
        if (this.dirty != NOT_DIRTY) {
            var parent = this.parent;
            while (!parent.node)
                { parent = parent.parent; }
            if (parent.dirty < this.dirty)
                { parent.dirty = this.dirty; }
            this.dirty = NOT_DIRTY;
        }
    };
    MarkViewDesc.prototype.slice = function slice (from, to, view) {
        var copy = MarkViewDesc.create(this.parent, this.mark, true, view);
        var nodes = this.children, size = this.size;
        if (to < size)
            { nodes = replaceNodes(nodes, to, size, view); }
        if (from > 0)
            { nodes = replaceNodes(nodes, 0, from, view); }
        for (var i = 0; i < nodes.length; i++)
            { nodes[i].parent = copy; }
        copy.children = nodes;
        return copy;
    };

    return MarkViewDesc;
}(ViewDesc));
// Node view descs are the main, most common type of view desc, and
// correspond to an actual node in the document. Unlike mark descs,
// they populate their child array themselves.
var NodeViewDesc = /*@__PURE__*/(function (ViewDesc) {
    function NodeViewDesc(parent, node, outerDeco, innerDeco, dom, contentDOM, nodeDOM, view, pos) {
        ViewDesc.call(this, parent, [], dom, contentDOM);
        this.node = node;
        this.outerDeco = outerDeco;
        this.innerDeco = innerDeco;
        this.nodeDOM = nodeDOM;
    }

    if ( ViewDesc ) NodeViewDesc.__proto__ = ViewDesc;
    NodeViewDesc.prototype = Object.create( ViewDesc && ViewDesc.prototype );
    NodeViewDesc.prototype.constructor = NodeViewDesc;

    var prototypeAccessors$3 = { size: { configurable: true },border: { configurable: true },domAtom: { configurable: true } };
    // By default, a node is rendered using the `toDOM` method from the
    // node type spec. But client code can use the `nodeViews` spec to
    // supply a custom node view, which can influence various aspects of
    // the way the node works.
    //
    // (Using subclassing for this was intentionally decided against,
    // since it'd require exposing a whole slew of finicky
    // implementation details to the user code that they probably will
    // never need.)
    NodeViewDesc.create = function create (parent, node, outerDeco, innerDeco, view, pos) {
        var assign;

        var custom = view.nodeViews[node.type.name], descObj;
        var spec = custom && custom(node, view, function () {
            // (This is a function that allows the custom view to find its
            // own position)
            if (!descObj)
                { return pos; }
            if (descObj.parent)
                { return descObj.parent.posBeforeChild(descObj); }
        }, outerDeco, innerDeco);
        var dom = spec && spec.dom, contentDOM = spec && spec.contentDOM;
        if (node.isText) {
            if (!dom)
                { dom = document.createTextNode(node.text); }
            else if (dom.nodeType != 3)
                { throw new RangeError("Text must be rendered as a DOM text node"); }
        }
        else if (!dom) {
            var spec$1 = DOMSerializer.renderSpec(document, node.type.spec.toDOM(node), null, node.attrs);
            ((assign = spec$1, dom = assign.dom, contentDOM = assign.contentDOM));
        }
        if (!contentDOM && !node.isText && dom.nodeName != "BR") { // Chrome gets confused by <br contenteditable=false>
            if (!dom.hasAttribute("contenteditable"))
                { dom.contentEditable = "false"; }
            if (node.type.spec.draggable)
                { dom.draggable = true; }
        }
        var nodeDOM = dom;
        dom = applyOuterDeco(dom, outerDeco, node);
        if (spec)
            { return descObj = new CustomNodeViewDesc(parent, node, outerDeco, innerDeco, dom, contentDOM || null, nodeDOM, spec, view, pos + 1); }
        else if (node.isText)
            { return new TextViewDesc(parent, node, outerDeco, innerDeco, dom, nodeDOM, view); }
        else
            { return new NodeViewDesc(parent, node, outerDeco, innerDeco, dom, contentDOM || null, nodeDOM); }
    };
    NodeViewDesc.prototype.parseRule = function parseRule () {
        var this$1$1 = this;

        // Experimental kludge to allow opt-in re-parsing of nodes
        if (this.node.type.spec.reparseInView)
            { return null; }
        // FIXME the assumption that this can always return the current
        // attrs means that if the user somehow manages to change the
        // attrs in the dom, that won't be picked up. Not entirely sure
        // whether this is a problem
        var rule = { node: this.node.type.name, attrs: this.node.attrs };
        if (this.node.type.whitespace == "pre")
            { rule.preserveWhitespace = "full"; }
        if (!this.contentDOM) {
            rule.getContent = function () { return this$1$1.node.content; };
        }
        else if (!this.contentLost) {
            rule.contentElement = this.contentDOM;
        }
        else {
            // Chrome likes to randomly recreate parent nodes when
            // backspacing things. When that happens, this tries to find the
            // new parent.
            for (var i = this.children.length - 1; i >= 0; i--) {
                var child = this.children[i];
                if (this.dom.contains(child.dom.parentNode)) {
                    rule.contentElement = child.dom.parentNode;
                    break;
                }
            }
            if (!rule.contentElement)
                { rule.getContent = function () { return Fragment.empty; }; }
        }
        return rule;
    };
    NodeViewDesc.prototype.matchesNode = function matchesNode (node, outerDeco, innerDeco) {
        return this.dirty == NOT_DIRTY && node.eq(this.node) &&
            sameOuterDeco(outerDeco, this.outerDeco) && innerDeco.eq(this.innerDeco);
    };
    prototypeAccessors$3.size.get = function () { return this.node.nodeSize; };
    prototypeAccessors$3.border.get = function () { return this.node.isLeaf ? 0 : 1; };
    // Syncs `this.children` to match `this.node.content` and the local
    // decorations, possibly introducing nesting for marks. Then, in a
    // separate step, syncs the DOM inside `this.contentDOM` to
    // `this.children`.
    NodeViewDesc.prototype.updateChildren = function updateChildren (view, pos) {
        var this$1$1 = this;

        var inline = this.node.inlineContent, off = pos;
        var composition = view.composing ? this.localCompositionInfo(view, pos) : null;
        var localComposition = composition && composition.pos > -1 ? composition : null;
        var compositionInChild = composition && composition.pos < 0;
        var updater = new ViewTreeUpdater(this, localComposition && localComposition.node, view);
        iterDeco(this.node, this.innerDeco, function (widget, i, insideNode) {
            if (widget.spec.marks)
                { updater.syncToMarks(widget.spec.marks, inline, view); }
            else if (widget.type.side >= 0 && !insideNode)
                { updater.syncToMarks(i == this$1$1.node.childCount ? Mark.none : this$1$1.node.child(i).marks, inline, view); }
            // If the next node is a desc matching this widget, reuse it,
            // otherwise insert the widget as a new view desc.
            updater.placeWidget(widget, view, off);
        }, function (child, outerDeco, innerDeco, i) {
            // Make sure the wrapping mark descs match the node's marks.
            updater.syncToMarks(child.marks, inline, view);
            // Try several strategies for drawing this node
            var compIndex;
            if (updater.findNodeMatch(child, outerDeco, innerDeco, i)) ;
            else if (compositionInChild && view.state.selection.from > off &&
                view.state.selection.to < off + child.nodeSize &&
                (compIndex = updater.findIndexWithChild(composition.node)) > -1 &&
                updater.updateNodeAt(child, outerDeco, innerDeco, compIndex, view)) ;
            else if (updater.updateNextNode(child, outerDeco, innerDeco, view, i, off)) ;
            else {
                // Add it as a new view
                updater.addNode(child, outerDeco, innerDeco, view, off);
            }
            off += child.nodeSize;
        });
        // Drop all remaining descs after the current position.
        updater.syncToMarks([], inline, view);
        if (this.node.isTextblock)
            { updater.addTextblockHacks(); }
        updater.destroyRest();
        // Sync the DOM if anything changed
        if (updater.changed || this.dirty == CONTENT_DIRTY) {
            // May have to protect focused DOM from being changed if a composition is active
            if (localComposition)
                { this.protectLocalComposition(view, localComposition); }
            renderDescs(this.contentDOM, this.children, view);
            if (ios$1)
                { iosHacks(this.dom); }
        }
    };
    NodeViewDesc.prototype.localCompositionInfo = function localCompositionInfo (view, pos) {
        // Only do something if both the selection and a focused text node
        // are inside of this node
        var ref = view.state.selection;
        var from = ref.from;
        var to = ref.to;
        if (!(view.state.selection instanceof TextSelection) || from < pos || to > pos + this.node.content.size)
            { return null; }
        var textNode = view.input.compositionNode;
        if (!textNode || !this.dom.contains(textNode.parentNode))
            { return null; }
        if (this.node.inlineContent) {
            // Find the text in the focused node in the node, stop if it's not
            // there (may have been modified through other means, in which
            // case it should overwritten)
            var text = textNode.nodeValue;
            var textPos = findTextInFragment(this.node.content, text, from - pos, to - pos);
            return textPos < 0 ? null : { node: textNode, pos: textPos, text: text };
        }
        else {
            return { node: textNode, pos: -1, text: "" };
        }
    };
    NodeViewDesc.prototype.protectLocalComposition = function protectLocalComposition (view, ref) {
        var node = ref.node;
        var pos = ref.pos;
        var text = ref.text;

        // The node is already part of a local view desc, leave it there
        if (this.getDesc(node))
            { return; }
        // Create a composition view for the orphaned nodes
        var topNode = node;
        for (;; topNode = topNode.parentNode) {
            if (topNode.parentNode == this.contentDOM)
                { break; }
            while (topNode.previousSibling)
                { topNode.parentNode.removeChild(topNode.previousSibling); }
            while (topNode.nextSibling)
                { topNode.parentNode.removeChild(topNode.nextSibling); }
            if (topNode.pmViewDesc)
                { topNode.pmViewDesc = undefined; }
        }
        var desc = new CompositionViewDesc(this, topNode, node, text);
        view.input.compositionNodes.push(desc);
        // Patch up this.children to contain the composition view
        this.children = replaceNodes(this.children, pos, pos + text.length, view, desc);
    };
    // If this desc must be updated to match the given node decoration,
    // do so and return true.
    NodeViewDesc.prototype.update = function update (node, outerDeco, innerDeco, view) {
        if (this.dirty == NODE_DIRTY ||
            !node.sameMarkup(this.node))
            { return false; }
        this.updateInner(node, outerDeco, innerDeco, view);
        return true;
    };
    NodeViewDesc.prototype.updateInner = function updateInner (node, outerDeco, innerDeco, view) {
        this.updateOuterDeco(outerDeco);
        this.node = node;
        this.innerDeco = innerDeco;
        if (this.contentDOM)
            { this.updateChildren(view, this.posAtStart); }
        this.dirty = NOT_DIRTY;
    };
    NodeViewDesc.prototype.updateOuterDeco = function updateOuterDeco (outerDeco) {
        if (sameOuterDeco(outerDeco, this.outerDeco))
            { return; }
        var needsWrap = this.nodeDOM.nodeType != 1;
        var oldDOM = this.dom;
        this.dom = patchOuterDeco(this.dom, this.nodeDOM, computeOuterDeco(this.outerDeco, this.node, needsWrap), computeOuterDeco(outerDeco, this.node, needsWrap));
        if (this.dom != oldDOM) {
            oldDOM.pmViewDesc = undefined;
            this.dom.pmViewDesc = this;
        }
        this.outerDeco = outerDeco;
    };
    // Mark this node as being the selected node.
    NodeViewDesc.prototype.selectNode = function selectNode () {
        if (this.nodeDOM.nodeType == 1)
            { this.nodeDOM.classList.add("ProseMirror-selectednode"); }
        if (this.contentDOM || !this.node.type.spec.draggable)
            { this.dom.draggable = true; }
    };
    // Remove selected node marking from this node.
    NodeViewDesc.prototype.deselectNode = function deselectNode () {
        if (this.nodeDOM.nodeType == 1) {
            this.nodeDOM.classList.remove("ProseMirror-selectednode");
            if (this.contentDOM || !this.node.type.spec.draggable)
                { this.dom.removeAttribute("draggable"); }
        }
    };
    prototypeAccessors$3.domAtom.get = function () { return this.node.isAtom; };

    Object.defineProperties( NodeViewDesc.prototype, prototypeAccessors$3 );

    return NodeViewDesc;
}(ViewDesc));
// Create a view desc for the top-level document node, to be exported
// and used by the view class.
function docViewDesc(doc, outerDeco, innerDeco, dom, view) {
    applyOuterDeco(dom, outerDeco, doc);
    var docView = new NodeViewDesc(undefined, doc, outerDeco, innerDeco, dom, dom, dom, view, 0);
    if (docView.contentDOM)
        { docView.updateChildren(view, 0); }
    return docView;
}
var TextViewDesc = /*@__PURE__*/(function (NodeViewDesc) {
    function TextViewDesc(parent, node, outerDeco, innerDeco, dom, nodeDOM, view) {
        NodeViewDesc.call(this, parent, node, outerDeco, innerDeco, dom, null, nodeDOM, view, 0);
    }

    if ( NodeViewDesc ) TextViewDesc.__proto__ = NodeViewDesc;
    TextViewDesc.prototype = Object.create( NodeViewDesc && NodeViewDesc.prototype );
    TextViewDesc.prototype.constructor = TextViewDesc;

    var prototypeAccessors$4 = { domAtom: { configurable: true } };
    TextViewDesc.prototype.parseRule = function parseRule () {
        var skip = this.nodeDOM.parentNode;
        while (skip && skip != this.dom && !skip.pmIsDeco)
            { skip = skip.parentNode; }
        return { skip: (skip || true) };
    };
    TextViewDesc.prototype.update = function update (node, outerDeco, innerDeco, view) {
        if (this.dirty == NODE_DIRTY || (this.dirty != NOT_DIRTY && !this.inParent()) ||
            !node.sameMarkup(this.node))
            { return false; }
        this.updateOuterDeco(outerDeco);
        if ((this.dirty != NOT_DIRTY || node.text != this.node.text) && node.text != this.nodeDOM.nodeValue) {
            this.nodeDOM.nodeValue = node.text;
            if (view.trackWrites == this.nodeDOM)
                { view.trackWrites = null; }
        }
        this.node = node;
        this.dirty = NOT_DIRTY;
        return true;
    };
    TextViewDesc.prototype.inParent = function inParent () {
        var parentDOM = this.parent.contentDOM;
        for (var n = this.nodeDOM; n; n = n.parentNode)
            { if (n == parentDOM)
                { return true; } }
        return false;
    };
    TextViewDesc.prototype.domFromPos = function domFromPos (pos) {
        return { node: this.nodeDOM, offset: pos };
    };
    TextViewDesc.prototype.localPosFromDOM = function localPosFromDOM (dom, offset, bias) {
        if (dom == this.nodeDOM)
            { return this.posAtStart + Math.min(offset, this.node.text.length); }
        return NodeViewDesc.prototype.localPosFromDOM.call(this, dom, offset, bias);
    };
    TextViewDesc.prototype.ignoreMutation = function ignoreMutation (mutation) {
        return mutation.type != "characterData" && mutation.type != "selection";
    };
    TextViewDesc.prototype.slice = function slice (from, to, view) {
        var node = this.node.cut(from, to), dom = document.createTextNode(node.text);
        return new TextViewDesc(this.parent, node, this.outerDeco, this.innerDeco, dom, dom, view);
    };
    TextViewDesc.prototype.markDirty = function markDirty (from, to) {
        NodeViewDesc.prototype.markDirty.call(this, from, to);
        if (this.dom != this.nodeDOM && (from == 0 || to == this.nodeDOM.nodeValue.length))
            { this.dirty = NODE_DIRTY; }
    };
    prototypeAccessors$4.domAtom.get = function () { return false; };
    TextViewDesc.prototype.isText = function isText (text) { return this.node.text == text; };

    Object.defineProperties( TextViewDesc.prototype, prototypeAccessors$4 );

    return TextViewDesc;
}(NodeViewDesc));
// A dummy desc used to tag trailing BR or IMG nodes created to work
// around contentEditable terribleness.
var TrailingHackViewDesc = /*@__PURE__*/(function (ViewDesc) {
    function TrailingHackViewDesc () {
        ViewDesc.apply(this, arguments);
    }

    if ( ViewDesc ) TrailingHackViewDesc.__proto__ = ViewDesc;
    TrailingHackViewDesc.prototype = Object.create( ViewDesc && ViewDesc.prototype );
    TrailingHackViewDesc.prototype.constructor = TrailingHackViewDesc;

    var prototypeAccessors$5 = { domAtom: { configurable: true },ignoreForCoords: { configurable: true } };

    TrailingHackViewDesc.prototype.parseRule = function parseRule () { return { ignore: true }; };
    TrailingHackViewDesc.prototype.matchesHack = function matchesHack (nodeName) { return this.dirty == NOT_DIRTY && this.dom.nodeName == nodeName; };
    prototypeAccessors$5.domAtom.get = function () { return true; };
    prototypeAccessors$5.ignoreForCoords.get = function () { return this.dom.nodeName == "IMG"; };

    Object.defineProperties( TrailingHackViewDesc.prototype, prototypeAccessors$5 );

    return TrailingHackViewDesc;
}(ViewDesc));
// A separate subclass is used for customized node views, so that the
// extra checks only have to be made for nodes that are actually
// customized.
var CustomNodeViewDesc = /*@__PURE__*/(function (NodeViewDesc) {
    function CustomNodeViewDesc(parent, node, outerDeco, innerDeco, dom, contentDOM, nodeDOM, spec, view, pos) {
        NodeViewDesc.call(this, parent, node, outerDeco, innerDeco, dom, contentDOM, nodeDOM, view, pos);
        this.spec = spec;
    }

    if ( NodeViewDesc ) CustomNodeViewDesc.__proto__ = NodeViewDesc;
    CustomNodeViewDesc.prototype = Object.create( NodeViewDesc && NodeViewDesc.prototype );
    CustomNodeViewDesc.prototype.constructor = CustomNodeViewDesc;
    // A custom `update` method gets to decide whether the update goes
    // through. If it does, and there's a `contentDOM` node, our logic
    // updates the children.
    CustomNodeViewDesc.prototype.update = function update (node, outerDeco, innerDeco, view) {
        if (this.dirty == NODE_DIRTY)
            { return false; }
        if (this.spec.update) {
            var result = this.spec.update(node, outerDeco, innerDeco);
            if (result)
                { this.updateInner(node, outerDeco, innerDeco, view); }
            return result;
        }
        else if (!this.contentDOM && !node.isLeaf) {
            return false;
        }
        else {
            return NodeViewDesc.prototype.update.call(this, node, outerDeco, innerDeco, view);
        }
    };
    CustomNodeViewDesc.prototype.selectNode = function selectNode () {
        this.spec.selectNode ? this.spec.selectNode() : NodeViewDesc.prototype.selectNode.call(this);
    };
    CustomNodeViewDesc.prototype.deselectNode = function deselectNode () {
        this.spec.deselectNode ? this.spec.deselectNode() : NodeViewDesc.prototype.deselectNode.call(this);
    };
    CustomNodeViewDesc.prototype.setSelection = function setSelection (anchor, head, root, force) {
        this.spec.setSelection ? this.spec.setSelection(anchor, head, root)
            : NodeViewDesc.prototype.setSelection.call(this, anchor, head, root, force);
    };
    CustomNodeViewDesc.prototype.destroy = function destroy () {
        if (this.spec.destroy)
            { this.spec.destroy(); }
        NodeViewDesc.prototype.destroy.call(this);
    };
    CustomNodeViewDesc.prototype.stopEvent = function stopEvent (event) {
        return this.spec.stopEvent ? this.spec.stopEvent(event) : false;
    };
    CustomNodeViewDesc.prototype.ignoreMutation = function ignoreMutation (mutation) {
        return this.spec.ignoreMutation ? this.spec.ignoreMutation(mutation) : NodeViewDesc.prototype.ignoreMutation.call(this, mutation);
    };

    return CustomNodeViewDesc;
}(NodeViewDesc));
// Sync the content of the given DOM node with the nodes associated
// with the given array of view descs, recursing into mark descs
// because this should sync the subtree for a whole node at a time.
function renderDescs(parentDOM, descs, view) {
    var dom = parentDOM.firstChild, written = false;
    for (var i = 0; i < descs.length; i++) {
        var desc = descs[i], childDOM = desc.dom;
        if (childDOM.parentNode == parentDOM) {
            while (childDOM != dom) {
                dom = rm(dom);
                written = true;
            }
            dom = dom.nextSibling;
        }
        else {
            written = true;
            parentDOM.insertBefore(childDOM, dom);
        }
        if (desc instanceof MarkViewDesc) {
            var pos = dom ? dom.previousSibling : parentDOM.lastChild;
            renderDescs(desc.contentDOM, desc.children, view);
            dom = pos ? pos.nextSibling : parentDOM.firstChild;
        }
    }
    while (dom) {
        dom = rm(dom);
        written = true;
    }
    if (written && view.trackWrites == parentDOM)
        { view.trackWrites = null; }
}
var OuterDecoLevel = function (nodeName) {
    if (nodeName)
        { this.nodeName = nodeName; }
};
OuterDecoLevel.prototype = Object.create(null);
var noDeco = [new OuterDecoLevel];
function computeOuterDeco(outerDeco, node, needsWrap) {
    if (outerDeco.length == 0)
        { return noDeco; }
    var top = needsWrap ? noDeco[0] : new OuterDecoLevel, result = [top];
    for (var i = 0; i < outerDeco.length; i++) {
        var attrs = outerDeco[i].type.attrs;
        if (!attrs)
            { continue; }
        if (attrs.nodeName)
            { result.push(top = new OuterDecoLevel(attrs.nodeName)); }
        for (var name in attrs) {
            var val = attrs[name];
            if (val == null)
                { continue; }
            if (needsWrap && result.length == 1)
                { result.push(top = new OuterDecoLevel(node.isInline ? "span" : "div")); }
            if (name == "class")
                { top.class = (top.class ? top.class + " " : "") + val; }
            else if (name == "style")
                { top.style = (top.style ? top.style + ";" : "") + val; }
            else if (name != "nodeName")
                { top[name] = val; }
        }
    }
    return result;
}
function patchOuterDeco(outerDOM, nodeDOM, prevComputed, curComputed) {
    // Shortcut for trivial case
    if (prevComputed == noDeco && curComputed == noDeco)
        { return nodeDOM; }
    var curDOM = nodeDOM;
    for (var i = 0; i < curComputed.length; i++) {
        var deco = curComputed[i], prev = prevComputed[i];
        if (i) {
            var parent = (void 0);
            if (prev && prev.nodeName == deco.nodeName && curDOM != outerDOM &&
                (parent = curDOM.parentNode) && parent.nodeName.toLowerCase() == deco.nodeName) {
                curDOM = parent;
            }
            else {
                parent = document.createElement(deco.nodeName);
                parent.pmIsDeco = true;
                parent.appendChild(curDOM);
                prev = noDeco[0];
                curDOM = parent;
            }
        }
        patchAttributes(curDOM, prev || noDeco[0], deco);
    }
    return curDOM;
}
function patchAttributes(dom, prev, cur) {
    for (var name in prev)
        { if (name != "class" && name != "style" && name != "nodeName" && !(name in cur))
            { dom.removeAttribute(name); } }
    for (var name$1 in cur)
        { if (name$1 != "class" && name$1 != "style" && name$1 != "nodeName" && cur[name$1] != prev[name$1])
            { dom.setAttribute(name$1, cur[name$1]); } }
    if (prev.class != cur.class) {
        var prevList = prev.class ? prev.class.split(" ").filter(Boolean) : [];
        var curList = cur.class ? cur.class.split(" ").filter(Boolean) : [];
        for (var i = 0; i < prevList.length; i++)
            { if (curList.indexOf(prevList[i]) == -1)
                { dom.classList.remove(prevList[i]); } }
        for (var i$1 = 0; i$1 < curList.length; i$1++)
            { if (prevList.indexOf(curList[i$1]) == -1)
                { dom.classList.add(curList[i$1]); } }
        if (dom.classList.length == 0)
            { dom.removeAttribute("class"); }
    }
    if (prev.style != cur.style) {
        if (prev.style) {
            var prop = /\s*([\w\-\xa1-\uffff]+)\s*:(?:"(?:\\.|[^"])*"|'(?:\\.|[^'])*'|\(.*?\)|[^;])*/g, m;
            while (m = prop.exec(prev.style))
                { dom.style.removeProperty(m[1]); }
        }
        if (cur.style)
            { dom.style.cssText += cur.style; }
    }
}
function applyOuterDeco(dom, deco, node) {
    return patchOuterDeco(dom, dom, noDeco, computeOuterDeco(deco, node, dom.nodeType != 1));
}
function sameOuterDeco(a, b) {
    if (a.length != b.length)
        { return false; }
    for (var i = 0; i < a.length; i++)
        { if (!a[i].type.eq(b[i].type))
            { return false; } }
    return true;
}
// Remove a DOM node and return its next sibling.
function rm(dom) {
    var next = dom.nextSibling;
    dom.parentNode.removeChild(dom);
    return next;
}
// Helper class for incrementally updating a tree of mark descs and
// the widget and node descs inside of them.
var ViewTreeUpdater = function ViewTreeUpdater(top, lock, view) {
    this.lock = lock;
    this.view = view;
    // Index into `this.top`'s child array, represents the current
    // update position.
    this.index = 0;
    // When entering a mark, the current top and index are pushed
    // onto this.
    this.stack = [];
    // Tracks whether anything was changed
    this.changed = false;
    this.top = top;
    this.preMatch = preMatch(top.node.content, top);
};
// Destroy and remove the children between the given indices in
// `this.top`.
ViewTreeUpdater.prototype.destroyBetween = function destroyBetween (start, end) {
    if (start == end)
        { return; }
    for (var i = start; i < end; i++)
        { this.top.children[i].destroy(); }
    this.top.children.splice(start, end - start);
    this.changed = true;
};
// Destroy all remaining children in `this.top`.
ViewTreeUpdater.prototype.destroyRest = function destroyRest () {
    this.destroyBetween(this.index, this.top.children.length);
};
// Sync the current stack of mark descs with the given array of
// marks, reusing existing mark descs when possible.
ViewTreeUpdater.prototype.syncToMarks = function syncToMarks (marks, inline, view) {
    var keep = 0, depth = this.stack.length >> 1;
    var maxKeep = Math.min(depth, marks.length);
    while (keep < maxKeep &&
        (keep == depth - 1 ? this.top : this.stack[(keep + 1) << 1])
            .matchesMark(marks[keep]) && marks[keep].type.spec.spanning !== false)
        { keep++; }
    while (keep < depth) {
        this.destroyRest();
        this.top.dirty = NOT_DIRTY;
        this.index = this.stack.pop();
        this.top = this.stack.pop();
        depth--;
    }
    while (depth < marks.length) {
        this.stack.push(this.top, this.index + 1);
        var found = -1;
        for (var i = this.index; i < Math.min(this.index + 3, this.top.children.length); i++) {
            var next = this.top.children[i];
            if (next.matchesMark(marks[depth]) && !this.isLocked(next.dom)) {
                found = i;
                break;
            }
        }
        if (found > -1) {
            if (found > this.index) {
                this.changed = true;
                this.destroyBetween(this.index, found);
            }
            this.top = this.top.children[this.index];
        }
        else {
            var markDesc = MarkViewDesc.create(this.top, marks[depth], inline, view);
            this.top.children.splice(this.index, 0, markDesc);
            this.top = markDesc;
            this.changed = true;
        }
        this.index = 0;
        depth++;
    }
};
// Try to find a node desc matching the given data. Skip over it and
// return true when successful.
ViewTreeUpdater.prototype.findNodeMatch = function findNodeMatch (node, outerDeco, innerDeco, index) {
    var found = -1, targetDesc;
    if (index >= this.preMatch.index &&
        (targetDesc = this.preMatch.matches[index - this.preMatch.index]).parent == this.top &&
        targetDesc.matchesNode(node, outerDeco, innerDeco)) {
        found = this.top.children.indexOf(targetDesc, this.index);
    }
    else {
        for (var i = this.index, e = Math.min(this.top.children.length, i + 5); i < e; i++) {
            var child = this.top.children[i];
            if (child.matchesNode(node, outerDeco, innerDeco) && !this.preMatch.matched.has(child)) {
                found = i;
                break;
            }
        }
    }
    if (found < 0)
        { return false; }
    this.destroyBetween(this.index, found);
    this.index++;
    return true;
};
ViewTreeUpdater.prototype.updateNodeAt = function updateNodeAt (node, outerDeco, innerDeco, index, view) {
    var child = this.top.children[index];
    if (child.dirty == NODE_DIRTY && child.dom == child.contentDOM)
        { child.dirty = CONTENT_DIRTY; }
    if (!child.update(node, outerDeco, innerDeco, view))
        { return false; }
    this.destroyBetween(this.index, index);
    this.index++;
    return true;
};
ViewTreeUpdater.prototype.findIndexWithChild = function findIndexWithChild (domNode) {
    for (;;) {
        var parent = domNode.parentNode;
        if (!parent)
            { return -1; }
        if (parent == this.top.contentDOM) {
            var desc = domNode.pmViewDesc;
            if (desc)
                { for (var i = this.index; i < this.top.children.length; i++) {
                    if (this.top.children[i] == desc)
                        { return i; }
                } }
            return -1;
        }
        domNode = parent;
    }
};
// Try to update the next node, if any, to the given data. Checks
// pre-matches to avoid overwriting nodes that could still be used.
ViewTreeUpdater.prototype.updateNextNode = function updateNextNode (node, outerDeco, innerDeco, view, index, pos) {
    for (var i = this.index; i < this.top.children.length; i++) {
        var next = this.top.children[i];
        if (next instanceof NodeViewDesc) {
            var preMatch = this.preMatch.matched.get(next);
            if (preMatch != null && preMatch != index)
                { return false; }
            var nextDOM = next.dom, updated = (void 0);
            // Can't update if nextDOM is or contains this.lock, except if
            // it's a text node whose content already matches the new text
            // and whose decorations match the new ones.
            var locked = this.isLocked(nextDOM) &&
                !(node.isText && next.node && next.node.isText && next.nodeDOM.nodeValue == node.text &&
                    next.dirty != NODE_DIRTY && sameOuterDeco(outerDeco, next.outerDeco));
            if (!locked && next.update(node, outerDeco, innerDeco, view)) {
                this.destroyBetween(this.index, i);
                if (next.dom != nextDOM)
                    { this.changed = true; }
                this.index++;
                return true;
            }
            else if (!locked && (updated = this.recreateWrapper(next, node, outerDeco, innerDeco, view, pos))) {
                this.destroyBetween(this.index, i);
                this.top.children[this.index] = updated;
                if (updated.contentDOM) {
                    updated.dirty = CONTENT_DIRTY;
                    updated.updateChildren(view, pos + 1);
                    updated.dirty = NOT_DIRTY;
                }
                this.changed = true;
                this.index++;
                return true;
            }
            break;
        }
    }
    return false;
};
// When a node with content is replaced by a different node with
// identical content, move over its children.
ViewTreeUpdater.prototype.recreateWrapper = function recreateWrapper (next, node, outerDeco, innerDeco, view, pos) {
    if (next.dirty || node.isAtom || !next.children.length ||
        !next.node.content.eq(node.content) ||
        !sameOuterDeco(outerDeco, next.outerDeco) || !innerDeco.eq(next.innerDeco))
        { return null; }
    var wrapper = NodeViewDesc.create(this.top, node, outerDeco, innerDeco, view, pos);
    if (wrapper.contentDOM) {
        wrapper.children = next.children;
        next.children = [];
        for (var ch of wrapper.children)
            ch.parent = wrapper;
    }
    next.destroy();
    return wrapper;
};
// Insert the node as a newly created node desc.
ViewTreeUpdater.prototype.addNode = function addNode (node, outerDeco, innerDeco, view, pos) {
    var desc = NodeViewDesc.create(this.top, node, outerDeco, innerDeco, view, pos);
    if (desc.contentDOM)
        { desc.updateChildren(view, pos + 1); }
    this.top.children.splice(this.index++, 0, desc);
    this.changed = true;
};
ViewTreeUpdater.prototype.placeWidget = function placeWidget (widget, view, pos) {
    var next = this.index < this.top.children.length ? this.top.children[this.index] : null;
    if (next && next.matchesWidget(widget) &&
        (widget == next.widget || !next.widget.type.toDOM.parentNode)) {
        this.index++;
    }
    else {
        var desc = new WidgetViewDesc(this.top, widget, view, pos);
        this.top.children.splice(this.index++, 0, desc);
        this.changed = true;
    }
};
// Make sure a textblock looks and behaves correctly in
// contentEditable.
ViewTreeUpdater.prototype.addTextblockHacks = function addTextblockHacks () {
    var lastChild = this.top.children[this.index - 1], parent = this.top;
    while (lastChild instanceof MarkViewDesc) {
        parent = lastChild;
        lastChild = parent.children[parent.children.length - 1];
    }
    if (!lastChild || // Empty textblock
        !(lastChild instanceof TextViewDesc) ||
        /\n$/.test(lastChild.node.text) ||
        (this.view.requiresGeckoHackNode && /\s$/.test(lastChild.node.text))) {
        // Avoid bugs in Safari's cursor drawing (#1165) and Chrome's mouse selection (#1152)
        if ((safari$1 || chrome$1) && lastChild && lastChild.dom.contentEditable == "false")
            { this.addHackNode("IMG", parent); }
        this.addHackNode("BR", this.top);
    }
};
ViewTreeUpdater.prototype.addHackNode = function addHackNode (nodeName, parent) {
    if (parent == this.top && this.index < parent.children.length && parent.children[this.index].matchesHack(nodeName)) {
        this.index++;
    }
    else {
        var dom = document.createElement(nodeName);
        if (nodeName == "IMG") {
            dom.className = "ProseMirror-separator";
            dom.alt = "";
        }
        if (nodeName == "BR")
            { dom.className = "ProseMirror-trailingBreak"; }
        var hack = new TrailingHackViewDesc(this.top, [], dom, null);
        if (parent != this.top)
            { parent.children.push(hack); }
        else
            { parent.children.splice(this.index++, 0, hack); }
        this.changed = true;
    }
};
ViewTreeUpdater.prototype.isLocked = function isLocked (node) {
    return this.lock && (node == this.lock || node.nodeType == 1 && node.contains(this.lock.parentNode));
};
// Iterate from the end of the fragment and array of descs to find
// directly matching ones, in order to avoid overeagerly reusing those
// for other nodes. Returns the fragment index of the first node that
// is part of the sequence of matched nodes at the end of the
// fragment.
function preMatch(frag, parentDesc) {
    var curDesc = parentDesc, descI = curDesc.children.length;
    var fI = frag.childCount, matched = new Map, matches = [];
    outer: while (fI > 0) {
        var desc = (void 0);
        for (;;) {
            if (descI) {
                var next = curDesc.children[descI - 1];
                if (next instanceof MarkViewDesc) {
                    curDesc = next;
                    descI = next.children.length;
                }
                else {
                    desc = next;
                    descI--;
                    break;
                }
            }
            else if (curDesc == parentDesc) {
                break outer;
            }
            else {
                // FIXME
                descI = curDesc.parent.children.indexOf(curDesc);
                curDesc = curDesc.parent;
            }
        }
        var node = desc.node;
        if (!node)
            { continue; }
        if (node != frag.child(fI - 1))
            { break; }
        --fI;
        matched.set(desc, fI);
        matches.push(desc);
    }
    return { index: fI, matched: matched, matches: matches.reverse() };
}
function compareSide(a, b) {
    return a.type.side - b.type.side;
}
// This function abstracts iterating over the nodes and decorations in
// a fragment. Calls `onNode` for each node, with its local and child
// decorations. Splits text nodes when there is a decoration starting
// or ending inside of them. Calls `onWidget` for each widget.
function iterDeco(parent, deco, onWidget, onNode) {
    var locals = deco.locals(parent), offset = 0;
    // Simple, cheap variant for when there are no local decorations
    if (locals.length == 0) {
        for (var i = 0; i < parent.childCount; i++) {
            var child = parent.child(i);
            onNode(child, locals, deco.forChild(offset, child), i);
            offset += child.nodeSize;
        }
        return;
    }
    var decoIndex = 0, active = [], restNode = null;
    for (var parentIndex = 0;;) {
        var widget = (void 0), widgets = (void 0);
        while (decoIndex < locals.length && locals[decoIndex].to == offset) {
            var next = locals[decoIndex++];
            if (next.widget) {
                if (!widget)
                    { widget = next; }
                else
                    { (widgets || (widgets = [widget])).push(next); }
            }
        }
        if (widget) {
            if (widgets) {
                widgets.sort(compareSide);
                for (var i$1 = 0; i$1 < widgets.length; i$1++)
                    { onWidget(widgets[i$1], parentIndex, !!restNode); }
            }
            else {
                onWidget(widget, parentIndex, !!restNode);
            }
        }
        var child$1 = (void 0), index = (void 0);
        if (restNode) {
            index = -1;
            child$1 = restNode;
            restNode = null;
        }
        else if (parentIndex < parent.childCount) {
            index = parentIndex;
            child$1 = parent.child(parentIndex++);
        }
        else {
            break;
        }
        for (var i$2 = 0; i$2 < active.length; i$2++)
            { if (active[i$2].to <= offset)
                { active.splice(i$2--, 1); } }
        while (decoIndex < locals.length && locals[decoIndex].from <= offset && locals[decoIndex].to > offset)
            { active.push(locals[decoIndex++]); }
        var end = offset + child$1.nodeSize;
        if (child$1.isText) {
            var cutAt = end;
            if (decoIndex < locals.length && locals[decoIndex].from < cutAt)
                { cutAt = locals[decoIndex].from; }
            for (var i$3 = 0; i$3 < active.length; i$3++)
                { if (active[i$3].to < cutAt)
                    { cutAt = active[i$3].to; } }
            if (cutAt < end) {
                restNode = child$1.cut(cutAt - offset);
                child$1 = child$1.cut(0, cutAt - offset);
                end = cutAt;
                index = -1;
            }
        }
        else {
            while (decoIndex < locals.length && locals[decoIndex].to < end)
                { decoIndex++; }
        }
        var outerDeco = child$1.isInline && !child$1.isLeaf ? active.filter(function (d) { return !d.inline; }) : active.slice();
        onNode(child$1, outerDeco, deco.forChild(offset, child$1), index);
        offset = end;
    }
}
// List markers in Mobile Safari will mysteriously disappear
// sometimes. This works around that.
function iosHacks(dom) {
    if (dom.nodeName == "UL" || dom.nodeName == "OL") {
        var oldCSS = dom.style.cssText;
        dom.style.cssText = oldCSS + "; list-style: square !important";
        window.getComputedStyle(dom).listStyle;
        dom.style.cssText = oldCSS;
    }
}
// Find a piece of text in an inline fragment, overlapping from-to
function findTextInFragment(frag, text, from, to) {
    for (var i = 0, pos = 0; i < frag.childCount && pos <= to;) {
        var child = frag.child(i++), childStart = pos;
        pos += child.nodeSize;
        if (!child.isText)
            { continue; }
        var str = child.text;
        while (i < frag.childCount) {
            var next = frag.child(i++);
            pos += next.nodeSize;
            if (!next.isText)
                { break; }
            str += next.text;
        }
        if (pos >= from) {
            if (pos >= to && str.slice(to - text.length - childStart, to - childStart) == text)
                { return to - text.length; }
            var found = childStart < to ? str.lastIndexOf(text, to - childStart - 1) : -1;
            if (found >= 0 && found + text.length + childStart >= from)
                { return childStart + found; }
            if (from == to && str.length >= (to + text.length) - childStart &&
                str.slice(to - childStart, to - childStart + text.length) == text)
                { return to; }
        }
    }
    return -1;
}
// Replace range from-to in an array of view descs with replacement
// (may be null to just delete). This goes very much against the grain
// of the rest of this code, which tends to create nodes with the
// right shape in one go, rather than messing with them after
// creation, but is necessary in the composition hack.
function replaceNodes(nodes, from, to, view, replacement) {
    var result = [];
    for (var i = 0, off = 0; i < nodes.length; i++) {
        var child = nodes[i], start = off, end = off += child.size;
        if (start >= to || end <= from) {
            result.push(child);
        }
        else {
            if (start < from)
                { result.push(child.slice(0, from - start, view)); }
            if (replacement) {
                result.push(replacement);
                replacement = undefined;
            }
            if (end > to)
                { result.push(child.slice(to - start, child.size, view)); }
        }
    }
    return result;
}

function selectionFromDOM(view, origin) {
    var assign;

    if ( origin === void 0 ) origin = null;
    var domSel = view.domSelectionRange(), doc = view.state.doc;
    if (!domSel.focusNode)
        { return null; }
    var nearestDesc = view.docView.nearestDesc(domSel.focusNode), inWidget = nearestDesc && nearestDesc.size == 0;
    var head = view.docView.posFromDOM(domSel.focusNode, domSel.focusOffset, 1);
    if (head < 0)
        { return null; }
    var $head = doc.resolve(head), anchor, selection;
    if (selectionCollapsed(domSel)) {
        anchor = head;
        while (nearestDesc && !nearestDesc.node)
            { nearestDesc = nearestDesc.parent; }
        var nearestDescNode = nearestDesc.node;
        if (nearestDesc && nearestDescNode.isAtom && NodeSelection.isSelectable(nearestDescNode) && nearestDesc.parent
            && !(nearestDescNode.isInline && isOnEdge(domSel.focusNode, domSel.focusOffset, nearestDesc.dom))) {
            var pos = nearestDesc.posBefore;
            selection = new NodeSelection(head == pos ? $head : doc.resolve(pos));
        }
    }
    else {
        if (domSel instanceof view.dom.ownerDocument.defaultView.Selection && domSel.rangeCount > 1) {
            var min = head, max = head;
            for (var i = 0; i < domSel.rangeCount; i++) {
                var range = domSel.getRangeAt(i);
                min = Math.min(min, view.docView.posFromDOM(range.startContainer, range.startOffset, 1));
                max = Math.max(max, view.docView.posFromDOM(range.endContainer, range.endOffset, -1));
            }
            if (min < 0)
                { return null; }
            (assign = max == view.state.selection.anchor ? [max, min] : [min, max], anchor = assign[0], head = assign[1]);
            $head = doc.resolve(head);
        }
        else {
            anchor = view.docView.posFromDOM(domSel.anchorNode, domSel.anchorOffset, 1);
        }
        if (anchor < 0)
            { return null; }
    }
    var $anchor = doc.resolve(anchor);
    if (!selection) {
        var bias = origin == "pointer" || (view.state.selection.head < $head.pos && !inWidget) ? 1 : -1;
        selection = selectionBetween(view, $anchor, $head, bias);
    }
    return selection;
}
function editorOwnsSelection(view) {
    return view.editable ? view.hasFocus() :
        hasSelection$1(view) && document.activeElement && document.activeElement.contains(view.dom);
}
function selectionToDOM(view, force) {
    if ( force === void 0 ) force = false;

    var sel = view.state.selection;
    syncNodeSelection(view, sel);
    if (!editorOwnsSelection(view))
        { return; }
    // The delayed drag selection causes issues with Cell Selections
    // in Safari. And the drag selection delay is to workarond issues
    // which only present in Chrome.
    if (!force && view.input.mouseDown && view.input.mouseDown.allowDefault && chrome$1) {
        var domSel = view.domSelectionRange(), curSel = view.domObserver.currentSelection;
        if (domSel.anchorNode && curSel.anchorNode &&
            isEquivalentPosition$1(domSel.anchorNode, domSel.anchorOffset, curSel.anchorNode, curSel.anchorOffset)) {
            view.input.mouseDown.delayedSelectionSync = true;
            view.domObserver.setCurSelection();
            return;
        }
    }
    view.domObserver.disconnectSelection();
    if (view.cursorWrapper) {
        selectCursorWrapper(view);
    }
    else {
        var anchor = sel.anchor;
        var head = sel.head;
        var resetEditableFrom, resetEditableTo;
        if (brokenSelectBetweenUneditable && !(sel instanceof TextSelection)) {
            if (!sel.$from.parent.inlineContent)
                { resetEditableFrom = temporarilyEditableNear(view, sel.from); }
            if (!sel.empty && !sel.$from.parent.inlineContent)
                { resetEditableTo = temporarilyEditableNear(view, sel.to); }
        }
        view.docView.setSelection(anchor, head, view.root, force);
        if (brokenSelectBetweenUneditable) {
            if (resetEditableFrom)
                { resetEditable(resetEditableFrom); }
            if (resetEditableTo)
                { resetEditable(resetEditableTo); }
        }
        if (sel.visible) {
            view.dom.classList.remove("ProseMirror-hideselection");
        }
        else {
            view.dom.classList.add("ProseMirror-hideselection");
            if ("onselectionchange" in document)
                { removeClassOnSelectionChange(view); }
        }
    }
    view.domObserver.setCurSelection();
    view.domObserver.connectSelection();
}
// Kludge to work around Webkit not allowing a selection to start/end
// between non-editable block nodes. We briefly make something
// editable, set the selection, then set it uneditable again.
var brokenSelectBetweenUneditable = safari$1 || chrome$1 && chrome_version < 63;
function temporarilyEditableNear(view, pos) {
    var ref = view.docView.domFromPos(pos, 0);
    var node = ref.node;
    var offset = ref.offset;
    var after = offset < node.childNodes.length ? node.childNodes[offset] : null;
    var before = offset ? node.childNodes[offset - 1] : null;
    if (safari$1 && after && after.contentEditable == "false")
        { return setEditable(after); }
    if ((!after || after.contentEditable == "false") &&
        (!before || before.contentEditable == "false")) {
        if (after)
            { return setEditable(after); }
        else if (before)
            { return setEditable(before); }
    }
}
function setEditable(element) {
    element.contentEditable = "true";
    if (safari$1 && element.draggable) {
        element.draggable = false;
        element.wasDraggable = true;
    }
    return element;
}
function resetEditable(element) {
    element.contentEditable = "false";
    if (element.wasDraggable) {
        element.draggable = true;
        element.wasDraggable = null;
    }
}
function removeClassOnSelectionChange(view) {
    var doc = view.dom.ownerDocument;
    doc.removeEventListener("selectionchange", view.input.hideSelectionGuard);
    var domSel = view.domSelectionRange();
    var node = domSel.anchorNode, offset = domSel.anchorOffset;
    doc.addEventListener("selectionchange", view.input.hideSelectionGuard = function () {
        if (domSel.anchorNode != node || domSel.anchorOffset != offset) {
            doc.removeEventListener("selectionchange", view.input.hideSelectionGuard);
            setTimeout(function () {
                if (!editorOwnsSelection(view) || view.state.selection.visible)
                    { view.dom.classList.remove("ProseMirror-hideselection"); }
            }, 20);
        }
    });
}
function selectCursorWrapper(view) {
    var domSel = view.domSelection(), range = document.createRange();
    if (!domSel)
        { return; }
    var node = view.cursorWrapper.dom, img = node.nodeName == "IMG";
    if (img)
        { range.setStart(node.parentNode, domIndex$1(node) + 1); }
    else
        { range.setStart(node, 0); }
    range.collapse(true);
    domSel.removeAllRanges();
    domSel.addRange(range);
    // Kludge to kill 'control selection' in IE11 when selecting an
    // invisible cursor wrapper, since that would result in those weird
    // resize handles and a selection that considers the absolutely
    // positioned wrapper, rather than the root editable node, the
    // focused element.
    if (!img && !view.state.selection.visible && ie$2 && ie_version <= 11) {
        node.disabled = true;
        node.disabled = false;
    }
}
function syncNodeSelection(view, sel) {
    if (sel instanceof NodeSelection) {
        var desc = view.docView.descAt(sel.from);
        if (desc != view.lastSelectedViewDesc) {
            clearNodeSelection(view);
            if (desc)
                { desc.selectNode(); }
            view.lastSelectedViewDesc = desc;
        }
    }
    else {
        clearNodeSelection(view);
    }
}
// Clear all DOM statefulness of the last node selection.
function clearNodeSelection(view) {
    if (view.lastSelectedViewDesc) {
        if (view.lastSelectedViewDesc.parent)
            { view.lastSelectedViewDesc.deselectNode(); }
        view.lastSelectedViewDesc = undefined;
    }
}
function selectionBetween(view, $anchor, $head, bias) {
    return view.someProp("createSelectionBetween", function (f) { return f(view, $anchor, $head); })
        || TextSelection.between($anchor, $head, bias);
}
function hasFocusAndSelection(view) {
    if (view.editable && !view.hasFocus())
        { return false; }
    return hasSelection$1(view);
}
function hasSelection$1(view) {
    var sel = view.domSelectionRange();
    if (!sel.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 view.dom.contains(sel.anchorNode.nodeType == 3 ? sel.anchorNode.parentNode : sel.anchorNode) &&
            (view.editable || view.dom.contains(sel.focusNode.nodeType == 3 ? sel.focusNode.parentNode : sel.focusNode));
    }
    catch (_) {
        return false;
    }
}
function anchorInRightPlace(view) {
    var anchorDOM = view.docView.domFromPos(view.state.selection.anchor, 0);
    var domSel = view.domSelectionRange();
    return isEquivalentPosition$1(anchorDOM.node, anchorDOM.offset, domSel.anchorNode, domSel.anchorOffset);
}

function moveSelectionBlock(state, dir) {
    var ref = state.selection;
    var $anchor = ref.$anchor;
    var $head = ref.$head;
    var $side = dir > 0 ? $anchor.max($head) : $anchor.min($head);
    var $start = !$side.parent.inlineContent ? $side : $side.depth ? state.doc.resolve(dir > 0 ? $side.after() : $side.before()) : null;
    return $start && Selection.findFrom($start, dir);
}
function apply(view, sel) {
    view.dispatch(view.state.tr.setSelection(sel).scrollIntoView());
    return true;
}
function selectHorizontally(view, dir, mods) {
    var sel = view.state.selection;
    if (sel instanceof TextSelection) {
        if (mods.indexOf("s") > -1) {
            var $head = sel.$head;
            var node = $head.textOffset ? null : dir < 0 ? $head.nodeBefore : $head.nodeAfter;
            if (!node || node.isText || !node.isLeaf)
                { return false; }
            var $newHead = view.state.doc.resolve($head.pos + node.nodeSize * (dir < 0 ? -1 : 1));
            return apply(view, new TextSelection(sel.$anchor, $newHead));
        }
        else if (!sel.empty) {
            return false;
        }
        else if (view.endOfTextblock(dir > 0 ? "forward" : "backward")) {
            var next = moveSelectionBlock(view.state, dir);
            if (next && (next instanceof NodeSelection))
                { return apply(view, next); }
            return false;
        }
        else if (!(mac$4 && mods.indexOf("m") > -1)) {
            var $head$1 = sel.$head, node$1 = $head$1.textOffset ? null : dir < 0 ? $head$1.nodeBefore : $head$1.nodeAfter, desc;
            if (!node$1 || node$1.isText)
                { return false; }
            var nodePos = dir < 0 ? $head$1.pos - node$1.nodeSize : $head$1.pos;
            if (!(node$1.isAtom || (desc = view.docView.descAt(nodePos)) && !desc.contentDOM))
                { return false; }
            if (NodeSelection.isSelectable(node$1)) {
                return apply(view, new NodeSelection(dir < 0 ? view.state.doc.resolve($head$1.pos - node$1.nodeSize) : $head$1));
            }
            else if (webkit$1) {
                // Chrome and Safari will introduce extra pointless cursor
                // positions around inline uneditable nodes, so we have to
                // take over and move the cursor past them (#937)
                return apply(view, new TextSelection(view.state.doc.resolve(dir < 0 ? nodePos : nodePos + node$1.nodeSize)));
            }
            else {
                return false;
            }
        }
    }
    else if (sel instanceof NodeSelection && sel.node.isInline) {
        return apply(view, new TextSelection(dir > 0 ? sel.$to : sel.$from));
    }
    else {
        var next$1 = moveSelectionBlock(view.state, dir);
        if (next$1)
            { return apply(view, next$1); }
        return false;
    }
}
function nodeLen(node) {
    return node.nodeType == 3 ? node.nodeValue.length : node.childNodes.length;
}
function isIgnorable(dom, dir) {
    var desc = dom.pmViewDesc;
    return desc && desc.size == 0 && (dir < 0 || dom.nextSibling || dom.nodeName != "BR");
}
function skipIgnoredNodes(view, dir) {
    return dir < 0 ? skipIgnoredNodesBefore(view) : skipIgnoredNodesAfter(view);
}
// Make sure the cursor isn't directly after one or more ignored
// nodes, which will confuse the browser's cursor motion logic.
function skipIgnoredNodesBefore(view) {
    var sel = view.domSelectionRange();
    var node = sel.focusNode, offset = sel.focusOffset;
    if (!node)
        { return; }
    var moveNode, moveOffset, force = false;
    // Gecko will do odd things when the selection is directly in front
    // of a non-editable node, so in that case, move it into the next
    // node if possible. Issue prosemirror/prosemirror#832.
    if (gecko$1 && node.nodeType == 1 && offset < nodeLen(node) && isIgnorable(node.childNodes[offset], -1))
        { force = true; }
    for (;;) {
        if (offset > 0) {
            if (node.nodeType != 1) {
                break;
            }
            else {
                var before = node.childNodes[offset - 1];
                if (isIgnorable(before, -1)) {
                    moveNode = node;
                    moveOffset = --offset;
                }
                else if (before.nodeType == 3) {
                    node = before;
                    offset = node.nodeValue.length;
                }
                else
                    { break; }
            }
        }
        else if (isBlockNode(node)) {
            break;
        }
        else {
            var prev = node.previousSibling;
            while (prev && isIgnorable(prev, -1)) {
                moveNode = node.parentNode;
                moveOffset = domIndex$1(prev);
                prev = prev.previousSibling;
            }
            if (!prev) {
                node = node.parentNode;
                if (node == view.dom)
                    { break; }
                offset = 0;
            }
            else {
                node = prev;
                offset = nodeLen(node);
            }
        }
    }
    if (force)
        { setSelFocus(view, node, offset); }
    else if (moveNode)
        { setSelFocus(view, moveNode, moveOffset); }
}
// Make sure the cursor isn't directly before one or more ignored
// nodes.
function skipIgnoredNodesAfter(view) {
    var sel = view.domSelectionRange();
    var node = sel.focusNode, offset = sel.focusOffset;
    if (!node)
        { return; }
    var len = nodeLen(node);
    var moveNode, moveOffset;
    for (;;) {
        if (offset < len) {
            if (node.nodeType != 1)
                { break; }
            var after = node.childNodes[offset];
            if (isIgnorable(after, 1)) {
                moveNode = node;
                moveOffset = ++offset;
            }
            else
                { break; }
        }
        else if (isBlockNode(node)) {
            break;
        }
        else {
            var next = node.nextSibling;
            while (next && isIgnorable(next, 1)) {
                moveNode = next.parentNode;
                moveOffset = domIndex$1(next) + 1;
                next = next.nextSibling;
            }
            if (!next) {
                node = node.parentNode;
                if (node == view.dom)
                    { break; }
                offset = len = 0;
            }
            else {
                node = next;
                offset = 0;
                len = nodeLen(node);
            }
        }
    }
    if (moveNode)
        { setSelFocus(view, moveNode, moveOffset); }
}
function isBlockNode(dom) {
    var desc = dom.pmViewDesc;
    return desc && desc.node && desc.node.isBlock;
}
function textNodeAfter$2(node, offset) {
    while (node && offset == node.childNodes.length && !hasBlockDesc(node)) {
        offset = domIndex$1(node) + 1;
        node = node.parentNode;
    }
    while (node && offset < node.childNodes.length) {
        var next = node.childNodes[offset];
        if (next.nodeType == 3)
            { return next; }
        if (next.nodeType == 1 && next.contentEditable == "false")
            { break; }
        node = next;
        offset = 0;
    }
}
function textNodeBefore$2(node, offset) {
    while (node && !offset && !hasBlockDesc(node)) {
        offset = domIndex$1(node);
        node = node.parentNode;
    }
    while (node && offset) {
        var next = node.childNodes[offset - 1];
        if (next.nodeType == 3)
            { return next; }
        if (next.nodeType == 1 && next.contentEditable == "false")
            { break; }
        node = next;
        offset = node.childNodes.length;
    }
}
function setSelFocus(view, node, offset) {
    if (node.nodeType != 3) {
        var before, after;
        if (after = textNodeAfter$2(node, offset)) {
            node = after;
            offset = 0;
        }
        else if (before = textNodeBefore$2(node, offset)) {
            node = before;
            offset = before.nodeValue.length;
        }
    }
    var sel = view.domSelection();
    if (!sel)
        { return; }
    if (selectionCollapsed(sel)) {
        var range = document.createRange();
        range.setEnd(node, offset);
        range.setStart(node, offset);
        sel.removeAllRanges();
        sel.addRange(range);
    }
    else if (sel.extend) {
        sel.extend(node, offset);
    }
    view.domObserver.setCurSelection();
    var state = view.state;
    // If no state update ends up happening, reset the selection.
    setTimeout(function () {
        if (view.state == state)
            { selectionToDOM(view); }
    }, 50);
}
function findDirection(view, pos) {
    var $pos = view.state.doc.resolve(pos);
    if (!(chrome$1 || windows) && $pos.parent.inlineContent) {
        var coords = view.coordsAtPos(pos);
        if (pos > $pos.start()) {
            var before = view.coordsAtPos(pos - 1);
            var mid = (before.top + before.bottom) / 2;
            if (mid > coords.top && mid < coords.bottom && Math.abs(before.left - coords.left) > 1)
                { return before.left < coords.left ? "ltr" : "rtl"; }
        }
        if (pos < $pos.end()) {
            var after = view.coordsAtPos(pos + 1);
            var mid$1 = (after.top + after.bottom) / 2;
            if (mid$1 > coords.top && mid$1 < coords.bottom && Math.abs(after.left - coords.left) > 1)
                { return after.left > coords.left ? "ltr" : "rtl"; }
        }
    }
    var computed = getComputedStyle(view.dom).direction;
    return computed == "rtl" ? "rtl" : "ltr";
}
// Check whether vertical selection motion would involve node
// selections. If so, apply it (if not, the result is left to the
// browser)
function selectVertically(view, dir, mods) {
    var sel = view.state.selection;
    if (sel instanceof TextSelection && !sel.empty || mods.indexOf("s") > -1)
        { return false; }
    if (mac$4 && mods.indexOf("m") > -1)
        { return false; }
    var $from = sel.$from;
    var $to = sel.$to;
    if (!$from.parent.inlineContent || view.endOfTextblock(dir < 0 ? "up" : "down")) {
        var next = moveSelectionBlock(view.state, dir);
        if (next && (next instanceof NodeSelection))
            { return apply(view, next); }
    }
    if (!$from.parent.inlineContent) {
        var side = dir < 0 ? $from : $to;
        var beyond = sel instanceof AllSelection ? Selection.near(side, dir) : Selection.findFrom(side, dir);
        return beyond ? apply(view, beyond) : false;
    }
    return false;
}
function stopNativeHorizontalDelete(view, dir) {
    if (!(view.state.selection instanceof TextSelection))
        { return true; }
    var ref = view.state.selection;
    var $head = ref.$head;
    var $anchor = ref.$anchor;
    var empty = ref.empty;
    if (!$head.sameParent($anchor))
        { return true; }
    if (!empty)
        { return false; }
    if (view.endOfTextblock(dir > 0 ? "forward" : "backward"))
        { return true; }
    var nextNode = !$head.textOffset && (dir < 0 ? $head.nodeBefore : $head.nodeAfter);
    if (nextNode && !nextNode.isText) {
        var tr = view.state.tr;
        if (dir < 0)
            { tr.delete($head.pos - nextNode.nodeSize, $head.pos); }
        else
            { tr.delete($head.pos, $head.pos + nextNode.nodeSize); }
        view.dispatch(tr);
        return true;
    }
    return false;
}
function switchEditable(view, node, state) {
    view.domObserver.stop();
    node.contentEditable = state;
    view.domObserver.start();
}
// Issue #867 / #1090 / https://bugs.chromium.org/p/chromium/issues/detail?id=903821
// In which Safari (and at some point in the past, Chrome) does really
// wrong things when the down arrow is pressed when the cursor is
// directly at the start of a textblock and has an uneditable node
// after it
function safariDownArrowBug(view) {
    if (!safari$1 || view.state.selection.$head.parentOffset > 0)
        { return false; }
    var ref = view.domSelectionRange();
    var focusNode = ref.focusNode;
    var focusOffset = ref.focusOffset;
    if (focusNode && focusNode.nodeType == 1 && focusOffset == 0 &&
        focusNode.firstChild && focusNode.firstChild.contentEditable == "false") {
        var child = focusNode.firstChild;
        switchEditable(view, child, "true");
        setTimeout(function () { return switchEditable(view, child, "false"); }, 20);
    }
    return false;
}
// A backdrop key mapping used to make sure we always suppress keys
// that have a dangerous default effect, even if the commands they are
// bound to return false, and to make sure that cursor-motion keys
// find a cursor (as opposed to a node selection) when pressed. For
// cursor-motion keys, the code in the handlers also takes care of
// block selections.
function getMods(event) {
    var result = "";
    if (event.ctrlKey)
        { result += "c"; }
    if (event.metaKey)
        { result += "m"; }
    if (event.altKey)
        { result += "a"; }
    if (event.shiftKey)
        { result += "s"; }
    return result;
}
function captureKeyDown(view, event) {
    var code = event.keyCode, mods = getMods(event);
    if (code == 8 || (mac$4 && code == 72 && mods == "c")) { // Backspace, Ctrl-h on Mac
        return stopNativeHorizontalDelete(view, -1) || skipIgnoredNodes(view, -1);
    }
    else if ((code == 46 && !event.shiftKey) || (mac$4 && code == 68 && mods == "c")) { // Delete, Ctrl-d on Mac
        return stopNativeHorizontalDelete(view, 1) || skipIgnoredNodes(view, 1);
    }
    else if (code == 13 || code == 27) { // Enter, Esc
        return true;
    }
    else if (code == 37 || (mac$4 && code == 66 && mods == "c")) { // Left arrow, Ctrl-b on Mac
        var dir = code == 37 ? (findDirection(view, view.state.selection.from) == "ltr" ? -1 : 1) : -1;
        return selectHorizontally(view, dir, mods) || skipIgnoredNodes(view, dir);
    }
    else if (code == 39 || (mac$4 && code == 70 && mods == "c")) { // Right arrow, Ctrl-f on Mac
        var dir$1 = code == 39 ? (findDirection(view, view.state.selection.from) == "ltr" ? 1 : -1) : 1;
        return selectHorizontally(view, dir$1, mods) || skipIgnoredNodes(view, dir$1);
    }
    else if (code == 38 || (mac$4 && code == 80 && mods == "c")) { // Up arrow, Ctrl-p on Mac
        return selectVertically(view, -1, mods) || skipIgnoredNodes(view, -1);
    }
    else if (code == 40 || (mac$4 && code == 78 && mods == "c")) { // Down arrow, Ctrl-n on Mac
        return safariDownArrowBug(view) || selectVertically(view, 1, mods) || skipIgnoredNodes(view, 1);
    }
    else if (mods == (mac$4 ? "m" : "c") &&
        (code == 66 || code == 73 || code == 89 || code == 90)) { // Mod-[biyz]
        return true;
    }
    return false;
}

function serializeForClipboard(view, slice) {
    view.someProp("transformCopied", function (f) { slice = f(slice, view); });
    var context = [];
    var content = slice.content;
    var openStart = slice.openStart;
    var openEnd = slice.openEnd;
    while (openStart > 1 && openEnd > 1 && content.childCount == 1 && content.firstChild.childCount == 1) {
        openStart--;
        openEnd--;
        var node = content.firstChild;
        context.push(node.type.name, node.attrs != node.type.defaultAttrs ? node.attrs : null);
        content = node.content;
    }
    var serializer = view.someProp("clipboardSerializer") || DOMSerializer.fromSchema(view.state.schema);
    var doc = detachedDoc(), wrap = doc.createElement("div");
    wrap.appendChild(serializer.serializeFragment(content, { document: doc }));
    var firstChild = wrap.firstChild, needsWrap, wrappers = 0;
    while (firstChild && firstChild.nodeType == 1 && (needsWrap = wrapMap[firstChild.nodeName.toLowerCase()])) {
        for (var i = needsWrap.length - 1; i >= 0; i--) {
            var wrapper = doc.createElement(needsWrap[i]);
            while (wrap.firstChild)
                { wrapper.appendChild(wrap.firstChild); }
            wrap.appendChild(wrapper);
            wrappers++;
        }
        firstChild = wrap.firstChild;
    }
    if (firstChild && firstChild.nodeType == 1)
        { firstChild.setAttribute("data-pm-slice", (openStart + " " + openEnd + (wrappers ? (" -" + wrappers) : "") + " " + (JSON.stringify(context)))); }
    var text = view.someProp("clipboardTextSerializer", function (f) { return f(slice, view); }) ||
        slice.content.textBetween(0, slice.content.size, "\n\n");
    return { dom: wrap, text: text, slice: slice };
}
// Read a slice of content from the clipboard (or drop data).
function parseFromClipboard(view, text, html, plainText, $context) {
    var inCode = $context.parent.type.spec.code;
    var dom, slice;
    if (!html && !text)
        { return null; }
    var asText = text && (plainText || inCode || !html);
    if (asText) {
        view.someProp("transformPastedText", function (f) { text = f(text, inCode || plainText, view); });
        if (inCode)
            { return text ? new Slice(Fragment.from(view.state.schema.text(text.replace(/\r\n?/g, "\n"))), 0, 0) : Slice.empty; }
        var parsed = view.someProp("clipboardTextParser", function (f) { return f(text, $context, plainText, view); });
        if (parsed) {
            slice = parsed;
        }
        else {
            var marks = $context.marks();
            var ref = view.state;
            var schema = ref.schema;
            var serializer = DOMSerializer.fromSchema(schema);
            dom = document.createElement("div");
            text.split(/(?:\r\n?|\n)+/).forEach(function (block) {
                var p = dom.appendChild(document.createElement("p"));
                if (block)
                    { p.appendChild(serializer.serializeNode(schema.text(block, marks))); }
            });
        }
    }
    else {
        view.someProp("transformPastedHTML", function (f) { html = f(html, view); });
        dom = readHTML(html);
        if (webkit$1)
            { restoreReplacedSpaces(dom); }
    }
    var contextNode = dom && dom.querySelector("[data-pm-slice]");
    var sliceData = contextNode && /^(\d+) (\d+)(?: -(\d+))? (.*)/.exec(contextNode.getAttribute("data-pm-slice") || "");
    if (sliceData && sliceData[3])
        { for (var i = +sliceData[3]; i > 0; i--) {
            var child = dom.firstChild;
            while (child && child.nodeType != 1)
                { child = child.nextSibling; }
            if (!child)
                { break; }
            dom = child;
        } }
    if (!slice) {
        var parser = view.someProp("clipboardParser") || view.someProp("domParser") || DOMParser.fromSchema(view.state.schema);
        slice = parser.parseSlice(dom, {
            preserveWhitespace: !!(asText || sliceData),
            context: $context,
            ruleFromNode: function ruleFromNode(dom) {
                if (dom.nodeName == "BR" && !dom.nextSibling &&
                    dom.parentNode && !inlineParents.test(dom.parentNode.nodeName))
                    { return { ignore: true }; }
                return null;
            }
        });
    }
    if (sliceData) {
        slice = addContext(closeSlice(slice, +sliceData[1], +sliceData[2]), sliceData[4]);
    }
    else { // HTML wasn't created by ProseMirror. Make sure top-level siblings are coherent
        slice = Slice.maxOpen(normalizeSiblings(slice.content, $context), true);
        if (slice.openStart || slice.openEnd) {
            var openStart = 0, openEnd = 0;
            for (var node = slice.content.firstChild; openStart < slice.openStart && !node.type.spec.isolating; openStart++, node = node.firstChild) { }
            for (var node$1 = slice.content.lastChild; openEnd < slice.openEnd && !node$1.type.spec.isolating; openEnd++, node$1 = node$1.lastChild) { }
            slice = closeSlice(slice, openStart, openEnd);
        }
    }
    view.someProp("transformPasted", function (f) { slice = f(slice, view); });
    return slice;
}
var inlineParents = /^(a|abbr|acronym|b|cite|code|del|em|i|ins|kbd|label|output|q|ruby|s|samp|span|strong|sub|sup|time|u|tt|var)$/i;
// Takes a slice parsed with parseSlice, which means there hasn't been
// any content-expression checking done on the top nodes, tries to
// find a parent node in the current context that might fit the nodes,
// and if successful, rebuilds the slice so that it fits into that parent.
//
// This addresses the problem that Transform.replace expects a
// coherent slice, and will fail to place a set of siblings that don't
// fit anywhere in the schema.
function normalizeSiblings(fragment, $context) {
    if (fragment.childCount < 2)
        { return fragment; }
    var loop = function ( d ) {
        var parent = $context.node(d);
        var match = parent.contentMatchAt($context.index(d));
        var lastWrap = (void 0), result = [];
        fragment.forEach(function (node) {
            if (!result)
                { return; }
            var wrap = match.findWrapping(node.type), inLast;
            if (!wrap)
                { return result = null; }
            if (inLast = result.length && lastWrap.length && addToSibling(wrap, lastWrap, node, result[result.length - 1], 0)) {
                result[result.length - 1] = inLast;
            }
            else {
                if (result.length)
                    { result[result.length - 1] = closeRight(result[result.length - 1], lastWrap.length); }
                var wrapped = withWrappers(node, wrap);
                result.push(wrapped);
                match = match.matchType(wrapped.type);
                lastWrap = wrap;
            }
        });
        if (result)
            { return { v: Fragment.from(result) }; }
    };

    for (var d = $context.depth; d >= 0; d--) {
        var returned = loop( d );

        if ( returned ) return returned.v;
    }
    return fragment;
}
function withWrappers(node, wrap, from) {
    if ( from === void 0 ) from = 0;

    for (var i = wrap.length - 1; i >= from; i--)
        { node = wrap[i].create(null, Fragment.from(node)); }
    return node;
}
// Used to group adjacent nodes wrapped in similar parents by
// normalizeSiblings into the same parent node
function addToSibling(wrap, lastWrap, node, sibling, depth) {
    if (depth < wrap.length && depth < lastWrap.length && wrap[depth] == lastWrap[depth]) {
        var inner = addToSibling(wrap, lastWrap, node, sibling.lastChild, depth + 1);
        if (inner)
            { return sibling.copy(sibling.content.replaceChild(sibling.childCount - 1, inner)); }
        var match = sibling.contentMatchAt(sibling.childCount);
        if (match.matchType(depth == wrap.length - 1 ? node.type : wrap[depth + 1]))
            { return sibling.copy(sibling.content.append(Fragment.from(withWrappers(node, wrap, depth + 1)))); }
    }
}
function closeRight(node, depth) {
    if (depth == 0)
        { return node; }
    var fragment = node.content.replaceChild(node.childCount - 1, closeRight(node.lastChild, depth - 1));
    var fill = node.contentMatchAt(node.childCount).fillBefore(Fragment.empty, true);
    return node.copy(fragment.append(fill));
}
function closeRange(fragment, side, from, to, depth, openEnd) {
    var node = side < 0 ? fragment.firstChild : fragment.lastChild, inner = node.content;
    if (fragment.childCount > 1)
        { openEnd = 0; }
    if (depth < to - 1)
        { inner = closeRange(inner, side, from, to, depth + 1, openEnd); }
    if (depth >= from)
        { inner = side < 0 ? node.contentMatchAt(0).fillBefore(inner, openEnd <= depth).append(inner)
            : inner.append(node.contentMatchAt(node.childCount).fillBefore(Fragment.empty, true)); }
    return fragment.replaceChild(side < 0 ? 0 : fragment.childCount - 1, node.copy(inner));
}
function closeSlice(slice, openStart, openEnd) {
    if (openStart < slice.openStart)
        { slice = new Slice(closeRange(slice.content, -1, openStart, slice.openStart, 0, slice.openEnd), openStart, slice.openEnd); }
    if (openEnd < slice.openEnd)
        { slice = new Slice(closeRange(slice.content, 1, openEnd, slice.openEnd, 0, 0), slice.openStart, openEnd); }
    return slice;
}
// Trick from jQuery -- some elements must be wrapped in other
// elements for innerHTML to work. I.e. if you do `div.innerHTML =
// "<td>..</td>"` the table cells are ignored.
var wrapMap = {
    thead: ["table"],
    tbody: ["table"],
    tfoot: ["table"],
    caption: ["table"],
    colgroup: ["table"],
    col: ["table", "colgroup"],
    tr: ["table", "tbody"],
    td: ["table", "tbody", "tr"],
    th: ["table", "tbody", "tr"]
};
var _detachedDoc = null;
function detachedDoc() {
    return _detachedDoc || (_detachedDoc = document.implementation.createHTMLDocument("title"));
}
function maybeWrapTrusted(html) {
    var trustedTypes = window.trustedTypes;
    if (!trustedTypes)
        { return html; }
    // With the require-trusted-types-for CSP, Chrome will block
    // innerHTML, even on a detached document. This wraps the string in
    // a way that makes the browser allow us to use its parser again.
    return trustedTypes.createPolicy("detachedDocument", { createHTML: function (s) { return s; } }).createHTML(html);
}
function readHTML(html) {
    var metas = /^(\s*<meta [^>]*>)*/.exec(html);
    if (metas)
        { html = html.slice(metas[0].length); }
    var elt = detachedDoc().createElement("div");
    var firstTag = /<([a-z][^>\s]+)/i.exec(html), wrap;
    if (wrap = firstTag && wrapMap[firstTag[1].toLowerCase()])
        { html = wrap.map(function (n) { return "<" + n + ">"; }).join("") + html + wrap.map(function (n) { return "</" + n + ">"; }).reverse().join(""); }
    elt.innerHTML = maybeWrapTrusted(html);
    if (wrap)
        { for (var i = 0; i < wrap.length; i++)
            { elt = elt.querySelector(wrap[i]) || elt; } }
    return elt;
}
// Webkit browsers do some hard-to-predict replacement of regular
// spaces with non-breaking spaces when putting content on the
// clipboard. This tries to convert such non-breaking spaces (which
// will be wrapped in a plain span on Chrome, a span with class
// Apple-converted-space on Safari) back to regular spaces.
function restoreReplacedSpaces(dom) {
    var nodes = dom.querySelectorAll(chrome$1 ? "span:not([class]):not([style])" : "span.Apple-converted-space");
    for (var i = 0; i < nodes.length; i++) {
        var node = nodes[i];
        if (node.childNodes.length == 1 && node.textContent == "\u00a0" && node.parentNode)
            { node.parentNode.replaceChild(dom.ownerDocument.createTextNode(" "), node); }
    }
}
function addContext(slice, context) {
    if (!slice.size)
        { return slice; }
    var schema = slice.content.firstChild.type.schema, array;
    try {
        array = JSON.parse(context);
    }
    catch (e) {
        return slice;
    }
    var content = slice.content;
    var openStart = slice.openStart;
    var openEnd = slice.openEnd;
    for (var i = array.length - 2; i >= 0; i -= 2) {
        var type = schema.nodes[array[i]];
        if (!type || type.hasRequiredAttrs())
            { break; }
        content = Fragment.from(type.create(array[i + 1], content));
        openStart++;
        openEnd++;
    }
    return new Slice(content, openStart, openEnd);
}

// A collection of DOM events that occur within the editor, and callback functions
// to invoke when the event fires.
var handlers$1 = {};
var editHandlers = {};
var passiveHandlers = { touchstart: true, touchmove: true };
var InputState$1 = function InputState() {
    this.shiftKey = false;
    this.mouseDown = null;
    this.lastKeyCode = null;
    this.lastKeyCodeTime = 0;
    this.lastClick = { time: 0, x: 0, y: 0, type: "" };
    this.lastSelectionOrigin = null;
    this.lastSelectionTime = 0;
    this.lastIOSEnter = 0;
    this.lastIOSEnterFallbackTimeout = -1;
    this.lastFocus = 0;
    this.lastTouch = 0;
    this.lastAndroidDelete = 0;
    this.composing = false;
    this.compositionNode = null;
    this.composingTimeout = -1;
    this.compositionNodes = [];
    this.compositionEndedAt = -2e8;
    this.compositionID = 1;
    // Set to a composition ID when there are pending changes at compositionend
    this.compositionPendingChanges = 0;
    this.domChangeCount = 0;
    this.eventHandlers = Object.create(null);
    this.hideSelectionGuard = null;
};
function initInput(view) {
    var loop = function ( event ) {
        var handler = handlers$1[event];
        view.dom.addEventListener(event, view.input.eventHandlers[event] = function (event) {
            if (eventBelongsToView(view, event) && !runCustomHandler(view, event) &&
                (view.editable || !(event.type in editHandlers)))
                { handler(view, event); }
        }, passiveHandlers[event] ? { passive: true } : undefined);
    };

    for (var event in handlers$1) loop( event );
    // On Safari, for reasons beyond my understanding, adding an input
    // event handler makes an issue where the composition vanishes when
    // you press enter go away.
    if (safari$1)
        { view.dom.addEventListener("input", function () { return null; }); }
    ensureListeners(view);
}
function setSelectionOrigin(view, origin) {
    view.input.lastSelectionOrigin = origin;
    view.input.lastSelectionTime = Date.now();
}
function destroyInput(view) {
    view.domObserver.stop();
    for (var type in view.input.eventHandlers)
        { view.dom.removeEventListener(type, view.input.eventHandlers[type]); }
    clearTimeout(view.input.composingTimeout);
    clearTimeout(view.input.lastIOSEnterFallbackTimeout);
}
function ensureListeners(view) {
    view.someProp("handleDOMEvents", function (currentHandlers) {
        for (var type in currentHandlers)
            { if (!view.input.eventHandlers[type])
                { view.dom.addEventListener(type, view.input.eventHandlers[type] = function (event) { return runCustomHandler(view, event); }); } }
    });
}
function runCustomHandler(view, event) {
    return view.someProp("handleDOMEvents", function (handlers) {
        var handler = handlers[event.type];
        return handler ? handler(view, event) || event.defaultPrevented : false;
    });
}
function eventBelongsToView(view, event) {
    if (!event.bubbles)
        { return true; }
    if (event.defaultPrevented)
        { return false; }
    for (var node = event.target; node != view.dom; node = node.parentNode)
        { if (!node || node.nodeType == 11 ||
            (node.pmViewDesc && node.pmViewDesc.stopEvent(event)))
            { return false; } }
    return true;
}
function dispatchEvent(view, event) {
    if (!runCustomHandler(view, event) && handlers$1[event.type] &&
        (view.editable || !(event.type in editHandlers)))
        { handlers$1[event.type](view, event); }
}
editHandlers.keydown = function (view, _event) {
    var event = _event;
    view.input.shiftKey = event.keyCode == 16 || event.shiftKey;
    if (inOrNearComposition(view, event))
        { return; }
    view.input.lastKeyCode = event.keyCode;
    view.input.lastKeyCodeTime = Date.now();
    // Suppress enter key events on Chrome Android, because those tend
    // to be part of a confused sequence of composition events fired,
    // and handling them eagerly tends to corrupt the input.
    if (android$1 && chrome$1 && event.keyCode == 13)
        { return; }
    if (view.domObserver.selectionChanged(view.domSelectionRange()))
        { view.domObserver.flush(); }
    else if (event.keyCode != 229)
        { view.domObserver.forceFlush(); }
    // On iOS, if we preventDefault enter key presses, the virtual
    // keyboard gets confused. So the hack here is to set a flag that
    // makes the DOM change code recognize that what just happens should
    // be replaced by whatever the Enter key handlers do.
    if (ios$1 && event.keyCode == 13 && !event.ctrlKey && !event.altKey && !event.metaKey) {
        var now = Date.now();
        view.input.lastIOSEnter = now;
        view.input.lastIOSEnterFallbackTimeout = setTimeout(function () {
            if (view.input.lastIOSEnter == now) {
                view.someProp("handleKeyDown", function (f) { return f(view, keyEvent(13, "Enter")); });
                view.input.lastIOSEnter = 0;
            }
        }, 200);
    }
    else if (view.someProp("handleKeyDown", function (f) { return f(view, event); }) || captureKeyDown(view, event)) {
        event.preventDefault();
    }
    else {
        setSelectionOrigin(view, "key");
    }
};
editHandlers.keyup = function (view, event) {
    if (event.keyCode == 16)
        { view.input.shiftKey = false; }
};
editHandlers.keypress = function (view, _event) {
    var event = _event;
    if (inOrNearComposition(view, event) || !event.charCode ||
        event.ctrlKey && !event.altKey || mac$4 && event.metaKey)
        { return; }
    if (view.someProp("handleKeyPress", function (f) { return f(view, event); })) {
        event.preventDefault();
        return;
    }
    var sel = view.state.selection;
    if (!(sel instanceof TextSelection) || !sel.$from.sameParent(sel.$to)) {
        var text = String.fromCharCode(event.charCode);
        if (!/[\r\n]/.test(text) && !view.someProp("handleTextInput", function (f) { return f(view, sel.$from.pos, sel.$to.pos, text); }))
            { view.dispatch(view.state.tr.insertText(text).scrollIntoView()); }
        event.preventDefault();
    }
};
function eventCoords(event) { return { left: event.clientX, top: event.clientY }; }
function isNear(event, click) {
    var dx = click.x - event.clientX, dy = click.y - event.clientY;
    return dx * dx + dy * dy < 100;
}
function runHandlerOnContext(view, propName, pos, inside, event) {
    if (inside == -1)
        { return false; }
    var $pos = view.state.doc.resolve(inside);
    var loop = function ( i ) {
        if (view.someProp(propName, function (f) { return i > $pos.depth ? f(view, pos, $pos.nodeAfter, $pos.before(i), event, true)
            : f(view, pos, $pos.node(i), $pos.before(i), event, false); }))
            { return { v: true }; }
    };

    for (var i = $pos.depth + 1; i > 0; i--) {
        var returned = loop( i );

        if ( returned ) return returned.v;
    }
    return false;
}
function updateSelection(view, selection, origin) {
    if (!view.focused)
        { view.focus(); }
    if (view.state.selection.eq(selection))
        { return; }
    var tr = view.state.tr.setSelection(selection);
    if (origin == "pointer")
        { tr.setMeta("pointer", true); }
    view.dispatch(tr);
}
function selectClickedLeaf(view, inside) {
    if (inside == -1)
        { return false; }
    var $pos = view.state.doc.resolve(inside), node = $pos.nodeAfter;
    if (node && node.isAtom && NodeSelection.isSelectable(node)) {
        updateSelection(view, new NodeSelection($pos), "pointer");
        return true;
    }
    return false;
}
function selectClickedNode(view, inside) {
    if (inside == -1)
        { return false; }
    var sel = view.state.selection, selectedNode, selectAt;
    if (sel instanceof NodeSelection)
        { selectedNode = sel.node; }
    var $pos = view.state.doc.resolve(inside);
    for (var i = $pos.depth + 1; i > 0; i--) {
        var node = i > $pos.depth ? $pos.nodeAfter : $pos.node(i);
        if (NodeSelection.isSelectable(node)) {
            if (selectedNode && sel.$from.depth > 0 &&
                i >= sel.$from.depth && $pos.before(sel.$from.depth + 1) == sel.$from.pos)
                { selectAt = $pos.before(sel.$from.depth); }
            else
                { selectAt = $pos.before(i); }
            break;
        }
    }
    if (selectAt != null) {
        updateSelection(view, NodeSelection.create(view.state.doc, selectAt), "pointer");
        return true;
    }
    else {
        return false;
    }
}
function handleSingleClick(view, pos, inside, event, selectNode) {
    return runHandlerOnContext(view, "handleClickOn", pos, inside, event) ||
        view.someProp("handleClick", function (f) { return f(view, pos, event); }) ||
        (selectNode ? selectClickedNode(view, inside) : selectClickedLeaf(view, inside));
}
function handleDoubleClick(view, pos, inside, event) {
    return runHandlerOnContext(view, "handleDoubleClickOn", pos, inside, event) ||
        view.someProp("handleDoubleClick", function (f) { return f(view, pos, event); });
}
function handleTripleClick$1(view, pos, inside, event) {
    return runHandlerOnContext(view, "handleTripleClickOn", pos, inside, event) ||
        view.someProp("handleTripleClick", function (f) { return f(view, pos, event); }) ||
        defaultTripleClick(view, inside, event);
}
function defaultTripleClick(view, inside, event) {
    if (event.button != 0)
        { return false; }
    var doc = view.state.doc;
    if (inside == -1) {
        if (doc.inlineContent) {
            updateSelection(view, TextSelection.create(doc, 0, doc.content.size), "pointer");
            return true;
        }
        return false;
    }
    var $pos = doc.resolve(inside);
    for (var i = $pos.depth + 1; i > 0; i--) {
        var node = i > $pos.depth ? $pos.nodeAfter : $pos.node(i);
        var nodePos = $pos.before(i);
        if (node.inlineContent)
            { updateSelection(view, TextSelection.create(doc, nodePos + 1, nodePos + 1 + node.content.size), "pointer"); }
        else if (NodeSelection.isSelectable(node))
            { updateSelection(view, NodeSelection.create(doc, nodePos), "pointer"); }
        else
            { continue; }
        return true;
    }
}
function forceDOMFlush(view) {
    return endComposition(view);
}
var selectNodeModifier = mac$4 ? "metaKey" : "ctrlKey";
handlers$1.mousedown = function (view, _event) {
    var event = _event;
    view.input.shiftKey = event.shiftKey;
    var flushed = forceDOMFlush(view);
    var now = Date.now(), type = "singleClick";
    if (now - view.input.lastClick.time < 500 && isNear(event, view.input.lastClick) && !event[selectNodeModifier]) {
        if (view.input.lastClick.type == "singleClick")
            { type = "doubleClick"; }
        else if (view.input.lastClick.type == "doubleClick")
            { type = "tripleClick"; }
    }
    view.input.lastClick = { time: now, x: event.clientX, y: event.clientY, type: type };
    var pos = view.posAtCoords(eventCoords(event));
    if (!pos)
        { return; }
    if (type == "singleClick") {
        if (view.input.mouseDown)
            { view.input.mouseDown.done(); }
        view.input.mouseDown = new MouseDown(view, pos, event, !!flushed);
    }
    else if ((type == "doubleClick" ? handleDoubleClick : handleTripleClick$1)(view, pos.pos, pos.inside, event)) {
        event.preventDefault();
    }
    else {
        setSelectionOrigin(view, "pointer");
    }
};
var MouseDown = function MouseDown(view, pos, event, flushed) {
    var this$1$1 = this;

    this.view = view;
    this.pos = pos;
    this.event = event;
    this.flushed = flushed;
    this.delayedSelectionSync = false;
    this.mightDrag = null;
    this.startDoc = view.state.doc;
    this.selectNode = !!event[selectNodeModifier];
    this.allowDefault = event.shiftKey;
    var targetNode, targetPos;
    if (pos.inside > -1) {
        targetNode = view.state.doc.nodeAt(pos.inside);
        targetPos = pos.inside;
    }
    else {
        var $pos = view.state.doc.resolve(pos.pos);
        targetNode = $pos.parent;
        targetPos = $pos.depth ? $pos.before() : 0;
    }
    var target = flushed ? null : event.target;
    var targetDesc = target ? view.docView.nearestDesc(target, true) : null;
    this.target = targetDesc && targetDesc.dom.nodeType == 1 ? targetDesc.dom : null;
    var ref = view.state;
    var selection = ref.selection;
    if (event.button == 0 &&
        targetNode.type.spec.draggable && targetNode.type.spec.selectable !== false ||
        selection instanceof NodeSelection && selection.from <= targetPos && selection.to > targetPos)
        { this.mightDrag = {
            node: targetNode,
            pos: targetPos,
            addAttr: !!(this.target && !this.target.draggable),
            setUneditable: !!(this.target && gecko$1 && !this.target.hasAttribute("contentEditable"))
        }; }
    if (this.target && this.mightDrag && (this.mightDrag.addAttr || this.mightDrag.setUneditable)) {
        this.view.domObserver.stop();
        if (this.mightDrag.addAttr)
            { this.target.draggable = true; }
        if (this.mightDrag.setUneditable)
            { setTimeout(function () {
                if (this$1$1.view.input.mouseDown == this$1$1)
                    { this$1$1.target.setAttribute("contentEditable", "false"); }
            }, 20); }
        this.view.domObserver.start();
    }
    view.root.addEventListener("mouseup", this.up = this.up.bind(this));
    view.root.addEventListener("mousemove", this.move = this.move.bind(this));
    setSelectionOrigin(view, "pointer");
};
MouseDown.prototype.done = function done () {
        var this$1$1 = this;

    this.view.root.removeEventListener("mouseup", this.up);
    this.view.root.removeEventListener("mousemove", this.move);
    if (this.mightDrag && this.target) {
        this.view.domObserver.stop();
        if (this.mightDrag.addAttr)
            { this.target.removeAttribute("draggable"); }
        if (this.mightDrag.setUneditable)
            { this.target.removeAttribute("contentEditable"); }
        this.view.domObserver.start();
    }
    if (this.delayedSelectionSync)
        { setTimeout(function () { return selectionToDOM(this$1$1.view); }); }
    this.view.input.mouseDown = null;
};
MouseDown.prototype.up = function up (event) {
    this.done();
    if (!this.view.dom.contains(event.target))
        { return; }
    var pos = this.pos;
    if (this.view.state.doc != this.startDoc)
        { pos = this.view.posAtCoords(eventCoords(event)); }
    this.updateAllowDefault(event);
    if (this.allowDefault || !pos) {
        setSelectionOrigin(this.view, "pointer");
    }
    else if (handleSingleClick(this.view, pos.pos, pos.inside, event, this.selectNode)) {
        event.preventDefault();
    }
    else if (event.button == 0 &&
        (this.flushed ||
            // Safari ignores clicks on draggable elements
            (safari$1 && this.mightDrag && !this.mightDrag.node.isAtom) ||
            // Chrome will sometimes treat a node selection as a
            // cursor, but still report that the node is selected
            // when asked through getSelection. You'll then get a
            // situation where clicking at the point where that
            // (hidden) cursor is doesn't change the selection, and
            // thus doesn't get a reaction from ProseMirror. This
            // works around that.
            (chrome$1 && !this.view.state.selection.visible &&
                Math.min(Math.abs(pos.pos - this.view.state.selection.from), Math.abs(pos.pos - this.view.state.selection.to)) <= 2))) {
        updateSelection(this.view, Selection.near(this.view.state.doc.resolve(pos.pos)), "pointer");
        event.preventDefault();
    }
    else {
        setSelectionOrigin(this.view, "pointer");
    }
};
MouseDown.prototype.move = function move (event) {
    this.updateAllowDefault(event);
    setSelectionOrigin(this.view, "pointer");
    if (event.buttons == 0)
        { this.done(); }
};
MouseDown.prototype.updateAllowDefault = function updateAllowDefault (event) {
    if (!this.allowDefault && (Math.abs(this.event.x - event.clientX) > 4 ||
        Math.abs(this.event.y - event.clientY) > 4))
        { this.allowDefault = true; }
};
handlers$1.touchstart = function (view) {
    view.input.lastTouch = Date.now();
    forceDOMFlush(view);
    setSelectionOrigin(view, "pointer");
};
handlers$1.touchmove = function (view) {
    view.input.lastTouch = Date.now();
    setSelectionOrigin(view, "pointer");
};
handlers$1.contextmenu = function (view) { return forceDOMFlush(view); };
function inOrNearComposition(view, event) {
    if (view.composing)
        { return true; }
    // See https://www.stum.de/2016/06/24/handling-ime-events-in-javascript/.
    // On Japanese input method editors (IMEs), the Enter key is used to confirm character
    // selection. On Safari, when Enter is pressed, compositionend and keydown events are
    // emitted. The keydown event triggers newline insertion, which we don't want.
    // This method returns true if the keydown event should be ignored.
    // We only ignore it once, as pressing Enter a second time *should* insert a newline.
    // Furthermore, the keydown event timestamp must be close to the compositionEndedAt timestamp.
    // This guards against the case where compositionend is triggered without the keyboard
    // (e.g. character confirmation may be done with the mouse), and keydown is triggered
    // afterwards- we wouldn't want to ignore the keydown event in this case.
    if (safari$1 && Math.abs(event.timeStamp - view.input.compositionEndedAt) < 500) {
        view.input.compositionEndedAt = -2e8;
        return true;
    }
    return false;
}
// Drop active composition after 5 seconds of inactivity on Android
var timeoutComposition = android$1 ? 5000 : -1;
editHandlers.compositionstart = editHandlers.compositionupdate = function (view) {
    if (!view.composing) {
        view.domObserver.flush();
        var state = view.state;
        var $pos = state.selection.$to;
        if (state.selection instanceof TextSelection &&
            (state.storedMarks ||
                (!$pos.textOffset && $pos.parentOffset && $pos.nodeBefore.marks.some(function (m) { return m.type.spec.inclusive === false; })))) {
            // Need to wrap the cursor in mark nodes different from the ones in the DOM context
            view.markCursor = view.state.storedMarks || $pos.marks();
            endComposition(view, true);
            view.markCursor = null;
        }
        else {
            endComposition(view, !state.selection.empty);
            // In firefox, if the cursor is after but outside a marked node,
            // the inserted text won't inherit the marks. So this moves it
            // inside if necessary.
            if (gecko$1 && state.selection.empty && $pos.parentOffset && !$pos.textOffset && $pos.nodeBefore.marks.length) {
                var sel = view.domSelectionRange();
                for (var node = sel.focusNode, offset = sel.focusOffset; node && node.nodeType == 1 && offset != 0;) {
                    var before = offset < 0 ? node.lastChild : node.childNodes[offset - 1];
                    if (!before)
                        { break; }
                    if (before.nodeType == 3) {
                        var sel$1 = view.domSelection();
                        if (sel$1)
                            { sel$1.collapse(before, before.nodeValue.length); }
                        break;
                    }
                    else {
                        node = before;
                        offset = -1;
                    }
                }
            }
        }
        view.input.composing = true;
    }
    scheduleComposeEnd(view, timeoutComposition);
};
editHandlers.compositionend = function (view, event) {
    if (view.composing) {
        view.input.composing = false;
        view.input.compositionEndedAt = event.timeStamp;
        view.input.compositionPendingChanges = view.domObserver.pendingRecords().length ? view.input.compositionID : 0;
        view.input.compositionNode = null;
        if (view.input.compositionPendingChanges)
            { Promise.resolve().then(function () { return view.domObserver.flush(); }); }
        view.input.compositionID++;
        scheduleComposeEnd(view, 20);
    }
};
function scheduleComposeEnd(view, delay) {
    clearTimeout(view.input.composingTimeout);
    if (delay > -1)
        { view.input.composingTimeout = setTimeout(function () { return endComposition(view); }, delay); }
}
function clearComposition(view) {
    if (view.composing) {
        view.input.composing = false;
        view.input.compositionEndedAt = timestampFromCustomEvent();
    }
    while (view.input.compositionNodes.length > 0)
        { view.input.compositionNodes.pop().markParentsDirty(); }
}
function findCompositionNode$1(view) {
    var sel = view.domSelectionRange();
    if (!sel.focusNode)
        { return null; }
    var textBefore = textNodeBefore$1(sel.focusNode, sel.focusOffset);
    var textAfter = textNodeAfter$1(sel.focusNode, sel.focusOffset);
    if (textBefore && textAfter && textBefore != textAfter) {
        var descAfter = textAfter.pmViewDesc, lastChanged = view.domObserver.lastChangedTextNode;
        if (textBefore == lastChanged || textAfter == lastChanged)
            { return lastChanged; }
        if (!descAfter || !descAfter.isText(textAfter.nodeValue)) {
            return textAfter;
        }
        else if (view.input.compositionNode == textAfter) {
            var descBefore = textBefore.pmViewDesc;
            if (!(!descBefore || !descBefore.isText(textBefore.nodeValue)))
                { return textAfter; }
        }
    }
    return textBefore || textAfter;
}
function timestampFromCustomEvent() {
    var event = document.createEvent("Event");
    event.initEvent("event", true, true);
    return event.timeStamp;
}
/**
@internal
*/
function endComposition(view, restarting) {
    if ( restarting === void 0 ) restarting = false;

    if (android$1 && view.domObserver.flushingSoon >= 0)
        { return; }
    view.domObserver.forceFlush();
    clearComposition(view);
    if (restarting || view.docView && view.docView.dirty) {
        var sel = selectionFromDOM(view);
        if (sel && !sel.eq(view.state.selection))
            { view.dispatch(view.state.tr.setSelection(sel)); }
        else if ((view.markCursor || restarting) && !view.state.selection.empty)
            { view.dispatch(view.state.tr.deleteSelection()); }
        else
            { view.updateState(view.state); }
        return true;
    }
    return false;
}
function captureCopy$1(view, dom) {
    // The extra wrapper is somehow necessary on IE/Edge to prevent the
    // content from being mangled when it is put onto the clipboard
    if (!view.dom.parentNode)
        { return; }
    var wrap = view.dom.parentNode.appendChild(document.createElement("div"));
    wrap.appendChild(dom);
    wrap.style.cssText = "position: fixed; left: -10000px; top: 10px";
    var sel = getSelection(), range = document.createRange();
    range.selectNodeContents(dom);
    // Done because IE will fire a selectionchange moving the selection
    // to its start when removeAllRanges is called and the editor still
    // has focus (which will mess up the editor's selection state).
    view.dom.blur();
    sel.removeAllRanges();
    sel.addRange(range);
    setTimeout(function () {
        if (wrap.parentNode)
            { wrap.parentNode.removeChild(wrap); }
        view.focus();
    }, 50);
}
// 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.
var brokenClipboardAPI$1 = (ie$2 && ie_version < 15) ||
    (ios$1 && webkit_version < 604);
handlers$1.copy = editHandlers.cut = function (view, _event) {
    var event = _event;
    var sel = view.state.selection, cut = event.type == "cut";
    if (sel.empty)
        { return; }
    // IE and Edge's clipboard interface is completely broken
    var data = brokenClipboardAPI$1 ? null : event.clipboardData;
    var slice = sel.content();
    var ref = serializeForClipboard(view, slice);
    var dom = ref.dom;
    var text = ref.text;
    if (data) {
        event.preventDefault();
        data.clearData();
        data.setData("text/html", dom.innerHTML);
        data.setData("text/plain", text);
    }
    else {
        captureCopy$1(view, dom);
    }
    if (cut)
        { view.dispatch(view.state.tr.deleteSelection().scrollIntoView().setMeta("uiEvent", "cut")); }
};
function sliceSingleNode(slice) {
    return slice.openStart == 0 && slice.openEnd == 0 && slice.content.childCount == 1 ? slice.content.firstChild : null;
}
function capturePaste$1(view, event) {
    if (!view.dom.parentNode)
        { return; }
    var plainText = view.input.shiftKey || view.state.selection.$from.parent.type.spec.code;
    var target = view.dom.parentNode.appendChild(document.createElement(plainText ? "textarea" : "div"));
    if (!plainText)
        { target.contentEditable = "true"; }
    target.style.cssText = "position: fixed; left: -10000px; top: 10px";
    target.focus();
    var plain = view.input.shiftKey && view.input.lastKeyCode != 45;
    setTimeout(function () {
        view.focus();
        if (target.parentNode)
            { target.parentNode.removeChild(target); }
        if (plainText)
            { doPaste$1(view, target.value, null, plain, event); }
        else
            { doPaste$1(view, target.textContent, target.innerHTML, plain, event); }
    }, 50);
}
function doPaste$1(view, text, html, preferPlain, event) {
    var slice = parseFromClipboard(view, text, html, preferPlain, view.state.selection.$from);
    if (view.someProp("handlePaste", function (f) { return f(view, event, slice || Slice.empty); }))
        { return true; }
    if (!slice)
        { return false; }
    var singleNode = sliceSingleNode(slice);
    var tr = singleNode
        ? view.state.tr.replaceSelectionWith(singleNode, preferPlain)
        : view.state.tr.replaceSelection(slice);
    view.dispatch(tr.scrollIntoView().setMeta("paste", true).setMeta("uiEvent", "paste"));
    return true;
}
function getText(clipboardData) {
    var text = clipboardData.getData("text/plain") || clipboardData.getData("Text");
    if (text)
        { return text; }
    var uris = clipboardData.getData("text/uri-list");
    return uris ? uris.replace(/\r?\n/g, " ") : "";
}
editHandlers.paste = function (view, _event) {
    var event = _event;
    // Handling paste from JavaScript during composition is very poorly
    // handled by browsers, so as a dodgy but preferable kludge, we just
    // let the browser do its native thing there, except on Android,
    // where the editor is almost always composing.
    if (view.composing && !android$1)
        { return; }
    var data = brokenClipboardAPI$1 ? null : event.clipboardData;
    var plain = view.input.shiftKey && view.input.lastKeyCode != 45;
    if (data && doPaste$1(view, getText(data), data.getData("text/html"), plain, event))
        { event.preventDefault(); }
    else
        { capturePaste$1(view, event); }
};
var Dragging = function Dragging(slice, move, node) {
    this.slice = slice;
    this.move = move;
    this.node = node;
};
var dragCopyModifier = mac$4 ? "altKey" : "ctrlKey";
handlers$1.dragstart = function (view, _event) {
    var event = _event;
    var mouseDown = view.input.mouseDown;
    if (mouseDown)
        { mouseDown.done(); }
    if (!event.dataTransfer)
        { return; }
    var sel = view.state.selection;
    var pos = sel.empty ? null : view.posAtCoords(eventCoords(event));
    var node;
    if (pos && pos.pos >= sel.from && pos.pos <= (sel instanceof NodeSelection ? sel.to - 1 : sel.to)) ;
    else if (mouseDown && mouseDown.mightDrag) {
        node = NodeSelection.create(view.state.doc, mouseDown.mightDrag.pos);
    }
    else if (event.target && event.target.nodeType == 1) {
        var desc = view.docView.nearestDesc(event.target, true);
        if (desc && desc.node.type.spec.draggable && desc != view.docView)
            { node = NodeSelection.create(view.state.doc, desc.posBefore); }
    }
    var draggedSlice = (node || view.state.selection).content();
    var ref = serializeForClipboard(view, draggedSlice);
    var dom = ref.dom;
    var text = ref.text;
    var slice = ref.slice;
    // Pre-120 Chrome versions clear files when calling `clearData` (#1472)
    if (!event.dataTransfer.files.length || !chrome$1 || chrome_version > 120)
        { event.dataTransfer.clearData(); }
    event.dataTransfer.setData(brokenClipboardAPI$1 ? "Text" : "text/html", dom.innerHTML);
    // See https://github.com/ProseMirror/prosemirror/issues/1156
    event.dataTransfer.effectAllowed = "copyMove";
    if (!brokenClipboardAPI$1)
        { event.dataTransfer.setData("text/plain", text); }
    view.dragging = new Dragging(slice, !event[dragCopyModifier], node);
};
handlers$1.dragend = function (view) {
    var dragging = view.dragging;
    window.setTimeout(function () {
        if (view.dragging == dragging)
            { view.dragging = null; }
    }, 50);
};
editHandlers.dragover = editHandlers.dragenter = function (_, e) { return e.preventDefault(); };
editHandlers.drop = function (view, _event) {
    var event = _event;
    var dragging = view.dragging;
    view.dragging = null;
    if (!event.dataTransfer)
        { return; }
    var eventPos = view.posAtCoords(eventCoords(event));
    if (!eventPos)
        { return; }
    var $mouse = view.state.doc.resolve(eventPos.pos);
    var slice = dragging && dragging.slice;
    if (slice) {
        view.someProp("transformPasted", function (f) { slice = f(slice, view); });
    }
    else {
        slice = parseFromClipboard(view, getText(event.dataTransfer), brokenClipboardAPI$1 ? null : event.dataTransfer.getData("text/html"), false, $mouse);
    }
    var move = !!(dragging && !event[dragCopyModifier]);
    if (view.someProp("handleDrop", function (f) { return f(view, event, slice || Slice.empty, move); })) {
        event.preventDefault();
        return;
    }
    if (!slice)
        { return; }
    event.preventDefault();
    var insertPos = slice ? dropPoint(view.state.doc, $mouse.pos, slice) : $mouse.pos;
    if (insertPos == null)
        { insertPos = $mouse.pos; }
    var tr = view.state.tr;
    if (move) {
        var node = dragging.node;
        if (node)
            { node.replace(tr); }
        else
            { tr.deleteSelection(); }
    }
    var pos = tr.mapping.map(insertPos);
    var isNode = slice.openStart == 0 && slice.openEnd == 0 && slice.content.childCount == 1;
    var beforeInsert = tr.doc;
    if (isNode)
        { tr.replaceRangeWith(pos, pos, slice.content.firstChild); }
    else
        { tr.replaceRange(pos, pos, slice); }
    if (tr.doc.eq(beforeInsert))
        { return; }
    var $pos = tr.doc.resolve(pos);
    if (isNode && NodeSelection.isSelectable(slice.content.firstChild) &&
        $pos.nodeAfter && $pos.nodeAfter.sameMarkup(slice.content.firstChild)) {
        tr.setSelection(new NodeSelection($pos));
    }
    else {
        var end = tr.mapping.map(insertPos);
        tr.mapping.maps[tr.mapping.maps.length - 1].forEach(function (_from, _to, _newFrom, newTo) { return end = newTo; });
        tr.setSelection(selectionBetween(view, $pos, tr.doc.resolve(end)));
    }
    view.focus();
    view.dispatch(tr.setMeta("uiEvent", "drop"));
};
handlers$1.focus = function (view) {
    view.input.lastFocus = Date.now();
    if (!view.focused) {
        view.domObserver.stop();
        view.dom.classList.add("ProseMirror-focused");
        view.domObserver.start();
        view.focused = true;
        setTimeout(function () {
            if (view.docView && view.hasFocus() && !view.domObserver.currentSelection.eq(view.domSelectionRange()))
                { selectionToDOM(view); }
        }, 20);
    }
};
handlers$1.blur = function (view, _event) {
    var event = _event;
    if (view.focused) {
        view.domObserver.stop();
        view.dom.classList.remove("ProseMirror-focused");
        view.domObserver.start();
        if (event.relatedTarget && view.dom.contains(event.relatedTarget))
            { view.domObserver.currentSelection.clear(); }
        view.focused = false;
    }
};
handlers$1.beforeinput = function (view, _event) {
    var event = _event;
    // We should probably do more with beforeinput events, but support
    // is so spotty that I'm still waiting to see where they are going.
    // Very specific hack to deal with backspace sometimes failing on
    // Chrome Android when after an uneditable node.
    if (chrome$1 && android$1 && event.inputType == "deleteContentBackward") {
        view.domObserver.flushSoon();
        var ref = view.input;
        var domChangeCount = ref.domChangeCount;
        setTimeout(function () {
            if (view.input.domChangeCount != domChangeCount)
                { return; } // Event already had some effect
            // This bug tends to close the virtual keyboard, so we refocus
            view.dom.blur();
            view.focus();
            if (view.someProp("handleKeyDown", function (f) { return f(view, keyEvent(8, "Backspace")); }))
                { return; }
            var ref = view.state.selection;
            var $cursor = ref.$cursor;
            // Crude approximation of backspace behavior when no command handled it
            if ($cursor && $cursor.pos > 0)
                { view.dispatch(view.state.tr.delete($cursor.pos - 1, $cursor.pos).scrollIntoView()); }
        }, 50);
    }
};
// Make sure all handlers get registered
for (var prop$1 in editHandlers)
    { handlers$1[prop$1] = editHandlers[prop$1]; }

function compareObjs(a, b) {
    if (a == b)
        { return true; }
    for (var p in a)
        { if (a[p] !== b[p])
            { return false; } }
    for (var p$1 in b)
        { if (!(p$1 in a))
            { return false; } }
    return true;
}
var WidgetType$1 = function WidgetType(toDOM, spec) {
    this.toDOM = toDOM;
    this.spec = spec || noSpec;
    this.side = this.spec.side || 0;
};
WidgetType$1.prototype.map = function map (mapping, span, offset, oldOffset) {
    var ref = mapping.mapResult(span.from + oldOffset, this.side < 0 ? -1 : 1);
        var pos = ref.pos;
        var deleted = ref.deleted;
    return deleted ? null : new Decoration$1(pos - offset, pos - offset, this);
};
WidgetType$1.prototype.valid = function valid () { return true; };
WidgetType$1.prototype.eq = function eq (other) {
    return this == other ||
        (other instanceof WidgetType$1 &&
            (this.spec.key && this.spec.key == other.spec.key ||
                this.toDOM == other.toDOM && compareObjs(this.spec, other.spec)));
};
WidgetType$1.prototype.destroy = function destroy (node) {
    if (this.spec.destroy)
        { this.spec.destroy(node); }
};
var InlineType = function InlineType(attrs, spec) {
    this.attrs = attrs;
    this.spec = spec || noSpec;
};
InlineType.prototype.map = function map (mapping, span, offset, oldOffset) {
    var from = mapping.map(span.from + oldOffset, this.spec.inclusiveStart ? -1 : 1) - offset;
    var to = mapping.map(span.to + oldOffset, this.spec.inclusiveEnd ? 1 : -1) - offset;
    return from >= to ? null : new Decoration$1(from, to, this);
};
InlineType.prototype.valid = function valid (_, span) { return span.from < span.to; };
InlineType.prototype.eq = function eq (other) {
    return this == other ||
        (other instanceof InlineType && compareObjs(this.attrs, other.attrs) &&
            compareObjs(this.spec, other.spec));
};
InlineType.is = function is (span) { return span.type instanceof InlineType; };
InlineType.prototype.destroy = function destroy () { };
var NodeType$1 = function NodeType(attrs, spec) {
    this.attrs = attrs;
    this.spec = spec || noSpec;
};
NodeType$1.prototype.map = function map (mapping, span, offset, oldOffset) {
    var from = mapping.mapResult(span.from + oldOffset, 1);
    if (from.deleted)
        { return null; }
    var to = mapping.mapResult(span.to + oldOffset, -1);
    if (to.deleted || to.pos <= from.pos)
        { return null; }
    return new Decoration$1(from.pos - offset, to.pos - offset, this);
};
NodeType$1.prototype.valid = function valid (node, span) {
    var ref = node.content.findIndex(span.from);
        var index = ref.index;
        var offset = ref.offset;
        var child;
    return offset == span.from && !(child = node.child(index)).isText && offset + child.nodeSize == span.to;
};
NodeType$1.prototype.eq = function eq (other) {
    return this == other ||
        (other instanceof NodeType$1 && compareObjs(this.attrs, other.attrs) &&
            compareObjs(this.spec, other.spec));
};
NodeType$1.prototype.destroy = function destroy () { };
/**
Decoration objects can be provided to the view through the
[`decorations` prop](https://prosemirror.net/docs/ref/#view.EditorProps.decorations). They come in
several variants—see the static members of this class for details.
*/
var Decoration$1 = function Decoration(
/**
The start position of the decoration.
*/
from, 
/**
The end position. Will be the same as `from` for [widget
decorations](https://prosemirror.net/docs/ref/#view.Decoration^widget).
*/
to, 
/**
@internal
*/
type) {
    this.from = from;
    this.to = to;
    this.type = type;
};

var prototypeAccessors$6$1 = { spec: { configurable: true },inline: { configurable: true },widget: { configurable: true } };
/**
@internal
*/
Decoration$1.prototype.copy = function copy (from, to) {
    return new Decoration$1(from, to, this.type);
};
/**
@internal
*/
Decoration$1.prototype.eq = function eq (other, offset) {
        if ( offset === void 0 ) offset = 0;

    return this.type.eq(other.type) && this.from + offset == other.from && this.to + offset == other.to;
};
/**
@internal
*/
Decoration$1.prototype.map = function map (mapping, offset, oldOffset) {
    return this.type.map(mapping, this, offset, oldOffset);
};
/**
Creates a widget decoration, which is a DOM node that's shown in
the document at the given position. It is recommended that you
delay rendering the widget by passing a function that will be
called when the widget is actually drawn in a view, but you can
also directly pass a DOM node. `getPos` can be used to find the
widget's current document position.
*/
Decoration$1.widget = function widget (pos, toDOM, spec) {
    return new Decoration$1(pos, pos, new WidgetType$1(toDOM, spec));
};
/**
Creates an inline decoration, which adds the given attributes to
each inline node between `from` and `to`.
*/
Decoration$1.inline = function inline (from, to, attrs, spec) {
    return new Decoration$1(from, to, new InlineType(attrs, spec));
};
/**
Creates a node decoration. `from` and `to` should point precisely
before and after a node in the document. That node, and only that
node, will receive the given attributes.
*/
Decoration$1.node = function node (from, to, attrs, spec) {
    return new Decoration$1(from, to, new NodeType$1(attrs, spec));
};
/**
The spec provided when creating this decoration. Can be useful
if you've stored extra information in that object.
*/
prototypeAccessors$6$1.spec.get = function () { return this.type.spec; };
/**
@internal
*/
prototypeAccessors$6$1.inline.get = function () { return this.type instanceof InlineType; };
/**
@internal
*/
prototypeAccessors$6$1.widget.get = function () { return this.type instanceof WidgetType$1; };

Object.defineProperties( Decoration$1.prototype, prototypeAccessors$6$1 );
var none$2 = [], noSpec = {};
/**
A collection of [decorations](https://prosemirror.net/docs/ref/#view.Decoration), organized in such
a way that the drawing algorithm can efficiently use and compare
them. This is a persistent data structure—it is not modified,
updates create a new value.
*/
var DecorationSet = function DecorationSet(local, children) {
    this.local = local.length ? local : none$2;
    this.children = children.length ? children : none$2;
};
/**
Create a set of decorations, using the structure of the given
document. This will consume (modify) the `decorations` array, so
you must make a copy if you want need to preserve that.
*/
DecorationSet.create = function create (doc, decorations) {
    return decorations.length ? buildTree$1(decorations, doc, 0, noSpec) : empty$1;
};
/**
Find all decorations in this set which touch the given range
(including decorations that start or end directly at the
boundaries) and match the given predicate on their spec. When
`start` and `end` are omitted, all decorations in the set are
considered. When `predicate` isn't given, all decorations are
assumed to match.
*/
DecorationSet.prototype.find = function find (start, end, predicate) {
    var result = [];
    this.findInner(start == null ? 0 : start, end == null ? 1e9 : end, result, 0, predicate);
    return result;
};
DecorationSet.prototype.findInner = function findInner (start, end, result, offset, predicate) {
    for (var i = 0; i < this.local.length; i++) {
        var span = this.local[i];
        if (span.from <= end && span.to >= start && (!predicate || predicate(span.spec)))
            { result.push(span.copy(span.from + offset, span.to + offset)); }
    }
    for (var i$1 = 0; i$1 < this.children.length; i$1 += 3) {
        if (this.children[i$1] < end && this.children[i$1 + 1] > start) {
            var childOff = this.children[i$1] + 1;
            this.children[i$1 + 2].findInner(start - childOff, end - childOff, result, offset + childOff, predicate);
        }
    }
};
/**
Map the set of decorations in response to a change in the
document.
*/
DecorationSet.prototype.map = function map (mapping, doc, options) {
    if (this == empty$1 || mapping.maps.length == 0)
        { return this; }
    return this.mapInner(mapping, doc, 0, 0, options || noSpec);
};
/**
@internal
*/
DecorationSet.prototype.mapInner = function mapInner (mapping, node, offset, oldOffset, options) {
    var newLocal;
    for (var i = 0; i < this.local.length; i++) {
        var mapped = this.local[i].map(mapping, offset, oldOffset);
        if (mapped && mapped.type.valid(node, mapped))
            { (newLocal || (newLocal = [])).push(mapped); }
        else if (options.onRemove)
            { options.onRemove(this.local[i].spec); }
    }
    if (this.children.length)
        { return mapChildren(this.children, newLocal || [], mapping, node, offset, oldOffset, options); }
    else
        { return newLocal ? new DecorationSet(newLocal.sort(byPos), none$2) : empty$1; }
};
/**
Add the given array of decorations to the ones in the set,
producing a new set. Consumes the `decorations` array. Needs
access to the current document to create the appropriate tree
structure.
*/
DecorationSet.prototype.add = function add (doc, decorations) {
    if (!decorations.length)
        { return this; }
    if (this == empty$1)
        { return DecorationSet.create(doc, decorations); }
    return this.addInner(doc, decorations, 0);
};
DecorationSet.prototype.addInner = function addInner (doc, decorations, offset) {
        var this$1$1 = this;

    var children, childIndex = 0;
    doc.forEach(function (childNode, childOffset) {
        var baseOffset = childOffset + offset, found;
        if (!(found = takeSpansForNode(decorations, childNode, baseOffset)))
            { return; }
        if (!children)
            { children = this$1$1.children.slice(); }
        while (childIndex < children.length && children[childIndex] < childOffset)
            { childIndex += 3; }
        if (children[childIndex] == childOffset)
            { children[childIndex + 2] = children[childIndex + 2].addInner(childNode, found, baseOffset + 1); }
        else
            { children.splice(childIndex, 0, childOffset, childOffset + childNode.nodeSize, buildTree$1(found, childNode, baseOffset + 1, noSpec)); }
        childIndex += 3;
    });
    var local = moveSpans(childIndex ? withoutNulls(decorations) : decorations, -offset);
    for (var i = 0; i < local.length; i++)
        { if (!local[i].type.valid(doc, local[i]))
            { local.splice(i--, 1); } }
    return new DecorationSet(local.length ? this.local.concat(local).sort(byPos) : this.local, children || this.children);
};
/**
Create a new set that contains the decorations in this set, minus
the ones in the given array.
*/
DecorationSet.prototype.remove = function remove (decorations) {
    if (decorations.length == 0 || this == empty$1)
        { return this; }
    return this.removeInner(decorations, 0);
};
DecorationSet.prototype.removeInner = function removeInner (decorations, offset) {
    var children = this.children, local = this.local;
    for (var i = 0; i < children.length; i += 3) {
        var found = (void 0);
        var from = children[i] + offset, to = children[i + 1] + offset;
        for (var j = 0, span = (void 0); j < decorations.length; j++)
            { if (span = decorations[j]) {
                if (span.from > from && span.to < to) {
                    decorations[j] = null;
                    (found || (found = [])).push(span);
                }
            } }
        if (!found)
            { continue; }
        if (children == this.children)
            { children = this.children.slice(); }
        var removed = children[i + 2].removeInner(found, from + 1);
        if (removed != empty$1) {
            children[i + 2] = removed;
        }
        else {
            children.splice(i, 3);
            i -= 3;
        }
    }
    if (local.length)
        { for (var i$1 = 0, span$1 = (void 0); i$1 < decorations.length; i$1++)
            { if (span$1 = decorations[i$1]) {
                for (var j$1 = 0; j$1 < local.length; j$1++)
                    { if (local[j$1].eq(span$1, offset)) {
                        if (local == this.local)
                            { local = this.local.slice(); }
                        local.splice(j$1--, 1);
                    } }
            } } }
    if (children == this.children && local == this.local)
        { return this; }
    return local.length || children.length ? new DecorationSet(local, children) : empty$1;
};
DecorationSet.prototype.forChild = function forChild (offset, node) {
    if (this == empty$1)
        { return this; }
    if (node.isLeaf)
        { return DecorationSet.empty; }
    var child, local;
    for (var i = 0; i < this.children.length; i += 3)
        { if (this.children[i] >= offset) {
            if (this.children[i] == offset)
                { child = this.children[i + 2]; }
            break;
        } }
    var start = offset + 1, end = start + node.content.size;
    for (var i$1 = 0; i$1 < this.local.length; i$1++) {
        var dec = this.local[i$1];
        if (dec.from < end && dec.to > start && (dec.type instanceof InlineType)) {
            var from = Math.max(start, dec.from) - start, to = Math.min(end, dec.to) - start;
            if (from < to)
                { (local || (local = [])).push(dec.copy(from, to)); }
        }
    }
    if (local) {
        var localSet = new DecorationSet(local.sort(byPos), none$2);
        return child ? new DecorationGroup([localSet, child]) : localSet;
    }
    return child || empty$1;
};
/**
@internal
*/
DecorationSet.prototype.eq = function eq (other) {
    if (this == other)
        { return true; }
    if (!(other instanceof DecorationSet) ||
        this.local.length != other.local.length ||
        this.children.length != other.children.length)
        { return false; }
    for (var i = 0; i < this.local.length; i++)
        { if (!this.local[i].eq(other.local[i]))
            { return false; } }
    for (var i$1 = 0; i$1 < this.children.length; i$1 += 3)
        { if (this.children[i$1] != other.children[i$1] ||
            this.children[i$1 + 1] != other.children[i$1 + 1] ||
            !this.children[i$1 + 2].eq(other.children[i$1 + 2]))
            { return false; } }
    return true;
};
/**
@internal
*/
DecorationSet.prototype.locals = function locals (node) {
    return removeOverlap(this.localsInner(node));
};
/**
@internal
*/
DecorationSet.prototype.localsInner = function localsInner (node) {
    if (this == empty$1)
        { return none$2; }
    if (node.inlineContent || !this.local.some(InlineType.is))
        { return this.local; }
    var result = [];
    for (var i = 0; i < this.local.length; i++) {
        if (!(this.local[i].type instanceof InlineType))
            { result.push(this.local[i]); }
    }
    return result;
};
DecorationSet.prototype.forEachSet = function forEachSet (f) { f(this); };
/**
The empty set of decorations.
*/
DecorationSet.empty = new DecorationSet([], []);
/**
@internal
*/
DecorationSet.removeOverlap = removeOverlap;
var empty$1 = DecorationSet.empty;
// An abstraction that allows the code dealing with decorations to
// treat multiple DecorationSet objects as if it were a single object
// with (a subset of) the same interface.
var DecorationGroup = function DecorationGroup(members) {
    this.members = members;
};
DecorationGroup.prototype.map = function map (mapping, doc) {
    var mappedDecos = this.members.map(function (member) { return member.map(mapping, doc, noSpec); });
    return DecorationGroup.from(mappedDecos);
};
DecorationGroup.prototype.forChild = function forChild (offset, child) {
    if (child.isLeaf)
        { return DecorationSet.empty; }
    var found = [];
    for (var i = 0; i < this.members.length; i++) {
        var result = this.members[i].forChild(offset, child);
        if (result == empty$1)
            { continue; }
        if (result instanceof DecorationGroup)
            { found = found.concat(result.members); }
        else
            { found.push(result); }
    }
    return DecorationGroup.from(found);
};
DecorationGroup.prototype.eq = function eq (other) {
    if (!(other instanceof DecorationGroup) ||
        other.members.length != this.members.length)
        { return false; }
    for (var i = 0; i < this.members.length; i++)
        { if (!this.members[i].eq(other.members[i]))
            { return false; } }
    return true;
};
DecorationGroup.prototype.locals = function locals (node) {
    var result, sorted = true;
    for (var i = 0; i < this.members.length; i++) {
        var locals = this.members[i].localsInner(node);
        if (!locals.length)
            { continue; }
        if (!result) {
            result = locals;
        }
        else {
            if (sorted) {
                result = result.slice();
                sorted = false;
            }
            for (var j = 0; j < locals.length; j++)
                { result.push(locals[j]); }
        }
    }
    return result ? removeOverlap(sorted ? result : result.sort(byPos)) : none$2;
};
// Create a group for the given array of decoration sets, or return
// a single set when possible.
DecorationGroup.from = function from (members) {
    switch (members.length) {
        case 0: return empty$1;
        case 1: return members[0];
        default: return new DecorationGroup(members.every(function (m) { return m instanceof DecorationSet; }) ? members :
            members.reduce(function (r, m) { return r.concat(m instanceof DecorationSet ? m : m.members); }, []));
    }
};
DecorationGroup.prototype.forEachSet = function forEachSet (f) {
    for (var i = 0; i < this.members.length; i++)
        { this.members[i].forEachSet(f); }
};
function mapChildren(oldChildren, newLocal, mapping, node, offset, oldOffset, options) {
    var children = oldChildren.slice();
    // Mark the children that are directly touched by changes, and
    // move those that are after the changes.
    var loop = function ( i, baseOffset$1 ) {
        var moved = 0;
        mapping.maps[i].forEach(function (oldStart, oldEnd, newStart, newEnd) {
            var dSize = (newEnd - newStart) - (oldEnd - oldStart);
            for (var i = 0; i < children.length; i += 3) {
                var end = children[i + 1];
                if (end < 0 || oldStart > end + baseOffset$1 - moved)
                    { continue; }
                var start = children[i] + baseOffset$1 - moved;
                if (oldEnd >= start) {
                    children[i + 1] = oldStart <= start ? -2 : -1;
                }
                else if (oldStart >= baseOffset$1 && dSize) {
                    children[i] += dSize;
                    children[i + 1] += dSize;
                }
            }
            moved += dSize;
        });
        baseOffset$1 = mapping.maps[i].map(baseOffset$1, -1);

        baseOffset = baseOffset$1;
    };

    for (var i = 0, baseOffset = oldOffset; i < mapping.maps.length; i++) loop( i, baseOffset );
    // Find the child nodes that still correspond to a single node,
    // recursively call mapInner on them and update their positions.
    var mustRebuild = false;
    for (var i$1 = 0; i$1 < children.length; i$1 += 3)
        { if (children[i$1 + 1] < 0) { // Touched nodes
            if (children[i$1 + 1] == -2) {
                mustRebuild = true;
                children[i$1 + 1] = -1;
                continue;
            }
            var from = mapping.map(oldChildren[i$1] + oldOffset), fromLocal = from - offset;
            if (fromLocal < 0 || fromLocal >= node.content.size) {
                mustRebuild = true;
                continue;
            }
            // Must read oldChildren because children was tagged with -1
            var to = mapping.map(oldChildren[i$1 + 1] + oldOffset, -1), toLocal = to - offset;
            var ref = node.content.findIndex(fromLocal);
            var index = ref.index;
            var childOffset = ref.offset;
            var childNode = node.maybeChild(index);
            if (childNode && childOffset == fromLocal && childOffset + childNode.nodeSize == toLocal) {
                var mapped = children[i$1 + 2]
                    .mapInner(mapping, childNode, from + 1, oldChildren[i$1] + oldOffset + 1, options);
                if (mapped != empty$1) {
                    children[i$1] = fromLocal;
                    children[i$1 + 1] = toLocal;
                    children[i$1 + 2] = mapped;
                }
                else {
                    children[i$1 + 1] = -2;
                    mustRebuild = true;
                }
            }
            else {
                mustRebuild = true;
            }
        } }
    // Remaining children must be collected and rebuilt into the appropriate structure
    if (mustRebuild) {
        var decorations = mapAndGatherRemainingDecorations(children, oldChildren, newLocal, mapping, offset, oldOffset, options);
        var built = buildTree$1(decorations, node, 0, options);
        newLocal = built.local;
        for (var i$2 = 0; i$2 < children.length; i$2 += 3)
            { if (children[i$2 + 1] < 0) {
                children.splice(i$2, 3);
                i$2 -= 3;
            } }
        for (var i$3 = 0, j = 0; i$3 < built.children.length; i$3 += 3) {
            var from$1 = built.children[i$3];
            while (j < children.length && children[j] < from$1)
                { j += 3; }
            children.splice(j, 0, built.children[i$3], built.children[i$3 + 1], built.children[i$3 + 2]);
        }
    }
    return new DecorationSet(newLocal.sort(byPos), children);
}
function moveSpans(spans, offset) {
    if (!offset || !spans.length)
        { return spans; }
    var result = [];
    for (var i = 0; i < spans.length; i++) {
        var span = spans[i];
        result.push(new Decoration$1(span.from + offset, span.to + offset, span.type));
    }
    return result;
}
function mapAndGatherRemainingDecorations(children, oldChildren, decorations, mapping, offset, oldOffset, options) {
    // Gather all decorations from the remaining marked children
    function gather(set, oldOffset) {
        for (var i = 0; i < set.local.length; i++) {
            var mapped = set.local[i].map(mapping, offset, oldOffset);
            if (mapped)
                { decorations.push(mapped); }
            else if (options.onRemove)
                { options.onRemove(set.local[i].spec); }
        }
        for (var i$1 = 0; i$1 < set.children.length; i$1 += 3)
            { gather(set.children[i$1 + 2], set.children[i$1] + oldOffset + 1); }
    }
    for (var i = 0; i < children.length; i += 3)
        { if (children[i + 1] == -1)
            { gather(children[i + 2], oldChildren[i] + oldOffset + 1); } }
    return decorations;
}
function takeSpansForNode(spans, node, offset) {
    if (node.isLeaf)
        { return null; }
    var end = offset + node.nodeSize, found = null;
    for (var i = 0, span = (void 0); i < spans.length; i++) {
        if ((span = spans[i]) && span.from > offset && span.to < end) {
            (found || (found = [])).push(span);
            spans[i] = null;
        }
    }
    return found;
}
function withoutNulls(array) {
    var result = [];
    for (var i = 0; i < array.length; i++)
        { if (array[i] != null)
            { result.push(array[i]); } }
    return result;
}
// Build up a tree that corresponds to a set of decorations. `offset`
// is a base offset that should be subtracted from the `from` and `to`
// positions in the spans (so that we don't have to allocate new spans
// for recursive calls).
function buildTree$1(spans, node, offset, options) {
    var children = [], hasNulls = false;
    node.forEach(function (childNode, localStart) {
        var found = takeSpansForNode(spans, childNode, localStart + offset);
        if (found) {
            hasNulls = true;
            var subtree = buildTree$1(found, childNode, offset + localStart + 1, options);
            if (subtree != empty$1)
                { children.push(localStart, localStart + childNode.nodeSize, subtree); }
        }
    });
    var locals = moveSpans(hasNulls ? withoutNulls(spans) : spans, -offset).sort(byPos);
    for (var i = 0; i < locals.length; i++)
        { if (!locals[i].type.valid(node, locals[i])) {
            if (options.onRemove)
                { options.onRemove(locals[i].spec); }
            locals.splice(i--, 1);
        } }
    return locals.length || children.length ? new DecorationSet(locals, children) : empty$1;
}
// Used to sort decorations so that ones with a low start position
// come first, and within a set with the same start position, those
// with an smaller end position come first.
function byPos(a, b) {
    return a.from - b.from || a.to - b.to;
}
// Scan a sorted array of decorations for partially overlapping spans,
// and split those so that only fully overlapping spans are left (to
// make subsequent rendering easier). Will return the input array if
// no partially overlapping spans are found (the common case).
function removeOverlap(spans) {
    var working = spans;
    for (var i = 0; i < working.length - 1; i++) {
        var span = working[i];
        if (span.from != span.to)
            { for (var j = i + 1; j < working.length; j++) {
                var next = working[j];
                if (next.from == span.from) {
                    if (next.to != span.to) {
                        if (working == spans)
                            { working = spans.slice(); }
                        // Followed by a partially overlapping larger span. Split that
                        // span.
                        working[j] = next.copy(next.from, span.to);
                        insertAhead(working, j + 1, next.copy(span.to, next.to));
                    }
                    continue;
                }
                else {
                    if (next.from < span.to) {
                        if (working == spans)
                            { working = spans.slice(); }
                        // The end of this one overlaps with a subsequent span. Split
                        // this one.
                        working[i] = span.copy(span.from, next.from);
                        insertAhead(working, j, span.copy(next.from, span.to));
                    }
                    break;
                }
            } }
    }
    return working;
}
function insertAhead(array, i, deco) {
    while (i < array.length && byPos(deco, array[i]) > 0)
        { i++; }
    array.splice(i, 0, deco);
}
// Get the decorations associated with the current props of a view.
function viewDecorations(view) {
    var found = [];
    view.someProp("decorations", function (f) {
        var result = f(view.state);
        if (result && result != empty$1)
            { found.push(result); }
    });
    if (view.cursorWrapper)
        { found.push(DecorationSet.create(view.state.doc, [view.cursorWrapper.deco])); }
    return DecorationGroup.from(found);
}

var observeOptions$1 = {
    childList: true,
    characterData: true,
    characterDataOldValue: true,
    attributes: true,
    attributeOldValue: true,
    subtree: true
};
// IE11 has very broken mutation observers, so we also listen to DOMCharacterDataModified
var useCharData$1 = ie$2 && ie_version <= 11;
var SelectionState = function SelectionState() {
    this.anchorNode = null;
    this.anchorOffset = 0;
    this.focusNode = null;
    this.focusOffset = 0;
};
SelectionState.prototype.set = function set (sel) {
    this.anchorNode = sel.anchorNode;
    this.anchorOffset = sel.anchorOffset;
    this.focusNode = sel.focusNode;
    this.focusOffset = sel.focusOffset;
};
SelectionState.prototype.clear = function clear () {
    this.anchorNode = this.focusNode = null;
};
SelectionState.prototype.eq = function eq (sel) {
    return sel.anchorNode == this.anchorNode && sel.anchorOffset == this.anchorOffset &&
        sel.focusNode == this.focusNode && sel.focusOffset == this.focusOffset;
};
var DOMObserver$1 = function DOMObserver(view, handleDOMChange) {
    var this$1$1 = this;

    this.view = view;
    this.handleDOMChange = handleDOMChange;
    this.queue = [];
    this.flushingSoon = -1;
    this.observer = null;
    this.currentSelection = new SelectionState;
    this.onCharData = null;
    this.suppressingSelectionUpdates = false;
    this.lastChangedTextNode = null;
    this.observer = window.MutationObserver &&
        new window.MutationObserver(function (mutations) {
            for (var i = 0; i < mutations.length; i++)
                { this$1$1.queue.push(mutations[i]); }
            // IE11 will sometimes (on backspacing out a single character
            // text node after a BR node) call the observer callback
            // before actually updating the DOM, which will cause
            // ProseMirror to miss the change (see #930)
            if (ie$2 && ie_version <= 11 && mutations.some(function (m) { return m.type == "childList" && m.removedNodes.length ||
                m.type == "characterData" && m.oldValue.length > m.target.nodeValue.length; }))
                { this$1$1.flushSoon(); }
            else
                { this$1$1.flush(); }
        });
    if (useCharData$1) {
        this.onCharData = function (e) {
            this$1$1.queue.push({ target: e.target, type: "characterData", oldValue: e.prevValue });
            this$1$1.flushSoon();
        };
    }
    this.onSelectionChange = this.onSelectionChange.bind(this);
};
DOMObserver$1.prototype.flushSoon = function flushSoon () {
        var this$1$1 = this;

    if (this.flushingSoon < 0)
        { this.flushingSoon = window.setTimeout(function () { this$1$1.flushingSoon = -1; this$1$1.flush(); }, 20); }
};
DOMObserver$1.prototype.forceFlush = function forceFlush () {
    if (this.flushingSoon > -1) {
        window.clearTimeout(this.flushingSoon);
        this.flushingSoon = -1;
        this.flush();
    }
};
DOMObserver$1.prototype.start = function start () {
    if (this.observer) {
        this.observer.takeRecords();
        this.observer.observe(this.view.dom, observeOptions$1);
    }
    if (this.onCharData)
        { this.view.dom.addEventListener("DOMCharacterDataModified", this.onCharData); }
    this.connectSelection();
};
DOMObserver$1.prototype.stop = function stop () {
        var this$1$1 = this;

    if (this.observer) {
        var take = this.observer.takeRecords();
        if (take.length) {
            for (var i = 0; i < take.length; i++)
                { this.queue.push(take[i]); }
            window.setTimeout(function () { return this$1$1.flush(); }, 20);
        }
        this.observer.disconnect();
    }
    if (this.onCharData)
        { this.view.dom.removeEventListener("DOMCharacterDataModified", this.onCharData); }
    this.disconnectSelection();
};
DOMObserver$1.prototype.connectSelection = function connectSelection () {
    this.view.dom.ownerDocument.addEventListener("selectionchange", this.onSelectionChange);
};
DOMObserver$1.prototype.disconnectSelection = function disconnectSelection () {
    this.view.dom.ownerDocument.removeEventListener("selectionchange", this.onSelectionChange);
};
DOMObserver$1.prototype.suppressSelectionUpdates = function suppressSelectionUpdates () {
        var this$1$1 = this;

    this.suppressingSelectionUpdates = true;
    setTimeout(function () { return this$1$1.suppressingSelectionUpdates = false; }, 50);
};
DOMObserver$1.prototype.onSelectionChange = function onSelectionChange () {
    if (!hasFocusAndSelection(this.view))
        { return; }
    if (this.suppressingSelectionUpdates)
        { return selectionToDOM(this.view); }
    // Deletions on IE11 fire their events in the wrong order, giving
    // us a selection change event before the DOM changes are
    // reported.
    if (ie$2 && ie_version <= 11 && !this.view.state.selection.empty) {
        var sel = this.view.domSelectionRange();
        // Selection.isCollapsed isn't reliable on IE
        if (sel.focusNode && isEquivalentPosition$1(sel.focusNode, sel.focusOffset, sel.anchorNode, sel.anchorOffset))
            { return this.flushSoon(); }
    }
    this.flush();
};
DOMObserver$1.prototype.setCurSelection = function setCurSelection () {
    this.currentSelection.set(this.view.domSelectionRange());
};
DOMObserver$1.prototype.ignoreSelectionChange = function ignoreSelectionChange (sel) {
    if (!sel.focusNode)
        { return true; }
    var ancestors = new Set, container;
    for (var scan = sel.focusNode; scan; scan = parentNode(scan))
        { ancestors.add(scan); }
    for (var scan$1 = sel.anchorNode; scan$1; scan$1 = parentNode(scan$1))
        { if (ancestors.has(scan$1)) {
            container = scan$1;
            break;
        } }
    var desc = container && this.view.docView.nearestDesc(container);
    if (desc && desc.ignoreMutation({
        type: "selection",
        target: container.nodeType == 3 ? container.parentNode : container
    })) {
        this.setCurSelection();
        return true;
    }
};
DOMObserver$1.prototype.pendingRecords = function pendingRecords () {
    if (this.observer)
        { for (var mut of this.observer.takeRecords())
            this.queue.push(mut); }
    return this.queue;
};
DOMObserver$1.prototype.selectionChanged = function selectionChanged (sel) {
    return !this.suppressingSelectionUpdates && !this.currentSelection.eq(sel) && hasFocusAndSelection(this.view) && !this.ignoreSelectionChange(sel);
};
DOMObserver$1.prototype.flush = function flush () {
    var ref = this;
        var view = ref.view;
    if (!view.docView || this.flushingSoon > -1)
        { return; }
    var mutations = this.pendingRecords();
    if (mutations.length)
        { this.queue = []; }
    var sel = view.domSelectionRange(), newSel = this.selectionChanged(sel);
    var from = -1, to = -1, typeOver = false, added = [];
    if (view.editable) {
        for (var i = 0; i < mutations.length; i++) {
            var result = this.registerMutation(mutations[i], added);
            if (result) {
                from = from < 0 ? result.from : Math.min(result.from, from);
                to = to < 0 ? result.to : Math.max(result.to, to);
                if (result.typeOver)
                    { typeOver = true; }
            }
        }
    }
    if (gecko$1 && added.length) {
        var brs = added.filter(function (n) { return n.nodeName == "BR"; });
        if (brs.length == 2) {
            var a = brs[0];
                var b = brs[1];
            if (a.parentNode && a.parentNode.parentNode == b.parentNode)
                { b.remove(); }
            else
                { a.remove(); }
        }
        else {
            var ref$1 = this.currentSelection;
                var focusNode = ref$1.focusNode;
            for (var br of brs) {
                var parent = br.parentNode;
                if (parent && parent.nodeName == "LI" && (!focusNode || blockParent(view, focusNode) != parent))
                    { br.remove(); }
            }
        }
    }
    var readSel = null;
    // If it looks like the browser has reset the selection to the
    // start of the document after focus, restore the selection from
    // the state
    if (from < 0 && newSel && view.input.lastFocus > Date.now() - 200 &&
        Math.max(view.input.lastTouch, view.input.lastClick.time) < Date.now() - 300 &&
        selectionCollapsed(sel) && (readSel = selectionFromDOM(view)) &&
        readSel.eq(Selection.near(view.state.doc.resolve(0), 1))) {
        view.input.lastFocus = 0;
        selectionToDOM(view);
        this.currentSelection.set(sel);
        view.scrollToSelection();
    }
    else if (from > -1 || newSel) {
        if (from > -1) {
            view.docView.markDirty(from, to);
            checkCSS(view);
        }
        this.handleDOMChange(from, to, typeOver, added);
        if (view.docView && view.docView.dirty)
            { view.updateState(view.state); }
        else if (!this.currentSelection.eq(sel))
            { selectionToDOM(view); }
        this.currentSelection.set(sel);
    }
};
DOMObserver$1.prototype.registerMutation = function registerMutation (mut, added) {
    // Ignore mutations inside nodes that were already noted as inserted
    if (added.indexOf(mut.target) > -1)
        { return null; }
    var desc = this.view.docView.nearestDesc(mut.target);
    if (mut.type == "attributes" &&
        (desc == this.view.docView || mut.attributeName == "contenteditable" ||
            // Firefox sometimes fires spurious events for null/empty styles
            (mut.attributeName == "style" && !mut.oldValue && !mut.target.getAttribute("style"))))
        { return null; }
    if (!desc || desc.ignoreMutation(mut))
        { return null; }
    if (mut.type == "childList") {
        for (var i = 0; i < mut.addedNodes.length; i++) {
            var node = mut.addedNodes[i];
            added.push(node);
            if (node.nodeType == 3)
                { this.lastChangedTextNode = node; }
        }
        if (desc.contentDOM && desc.contentDOM != desc.dom && !desc.contentDOM.contains(mut.target))
            { return { from: desc.posBefore, to: desc.posAfter }; }
        var prev = mut.previousSibling, next = mut.nextSibling;
        if (ie$2 && ie_version <= 11 && mut.addedNodes.length) {
            // IE11 gives us incorrect next/prev siblings for some
            // insertions, so if there are added nodes, recompute those
            for (var i$1 = 0; i$1 < mut.addedNodes.length; i$1++) {
                var ref = mut.addedNodes[i$1];
                    var previousSibling = ref.previousSibling;
                    var nextSibling = ref.nextSibling;
                if (!previousSibling || Array.prototype.indexOf.call(mut.addedNodes, previousSibling) < 0)
                    { prev = previousSibling; }
                if (!nextSibling || Array.prototype.indexOf.call(mut.addedNodes, nextSibling) < 0)
                    { next = nextSibling; }
            }
        }
        var fromOffset = prev && prev.parentNode == mut.target
            ? domIndex$1(prev) + 1 : 0;
        var from = desc.localPosFromDOM(mut.target, fromOffset, -1);
        var toOffset = next && next.parentNode == mut.target
            ? domIndex$1(next) : mut.target.childNodes.length;
        var to = desc.localPosFromDOM(mut.target, toOffset, 1);
        return { from: from, to: to };
    }
    else if (mut.type == "attributes") {
        return { from: desc.posAtStart - desc.border, to: desc.posAtEnd + desc.border };
    }
    else { // "characterData"
        this.lastChangedTextNode = mut.target;
        return {
            from: desc.posAtStart,
            to: desc.posAtEnd,
            // An event was generated for a text change that didn't change
            // any text. Mark the dom change to fall back to assuming the
            // selection was typed over with an identical value if it can't
            // find another change.
            typeOver: mut.target.nodeValue == mut.oldValue
        };
    }
};
var cssChecked = new WeakMap();
var cssCheckWarned = false;
function checkCSS(view) {
    if (cssChecked.has(view))
        { return; }
    cssChecked.set(view, null);
    if (['normal', 'nowrap', 'pre-line'].indexOf(getComputedStyle(view.dom).whiteSpace) !== -1) {
        view.requiresGeckoHackNode = gecko$1;
        if (cssCheckWarned)
            { return; }
        console["warn"]("ProseMirror expects the CSS white-space property to be set, preferably to 'pre-wrap'. It is recommended to load style/prosemirror.css from the prosemirror-view package.");
        cssCheckWarned = true;
    }
}
function rangeToSelectionRange(view, range) {
    var assign;

    var anchorNode = range.startContainer, anchorOffset = range.startOffset;
    var focusNode = range.endContainer, focusOffset = range.endOffset;
    var currentAnchor = view.domAtPos(view.state.selection.anchor);
    // 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$1(currentAnchor.node, currentAnchor.offset, focusNode, focusOffset))
        { (assign = [focusNode, focusOffset, anchorNode, anchorOffset], anchorNode = assign[0], anchorOffset = assign[1], focusNode = assign[2], focusOffset = assign[3]); }
    return { anchorNode: anchorNode, anchorOffset: anchorOffset, focusNode: focusNode, focusOffset: focusOffset };
}
// Used to work around a Safari Selection/shadow DOM bug
// Based on https://github.com/codemirror/dev/issues/414 fix
function safariShadowSelectionRange(view, selection) {
    if (selection.getComposedRanges) {
        var range = selection.getComposedRanges(view.root)[0];
        if (range)
            { return rangeToSelectionRange(view, range); }
    }
    var found;
    function read(event) {
        event.preventDefault();
        event.stopImmediatePropagation();
        found = event.getTargetRanges()[0];
    }
    // Because Safari (at least in 2018-2022) 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.
    view.dom.addEventListener("beforeinput", read, true);
    document.execCommand("indent");
    view.dom.removeEventListener("beforeinput", read, true);
    return found ? rangeToSelectionRange(view, found) : null;
}
function blockParent(view, node) {
    for (var p = node.parentNode; p && p != view.dom; p = p.parentNode) {
        var desc = view.docView.nearestDesc(p, true);
        if (desc && desc.node.isBlock)
            { return p; }
    }
    return null;
}

// Note that all referencing and parsing is done with the
// start-of-operation selection and document, since that's the one
// that the DOM represents. If any changes came in in the meantime,
// the modification is mapped over those before it is applied, in
// readDOMChange.
function parseBetween(view, from_, to_) {
    var ref = view.docView.parseRange(from_, to_);
    var parent = ref.node;
    var fromOffset = ref.fromOffset;
    var toOffset = ref.toOffset;
    var from = ref.from;
    var to = ref.to;
    var domSel = view.domSelectionRange();
    var find;
    var anchor = domSel.anchorNode;
    if (anchor && view.dom.contains(anchor.nodeType == 1 ? anchor : anchor.parentNode)) {
        find = [{ node: anchor, offset: domSel.anchorOffset }];
        if (!selectionCollapsed(domSel))
            { find.push({ node: domSel.focusNode, offset: domSel.focusOffset }); }
    }
    // Work around issue in Chrome where backspacing sometimes replaces
    // the deleted content with a random BR node (issues #799, #831)
    if (chrome$1 && view.input.lastKeyCode === 8) {
        for (var off = toOffset; off > fromOffset; off--) {
            var node = parent.childNodes[off - 1], desc = node.pmViewDesc;
            if (node.nodeName == "BR" && !desc) {
                toOffset = off;
                break;
            }
            if (!desc || desc.size)
                { break; }
        }
    }
    var startDoc = view.state.doc;
    var parser = view.someProp("domParser") || DOMParser.fromSchema(view.state.schema);
    var $from = startDoc.resolve(from);
    var sel = null, doc = parser.parse(parent, {
        topNode: $from.parent,
        topMatch: $from.parent.contentMatchAt($from.index()),
        topOpen: true,
        from: fromOffset,
        to: toOffset,
        preserveWhitespace: $from.parent.type.whitespace == "pre" ? "full" : true,
        findPositions: find,
        ruleFromNode: ruleFromNode,
        context: $from
    });
    if (find && find[0].pos != null) {
        var anchor$1 = find[0].pos, head = find[1] && find[1].pos;
        if (head == null)
            { head = anchor$1; }
        sel = { anchor: anchor$1 + from, head: head + from };
    }
    return { doc: doc, sel: sel, from: from, to: to };
}
function ruleFromNode(dom) {
    var desc = dom.pmViewDesc;
    if (desc) {
        return desc.parseRule();
    }
    else if (dom.nodeName == "BR" && dom.parentNode) {
        // Safari replaces the list item or table cell with a BR
        // directly in the list node (?!) if you delete the last
        // character in a list item or table cell (#708, #862)
        if (safari$1 && /^(ul|ol)$/i.test(dom.parentNode.nodeName)) {
            var skip = document.createElement("div");
            skip.appendChild(document.createElement("li"));
            return { skip: skip };
        }
        else if (dom.parentNode.lastChild == dom || safari$1 && /^(tr|table)$/i.test(dom.parentNode.nodeName)) {
            return { ignore: true };
        }
    }
    else if (dom.nodeName == "IMG" && dom.getAttribute("mark-placeholder")) {
        return { ignore: true };
    }
    return null;
}
var isInline = /^(a|abbr|acronym|b|bd[io]|big|br|button|cite|code|data(list)?|del|dfn|em|i|ins|kbd|label|map|mark|meter|output|q|ruby|s|samp|small|span|strong|su[bp]|time|u|tt|var)$/i;
function readDOMChange(view, from, to, typeOver, addedNodes) {
    var compositionID = view.input.compositionPendingChanges || (view.composing ? view.input.compositionID : 0);
    view.input.compositionPendingChanges = 0;
    if (from < 0) {
        var origin = view.input.lastSelectionTime > Date.now() - 50 ? view.input.lastSelectionOrigin : null;
        var newSel = selectionFromDOM(view, origin);
        if (newSel && !view.state.selection.eq(newSel)) {
            if (chrome$1 && android$1 &&
                view.input.lastKeyCode === 13 && Date.now() - 100 < view.input.lastKeyCodeTime &&
                view.someProp("handleKeyDown", function (f) { return f(view, keyEvent(13, "Enter")); }))
                { return; }
            var tr$1 = view.state.tr.setSelection(newSel);
            if (origin == "pointer")
                { tr$1.setMeta("pointer", true); }
            else if (origin == "key")
                { tr$1.scrollIntoView(); }
            if (compositionID)
                { tr$1.setMeta("composition", compositionID); }
            view.dispatch(tr$1);
        }
        return;
    }
    var $before = view.state.doc.resolve(from);
    var shared = $before.sharedDepth(to);
    from = $before.before(shared + 1);
    to = view.state.doc.resolve(to).after(shared + 1);
    var sel = view.state.selection;
    var parse = parseBetween(view, from, to);
    var doc = view.state.doc, compare = doc.slice(parse.from, parse.to);
    var preferredPos, preferredSide;
    // Prefer anchoring to end when Backspace is pressed
    if (view.input.lastKeyCode === 8 && Date.now() - 100 < view.input.lastKeyCodeTime) {
        preferredPos = view.state.selection.to;
        preferredSide = "end";
    }
    else {
        preferredPos = view.state.selection.from;
        preferredSide = "start";
    }
    view.input.lastKeyCode = null;
    var change = findDiff$1(compare.content, parse.doc.content, parse.from, preferredPos, preferredSide);
    if (change)
        { view.input.domChangeCount++; }
    if ((ios$1 && view.input.lastIOSEnter > Date.now() - 225 || android$1) &&
        addedNodes.some(function (n) { return n.nodeType == 1 && !isInline.test(n.nodeName); }) &&
        (!change || change.endA >= change.endB) &&
        view.someProp("handleKeyDown", function (f) { return f(view, keyEvent(13, "Enter")); })) {
        view.input.lastIOSEnter = 0;
        return;
    }
    if (!change) {
        if (typeOver && sel instanceof TextSelection && !sel.empty && sel.$head.sameParent(sel.$anchor) &&
            !view.composing && !(parse.sel && parse.sel.anchor != parse.sel.head)) {
            change = { start: sel.from, endA: sel.to, endB: sel.to };
        }
        else {
            if (parse.sel) {
                var sel$1 = resolveSelection(view, view.state.doc, parse.sel);
                if (sel$1 && !sel$1.eq(view.state.selection)) {
                    var tr$2 = view.state.tr.setSelection(sel$1);
                    if (compositionID)
                        { tr$2.setMeta("composition", compositionID); }
                    view.dispatch(tr$2);
                }
            }
            return;
        }
    }
    // Handle the case where overwriting a selection by typing matches
    // the start or end of the selected content, creating a change
    // that's smaller than what was actually overwritten.
    if (view.state.selection.from < view.state.selection.to &&
        change.start == change.endB &&
        view.state.selection instanceof TextSelection) {
        if (change.start > view.state.selection.from && change.start <= view.state.selection.from + 2 &&
            view.state.selection.from >= parse.from) {
            change.start = view.state.selection.from;
        }
        else if (change.endA < view.state.selection.to && change.endA >= view.state.selection.to - 2 &&
            view.state.selection.to <= parse.to) {
            change.endB += (view.state.selection.to - change.endA);
            change.endA = view.state.selection.to;
        }
    }
    // IE11 will insert a non-breaking space _ahead_ of the space after
    // the cursor space when adding a space before another space. When
    // that happened, adjust the change to cover the space instead.
    if (ie$2 && ie_version <= 11 && change.endB == change.start + 1 &&
        change.endA == change.start && change.start > parse.from &&
        parse.doc.textBetween(change.start - parse.from - 1, change.start - parse.from + 1) == " \u00a0") {
        change.start--;
        change.endA--;
        change.endB--;
    }
    var $from = parse.doc.resolveNoCache(change.start - parse.from);
    var $to = parse.doc.resolveNoCache(change.endB - parse.from);
    var $fromA = doc.resolve(change.start);
    var inlineChange = $from.sameParent($to) && $from.parent.inlineContent && $fromA.end() >= change.endA;
    var nextSel;
    // If this looks like the effect of pressing Enter (or was recorded
    // as being an iOS enter press), just dispatch an Enter key instead.
    if (((ios$1 && view.input.lastIOSEnter > Date.now() - 225 &&
        (!inlineChange || addedNodes.some(function (n) { return n.nodeName == "DIV" || n.nodeName == "P"; }))) ||
        (!inlineChange && $from.pos < parse.doc.content.size && !$from.sameParent($to) &&
            (nextSel = Selection.findFrom(parse.doc.resolve($from.pos + 1), 1, true)) &&
            nextSel.head == $to.pos)) &&
        view.someProp("handleKeyDown", function (f) { return f(view, keyEvent(13, "Enter")); })) {
        view.input.lastIOSEnter = 0;
        return;
    }
    // Same for backspace
    if (view.state.selection.anchor > change.start &&
        looksLikeBackspace(doc, change.start, change.endA, $from, $to) &&
        view.someProp("handleKeyDown", function (f) { return f(view, keyEvent(8, "Backspace")); })) {
        if (android$1 && chrome$1)
            { view.domObserver.suppressSelectionUpdates(); } // #820
        return;
    }
    // Chrome Android will occasionally, during composition, delete the
    // entire composition and then immediately insert it again. This is
    // used to detect that situation.
    if (chrome$1 && android$1 && change.endB == change.start)
        { view.input.lastAndroidDelete = Date.now(); }
    // This tries to detect Android virtual keyboard
    // enter-and-pick-suggestion action. That sometimes (see issue
    // #1059) first fires a DOM mutation, before moving the selection to
    // the newly created block. And then, because ProseMirror cleans up
    // the DOM selection, it gives up moving the selection entirely,
    // leaving the cursor in the wrong place. When that happens, we drop
    // the new paragraph from the initial change, and fire a simulated
    // enter key afterwards.
    if (android$1 && !inlineChange && $from.start() != $to.start() && $to.parentOffset == 0 && $from.depth == $to.depth &&
        parse.sel && parse.sel.anchor == parse.sel.head && parse.sel.head == change.endA) {
        change.endB -= 2;
        $to = parse.doc.resolveNoCache(change.endB - parse.from);
        setTimeout(function () {
            view.someProp("handleKeyDown", function (f) { return f(view, keyEvent(13, "Enter")); });
        }, 20);
    }
    var chFrom = change.start, chTo = change.endA;
    var tr, storedMarks, markChange;
    if (inlineChange) {
        if ($from.pos == $to.pos) { // Deletion
            // IE11 sometimes weirdly moves the DOM selection around after
            // backspacing out the first element in a textblock
            if (ie$2 && ie_version <= 11 && $from.parentOffset == 0) {
                view.domObserver.suppressSelectionUpdates();
                setTimeout(function () { return selectionToDOM(view); }, 20);
            }
            tr = view.state.tr.delete(chFrom, chTo);
            storedMarks = doc.resolve(change.start).marksAcross(doc.resolve(change.endA));
        }
        else if ( // Adding or removing a mark
        change.endA == change.endB &&
            (markChange = isMarkChange($from.parent.content.cut($from.parentOffset, $to.parentOffset), $fromA.parent.content.cut($fromA.parentOffset, change.endA - $fromA.start())))) {
            tr = view.state.tr;
            if (markChange.type == "add")
                { tr.addMark(chFrom, chTo, markChange.mark); }
            else
                { tr.removeMark(chFrom, chTo, markChange.mark); }
        }
        else if ($from.parent.child($from.index()).isText && $from.index() == $to.index() - ($to.textOffset ? 0 : 1)) {
            // Both positions in the same text node -- simply insert text
            var text = $from.parent.textBetween($from.parentOffset, $to.parentOffset);
            if (view.someProp("handleTextInput", function (f) { return f(view, chFrom, chTo, text); }))
                { return; }
            tr = view.state.tr.insertText(text, chFrom, chTo);
        }
    }
    if (!tr)
        { tr = view.state.tr.replace(chFrom, chTo, parse.doc.slice(change.start - parse.from, change.endB - parse.from)); }
    if (parse.sel) {
        var sel$2 = resolveSelection(view, tr.doc, parse.sel);
        // Chrome Android will sometimes, during composition, report the
        // selection in the wrong place. If it looks like that is
        // happening, don't update the selection.
        // Edge just doesn't move the cursor forward when you start typing
        // in an empty block or between br nodes.
        if (sel$2 && !(chrome$1 && android$1 && view.composing && sel$2.empty &&
            (change.start != change.endB || view.input.lastAndroidDelete < Date.now() - 100) &&
            (sel$2.head == chFrom || sel$2.head == tr.mapping.map(chTo) - 1) ||
            ie$2 && sel$2.empty && sel$2.head == chFrom))
            { tr.setSelection(sel$2); }
    }
    if (storedMarks)
        { tr.ensureMarks(storedMarks); }
    if (compositionID)
        { tr.setMeta("composition", compositionID); }
    view.dispatch(tr.scrollIntoView());
}
function resolveSelection(view, doc, parsedSel) {
    if (Math.max(parsedSel.anchor, parsedSel.head) > doc.content.size)
        { return null; }
    return selectionBetween(view, doc.resolve(parsedSel.anchor), doc.resolve(parsedSel.head));
}
// Given two same-length, non-empty fragments of inline content,
// determine whether the first could be created from the second by
// removing or adding a single mark type.
function isMarkChange(cur, prev) {
    var curMarks = cur.firstChild.marks, prevMarks = prev.firstChild.marks;
    var added = curMarks, removed = prevMarks, type, mark, update;
    for (var i = 0; i < prevMarks.length; i++)
        { added = prevMarks[i].removeFromSet(added); }
    for (var i$1 = 0; i$1 < curMarks.length; i$1++)
        { removed = curMarks[i$1].removeFromSet(removed); }
    if (added.length == 1 && removed.length == 0) {
        mark = added[0];
        type = "add";
        update = function (node) { return node.mark(mark.addToSet(node.marks)); };
    }
    else if (added.length == 0 && removed.length == 1) {
        mark = removed[0];
        type = "remove";
        update = function (node) { return node.mark(mark.removeFromSet(node.marks)); };
    }
    else {
        return null;
    }
    var updated = [];
    for (var i$2 = 0; i$2 < prev.childCount; i$2++)
        { updated.push(update(prev.child(i$2))); }
    if (Fragment.from(updated).eq(cur))
        { return { mark: mark, type: type }; }
}
function looksLikeBackspace(old, start, end, $newStart, $newEnd) {
    if ( // The content must have shrunk
    end - start <= $newEnd.pos - $newStart.pos ||
        // newEnd must point directly at or after the end of the block that newStart points into
        skipClosingAndOpening($newStart, true, false) < $newEnd.pos)
        { return false; }
    var $start = old.resolve(start);
    // Handle the case where, rather than joining blocks, the change just removed an entire block
    if (!$newStart.parent.isTextblock) {
        var after = $start.nodeAfter;
        return after != null && end == start + after.nodeSize;
    }
    // Start must be at the end of a block
    if ($start.parentOffset < $start.parent.content.size || !$start.parent.isTextblock)
        { return false; }
    var $next = old.resolve(skipClosingAndOpening($start, true, true));
    // The next textblock must start before end and end near it
    if (!$next.parent.isTextblock || $next.pos > end ||
        skipClosingAndOpening($next, true, false) < end)
        { return false; }
    // The fragments after the join point must match
    return $newStart.parent.content.cut($newStart.parentOffset).eq($next.parent.content);
}
function skipClosingAndOpening($pos, fromEnd, mayOpen) {
    var depth = $pos.depth, end = fromEnd ? $pos.end() : $pos.pos;
    while (depth > 0 && (fromEnd || $pos.indexAfter(depth) == $pos.node(depth).childCount)) {
        depth--;
        end++;
        fromEnd = false;
    }
    if (mayOpen) {
        var next = $pos.node(depth).maybeChild($pos.indexAfter(depth));
        while (next && !next.isLeaf) {
            next = next.firstChild;
            end++;
        }
    }
    return end;
}
function findDiff$1(a, b, pos, preferredPos, preferredSide) {
    var start = a.findDiffStart(b, pos);
    if (start == null)
        { return null; }
    var ref = a.findDiffEnd(b, pos + a.size, pos + b.size);
    var endA = ref.a;
    var endB = ref.b;
    if (preferredSide == "end") {
        var adjust = Math.max(0, start - Math.min(endA, endB));
        preferredPos -= endA + adjust - start;
    }
    if (endA < start && a.size < b.size) {
        var move = preferredPos <= start && preferredPos >= endA ? start - preferredPos : 0;
        start -= move;
        if (start && start < b.size && isSurrogatePair(b.textBetween(start - 1, start + 1)))
            { start += move ? 1 : -1; }
        endB = start + (endB - endA);
        endA = start;
    }
    else if (endB < start) {
        var move$1 = preferredPos <= start && preferredPos >= endB ? start - preferredPos : 0;
        start -= move$1;
        if (start && start < a.size && isSurrogatePair(a.textBetween(start - 1, start + 1)))
            { start += move$1 ? 1 : -1; }
        endA = start + (endA - endB);
        endB = start;
    }
    return { start: start, endA: endA, endB: endB };
}
function isSurrogatePair(str) {
    if (str.length != 2)
        { return false; }
    var a = str.charCodeAt(0), b = str.charCodeAt(1);
    return a >= 0xDC00 && a <= 0xDFFF && b >= 0xD800 && b <= 0xDBFF;
}

/**
@internal
*/
var __serializeForClipboard = serializeForClipboard;
/**
@internal
*/
var __parseFromClipboard = parseFromClipboard;
/**
@internal
*/
var __endComposition = endComposition;
/**
An editor view manages the DOM structure that represents an
editable document. Its state and behavior are determined by its
[props](https://prosemirror.net/docs/ref/#view.DirectEditorProps).
*/
var EditorView$1 = function EditorView(place, props) {
    var this$1$1 = this;

    this._root = null;
    /**
    @internal
    */
    this.focused = false;
    /**
    Kludge used to work around a Chrome bug @internal
    */
    this.trackWrites = null;
    this.mounted = false;
    /**
    @internal
    */
    this.markCursor = null;
    /**
    @internal
    */
    this.cursorWrapper = null;
    /**
    @internal
    */
    this.lastSelectedViewDesc = undefined;
    /**
    @internal
    */
    this.input = new InputState$1;
    this.prevDirectPlugins = [];
    this.pluginViews = [];
    /**
    Holds `true` when a hack node is needed in Firefox to prevent the
    [space is eaten issue](https://github.com/ProseMirror/prosemirror/issues/651)
    @internal
    */
    this.requiresGeckoHackNode = false;
    /**
    When editor content is being dragged, this object contains
    information about the dragged slice and whether it is being
    copied or moved. At any other time, it is null.
    */
    this.dragging = null;
    this._props = props;
    this.state = props.state;
    this.directPlugins = props.plugins || [];
    this.directPlugins.forEach(checkStateComponent);
    this.dispatch = this.dispatch.bind(this);
    this.dom = (place && place.mount) || document.createElement("div");
    if (place) {
        if (place.appendChild)
            { place.appendChild(this.dom); }
        else if (typeof place == "function")
            { place(this.dom); }
        else if (place.mount)
            { this.mounted = true; }
    }
    this.editable = getEditable(this);
    updateCursorWrapper(this);
    this.nodeViews = buildNodeViews(this);
    this.docView = docViewDesc(this.state.doc, computeDocDeco(this), viewDecorations(this), this.dom, this);
    this.domObserver = new DOMObserver$1(this, function (from, to, typeOver, added) { return readDOMChange(this$1$1, from, to, typeOver, added); });
    this.domObserver.start();
    initInput(this);
    this.updatePluginViews();
};

var prototypeAccessors$7$1 = { composing: { configurable: true },props: { configurable: true },root: { configurable: true },isDestroyed: { configurable: true } };
/**
Holds `true` when a
[composition](https://w3c.github.io/uievents/#events-compositionevents)
is active.
*/
prototypeAccessors$7$1.composing.get = function () { return this.input.composing; };
/**
The view's current [props](https://prosemirror.net/docs/ref/#view.EditorProps).
*/
prototypeAccessors$7$1.props.get = function () {
    if (this._props.state != this.state) {
        var prev = this._props;
        this._props = {};
        for (var name in prev)
            { this._props[name] = prev[name]; }
        this._props.state = this.state;
    }
    return this._props;
};
/**
Update the view's props. Will immediately cause an update to
the DOM.
*/
EditorView$1.prototype.update = function update (props) {
    if (props.handleDOMEvents != this._props.handleDOMEvents)
        { ensureListeners(this); }
    var prevProps = this._props;
    this._props = props;
    if (props.plugins) {
        props.plugins.forEach(checkStateComponent);
        this.directPlugins = props.plugins;
    }
    this.updateStateInner(props.state, prevProps);
};
/**
Update the view by updating existing props object with the object
given as argument. Equivalent to `view.update(Object.assign({},
view.props, props))`.
*/
EditorView$1.prototype.setProps = function setProps (props) {
    var updated = {};
    for (var name in this._props)
        { updated[name] = this._props[name]; }
    updated.state = this.state;
    for (var name$1 in props)
        { updated[name$1] = props[name$1]; }
    this.update(updated);
};
/**
Update the editor's `state` prop, without touching any of the
other props.
*/
EditorView$1.prototype.updateState = function updateState (state) {
    this.updateStateInner(state, this._props);
};
EditorView$1.prototype.updateStateInner = function updateStateInner (state, prevProps) {
    var _a;
    var prev = this.state, redraw = false, updateSel = false;
    // When stored marks are added, stop composition, so that they can
    // be displayed.
    if (state.storedMarks && this.composing) {
        clearComposition(this);
        updateSel = true;
    }
    this.state = state;
    var pluginsChanged = prev.plugins != state.plugins || this._props.plugins != prevProps.plugins;
    if (pluginsChanged || this._props.plugins != prevProps.plugins || this._props.nodeViews != prevProps.nodeViews) {
        var nodeViews = buildNodeViews(this);
        if (changedNodeViews(nodeViews, this.nodeViews)) {
            this.nodeViews = nodeViews;
            redraw = true;
        }
    }
    if (pluginsChanged || prevProps.handleDOMEvents != this._props.handleDOMEvents) {
        ensureListeners(this);
    }
    this.editable = getEditable(this);
    updateCursorWrapper(this);
    var innerDeco = viewDecorations(this), outerDeco = computeDocDeco(this);
    var scroll = prev.plugins != state.plugins && !prev.doc.eq(state.doc) ? "reset"
        : state.scrollToSelection > prev.scrollToSelection ? "to selection" : "preserve";
    var updateDoc = redraw || !this.docView.matchesNode(state.doc, outerDeco, innerDeco);
    if (updateDoc || !state.selection.eq(prev.selection))
        { updateSel = true; }
    var oldScrollPos = scroll == "preserve" && updateSel && this.dom.style.overflowAnchor == null && storeScrollPos(this);
    if (updateSel) {
        this.domObserver.stop();
        // Work around an issue in Chrome, IE, and Edge where changing
        // the DOM around an active selection puts it into a broken
        // state where the thing the user sees differs from the
        // selection reported by the Selection object (#710, #973,
        // #1011, #1013, #1035).
        var forceSelUpdate = updateDoc && (ie$2 || chrome$1) && !this.composing &&
            !prev.selection.empty && !state.selection.empty && selectionContextChanged(prev.selection, state.selection);
        if (updateDoc) {
            // If the node that the selection points into is written to,
            // Chrome sometimes starts misreporting the selection, so this
            // tracks that and forces a selection reset when our update
            // did write to the node.
            var chromeKludge = chrome$1 ? (this.trackWrites = this.domSelectionRange().focusNode) : null;
            if (this.composing)
                { this.input.compositionNode = findCompositionNode$1(this); }
            if (redraw || !this.docView.update(state.doc, outerDeco, innerDeco, this)) {
                this.docView.updateOuterDeco(outerDeco);
                this.docView.destroy();
                this.docView = docViewDesc(state.doc, outerDeco, innerDeco, this.dom, this);
            }
            if (chromeKludge && !this.trackWrites)
                { forceSelUpdate = true; }
        }
        // Work around for an issue where an update arriving right between
        // a DOM selection change and the "selectionchange" event for it
        // can cause a spurious DOM selection update, disrupting mouse
        // drag selection.
        if (forceSelUpdate ||
            !(this.input.mouseDown && this.domObserver.currentSelection.eq(this.domSelectionRange()) &&
                anchorInRightPlace(this))) {
            selectionToDOM(this, forceSelUpdate);
        }
        else {
            syncNodeSelection(this, state.selection);
            this.domObserver.setCurSelection();
        }
        this.domObserver.start();
    }
    this.updatePluginViews(prev);
    if (((_a = this.dragging) === null || _a === void 0 ? void 0 : _a.node) && !prev.doc.eq(state.doc))
        { this.updateDraggedNode(this.dragging, prev); }
    if (scroll == "reset") {
        this.dom.scrollTop = 0;
    }
    else if (scroll == "to selection") {
        this.scrollToSelection();
    }
    else if (oldScrollPos) {
        resetScrollPos(oldScrollPos);
    }
};
/**
@internal
*/
EditorView$1.prototype.scrollToSelection = function scrollToSelection () {
        var this$1$1 = this;

    var startDOM = this.domSelectionRange().focusNode;
    if (this.someProp("handleScrollToSelection", function (f) { return f(this$1$1); })) ;
    else if (this.state.selection instanceof NodeSelection) {
        var target = this.docView.domAfterPos(this.state.selection.from);
        if (target.nodeType == 1)
            { scrollRectIntoView$1(this, target.getBoundingClientRect(), startDOM); }
    }
    else {
        scrollRectIntoView$1(this, this.coordsAtPos(this.state.selection.head, 1), startDOM);
    }
};
EditorView$1.prototype.destroyPluginViews = function destroyPluginViews () {
    var view;
    while (view = this.pluginViews.pop())
        { if (view.destroy)
            { view.destroy(); } }
};
EditorView$1.prototype.updatePluginViews = function updatePluginViews (prevState) {
    if (!prevState || prevState.plugins != this.state.plugins || this.directPlugins != this.prevDirectPlugins) {
        this.prevDirectPlugins = this.directPlugins;
        this.destroyPluginViews();
        for (var i = 0; i < this.directPlugins.length; i++) {
            var plugin = this.directPlugins[i];
            if (plugin.spec.view)
                { this.pluginViews.push(plugin.spec.view(this)); }
        }
        for (var i$1 = 0; i$1 < this.state.plugins.length; i$1++) {
            var plugin$1 = this.state.plugins[i$1];
            if (plugin$1.spec.view)
                { this.pluginViews.push(plugin$1.spec.view(this)); }
        }
    }
    else {
        for (var i$2 = 0; i$2 < this.pluginViews.length; i$2++) {
            var pluginView = this.pluginViews[i$2];
            if (pluginView.update)
                { pluginView.update(this, prevState); }
        }
    }
};
EditorView$1.prototype.updateDraggedNode = function updateDraggedNode (dragging, prev) {
    var sel = dragging.node, found = -1;
    if (this.state.doc.nodeAt(sel.from) == sel.node) {
        found = sel.from;
    }
    else {
        var movedPos = sel.from + (this.state.doc.content.size - prev.doc.content.size);
        var moved = movedPos > 0 && this.state.doc.nodeAt(movedPos);
        if (moved == sel.node)
            { found = movedPos; }
    }
    this.dragging = new Dragging(dragging.slice, dragging.move, found < 0 ? undefined : NodeSelection.create(this.state.doc, found));
};
EditorView$1.prototype.someProp = function someProp (propName, f) {
    var prop = this._props && this._props[propName], value;
    if (prop != null && (value = f ? f(prop) : prop))
        { return value; }
    for (var i = 0; i < this.directPlugins.length; i++) {
        var prop$1 = this.directPlugins[i].props[propName];
        if (prop$1 != null && (value = f ? f(prop$1) : prop$1))
            { return value; }
    }
    var plugins = this.state.plugins;
    if (plugins)
        { for (var i$1 = 0; i$1 < plugins.length; i$1++) {
            var prop$2 = plugins[i$1].props[propName];
            if (prop$2 != null && (value = f ? f(prop$2) : prop$2))
                { return value; }
        } }
};
/**
Query whether the view has focus.
*/
EditorView$1.prototype.hasFocus = function hasFocus () {
    // Work around IE not handling focus correctly if resize handles are shown.
    // If the cursor is inside an element with resize handles, activeElement
    // will be that element instead of this.dom.
    if (ie$2) {
        // If activeElement is within this.dom, and there are no other elements
        // setting `contenteditable` to false in between, treat it as focused.
        var node = this.root.activeElement;
        if (node == this.dom)
            { return true; }
        if (!node || !this.dom.contains(node))
            { return false; }
        while (node && this.dom != node && this.dom.contains(node)) {
            if (node.contentEditable == 'false')
                { return false; }
            node = node.parentElement;
        }
        return true;
    }
    return this.root.activeElement == this.dom;
};
/**
Focus the editor.
*/
EditorView$1.prototype.focus = function focus () {
    this.domObserver.stop();
    if (this.editable)
        { focusPreventScroll$1(this.dom); }
    selectionToDOM(this);
    this.domObserver.start();
};
/**
Get the document root in which the editor exists. This will
usually be the top-level `document`, but might be a [shadow
DOM](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Shadow_DOM)
root if the editor is inside one.
*/
prototypeAccessors$7$1.root.get = function () {
        var this$1$1 = this;

    var cached = this._root;
    if (cached == null)
        { var loop = function ( search ) {
            if (search.nodeType == 9 || (search.nodeType == 11 && search.host)) {
                if (!search.getSelection)
                    { Object.getPrototypeOf(search).getSelection = function () { return search.ownerDocument.getSelection(); }; }
                return { v: this$1$1._root = search };
            }
        };

                for (var search = this$1$1.dom.parentNode; search; search = search.parentNode) {
                    var returned = loop( search );

                    if ( returned ) return returned.v;
                } }
    return cached || document;
};
/**
When an existing editor view is moved to a new document or
shadow tree, call this to make it recompute its root.
*/
EditorView$1.prototype.updateRoot = function updateRoot () {
    this._root = null;
};
/**
Given a pair of viewport coordinates, return the document
position that corresponds to them. May return null if the given
coordinates aren't inside of the editor. When an object is
returned, its `pos` property is the position nearest to the
coordinates, and its `inside` property holds the position of the
inner node that the position falls inside of, or -1 if it is at
the top level, not in any node.
*/
EditorView$1.prototype.posAtCoords = function posAtCoords$1$1 (coords) {
    return posAtCoords$1(this, coords);
};
/**
Returns the viewport rectangle at a given document position.
`left` and `right` will be the same number, as this returns a
flat cursor-ish rectangle. If the position is between two things
that aren't directly adjacent, `side` determines which element
is used. When < 0, the element before the position is used,
otherwise the element after.
*/
EditorView$1.prototype.coordsAtPos = function coordsAtPos$1 (pos, side) {
        if ( side === void 0 ) side = 1;

    return coordsAtPos(this, pos, side);
};
/**
Find the DOM position that corresponds to the given document
position. When `side` is negative, find the position as close as
possible to the content before the position. When positive,
prefer positions close to the content after the position. When
zero, prefer as shallow a position as possible.
    
Note that you should **not** mutate the editor's internal DOM,
only inspect it (and even that is usually not necessary).
*/
EditorView$1.prototype.domAtPos = function domAtPos (pos, side) {
        if ( side === void 0 ) side = 0;

    return this.docView.domFromPos(pos, side);
};
/**
Find the DOM node that represents the document node after the
given position. May return `null` when the position doesn't point
in front of a node or if the node is inside an opaque node view.
    
This is intended to be able to call things like
`getBoundingClientRect` on that DOM node. Do **not** mutate the
editor DOM directly, or add styling this way, since that will be
immediately overriden by the editor as it redraws the node.
*/
EditorView$1.prototype.nodeDOM = function nodeDOM (pos) {
    var desc = this.docView.descAt(pos);
    return desc ? desc.nodeDOM : null;
};
/**
Find the document position that corresponds to a given DOM
position. (Whenever possible, it is preferable to inspect the
document structure directly, rather than poking around in the
DOM, but sometimes—for example when interpreting an event
target—you don't have a choice.)
    
The `bias` parameter can be used to influence which side of a DOM
node to use when the position is inside a leaf node.
*/
EditorView$1.prototype.posAtDOM = function posAtDOM (node, offset, bias) {
        if ( bias === void 0 ) bias = -1;

    var pos = this.docView.posFromDOM(node, offset, bias);
    if (pos == null)
        { throw new RangeError("DOM position not inside the editor"); }
    return pos;
};
/**
Find out whether the selection is at the end of a textblock when
moving in a given direction. When, for example, given `"left"`,
it will return true if moving left from the current cursor
position would leave that position's parent textblock. Will apply
to the view's current state by default, but it is possible to
pass a different state.
*/
EditorView$1.prototype.endOfTextblock = function endOfTextblock$1 (dir, state) {
    return endOfTextblock(this, state || this.state, dir);
};
/**
Run the editor's paste logic with the given HTML string. The
`event`, if given, will be passed to the
[`handlePaste`](https://prosemirror.net/docs/ref/#view.EditorProps.handlePaste) hook.
*/
EditorView$1.prototype.pasteHTML = function pasteHTML (html, event) {
    return doPaste$1(this, "", html, false, event || new ClipboardEvent("paste"));
};
/**
Run the editor's paste logic with the given plain-text input.
*/
EditorView$1.prototype.pasteText = function pasteText (text, event) {
    return doPaste$1(this, text, null, true, event || new ClipboardEvent("paste"));
};
/**
Removes the editor from the DOM and destroys all [node
views](https://prosemirror.net/docs/ref/#view.NodeView).
*/
EditorView$1.prototype.destroy = function destroy () {
    if (!this.docView)
        { return; }
    destroyInput(this);
    this.destroyPluginViews();
    if (this.mounted) {
        this.docView.update(this.state.doc, [], viewDecorations(this), this);
        this.dom.textContent = "";
    }
    else if (this.dom.parentNode) {
        this.dom.parentNode.removeChild(this.dom);
    }
    this.docView.destroy();
    this.docView = null;
    clearReusedRange();
};
/**
This is true when the view has been
[destroyed](https://prosemirror.net/docs/ref/#view.EditorView.destroy) (and thus should not be
used anymore).
*/
prototypeAccessors$7$1.isDestroyed.get = function () {
    return this.docView == null;
};
/**
Used for testing.
*/
EditorView$1.prototype.dispatchEvent = function dispatchEvent$1 (event) {
    return dispatchEvent(this, event);
};
/**
Dispatch a transaction. Will call
[`dispatchTransaction`](https://prosemirror.net/docs/ref/#view.DirectEditorProps.dispatchTransaction)
when given, and otherwise defaults to applying the transaction to
the current state and calling
[`updateState`](https://prosemirror.net/docs/ref/#view.EditorView.updateState) with the result.
This method is bound to the view instance, so that it can be
easily passed around.
*/
EditorView$1.prototype.dispatch = function dispatch (tr) {
    var dispatchTransaction = this._props.dispatchTransaction;
    if (dispatchTransaction)
        { dispatchTransaction.call(this, tr); }
    else
        { this.updateState(this.state.apply(tr)); }
};
/**
@internal
*/
EditorView$1.prototype.domSelectionRange = function domSelectionRange () {
    var sel = this.domSelection();
    if (!sel)
        { return { focusNode: null, focusOffset: 0, anchorNode: null, anchorOffset: 0 }; }
    return safari$1 && this.root.nodeType === 11 &&
        deepActiveElement(this.dom.ownerDocument) == this.dom && safariShadowSelectionRange(this, sel) || sel;
};
/**
@internal
*/
EditorView$1.prototype.domSelection = function domSelection () {
    return this.root.getSelection();
};

Object.defineProperties( EditorView$1.prototype, prototypeAccessors$7$1 );
function computeDocDeco(view) {
    var attrs = Object.create(null);
    attrs.class = "ProseMirror";
    attrs.contenteditable = String(view.editable);
    view.someProp("attributes", function (value) {
        if (typeof value == "function")
            { value = value(view.state); }
        if (value)
            { for (var attr in value) {
                if (attr == "class")
                    { attrs.class += " " + value[attr]; }
                else if (attr == "style")
                    { attrs.style = (attrs.style ? attrs.style + ";" : "") + value[attr]; }
                else if (!attrs[attr] && attr != "contenteditable" && attr != "nodeName")
                    { attrs[attr] = String(value[attr]); }
            } }
    });
    if (!attrs.translate)
        { attrs.translate = "no"; }
    return [Decoration$1.node(0, view.state.doc.content.size, attrs)];
}
function updateCursorWrapper(view) {
    if (view.markCursor) {
        var dom = document.createElement("img");
        dom.className = "ProseMirror-separator";
        dom.setAttribute("mark-placeholder", "true");
        dom.setAttribute("alt", "");
        view.cursorWrapper = { dom: dom, deco: Decoration$1.widget(view.state.selection.from, dom, { raw: true, marks: view.markCursor }) };
    }
    else {
        view.cursorWrapper = null;
    }
}
function getEditable(view) {
    return !view.someProp("editable", function (value) { return value(view.state) === false; });
}
function selectionContextChanged(sel1, sel2) {
    var depth = Math.min(sel1.$anchor.sharedDepth(sel1.head), sel2.$anchor.sharedDepth(sel2.head));
    return sel1.$anchor.start(depth) != sel2.$anchor.start(depth);
}
function buildNodeViews(view) {
    var result = Object.create(null);
    function add(obj) {
        for (var prop in obj)
            { if (!Object.prototype.hasOwnProperty.call(result, prop))
                { result[prop] = obj[prop]; } }
    }
    view.someProp("nodeViews", add);
    view.someProp("markViews", add);
    return result;
}
function changedNodeViews(a, b) {
    var nA = 0, nB = 0;
    for (var prop in a) {
        if (a[prop] != b[prop])
            { return true; }
        nA++;
    }
    for (var _ in b)
        { nB++; }
    return nA != nB;
}
function checkStateComponent(plugin) {
    if (plugin.spec.state || plugin.spec.filterTransaction || plugin.spec.appendTransaction)
        { throw new RangeError("Plugins passed directly to the view must not have a state component"); }
}var view=/*#__PURE__*/Object.freeze({__proto__:null,Decoration:Decoration$1,DecorationSet:DecorationSet,EditorView:EditorView$1,__endComposition:__endComposition,__parseFromClipboard:__parseFromClipboard,__serializeForClipboard:__serializeForClipboard});/**
Input rules are regular expressions describing a piece of text
that, when typed, causes something to happen. This might be
changing two dashes into an emdash, wrapping a paragraph starting
with `"> "` into a blockquote, or something entirely different.
*/
var InputRule = function InputRule(
/**
@internal
*/
match, handler, options) {
    if ( options === void 0 ) options = {};

    this.match = match;
    this.match = match;
    this.handler = typeof handler == "string" ? stringHandler(handler) : handler;
    this.undoable = options.undoable !== false;
    this.inCode = options.inCode || false;
};
function stringHandler(string) {
    return function (state, match, start, end) {
        var insert = string;
        if (match[1]) {
            var offset = match[0].lastIndexOf(match[1]);
            insert += match[0].slice(offset + match[1].length);
            start += offset;
            var cutOff = start - end;
            if (cutOff > 0) {
                insert = match[0].slice(offset - cutOff, offset) + insert;
                start = end;
            }
        }
        return state.tr.insertText(insert, start, end);
    };
}
var MAX_MATCH = 500;
/**
Create an input rules plugin. When enabled, it will cause text
input that matches any of the given rules to trigger the rule's
action.
*/
function inputRules(ref) {
    var rules = ref.rules;

    var plugin = new Plugin({
        state: {
            init: function init() { return null; },
            apply: function apply(tr, prev) {
                var stored = tr.getMeta(this);
                if (stored)
                    { return stored; }
                return tr.selectionSet || tr.docChanged ? null : prev;
            }
        },
        props: {
            handleTextInput: function handleTextInput(view, from, to, text) {
                return run(view, from, to, text, rules, plugin);
            },
            handleDOMEvents: {
                compositionend: function (view) {
                    setTimeout(function () {
                        var ref = view.state.selection;
                        var $cursor = ref.$cursor;
                        if ($cursor)
                            { run(view, $cursor.pos, $cursor.pos, "", rules, plugin); }
                    });
                }
            }
        },
        isInputRules: true
    });
    return plugin;
}
function run(view, from, to, text, rules, plugin) {
    if (view.composing)
        { return false; }
    var state = view.state, $from = state.doc.resolve(from);
    var textBefore = $from.parent.textBetween(Math.max(0, $from.parentOffset - MAX_MATCH), $from.parentOffset, null, "\ufffc") + text;
    for (var i = 0; i < rules.length; i++) {
        var rule = rules[i];
        if ($from.parent.type.spec.code) {
            if (!rule.inCode)
                { continue; }
        }
        else if (rule.inCode === "only") {
            continue;
        }
        var match = rule.match.exec(textBefore);
        var tr = match && rule.handler(state, match, from - (match[0].length - text.length), to);
        if (!tr)
            { continue; }
        if (rule.undoable)
            { tr.setMeta(plugin, { transform: tr, from: from, to: to, text: text }); }
        view.dispatch(tr);
        return true;
    }
    return false;
}
/**
This is a command that will undo an input rule, if applying such a
rule was the last thing that the user did.
*/
var undoInputRule = function (state, dispatch) {
    var plugins = state.plugins;
    for (var i = 0; i < plugins.length; i++) {
        var plugin = plugins[i], undoable = (void 0);
        if (plugin.spec.isInputRules && (undoable = plugin.getState(state))) {
            if (dispatch) {
                var tr = state.tr, toUndo = undoable.transform;
                for (var j = toUndo.steps.length - 1; j >= 0; j--)
                    { tr.step(toUndo.steps[j].invert(toUndo.docs[j])); }
                if (undoable.text) {
                    var marks = tr.doc.resolve(undoable.from).marks();
                    tr.replaceWith(undoable.from, undoable.to, state.schema.text(undoable.text, marks));
                }
                else {
                    tr.delete(undoable.from, undoable.to);
                }
                dispatch(tr);
            }
            return true;
        }
    }
    return false;
};

/**
Converts double dashes to an emdash.
*/
var emDash = new InputRule(/--$/, "—");
/**
Converts three dots to an ellipsis character.
*/
var ellipsis = new InputRule(/\.\.\.$/, "…");
/**
“Smart” opening double quotes.
*/
var openDoubleQuote = new InputRule(/(?:^|[\s\{\[\(\<'"\u2018\u201C])(")$/, "“");
/**
“Smart” closing double quotes.
*/
var closeDoubleQuote = new InputRule(/"$/, "”");
/**
“Smart” opening single quotes.
*/
var openSingleQuote = new InputRule(/(?:^|[\s\{\[\(\<'"\u2018\u201C])(')$/, "‘");
/**
“Smart” closing single quotes.
*/
var closeSingleQuote = new InputRule(/'$/, "’");
/**
Smart-quote related input rules.
*/
var smartQuotes = [openDoubleQuote, closeDoubleQuote, openSingleQuote, closeSingleQuote];

/**
Build an input rule for automatically wrapping a textblock when a
given string is typed. The `regexp` argument is
directly passed through to the `InputRule` constructor. You'll
probably want the regexp to start with `^`, so that the pattern can
only occur at the start of a textblock.

`nodeType` is the type of node to wrap in. If it needs attributes,
you can either pass them directly, or pass a function that will
compute them from the regular expression match.

By default, if there's a node with the same type above the newly
wrapped node, the rule will try to [join](https://prosemirror.net/docs/ref/#transform.Transform.join) those
two nodes. You can pass a join predicate, which takes a regular
expression match and the node before the wrapped node, and can
return a boolean to indicate whether a join should happen.
*/
function wrappingInputRule(regexp, nodeType, getAttrs, joinPredicate) {
    if ( getAttrs === void 0 ) getAttrs = null;

    return new InputRule(regexp, function (state, match, start, end) {
        var attrs = getAttrs instanceof Function ? getAttrs(match) : getAttrs;
        var tr = state.tr.delete(start, end);
        var $start = tr.doc.resolve(start), range = $start.blockRange(), wrapping = range && findWrapping(range, nodeType, attrs);
        if (!wrapping)
            { return null; }
        tr.wrap(range, wrapping);
        var before = tr.doc.resolve(start - 1).nodeBefore;
        if (before && before.type == nodeType && canJoin(tr.doc, start - 1) &&
            (!joinPredicate || joinPredicate(match, before)))
            { tr.join(start - 1); }
        return tr;
    });
}
/**
Build an input rule that changes the type of a textblock when the
matched text is typed into it. You'll usually want to start your
regexp with `^` to that it is only matched at the start of a
textblock. The optional `getAttrs` parameter can be used to compute
the new node's attributes, and works the same as in the
`wrappingInputRule` function.
*/
function textblockTypeInputRule(regexp, nodeType, getAttrs) {
    if ( getAttrs === void 0 ) getAttrs = null;

    return new InputRule(regexp, function (state, match, start, end) {
        var $start = state.doc.resolve(start);
        var attrs = getAttrs instanceof Function ? getAttrs(match) : getAttrs;
        if (!$start.node(-1).canReplaceWith($start.index(-1), $start.indexAfter(-1), nodeType))
            { return null; }
        return state.tr
            .delete(start, end)
            .setBlockType(start, start, nodeType, attrs);
    });
}var inputRules$1=/*#__PURE__*/Object.freeze({__proto__:null,InputRule:InputRule,closeDoubleQuote:closeDoubleQuote,closeSingleQuote:closeSingleQuote,ellipsis:ellipsis,emDash:emDash,inputRules:inputRules,openDoubleQuote:openDoubleQuote,openSingleQuote:openSingleQuote,smartQuotes:smartQuotes,textblockTypeInputRule:textblockTypeInputRule,undoInputRule:undoInputRule,wrappingInputRule:wrappingInputRule});/**
Delete the selection, if there is one.
*/
var deleteSelection = function (state, dispatch) {
    if (state.selection.empty)
        { return false; }
    if (dispatch)
        { dispatch(state.tr.deleteSelection().scrollIntoView()); }
    return true;
};
function atBlockStart(state, view) {
    var ref = state.selection;
    var $cursor = ref.$cursor;
    if (!$cursor || (view ? !view.endOfTextblock("backward", state)
        : $cursor.parentOffset > 0))
        { return null; }
    return $cursor;
}
/**
If the selection is empty and at the start of a textblock, try to
reduce the distance between that block and the one before it—if
there's a block directly before it that can be joined, join them.
If not, try to move the selected block closer to the next one in
the document structure by lifting it out of its parent or moving it
into a parent of the previous block. Will use the view for accurate
(bidi-aware) start-of-textblock detection if given.
*/
var joinBackward = function (state, dispatch, view) {
    var $cursor = atBlockStart(state, view);
    if (!$cursor)
        { return false; }
    var $cut = findCutBefore($cursor);
    // If there is no node before this, try to lift
    if (!$cut) {
        var range = $cursor.blockRange(), target = range && liftTarget(range);
        if (target == null)
            { return false; }
        if (dispatch)
            { dispatch(state.tr.lift(range, target).scrollIntoView()); }
        return true;
    }
    var before = $cut.nodeBefore;
    // Apply the joining algorithm
    if (deleteBarrier(state, $cut, dispatch, -1))
        { return true; }
    // If the node below has no content and the node above is
    // selectable, delete the node below and select the one above.
    if ($cursor.parent.content.size == 0 &&
        (textblockAt(before, "end") || NodeSelection.isSelectable(before))) {
        for (var depth = $cursor.depth;; depth--) {
            var delStep = replaceStep(state.doc, $cursor.before(depth), $cursor.after(depth), Slice.empty);
            if (delStep && delStep.slice.size < delStep.to - delStep.from) {
                if (dispatch) {
                    var tr = state.tr.step(delStep);
                    tr.setSelection(textblockAt(before, "end")
                        ? Selection.findFrom(tr.doc.resolve(tr.mapping.map($cut.pos, -1)), -1)
                        : NodeSelection.create(tr.doc, $cut.pos - before.nodeSize));
                    dispatch(tr.scrollIntoView());
                }
                return true;
            }
            if (depth == 1 || $cursor.node(depth - 1).childCount > 1)
                { break; }
        }
    }
    // If the node before is an atom, delete it
    if (before.isAtom && $cut.depth == $cursor.depth - 1) {
        if (dispatch)
            { dispatch(state.tr.delete($cut.pos - before.nodeSize, $cut.pos).scrollIntoView()); }
        return true;
    }
    return false;
};
/**
A more limited form of [`joinBackward`]($commands.joinBackward)
that only tries to join the current textblock to the one before
it, if the cursor is at the start of a textblock.
*/
var joinTextblockBackward = function (state, dispatch, view) {
    var $cursor = atBlockStart(state, view);
    if (!$cursor)
        { return false; }
    var $cut = findCutBefore($cursor);
    return $cut ? joinTextblocksAround(state, $cut, dispatch) : false;
};
/**
A more limited form of [`joinForward`]($commands.joinForward)
that only tries to join the current textblock to the one after
it, if the cursor is at the end of a textblock.
*/
var joinTextblockForward = function (state, dispatch, view) {
    var $cursor = atBlockEnd(state, view);
    if (!$cursor)
        { return false; }
    var $cut = findCutAfter($cursor);
    return $cut ? joinTextblocksAround(state, $cut, dispatch) : false;
};
function joinTextblocksAround(state, $cut, dispatch) {
    var before = $cut.nodeBefore, beforeText = before, beforePos = $cut.pos - 1;
    for (; !beforeText.isTextblock; beforePos--) {
        if (beforeText.type.spec.isolating)
            { return false; }
        var child = beforeText.lastChild;
        if (!child)
            { return false; }
        beforeText = child;
    }
    var after = $cut.nodeAfter, afterText = after, afterPos = $cut.pos + 1;
    for (; !afterText.isTextblock; afterPos++) {
        if (afterText.type.spec.isolating)
            { return false; }
        var child$1 = afterText.firstChild;
        if (!child$1)
            { return false; }
        afterText = child$1;
    }
    var step = replaceStep(state.doc, beforePos, afterPos, Slice.empty);
    if (!step || step.from != beforePos ||
        step instanceof ReplaceStep && step.slice.size >= afterPos - beforePos)
        { return false; }
    if (dispatch) {
        var tr = state.tr.step(step);
        tr.setSelection(TextSelection.create(tr.doc, beforePos));
        dispatch(tr.scrollIntoView());
    }
    return true;
}
function textblockAt(node, side, only) {
    if ( only === void 0 ) only = false;

    for (var scan = node; scan; scan = (side == "start" ? scan.firstChild : scan.lastChild)) {
        if (scan.isTextblock)
            { return true; }
        if (only && scan.childCount != 1)
            { return false; }
    }
    return false;
}
/**
When the selection is empty and at the start of a textblock, select
the node before that textblock, if possible. This is intended to be
bound to keys like backspace, after
[`joinBackward`](https://prosemirror.net/docs/ref/#commands.joinBackward) or other deleting
commands, as a fall-back behavior when the schema doesn't allow
deletion at the selected point.
*/
var selectNodeBackward = function (state, dispatch, view) {
    var ref = state.selection;
    var $head = ref.$head;
    var empty = ref.empty;
    var $cut = $head;
    if (!empty)
        { return false; }
    if ($head.parent.isTextblock) {
        if (view ? !view.endOfTextblock("backward", state) : $head.parentOffset > 0)
            { return false; }
        $cut = findCutBefore($head);
    }
    var node = $cut && $cut.nodeBefore;
    if (!node || !NodeSelection.isSelectable(node))
        { return false; }
    if (dispatch)
        { dispatch(state.tr.setSelection(NodeSelection.create(state.doc, $cut.pos - node.nodeSize)).scrollIntoView()); }
    return true;
};
function findCutBefore($pos) {
    if (!$pos.parent.type.spec.isolating)
        { for (var i = $pos.depth - 1; i >= 0; i--) {
            if ($pos.index(i) > 0)
                { return $pos.doc.resolve($pos.before(i + 1)); }
            if ($pos.node(i).type.spec.isolating)
                { break; }
        } }
    return null;
}
function atBlockEnd(state, view) {
    var ref = state.selection;
    var $cursor = ref.$cursor;
    if (!$cursor || (view ? !view.endOfTextblock("forward", state)
        : $cursor.parentOffset < $cursor.parent.content.size))
        { return null; }
    return $cursor;
}
/**
If the selection is empty and the cursor is at the end of a
textblock, try to reduce or remove the boundary between that block
and the one after it, either by joining them or by moving the other
block closer to this one in the tree structure. Will use the view
for accurate start-of-textblock detection if given.
*/
var joinForward = function (state, dispatch, view) {
    var $cursor = atBlockEnd(state, view);
    if (!$cursor)
        { return false; }
    var $cut = findCutAfter($cursor);
    // If there is no node after this, there's nothing to do
    if (!$cut)
        { return false; }
    var after = $cut.nodeAfter;
    // Try the joining algorithm
    if (deleteBarrier(state, $cut, dispatch, 1))
        { return true; }
    // If the node above has no content and the node below is
    // selectable, delete the node above and select the one below.
    if ($cursor.parent.content.size == 0 &&
        (textblockAt(after, "start") || NodeSelection.isSelectable(after))) {
        var delStep = replaceStep(state.doc, $cursor.before(), $cursor.after(), Slice.empty);
        if (delStep && delStep.slice.size < delStep.to - delStep.from) {
            if (dispatch) {
                var tr = state.tr.step(delStep);
                tr.setSelection(textblockAt(after, "start") ? Selection.findFrom(tr.doc.resolve(tr.mapping.map($cut.pos)), 1)
                    : NodeSelection.create(tr.doc, tr.mapping.map($cut.pos)));
                dispatch(tr.scrollIntoView());
            }
            return true;
        }
    }
    // If the next node is an atom, delete it
    if (after.isAtom && $cut.depth == $cursor.depth - 1) {
        if (dispatch)
            { dispatch(state.tr.delete($cut.pos, $cut.pos + after.nodeSize).scrollIntoView()); }
        return true;
    }
    return false;
};
/**
When the selection is empty and at the end of a textblock, select
the node coming after that textblock, if possible. This is intended
to be bound to keys like delete, after
[`joinForward`](https://prosemirror.net/docs/ref/#commands.joinForward) and similar deleting
commands, to provide a fall-back behavior when the schema doesn't
allow deletion at the selected point.
*/
var selectNodeForward = function (state, dispatch, view) {
    var ref = state.selection;
    var $head = ref.$head;
    var empty = ref.empty;
    var $cut = $head;
    if (!empty)
        { return false; }
    if ($head.parent.isTextblock) {
        if (view ? !view.endOfTextblock("forward", state) : $head.parentOffset < $head.parent.content.size)
            { return false; }
        $cut = findCutAfter($head);
    }
    var node = $cut && $cut.nodeAfter;
    if (!node || !NodeSelection.isSelectable(node))
        { return false; }
    if (dispatch)
        { dispatch(state.tr.setSelection(NodeSelection.create(state.doc, $cut.pos)).scrollIntoView()); }
    return true;
};
function findCutAfter($pos) {
    if (!$pos.parent.type.spec.isolating)
        { for (var i = $pos.depth - 1; i >= 0; i--) {
            var parent = $pos.node(i);
            if ($pos.index(i) + 1 < parent.childCount)
                { return $pos.doc.resolve($pos.after(i + 1)); }
            if (parent.type.spec.isolating)
                { break; }
        } }
    return null;
}
/**
Join the selected block or, if there is a text selection, the
closest ancestor block of the selection that can be joined, with
the sibling above it.
*/
var joinUp = function (state, dispatch) {
    var sel = state.selection, nodeSel = sel instanceof NodeSelection, point;
    if (nodeSel) {
        if (sel.node.isTextblock || !canJoin(state.doc, sel.from))
            { return false; }
        point = sel.from;
    }
    else {
        point = joinPoint(state.doc, sel.from, -1);
        if (point == null)
            { return false; }
    }
    if (dispatch) {
        var tr = state.tr.join(point);
        if (nodeSel)
            { tr.setSelection(NodeSelection.create(tr.doc, point - state.doc.resolve(point).nodeBefore.nodeSize)); }
        dispatch(tr.scrollIntoView());
    }
    return true;
};
/**
Join the selected block, or the closest ancestor of the selection
that can be joined, with the sibling after it.
*/
var joinDown = function (state, dispatch) {
    var sel = state.selection, point;
    if (sel instanceof NodeSelection) {
        if (sel.node.isTextblock || !canJoin(state.doc, sel.to))
            { return false; }
        point = sel.to;
    }
    else {
        point = joinPoint(state.doc, sel.to, 1);
        if (point == null)
            { return false; }
    }
    if (dispatch)
        { dispatch(state.tr.join(point).scrollIntoView()); }
    return true;
};
/**
Lift the selected block, or the closest ancestor block of the
selection that can be lifted, out of its parent node.
*/
var lift$1 = function (state, dispatch) {
    var ref = state.selection;
    var $from = ref.$from;
    var $to = ref.$to;
    var range = $from.blockRange($to), target = range && liftTarget(range);
    if (target == null)
        { return false; }
    if (dispatch)
        { dispatch(state.tr.lift(range, target).scrollIntoView()); }
    return true;
};
/**
If the selection is in a node whose type has a truthy
[`code`](https://prosemirror.net/docs/ref/#model.NodeSpec.code) property in its spec, replace the
selection with a newline character.
*/
var newlineInCode = function (state, dispatch) {
    var ref = state.selection;
    var $head = ref.$head;
    var $anchor = ref.$anchor;
    if (!$head.parent.type.spec.code || !$head.sameParent($anchor))
        { return false; }
    if (dispatch)
        { dispatch(state.tr.insertText("\n").scrollIntoView()); }
    return true;
};
function defaultBlockAt(match) {
    for (var i = 0; i < match.edgeCount; i++) {
        var ref = match.edge(i);
        var type = ref.type;
        if (type.isTextblock && !type.hasRequiredAttrs())
            { return type; }
    }
    return null;
}
/**
When the selection is in a node with a truthy
[`code`](https://prosemirror.net/docs/ref/#model.NodeSpec.code) property in its spec, create a
default block after the code block, and move the cursor there.
*/
var exitCode = function (state, dispatch) {
    var ref = state.selection;
    var $head = ref.$head;
    var $anchor = ref.$anchor;
    if (!$head.parent.type.spec.code || !$head.sameParent($anchor))
        { return false; }
    var above = $head.node(-1), after = $head.indexAfter(-1), type = defaultBlockAt(above.contentMatchAt(after));
    if (!type || !above.canReplaceWith(after, after, type))
        { return false; }
    if (dispatch) {
        var pos = $head.after(), tr = state.tr.replaceWith(pos, pos, type.createAndFill());
        tr.setSelection(Selection.near(tr.doc.resolve(pos), 1));
        dispatch(tr.scrollIntoView());
    }
    return true;
};
/**
If a block node is selected, create an empty paragraph before (if
it is its parent's first child) or after it.
*/
var createParagraphNear = function (state, dispatch) {
    var sel = state.selection;
    var $from = sel.$from;
    var $to = sel.$to;
    if (sel instanceof AllSelection || $from.parent.inlineContent || $to.parent.inlineContent)
        { return false; }
    var type = defaultBlockAt($to.parent.contentMatchAt($to.indexAfter()));
    if (!type || !type.isTextblock)
        { return false; }
    if (dispatch) {
        var side = (!$from.parentOffset && $to.index() < $to.parent.childCount ? $from : $to).pos;
        var tr = state.tr.insert(side, type.createAndFill());
        tr.setSelection(TextSelection.create(tr.doc, side + 1));
        dispatch(tr.scrollIntoView());
    }
    return true;
};
/**
If the cursor is in an empty textblock that can be lifted, lift the
block.
*/
var liftEmptyBlock = function (state, dispatch) {
    var ref = state.selection;
    var $cursor = ref.$cursor;
    if (!$cursor || $cursor.parent.content.size)
        { return false; }
    if ($cursor.depth > 1 && $cursor.after() != $cursor.end(-1)) {
        var before = $cursor.before();
        if (canSplit(state.doc, before)) {
            if (dispatch)
                { dispatch(state.tr.split(before).scrollIntoView()); }
            return true;
        }
    }
    var range = $cursor.blockRange(), target = range && liftTarget(range);
    if (target == null)
        { return false; }
    if (dispatch)
        { dispatch(state.tr.lift(range, target).scrollIntoView()); }
    return true;
};
/**
Create a variant of [`splitBlock`](https://prosemirror.net/docs/ref/#commands.splitBlock) that uses
a custom function to determine the type of the newly split off block.
*/
function splitBlockAs(splitNode) {
    return function (state, dispatch) {
        var ref = state.selection;
        var $from = ref.$from;
        var $to = ref.$to;
        if (state.selection instanceof NodeSelection && state.selection.node.isBlock) {
            if (!$from.parentOffset || !canSplit(state.doc, $from.pos))
                { return false; }
            if (dispatch)
                { dispatch(state.tr.split($from.pos).scrollIntoView()); }
            return true;
        }
        if (!$from.parent.isBlock)
            { return false; }
        if (dispatch) {
            var atEnd = $to.parentOffset == $to.parent.content.size;
            var tr = state.tr;
            if (state.selection instanceof TextSelection || state.selection instanceof AllSelection)
                { tr.deleteSelection(); }
            var deflt = $from.depth == 0 ? null : defaultBlockAt($from.node(-1).contentMatchAt($from.indexAfter(-1)));
            var splitType = splitNode && splitNode($to.parent, atEnd, $from);
            var types = splitType ? [splitType] : atEnd && deflt ? [{ type: deflt }] : undefined;
            var can = canSplit(tr.doc, tr.mapping.map($from.pos), 1, types);
            if (!types && !can && canSplit(tr.doc, tr.mapping.map($from.pos), 1, deflt ? [{ type: deflt }] : undefined)) {
                if (deflt)
                    { types = [{ type: deflt }]; }
                can = true;
            }
            if (can) {
                tr.split(tr.mapping.map($from.pos), 1, types);
                if (!atEnd && !$from.parentOffset && $from.parent.type != deflt) {
                    var first = tr.mapping.map($from.before()), $first = tr.doc.resolve(first);
                    if (deflt && $from.node(-1).canReplaceWith($first.index(), $first.index() + 1, deflt))
                        { tr.setNodeMarkup(tr.mapping.map($from.before()), deflt); }
                }
            }
            dispatch(tr.scrollIntoView());
        }
        return true;
    };
}
/**
Split the parent block of the selection. If the selection is a text
selection, also delete its content.
*/
var splitBlock = splitBlockAs();
/**
Acts like [`splitBlock`](https://prosemirror.net/docs/ref/#commands.splitBlock), but without
resetting the set of active marks at the cursor.
*/
var splitBlockKeepMarks = function (state, dispatch) {
    return splitBlock(state, dispatch && (function (tr) {
        var marks = state.storedMarks || (state.selection.$to.parentOffset && state.selection.$from.marks());
        if (marks)
            { tr.ensureMarks(marks); }
        dispatch(tr);
    }));
};
/**
Move the selection to the node wrapping the current selection, if
any. (Will not select the document node.)
*/
var selectParentNode = function (state, dispatch) {
    var ref = state.selection;
    var $from = ref.$from;
    var to = ref.to;
    var pos;
    var same = $from.sharedDepth(to);
    if (same == 0)
        { return false; }
    pos = $from.before(same);
    if (dispatch)
        { dispatch(state.tr.setSelection(NodeSelection.create(state.doc, pos))); }
    return true;
};
/**
Select the whole document.
*/
var selectAll$1 = function (state, dispatch) {
    if (dispatch)
        { dispatch(state.tr.setSelection(new AllSelection(state.doc))); }
    return true;
};
function joinMaybeClear(state, $pos, dispatch) {
    var before = $pos.nodeBefore, after = $pos.nodeAfter, index = $pos.index();
    if (!before || !after || !before.type.compatibleContent(after.type))
        { return false; }
    if (!before.content.size && $pos.parent.canReplace(index - 1, index)) {
        if (dispatch)
            { dispatch(state.tr.delete($pos.pos - before.nodeSize, $pos.pos).scrollIntoView()); }
        return true;
    }
    if (!$pos.parent.canReplace(index, index + 1) || !(after.isTextblock || canJoin(state.doc, $pos.pos)))
        { return false; }
    if (dispatch)
        { dispatch(state.tr
            .clearIncompatible($pos.pos, before.type, before.contentMatchAt(before.childCount))
            .join($pos.pos)
            .scrollIntoView()); }
    return true;
}
function deleteBarrier(state, $cut, dispatch, dir) {
    var before = $cut.nodeBefore, after = $cut.nodeAfter, conn, match;
    var isolated = before.type.spec.isolating || after.type.spec.isolating;
    if (!isolated && joinMaybeClear(state, $cut, dispatch))
        { return true; }
    var canDelAfter = !isolated && $cut.parent.canReplace($cut.index(), $cut.index() + 1);
    if (canDelAfter &&
        (conn = (match = before.contentMatchAt(before.childCount)).findWrapping(after.type)) &&
        match.matchType(conn[0] || after.type).validEnd) {
        if (dispatch) {
            var end = $cut.pos + after.nodeSize, wrap = Fragment.empty;
            for (var i = conn.length - 1; i >= 0; i--)
                { wrap = Fragment.from(conn[i].create(null, wrap)); }
            wrap = Fragment.from(before.copy(wrap));
            var tr = state.tr.step(new ReplaceAroundStep($cut.pos - 1, end, $cut.pos, end, new Slice(wrap, 1, 0), conn.length, true));
            var joinAt = end + 2 * conn.length;
            if (canJoin(tr.doc, joinAt))
                { tr.join(joinAt); }
            dispatch(tr.scrollIntoView());
        }
        return true;
    }
    var selAfter = after.type.spec.isolating || (dir > 0 && isolated) ? null : Selection.findFrom($cut, 1);
    var range = selAfter && selAfter.$from.blockRange(selAfter.$to), target = range && liftTarget(range);
    if (target != null && target >= $cut.depth) {
        if (dispatch)
            { dispatch(state.tr.lift(range, target).scrollIntoView()); }
        return true;
    }
    if (canDelAfter && textblockAt(after, "start", true) && textblockAt(before, "end")) {
        var at = before, wrap$1 = [];
        for (;;) {
            wrap$1.push(at);
            if (at.isTextblock)
                { break; }
            at = at.lastChild;
        }
        var afterText = after, afterDepth = 1;
        for (; !afterText.isTextblock; afterText = afterText.firstChild)
            { afterDepth++; }
        if (at.canReplace(at.childCount, at.childCount, afterText.content)) {
            if (dispatch) {
                var end$1 = Fragment.empty;
                for (var i$1 = wrap$1.length - 1; i$1 >= 0; i$1--)
                    { end$1 = Fragment.from(wrap$1[i$1].copy(end$1)); }
                var tr$1 = state.tr.step(new ReplaceAroundStep($cut.pos - wrap$1.length, $cut.pos + after.nodeSize, $cut.pos + afterDepth, $cut.pos + after.nodeSize - afterDepth, new Slice(end$1, wrap$1.length, 0), 0, true));
                dispatch(tr$1.scrollIntoView());
            }
            return true;
        }
    }
    return false;
}
function selectTextblockSide(side) {
    return function (state, dispatch) {
        var sel = state.selection, $pos = side < 0 ? sel.$from : sel.$to;
        var depth = $pos.depth;
        while ($pos.node(depth).isInline) {
            if (!depth)
                { return false; }
            depth--;
        }
        if (!$pos.node(depth).isTextblock)
            { return false; }
        if (dispatch)
            { dispatch(state.tr.setSelection(TextSelection.create(state.doc, side < 0 ? $pos.start(depth) : $pos.end(depth)))); }
        return true;
    };
}
/**
Moves the cursor to the start of current text block.
*/
var selectTextblockStart = selectTextblockSide(-1);
/**
Moves the cursor to the end of current text block.
*/
var selectTextblockEnd = selectTextblockSide(1);
// Parameterized commands
/**
Wrap the selection in a node of the given type with the given
attributes.
*/
function wrapIn(nodeType, attrs) {
    if ( attrs === void 0 ) attrs = null;

    return function (state, dispatch) {
        var ref = state.selection;
        var $from = ref.$from;
        var $to = ref.$to;
        var range = $from.blockRange($to), wrapping = range && findWrapping(range, nodeType, attrs);
        if (!wrapping)
            { return false; }
        if (dispatch)
            { dispatch(state.tr.wrap(range, wrapping).scrollIntoView()); }
        return true;
    };
}
/**
Returns a command that tries to set the selected textblocks to the
given node type with the given attributes.
*/
function setBlockType(nodeType, attrs) {
    if ( attrs === void 0 ) attrs = null;

    return function (state, dispatch) {
        var applicable = false;
        for (var i = 0; i < state.selection.ranges.length && !applicable; i++) {
            var ref = state.selection.ranges[i];
            var from = ref.$from.pos;
            var to = ref.$to.pos;
            state.doc.nodesBetween(from, to, function (node, pos) {
                if (applicable)
                    { return false; }
                if (!node.isTextblock || node.hasMarkup(nodeType, attrs))
                    { return; }
                if (node.type == nodeType) {
                    applicable = true;
                }
                else {
                    var $pos = state.doc.resolve(pos), index = $pos.index();
                    applicable = $pos.parent.canReplaceWith(index, index + 1, nodeType);
                }
            });
        }
        if (!applicable)
            { return false; }
        if (dispatch) {
            var tr = state.tr;
            for (var i$1 = 0; i$1 < state.selection.ranges.length; i$1++) {
                var ref$1 = state.selection.ranges[i$1];
                var from$1 = ref$1.$from.pos;
                var to$1 = ref$1.$to.pos;
                tr.setBlockType(from$1, to$1, nodeType, attrs);
            }
            dispatch(tr.scrollIntoView());
        }
        return true;
    };
}
function markApplies$1(doc, ranges, type, enterAtoms) {
    var loop = function ( i ) {
        var ref = ranges[i];
        var $from = ref.$from;
        var $to = ref.$to;
        var can = $from.depth == 0 ? doc.inlineContent && doc.type.allowsMarkType(type) : false;
        doc.nodesBetween($from.pos, $to.pos, function (node, pos) {
            if (can || !enterAtoms && node.isAtom && node.isInline && pos >= $from.pos && pos + node.nodeSize <= $to.pos)
                { return false; }
            can = node.inlineContent && node.type.allowsMarkType(type);
        });
        if (can)
            { return { v: true }; }
    };

    for (var i = 0; i < ranges.length; i++) {
        var returned = loop( i );

        if ( returned ) return returned.v;
    }
    return false;
}
function removeInlineAtoms(ranges) {
    var result = [];
    var loop = function ( i ) {
        var ref = ranges[i];
        var $from = ref.$from;
        var $to = ref.$to;
        $from.doc.nodesBetween($from.pos, $to.pos, function (node, pos) {
            if (node.isAtom && node.content.size && node.isInline && pos >= $from.pos && pos + node.nodeSize <= $to.pos) {
                if (pos + 1 > $from.pos)
                    { result.push(new SelectionRange$1($from, $from.doc.resolve(pos + 1))); }
                $from = $from.doc.resolve(pos + 1 + node.content.size);
                return false;
            }
        });
        if ($from.pos < $to.pos)
            { result.push(new SelectionRange$1($from, $to)); }
    };

    for (var i = 0; i < ranges.length; i++) loop( i );
    return result;
}
/**
Create a command function that toggles the given mark with the
given attributes. Will return `false` when the current selection
doesn't support that mark. This will remove the mark if any marks
of that type exist in the selection, or add it otherwise. If the
selection is empty, this applies to the [stored
marks](https://prosemirror.net/docs/ref/#state.EditorState.storedMarks) instead of a range of the
document.
*/
function toggleMark(markType, attrs, options) {
    if ( attrs === void 0 ) attrs = null;

    var removeWhenPresent = (options && options.removeWhenPresent) !== false;
    var enterAtoms = (options && options.enterInlineAtoms) !== false;
    return function (state, dispatch) {
        var ref = state.selection;
        var empty = ref.empty;
        var $cursor = ref.$cursor;
        var ranges = ref.ranges;
        if ((empty && !$cursor) || !markApplies$1(state.doc, ranges, markType, enterAtoms))
            { return false; }
        if (dispatch) {
            if ($cursor) {
                if (markType.isInSet(state.storedMarks || $cursor.marks()))
                    { dispatch(state.tr.removeStoredMark(markType)); }
                else
                    { dispatch(state.tr.addStoredMark(markType.create(attrs))); }
            }
            else {
                var add, tr = state.tr;
                if (!enterAtoms)
                    { ranges = removeInlineAtoms(ranges); }
                if (removeWhenPresent) {
                    add = !ranges.some(function (r) { return state.doc.rangeHasMark(r.$from.pos, r.$to.pos, markType); });
                }
                else {
                    add = !ranges.every(function (r) {
                        var missing = false;
                        tr.doc.nodesBetween(r.$from.pos, r.$to.pos, function (node, pos, parent) {
                            if (missing)
                                { return false; }
                            missing = !markType.isInSet(node.marks) && !!parent && parent.type.allowsMarkType(markType) &&
                                !(node.isText && /^\s*$/.test(node.textBetween(Math.max(0, r.$from.pos - pos), Math.min(node.nodeSize, r.$to.pos - pos))));
                        });
                        return !missing;
                    });
                }
                for (var i = 0; i < ranges.length; i++) {
                    var ref$1 = ranges[i];
                    var $from = ref$1.$from;
                    var $to = ref$1.$to;
                    if (!add) {
                        tr.removeMark($from.pos, $to.pos, markType);
                    }
                    else {
                        var from = $from.pos, to = $to.pos, start = $from.nodeAfter, end = $to.nodeBefore;
                        var spaceStart = start && start.isText ? /^\s*/.exec(start.text)[0].length : 0;
                        var spaceEnd = end && end.isText ? /\s*$/.exec(end.text)[0].length : 0;
                        if (from + spaceStart < to) {
                            from += spaceStart;
                            to -= spaceEnd;
                        }
                        tr.addMark(from, to, markType.create(attrs));
                    }
                }
                dispatch(tr.scrollIntoView());
            }
        }
        return true;
    };
}
function wrapDispatchForJoin(dispatch, isJoinable) {
    return function (tr) {
        if (!tr.isGeneric)
            { return dispatch(tr); }
        var ranges = [];
        for (var i = 0; i < tr.mapping.maps.length; i++) {
            var map = tr.mapping.maps[i];
            for (var j = 0; j < ranges.length; j++)
                { ranges[j] = map.map(ranges[j]); }
            map.forEach(function (_s, _e, from, to) { return ranges.push(from, to); });
        }
        // Figure out which joinable points exist inside those ranges,
        // by checking all node boundaries in their parent nodes.
        var joinable = [];
        for (var i$1 = 0; i$1 < ranges.length; i$1 += 2) {
            var from = ranges[i$1], to = ranges[i$1 + 1];
            var $from = tr.doc.resolve(from), depth = $from.sharedDepth(to), parent = $from.node(depth);
            for (var index = $from.indexAfter(depth), pos = $from.after(depth + 1); pos <= to; ++index) {
                var after = parent.maybeChild(index);
                if (!after)
                    { break; }
                if (index && joinable.indexOf(pos) == -1) {
                    var before = parent.child(index - 1);
                    if (before.type == after.type && isJoinable(before, after))
                        { joinable.push(pos); }
                }
                pos += after.nodeSize;
            }
        }
        // Join the joinable points
        joinable.sort(function (a, b) { return a - b; });
        for (var i$2 = joinable.length - 1; i$2 >= 0; i$2--) {
            if (canJoin(tr.doc, joinable[i$2]))
                { tr.join(joinable[i$2]); }
        }
        dispatch(tr);
    };
}
/**
Wrap a command so that, when it produces a transform that causes
two joinable nodes to end up next to each other, those are joined.
Nodes are considered joinable when they are of the same type and
when the `isJoinable` predicate returns true for them or, if an
array of strings was passed, if their node type name is in that
array.
*/
function autoJoin(command, isJoinable) {
    var canJoin = Array.isArray(isJoinable) ? function (node) { return isJoinable.indexOf(node.type.name) > -1; }
        : isJoinable;
    return function (state, dispatch, view) { return command(state, dispatch && wrapDispatchForJoin(dispatch, canJoin), view); };
}
/**
Combine a number of command functions into a single function (which
calls them one by one until one returns true).
*/
function chainCommands() {
    var commands = [], len = arguments.length;
    while ( len-- ) commands[ len ] = arguments[ len ];

    return function (state, dispatch, view) {
        for (var i = 0; i < commands.length; i++)
            { if (commands[i](state, dispatch, view))
                { return true; } }
        return false;
    };
}
var backspace = chainCommands(deleteSelection, joinBackward, selectNodeBackward);
var del = chainCommands(deleteSelection, joinForward, selectNodeForward);
/**
A basic keymap containing bindings not specific to any schema.
Binds the following keys (when multiple commands are listed, they
are chained with [`chainCommands`](https://prosemirror.net/docs/ref/#commands.chainCommands)):

* **Enter** to `newlineInCode`, `createParagraphNear`, `liftEmptyBlock`, `splitBlock`
* **Mod-Enter** to `exitCode`
* **Backspace** and **Mod-Backspace** to `deleteSelection`, `joinBackward`, `selectNodeBackward`
* **Delete** and **Mod-Delete** to `deleteSelection`, `joinForward`, `selectNodeForward`
* **Mod-Delete** to `deleteSelection`, `joinForward`, `selectNodeForward`
* **Mod-a** to `selectAll`
*/
var pcBaseKeymap = {
    "Enter": chainCommands(newlineInCode, createParagraphNear, liftEmptyBlock, splitBlock),
    "Mod-Enter": exitCode,
    "Backspace": backspace,
    "Mod-Backspace": backspace,
    "Shift-Backspace": backspace,
    "Delete": del,
    "Mod-Delete": del,
    "Mod-a": selectAll$1
};
/**
A copy of `pcBaseKeymap` that also binds **Ctrl-h** like Backspace,
**Ctrl-d** like Delete, **Alt-Backspace** like Ctrl-Backspace, and
**Ctrl-Alt-Backspace**, **Alt-Delete**, and **Alt-d** like
Ctrl-Delete.
*/
var macBaseKeymap = {
    "Ctrl-h": pcBaseKeymap["Backspace"],
    "Alt-Backspace": pcBaseKeymap["Mod-Backspace"],
    "Ctrl-d": pcBaseKeymap["Delete"],
    "Ctrl-Alt-Backspace": pcBaseKeymap["Mod-Delete"],
    "Alt-Delete": pcBaseKeymap["Mod-Delete"],
    "Alt-d": pcBaseKeymap["Mod-Delete"],
    "Ctrl-a": selectTextblockStart,
    "Ctrl-e": selectTextblockEnd
};
for (var key$3 in pcBaseKeymap)
    { macBaseKeymap[key$3] = pcBaseKeymap[key$3]; }
var mac$3 = typeof navigator != "undefined" ? /Mac|iP(hone|[oa]d)/.test(navigator.platform)
    // @ts-ignore
    : typeof os != "undefined" && os.platform ? os.platform() == "darwin" : false;
/**
Depending on the detected platform, this will hold
[`pcBasekeymap`](https://prosemirror.net/docs/ref/#commands.pcBaseKeymap) or
[`macBaseKeymap`](https://prosemirror.net/docs/ref/#commands.macBaseKeymap).
*/
var baseKeymap = mac$3 ? macBaseKeymap : pcBaseKeymap;var commands=/*#__PURE__*/Object.freeze({__proto__:null,autoJoin:autoJoin,baseKeymap:baseKeymap,chainCommands:chainCommands,createParagraphNear:createParagraphNear,deleteSelection:deleteSelection,exitCode:exitCode,joinBackward:joinBackward,joinDown:joinDown,joinForward:joinForward,joinTextblockBackward:joinTextblockBackward,joinTextblockForward:joinTextblockForward,joinUp:joinUp,lift:lift$1,liftEmptyBlock:liftEmptyBlock,macBaseKeymap:macBaseKeymap,newlineInCode:newlineInCode,pcBaseKeymap:pcBaseKeymap,selectAll:selectAll$1,selectNodeBackward:selectNodeBackward,selectNodeForward:selectNodeForward,selectParentNode:selectParentNode,selectTextblockEnd:selectTextblockEnd,selectTextblockStart:selectTextblockStart,setBlockType:setBlockType,splitBlock:splitBlock,splitBlockAs:splitBlockAs,splitBlockKeepMarks:splitBlockKeepMarks,toggleMark:toggleMark,wrapIn:wrapIn});var GOOD_LEAF_SIZE = 200;

// :: class<T> A rope sequence is a persistent sequence data structure
// that supports appending, prepending, and slicing without doing a
// full copy. It is represented as a mostly-balanced tree.
var RopeSequence = function RopeSequence () {};

RopeSequence.prototype.append = function append (other) {
  if (!other.length) { return this }
  other = RopeSequence.from(other);

  return (!this.length && other) ||
    (other.length < GOOD_LEAF_SIZE && this.leafAppend(other)) ||
    (this.length < GOOD_LEAF_SIZE && other.leafPrepend(this)) ||
    this.appendInner(other)
};

// :: (union<[T], RopeSequence<T>>) → RopeSequence<T>
// Prepend an array or other rope to this one, returning a new rope.
RopeSequence.prototype.prepend = function prepend (other) {
  if (!other.length) { return this }
  return RopeSequence.from(other).append(this)
};

RopeSequence.prototype.appendInner = function appendInner (other) {
  return new Append(this, other)
};

// :: (?number, ?number) → RopeSequence<T>
// Create a rope repesenting a sub-sequence of this rope.
RopeSequence.prototype.slice = function slice (from, to) {
    if ( from === void 0 ) { from = 0; }
    if ( to === void 0 ) { to = this.length; }

  if (from >= to) { return RopeSequence.empty }
  return this.sliceInner(Math.max(0, from), Math.min(this.length, to))
};

// :: (number) → T
// Retrieve the element at the given position from this rope.
RopeSequence.prototype.get = function get (i) {
  if (i < 0 || i >= this.length) { return undefined }
  return this.getInner(i)
};

// :: ((element: T, index: number) → ?bool, ?number, ?number)
// Call the given function for each element between the given
// indices. This tends to be more efficient than looping over the
// indices and calling `get`, because it doesn't have to descend the
// tree for every element.
RopeSequence.prototype.forEach = function forEach (f, from, to) {
    if ( from === void 0 ) { from = 0; }
    if ( to === void 0 ) { to = this.length; }

  if (from <= to)
    { this.forEachInner(f, from, to, 0); }
  else
    { this.forEachInvertedInner(f, from, to, 0); }
};

// :: ((element: T, index: number) → U, ?number, ?number) → [U]
// Map the given functions over the elements of the rope, producing
// a flat array.
RopeSequence.prototype.map = function map (f, from, to) {
    if ( from === void 0 ) { from = 0; }
    if ( to === void 0 ) { to = this.length; }

  var result = [];
  this.forEach(function (elt, i) { return result.push(f(elt, i)); }, from, to);
  return result
};

// :: (?union<[T], RopeSequence<T>>) → RopeSequence<T>
// Create a rope representing the given array, or return the rope
// itself if a rope was given.
RopeSequence.from = function from (values) {
  if (values instanceof RopeSequence) { return values }
  return values && values.length ? new Leaf(values) : RopeSequence.empty
};

var Leaf = /*@__PURE__*/(function (RopeSequence) {
  function Leaf(values) {
    RopeSequence.call(this);
    this.values = values;
  }

  if ( RopeSequence ) { Leaf.__proto__ = RopeSequence; }
  Leaf.prototype = Object.create( RopeSequence && RopeSequence.prototype );
  Leaf.prototype.constructor = Leaf;

  var prototypeAccessors = { length: { configurable: true },depth: { configurable: true } };

  Leaf.prototype.flatten = function flatten () {
    return this.values
  };

  Leaf.prototype.sliceInner = function sliceInner (from, to) {
    if (from == 0 && to == this.length) { return this }
    return new Leaf(this.values.slice(from, to))
  };

  Leaf.prototype.getInner = function getInner (i) {
    return this.values[i]
  };

  Leaf.prototype.forEachInner = function forEachInner (f, from, to, start) {
    for (var i = from; i < to; i++)
      { if (f(this.values[i], start + i) === false) { return false } }
  };

  Leaf.prototype.forEachInvertedInner = function forEachInvertedInner (f, from, to, start) {
    for (var i = from - 1; i >= to; i--)
      { if (f(this.values[i], start + i) === false) { return false } }
  };

  Leaf.prototype.leafAppend = function leafAppend (other) {
    if (this.length + other.length <= GOOD_LEAF_SIZE)
      { return new Leaf(this.values.concat(other.flatten())) }
  };

  Leaf.prototype.leafPrepend = function leafPrepend (other) {
    if (this.length + other.length <= GOOD_LEAF_SIZE)
      { return new Leaf(other.flatten().concat(this.values)) }
  };

  prototypeAccessors.length.get = function () { return this.values.length };

  prototypeAccessors.depth.get = function () { return 0 };

  Object.defineProperties( Leaf.prototype, prototypeAccessors );

  return Leaf;
}(RopeSequence));

// :: RopeSequence
// The empty rope sequence.
RopeSequence.empty = new Leaf([]);

var Append = /*@__PURE__*/(function (RopeSequence) {
  function Append(left, right) {
    RopeSequence.call(this);
    this.left = left;
    this.right = right;
    this.length = left.length + right.length;
    this.depth = Math.max(left.depth, right.depth) + 1;
  }

  if ( RopeSequence ) { Append.__proto__ = RopeSequence; }
  Append.prototype = Object.create( RopeSequence && RopeSequence.prototype );
  Append.prototype.constructor = Append;

  Append.prototype.flatten = function flatten () {
    return this.left.flatten().concat(this.right.flatten())
  };

  Append.prototype.getInner = function getInner (i) {
    return i < this.left.length ? this.left.get(i) : this.right.get(i - this.left.length)
  };

  Append.prototype.forEachInner = function forEachInner (f, from, to, start) {
    var leftLen = this.left.length;
    if (from < leftLen &&
        this.left.forEachInner(f, from, Math.min(to, leftLen), start) === false)
      { return false }
    if (to > leftLen &&
        this.right.forEachInner(f, Math.max(from - leftLen, 0), Math.min(this.length, to) - leftLen, start + leftLen) === false)
      { return false }
  };

  Append.prototype.forEachInvertedInner = function forEachInvertedInner (f, from, to, start) {
    var leftLen = this.left.length;
    if (from > leftLen &&
        this.right.forEachInvertedInner(f, from - leftLen, Math.max(to, leftLen) - leftLen, start + leftLen) === false)
      { return false }
    if (to < leftLen &&
        this.left.forEachInvertedInner(f, Math.min(from, leftLen), to, start) === false)
      { return false }
  };

  Append.prototype.sliceInner = function sliceInner (from, to) {
    if (from == 0 && to == this.length) { return this }
    var leftLen = this.left.length;
    if (to <= leftLen) { return this.left.slice(from, to) }
    if (from >= leftLen) { return this.right.slice(from - leftLen, to - leftLen) }
    return this.left.slice(from, leftLen).append(this.right.slice(0, to - leftLen))
  };

  Append.prototype.leafAppend = function leafAppend (other) {
    var inner = this.right.leafAppend(other);
    if (inner) { return new Append(this.left, inner) }
  };

  Append.prototype.leafPrepend = function leafPrepend (other) {
    var inner = this.left.leafPrepend(other);
    if (inner) { return new Append(inner, this.right) }
  };

  Append.prototype.appendInner = function appendInner (other) {
    if (this.left.depth >= Math.max(this.right.depth, other.depth) + 1)
      { return new Append(this.left, new Append(this.right, other)) }
    return new Append(this, other)
  };

  return Append;
}(RopeSequence));// ProseMirror's history isn't simply a way to roll back to a previous
// state, because ProseMirror supports applying changes without adding
// them to the history (for example during collaboration).
//
// To this end, each 'Branch' (one for the undo history and one for
// the redo history) keeps an array of 'Items', which can optionally
// hold a step (an actual undoable change), and always hold a position
// map (which is needed to move changes below them to apply to the
// current document).
//
// An item that has both a step and a selection bookmark is the start
// of an 'event' — a group of changes that will be undone or redone at
// once. (It stores only the bookmark, since that way we don't have to
// provide a document until the selection is actually applied, which
// is useful when compressing.)
// Used to schedule history compression
var max_empty_items = 500;
var Branch = function Branch(items, eventCount) {
    this.items = items;
    this.eventCount = eventCount;
};
// Pop the latest event off the branch's history and apply it
// to a document transform.
Branch.prototype.popEvent = function popEvent (state, preserveItems) {
        var this$1$1 = this;

    if (this.eventCount == 0)
        { return null; }
    var end = this.items.length;
    for (;; end--) {
        var next = this.items.get(end - 1);
        if (next.selection) {
            --end;
            break;
        }
    }
    var remap, mapFrom;
    if (preserveItems) {
        remap = this.remapping(end, this.items.length);
        mapFrom = remap.maps.length;
    }
    var transform = state.tr;
    var selection, remaining;
    var addAfter = [], addBefore = [];
    this.items.forEach(function (item, i) {
        if (!item.step) {
            if (!remap) {
                remap = this$1$1.remapping(end, i + 1);
                mapFrom = remap.maps.length;
            }
            mapFrom--;
            addBefore.push(item);
            return;
        }
        if (remap) {
            addBefore.push(new Item(item.map));
            var step = item.step.map(remap.slice(mapFrom)), map;
            if (step && transform.maybeStep(step).doc) {
                map = transform.mapping.maps[transform.mapping.maps.length - 1];
                addAfter.push(new Item(map, undefined, undefined, addAfter.length + addBefore.length));
            }
            mapFrom--;
            if (map)
                { remap.appendMap(map, mapFrom); }
        }
        else {
            transform.maybeStep(item.step);
        }
        if (item.selection) {
            selection = remap ? item.selection.map(remap.slice(mapFrom)) : item.selection;
            remaining = new Branch(this$1$1.items.slice(0, end).append(addBefore.reverse().concat(addAfter)), this$1$1.eventCount - 1);
            return false;
        }
    }, this.items.length, 0);
    return { remaining: remaining, transform: transform, selection: selection };
};
// Create a new branch with the given transform added.
Branch.prototype.addTransform = function addTransform (transform, selection, histOptions, preserveItems) {
    var newItems = [], eventCount = this.eventCount;
    var oldItems = this.items, lastItem = !preserveItems && oldItems.length ? oldItems.get(oldItems.length - 1) : null;
    for (var i = 0; i < transform.steps.length; i++) {
        var step = transform.steps[i].invert(transform.docs[i]);
        var item = new Item(transform.mapping.maps[i], step, selection), merged = (void 0);
        if (merged = lastItem && lastItem.merge(item)) {
            item = merged;
            if (i)
                { newItems.pop(); }
            else
                { oldItems = oldItems.slice(0, oldItems.length - 1); }
        }
        newItems.push(item);
        if (selection) {
            eventCount++;
            selection = undefined;
        }
        if (!preserveItems)
            { lastItem = item; }
    }
    var overflow = eventCount - histOptions.depth;
    if (overflow > DEPTH_OVERFLOW) {
        oldItems = cutOffEvents(oldItems, overflow);
        eventCount -= overflow;
    }
    return new Branch(oldItems.append(newItems), eventCount);
};
Branch.prototype.remapping = function remapping (from, to) {
    var maps = new Mapping;
    this.items.forEach(function (item, i) {
        var mirrorPos = item.mirrorOffset != null && i - item.mirrorOffset >= from
            ? maps.maps.length - item.mirrorOffset : undefined;
        maps.appendMap(item.map, mirrorPos);
    }, from, to);
    return maps;
};
Branch.prototype.addMaps = function addMaps (array) {
    if (this.eventCount == 0)
        { return this; }
    return new Branch(this.items.append(array.map(function (map) { return new Item(map); })), this.eventCount);
};
// When the collab module receives remote changes, the history has
// to know about those, so that it can adjust the steps that were
// rebased on top of the remote changes, and include the position
// maps for the remote changes in its array of items.
Branch.prototype.rebased = function rebased (rebasedTransform, rebasedCount) {
    if (!this.eventCount)
        { return this; }
    var rebasedItems = [], start = Math.max(0, this.items.length - rebasedCount);
    var mapping = rebasedTransform.mapping;
    var newUntil = rebasedTransform.steps.length;
    var eventCount = this.eventCount;
    this.items.forEach(function (item) { if (item.selection)
        { eventCount--; } }, start);
    var iRebased = rebasedCount;
    this.items.forEach(function (item) {
        var pos = mapping.getMirror(--iRebased);
        if (pos == null)
            { return; }
        newUntil = Math.min(newUntil, pos);
        var map = mapping.maps[pos];
        if (item.step) {
            var step = rebasedTransform.steps[pos].invert(rebasedTransform.docs[pos]);
            var selection = item.selection && item.selection.map(mapping.slice(iRebased + 1, pos));
            if (selection)
                { eventCount++; }
            rebasedItems.push(new Item(map, step, selection));
        }
        else {
            rebasedItems.push(new Item(map));
        }
    }, start);
    var newMaps = [];
    for (var i = rebasedCount; i < newUntil; i++)
        { newMaps.push(new Item(mapping.maps[i])); }
    var items = this.items.slice(0, start).append(newMaps).append(rebasedItems);
    var branch = new Branch(items, eventCount);
    if (branch.emptyItemCount() > max_empty_items)
        { branch = branch.compress(this.items.length - rebasedItems.length); }
    return branch;
};
Branch.prototype.emptyItemCount = function emptyItemCount () {
    var count = 0;
    this.items.forEach(function (item) { if (!item.step)
        { count++; } });
    return count;
};
// Compressing a branch means rewriting it to push the air (map-only
// items) out. During collaboration, these naturally accumulate
// because each remote change adds one. The `upto` argument is used
// to ensure that only the items below a given level are compressed,
// because `rebased` relies on a clean, untouched set of items in
// order to associate old items with rebased steps.
Branch.prototype.compress = function compress (upto) {
        if ( upto === void 0 ) upto = this.items.length;

    var remap = this.remapping(0, upto), mapFrom = remap.maps.length;
    var items = [], events = 0;
    this.items.forEach(function (item, i) {
        if (i >= upto) {
            items.push(item);
            if (item.selection)
                { events++; }
        }
        else if (item.step) {
            var step = item.step.map(remap.slice(mapFrom)), map = step && step.getMap();
            mapFrom--;
            if (map)
                { remap.appendMap(map, mapFrom); }
            if (step) {
                var selection = item.selection && item.selection.map(remap.slice(mapFrom));
                if (selection)
                    { events++; }
                var newItem = new Item(map.invert(), step, selection), merged, last = items.length - 1;
                if (merged = items.length && items[last].merge(newItem))
                    { items[last] = merged; }
                else
                    { items.push(newItem); }
            }
        }
        else if (item.map) {
            mapFrom--;
        }
    }, this.items.length, 0);
    return new Branch(RopeSequence.from(items.reverse()), events);
};
Branch.empty = new Branch(RopeSequence.empty, 0);
function cutOffEvents(items, n) {
    var cutPoint;
    items.forEach(function (item, i) {
        if (item.selection && (n-- == 0)) {
            cutPoint = i;
            return false;
        }
    });
    return items.slice(cutPoint);
}
var Item = function Item(
// The (forward) step map for this item.
map, 
// The inverted step
step, 
// If this is non-null, this item is the start of a group, and
// this selection is the starting selection for the group (the one
// that was active before the first step was applied)
selection, 
// If this item is the inverse of a previous mapping on the stack,
// this points at the inverse's offset
mirrorOffset) {
    this.map = map;
    this.step = step;
    this.selection = selection;
    this.mirrorOffset = mirrorOffset;
};
Item.prototype.merge = function merge (other) {
    if (this.step && other.step && !other.selection) {
        var step = other.step.merge(this.step);
        if (step)
            { return new Item(step.getMap().invert(), step, this.selection); }
    }
};
// The value of the state field that tracks undo/redo history for that
// state. Will be stored in the plugin state when the history plugin
// is active.
var HistoryState = function HistoryState(done, undone, prevRanges, prevTime, prevComposition) {
    this.done = done;
    this.undone = undone;
    this.prevRanges = prevRanges;
    this.prevTime = prevTime;
    this.prevComposition = prevComposition;
};
var DEPTH_OVERFLOW = 20;
// Record a transformation in undo history.
function applyTransaction(history, state, tr, options) {
    var historyTr = tr.getMeta(historyKey), rebased;
    if (historyTr)
        { return historyTr.historyState; }
    if (tr.getMeta(closeHistoryKey))
        { history = new HistoryState(history.done, history.undone, null, 0, -1); }
    var appended = tr.getMeta("appendedTransaction");
    if (tr.steps.length == 0) {
        return history;
    }
    else if (appended && appended.getMeta(historyKey)) {
        if (appended.getMeta(historyKey).redo)
            { return new HistoryState(history.done.addTransform(tr, undefined, options, mustPreserveItems(state)), history.undone, rangesFor(tr.mapping.maps), history.prevTime, history.prevComposition); }
        else
            { return new HistoryState(history.done, history.undone.addTransform(tr, undefined, options, mustPreserveItems(state)), null, history.prevTime, history.prevComposition); }
    }
    else if (tr.getMeta("addToHistory") !== false && !(appended && appended.getMeta("addToHistory") === false)) {
        // Group transforms that occur in quick succession into one event.
        var composition = tr.getMeta("composition");
        var newGroup = history.prevTime == 0 ||
            (!appended && history.prevComposition != composition &&
                (history.prevTime < (tr.time || 0) - options.newGroupDelay || !isAdjacentTo(tr, history.prevRanges)));
        var prevRanges = appended ? mapRanges(history.prevRanges, tr.mapping) : rangesFor(tr.mapping.maps);
        return new HistoryState(history.done.addTransform(tr, newGroup ? state.selection.getBookmark() : undefined, options, mustPreserveItems(state)), Branch.empty, prevRanges, tr.time, composition == null ? history.prevComposition : composition);
    }
    else if (rebased = tr.getMeta("rebased")) {
        // Used by the collab module to tell the history that some of its
        // content has been rebased.
        return new HistoryState(history.done.rebased(tr, rebased), history.undone.rebased(tr, rebased), mapRanges(history.prevRanges, tr.mapping), history.prevTime, history.prevComposition);
    }
    else {
        return new HistoryState(history.done.addMaps(tr.mapping.maps), history.undone.addMaps(tr.mapping.maps), mapRanges(history.prevRanges, tr.mapping), history.prevTime, history.prevComposition);
    }
}
function isAdjacentTo(transform, prevRanges) {
    if (!prevRanges)
        { return false; }
    if (!transform.docChanged)
        { return true; }
    var adjacent = false;
    transform.mapping.maps[0].forEach(function (start, end) {
        for (var i = 0; i < prevRanges.length; i += 2)
            { if (start <= prevRanges[i + 1] && end >= prevRanges[i])
                { adjacent = true; } }
    });
    return adjacent;
}
function rangesFor(maps) {
    var result = [];
    for (var i = maps.length - 1; i >= 0 && result.length == 0; i--)
        { maps[i].forEach(function (_from, _to, from, to) { return result.push(from, to); }); }
    return result;
}
function mapRanges(ranges, mapping) {
    if (!ranges)
        { return null; }
    var result = [];
    for (var i = 0; i < ranges.length; i += 2) {
        var from = mapping.map(ranges[i], 1), to = mapping.map(ranges[i + 1], -1);
        if (from <= to)
            { result.push(from, to); }
    }
    return result;
}
// Apply the latest event from one branch to the document and shift the event
// onto the other branch.
function histTransaction(history, state, redo) {
    var preserveItems = mustPreserveItems(state);
    var histOptions = historyKey.get(state).spec.config;
    var pop = (redo ? history.undone : history.done).popEvent(state, preserveItems);
    if (!pop)
        { return null; }
    var selection = pop.selection.resolve(pop.transform.doc);
    var added = (redo ? history.done : history.undone).addTransform(pop.transform, state.selection.getBookmark(), histOptions, preserveItems);
    var newHist = new HistoryState(redo ? added : pop.remaining, redo ? pop.remaining : added, null, 0, -1);
    return pop.transform.setSelection(selection).setMeta(historyKey, { redo: redo, historyState: newHist });
}
var cachedPreserveItems = false, cachedPreserveItemsPlugins = null;
// Check whether any plugin in the given state has a
// `historyPreserveItems` property in its spec, in which case we must
// preserve steps exactly as they came in, so that they can be
// rebased.
function mustPreserveItems(state) {
    var plugins = state.plugins;
    if (cachedPreserveItemsPlugins != plugins) {
        cachedPreserveItems = false;
        cachedPreserveItemsPlugins = plugins;
        for (var i = 0; i < plugins.length; i++)
            { if (plugins[i].spec.historyPreserveItems) {
                cachedPreserveItems = true;
                break;
            } }
    }
    return cachedPreserveItems;
}
/**
Set a flag on the given transaction that will prevent further steps
from being appended to an existing history event (so that they
require a separate undo command to undo).
*/
function closeHistory(tr) {
    return tr.setMeta(closeHistoryKey, true);
}
var historyKey = new PluginKey("history");
var closeHistoryKey = new PluginKey("closeHistory");
/**
Returns a plugin that enables the undo history for an editor. The
plugin will track undo and redo stacks, which can be used with the
[`undo`](https://prosemirror.net/docs/ref/#history.undo) and [`redo`](https://prosemirror.net/docs/ref/#history.redo) commands.

You can set an `"addToHistory"` [metadata
property](https://prosemirror.net/docs/ref/#state.Transaction.setMeta) of `false` on a transaction
to prevent it from being rolled back by undo.
*/
function history(config) {
    if ( config === void 0 ) config = {};

    config = { depth: config.depth || 100,
        newGroupDelay: config.newGroupDelay || 500 };
    return new Plugin({
        key: historyKey,
        state: {
            init: function init() {
                return new HistoryState(Branch.empty, Branch.empty, null, 0, -1);
            },
            apply: function apply(tr, hist, state) {
                return applyTransaction(hist, state, tr, config);
            }
        },
        config: config,
        props: {
            handleDOMEvents: {
                beforeinput: function beforeinput(view, e) {
                    var inputType = e.inputType;
                    var command = inputType == "historyUndo" ? undo : inputType == "historyRedo" ? redo : null;
                    if (!command)
                        { return false; }
                    e.preventDefault();
                    return command(view.state, view.dispatch);
                }
            }
        }
    });
}
function buildCommand(redo, scroll) {
    return function (state, dispatch) {
        var hist = historyKey.getState(state);
        if (!hist || (redo ? hist.undone : hist.done).eventCount == 0)
            { return false; }
        if (dispatch) {
            var tr = histTransaction(hist, state, redo);
            if (tr)
                { dispatch(scroll ? tr.scrollIntoView() : tr); }
        }
        return true;
    };
}
/**
A command function that undoes the last change, if any.
*/
var undo = buildCommand(false, true);
/**
A command function that redoes the last undone change, if any.
*/
var redo = buildCommand(true, true);
/**
A command function that undoes the last change. Don't scroll the
selection into view.
*/
var undoNoScroll = buildCommand(false, false);
/**
A command function that redoes the last undone change. Don't
scroll the selection into view.
*/
var redoNoScroll = buildCommand(true, false);
/**
The amount of undoable events available in a given state.
*/
function undoDepth(state) {
    var hist = historyKey.getState(state);
    return hist ? hist.done.eventCount : 0;
}
/**
The amount of redoable events available in a given editor state.
*/
function redoDepth(state) {
    var hist = historyKey.getState(state);
    return hist ? hist.undone.eventCount : 0;
}var history$1=/*#__PURE__*/Object.freeze({__proto__:null,closeHistory:closeHistory,history:history,redo:redo,redoDepth:redoDepth,redoNoScroll:redoNoScroll,undo:undo,undoDepth:undoDepth,undoNoScroll:undoNoScroll});var base$2 = {
  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: "\""
};

var mac$2 = typeof navigator != "undefined" && /Mac/.test(navigator.platform);
var ie$1 = typeof navigator != "undefined" && /MSIE \d|Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(navigator.userAgent);

// Fill in the digit keys
for (var i$4 = 0; i$4 < 10; i$4++) { base$2[48 + i$4] = base$2[96 + i$4] = String(i$4); }

// The function keys
for (var i$4 = 1; i$4 <= 24; i$4++) { base$2[i$4 + 111] = "F" + i$4; }

// And the alphabetic keys
for (var i$4 = 65; i$4 <= 90; i$4++) {
  base$2[i$4] = String.fromCharCode(i$4 + 32);
  shift[i$4] = String.fromCharCode(i$4);
}

// For each code that doesn't have a shift-equivalent, copy the base name
for (var code$3 in base$2) { if (!shift.hasOwnProperty(code$3)) { shift[code$3] = base$2[code$3]; } }

function keyName(event) {
  // On macOS, keys held with Shift and Cmd don't reflect the effect of Shift in `.key`.
  // On IE, shift effect is never included in `.key`.
  var ignoreKey = mac$2 && event.metaKey && event.shiftKey && !event.ctrlKey && !event.altKey ||
      ie$1 && event.shiftKey && event.key && event.key.length == 1 ||
      event.key == "Unidentified";
  var name = (!ignoreKey && event.key) ||
    (event.shiftKey ? shift : base$2)[event.keyCode] ||
    event.key || "Unidentified";
  // Edge sometimes produces wrong names (Issue #3)
  if (name == "Esc") { name = "Escape"; }
  if (name == "Del") { name = "Delete"; }
  // https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/8860571/
  if (name == "Left") { name = "ArrowLeft"; }
  if (name == "Up") { name = "ArrowUp"; }
  if (name == "Right") { name = "ArrowRight"; }
  if (name == "Down") { name = "ArrowDown"; }
  return name
}var mac$1 = typeof navigator != "undefined" ? /Mac|iP(hone|[oa]d)/.test(navigator.platform) : false;
function normalizeKeyName$1(name) {
    var parts = name.split(/-(?!$)/), result = parts[parts.length - 1];
    if (result == "Space")
        { result = " "; }
    var alt, ctrl, shift, meta;
    for (var i = 0; i < parts.length - 1; i++) {
        var mod = parts[i];
        if (/^(cmd|meta|m)$/i.test(mod))
            { meta = true; }
        else if (/^a(lt)?$/i.test(mod))
            { alt = true; }
        else if (/^(c|ctrl|control)$/i.test(mod))
            { ctrl = true; }
        else if (/^s(hift)?$/i.test(mod))
            { shift = true; }
        else if (/^mod$/i.test(mod)) {
            if (mac$1)
                { meta = true; }
            else
                { ctrl = true; }
        }
        else
            { throw new Error("Unrecognized modifier name: " + mod); }
    }
    if (alt)
        { result = "Alt-" + result; }
    if (ctrl)
        { result = "Ctrl-" + result; }
    if (meta)
        { result = "Meta-" + result; }
    if (shift)
        { result = "Shift-" + result; }
    return result;
}
function normalize$2(map) {
    var copy = Object.create(null);
    for (var prop in map)
        { copy[normalizeKeyName$1(prop)] = map[prop]; }
    return copy;
}
function modifiers$1(name, event, shift) {
    if ( shift === void 0 ) shift = true;

    if (event.altKey)
        { name = "Alt-" + name; }
    if (event.ctrlKey)
        { name = "Ctrl-" + name; }
    if (event.metaKey)
        { name = "Meta-" + name; }
    if (shift && event.shiftKey)
        { name = "Shift-" + name; }
    return name;
}
/**
Create a keymap plugin for the given set of bindings.

Bindings should map key names to [command](https://prosemirror.net/docs/ref/#commands)-style
functions, which will be called with `(EditorState, dispatch,
EditorView)` arguments, and should return true when they've handled
the key. Note that the view argument isn't part of the command
protocol, but can be used as an escape hatch if a binding needs to
directly interact with the UI.

Key names may be strings like `"Shift-Ctrl-Enter"`—a key
identifier prefixed with zero or more modifiers. Key identifiers
are based on the strings that can appear in
[`KeyEvent.key`](https:developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key).
Use lowercase letters to refer to letter keys (or uppercase letters
if you want shift to be held). You may use `"Space"` as an alias
for the `" "` name.

Modifiers can be given in any order. `Shift-` (or `s-`), `Alt-` (or
`a-`), `Ctrl-` (or `c-` or `Control-`) and `Cmd-` (or `m-` or
`Meta-`) are recognized. For characters that are created by holding
shift, the `Shift-` prefix is implied, and should not be added
explicitly.

You can use `Mod-` as a shorthand for `Cmd-` on Mac and `Ctrl-` on
other platforms.

You can add multiple keymap plugins to an editor. The order in
which they appear determines their precedence (the ones early in
the array get to dispatch first).
*/
function keymap$5(bindings) {
    return new Plugin({ props: { handleKeyDown: keydownHandler(bindings) } });
}
/**
Given a set of bindings (using the same format as
[`keymap`](https://prosemirror.net/docs/ref/#keymap.keymap)), return a [keydown
handler](https://prosemirror.net/docs/ref/#view.EditorProps.handleKeyDown) that handles them.
*/
function keydownHandler(bindings) {
    var map = normalize$2(bindings);
    return function (view, event) {
        var name = keyName(event), baseName, direct = map[modifiers$1(name, event)];
        if (direct && direct(view.state, view.dispatch, view))
            { return true; }
        // A character key
        if (name.length == 1 && name != " ") {
            if (event.shiftKey) {
                // In case the name was already modified by shift, try looking
                // it up without its shift modifier
                var noShift = map[modifiers$1(name, event, false)];
                if (noShift && noShift(view.state, view.dispatch, view))
                    { return true; }
            }
            if ((event.shiftKey || event.altKey || event.metaKey || name.charCodeAt(0) > 127) &&
                (baseName = base$2[event.keyCode]) && baseName != name) {
                // Try falling back to the keyCode when there's a modifier
                // active or the character produced isn't ASCII, and our table
                // produces a different name from the the keyCode. See #668,
                // #1060
                var fromCode = map[modifiers$1(baseName, event)];
                if (fromCode && fromCode(view.state, view.dispatch, view))
                    { return true; }
            }
        }
        return false;
    };
}var keymap$6=/*#__PURE__*/Object.freeze({__proto__:null,keydownHandler:keydownHandler,keymap:keymap$5});function crelt() {
  var arguments$1 = arguments;

  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$1[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)
  }
}var SVG$1 = "http://www.w3.org/2000/svg";
var XLINK$1 = "http://www.w3.org/1999/xlink";
var prefix$2$1 = "ProseMirror-icon";
function hashPath(path) {
    var hash = 0;
    for (var i = 0; i < path.length; i++)
        { hash = (((hash << 5) - hash) + path.charCodeAt(i)) | 0; }
    return hash;
}
function getIcon$1(root, icon) {
    var doc = (root.nodeType == 9 ? root : root.ownerDocument) || document;
    var node = doc.createElement("div");
    node.className = prefix$2$1;
    if (icon.path) {
        var path = icon.path;
        var width = icon.width;
        var height = icon.height;
        var name = "pm-icon-" + hashPath(path).toString(16);
        if (!doc.getElementById(name))
            { buildSVG$1(root, name, icon); }
        var svg = node.appendChild(doc.createElementNS(SVG$1, "svg"));
        svg.style.width = (width / height) + "em";
        var use = svg.appendChild(doc.createElementNS(SVG$1, "use"));
        use.setAttributeNS(XLINK$1, "href", /([^#]*)/.exec(doc.location.toString())[1] + "#" + name);
    }
    else if (icon.dom) {
        node.appendChild(icon.dom.cloneNode(true));
    }
    else {
        var text = icon.text;
        var css = icon.css;
        node.appendChild(doc.createElement("span")).textContent = text || '';
        if (css)
            { node.firstChild.style.cssText = css; }
    }
    return node;
}
function buildSVG$1(root, name, data) {
    var ref = root.nodeType == 9 ? [root, root.body] : [root.ownerDocument || document, root];
    var doc = ref[0];
    var top = ref[1];
    var collection = doc.getElementById(prefix$2$1 + "-collection");
    if (!collection) {
        collection = doc.createElementNS(SVG$1, "svg");
        collection.id = prefix$2$1 + "-collection";
        collection.style.display = "none";
        top.insertBefore(collection, top.firstChild);
    }
    var sym = doc.createElementNS(SVG$1, "symbol");
    sym.id = name;
    sym.setAttribute("viewBox", "0 0 " + data.width + " " + data.height);
    var path = sym.appendChild(doc.createElementNS(SVG$1, "path"));
    path.setAttribute("d", data.path);
    collection.appendChild(sym);
}

var prefix$1$1 = "ProseMirror-menu";
/**
An icon or label that, when clicked, executes a command.
*/
var MenuItem$1 = function MenuItem(
/**
The spec used to create this item.
*/
spec) {
    this.spec = spec;
};
/**
Renders the icon according to its [display
spec](https://prosemirror.net/docs/ref/#menu.MenuItemSpec.display), and adds an event handler which
executes the command when the representation is clicked.
*/
MenuItem$1.prototype.render = function render (view) {
    var spec = this.spec;
    var dom = spec.render ? spec.render(view)
        : spec.icon ? getIcon$1(view.root, spec.icon)
            : spec.label ? crelt("div", null, translate$2(view, spec.label))
                : null;
    if (!dom)
        { throw new RangeError("MenuItem without icon or label property"); }
    if (spec.title) {
        var title = (typeof spec.title === "function" ? spec.title(view.state) : spec.title);
        dom.setAttribute("title", translate$2(view, title));
    }
    if (spec.class)
        { dom.classList.add(spec.class); }
    if (spec.css)
        { dom.style.cssText += spec.css; }
    dom.addEventListener("mousedown", function (e) {
        e.preventDefault();
        if (!dom.classList.contains(prefix$1$1 + "-disabled"))
            { spec.run(view.state, view.dispatch, view, e); }
    });
    function update(state) {
        if (spec.select) {
            var selected = spec.select(state);
            dom.style.display = selected ? "" : "none";
            if (!selected)
                { return false; }
        }
        var enabled = true;
        if (spec.enable) {
            enabled = spec.enable(state) || false;
            setClass$1(dom, prefix$1$1 + "-disabled", !enabled);
        }
        if (spec.active) {
            var active = enabled && spec.active(state) || false;
            setClass$1(dom, prefix$1$1 + "-active", active);
        }
        return true;
    }
    return { dom: dom, update: update };
};
function translate$2(view, text) {
    return view._props.translate ? view._props.translate(text) : text;
}
var lastMenuEvent$1 = { time: 0, node: null };
function markMenuEvent$1(e) {
    lastMenuEvent$1.time = Date.now();
    lastMenuEvent$1.node = e.target;
}
function isMenuEvent$1(wrapper) {
    return Date.now() - 100 < lastMenuEvent$1.time &&
        lastMenuEvent$1.node && wrapper.contains(lastMenuEvent$1.node);
}
/**
A drop-down menu, displayed as a label with a downwards-pointing
triangle to the right of it.
*/
var Dropdown$1 = function Dropdown(content, 
/**
@internal
*/
options) {
    if ( options === void 0 ) options = {};

    this.options = options;
    this.options = options || {};
    this.content = Array.isArray(content) ? content : [content];
};
/**
Render the dropdown menu and sub-items.
*/
Dropdown$1.prototype.render = function render (view) {
        var this$1$1 = this;

    var content = renderDropdownItems(this.content, view);
    var win = view.dom.ownerDocument.defaultView || window;
    var label = crelt("div", { class: prefix$1$1 + "-dropdown " + (this.options.class || ""),
        style: this.options.css }, translate$2(view, this.options.label || ""));
    if (this.options.title)
        { label.setAttribute("title", translate$2(view, this.options.title)); }
    var wrap = crelt("div", { class: prefix$1$1 + "-dropdown-wrap" }, label);
    var open = null;
    var listeningOnClose = null;
    var close = function () {
        if (open && open.close()) {
            open = null;
            win.removeEventListener("mousedown", listeningOnClose);
        }
    };
    label.addEventListener("mousedown", function (e) {
        e.preventDefault();
        markMenuEvent$1(e);
        if (open) {
            close();
        }
        else {
            open = this$1$1.expand(wrap, content.dom);
            win.addEventListener("mousedown", listeningOnClose = function () {
                if (!isMenuEvent$1(wrap))
                    { close(); }
            });
        }
    });
    function update(state) {
        var inner = content.update(state);
        wrap.style.display = inner ? "" : "none";
        return inner;
    }
    return { dom: wrap, update: update };
};
/**
@internal
*/
Dropdown$1.prototype.expand = function expand (dom, items) {
    var menuDOM = crelt("div", { class: prefix$1$1 + "-dropdown-menu " + (this.options.class || "") }, items);
    var done = false;
    function close() {
        if (done)
            { return false; }
        done = true;
        dom.removeChild(menuDOM);
        return true;
    }
    dom.appendChild(menuDOM);
    return { close: close, node: menuDOM };
};
function renderDropdownItems(items, view) {
    var rendered = [], updates = [];
    for (var i = 0; i < items.length; i++) {
        var ref = items[i].render(view);
        var dom = ref.dom;
        var update = ref.update;
        rendered.push(crelt("div", { class: prefix$1$1 + "-dropdown-item" }, dom));
        updates.push(update);
    }
    return { dom: rendered, update: combineUpdates(updates, rendered) };
}
function combineUpdates(updates, nodes) {
    return function (state) {
        var something = false;
        for (var i = 0; i < updates.length; i++) {
            var up = updates[i](state);
            nodes[i].style.display = up ? "" : "none";
            if (up)
                { something = true; }
        }
        return something;
    };
}
/**
Represents a submenu wrapping a group of elements that start
hidden and expand to the right when hovered over or tapped.
*/
var DropdownSubmenu$1 = function DropdownSubmenu(content, 
/**
@internal
*/
options) {
    if ( options === void 0 ) options = {};

    this.options = options;
    this.content = Array.isArray(content) ? content : [content];
};
/**
Renders the submenu.
*/
DropdownSubmenu$1.prototype.render = function render (view) {
    var items = renderDropdownItems(this.content, view);
    var win = view.dom.ownerDocument.defaultView || window;
    var label = crelt("div", { class: prefix$1$1 + "-submenu-label" }, translate$2(view, this.options.label || ""));
    var wrap = crelt("div", { class: prefix$1$1 + "-submenu-wrap" }, label, crelt("div", { class: prefix$1$1 + "-submenu" }, items.dom));
    var listeningOnClose = null;
    label.addEventListener("mousedown", function (e) {
        e.preventDefault();
        markMenuEvent$1(e);
        setClass$1(wrap, prefix$1$1 + "-submenu-wrap-active", false);
        if (!listeningOnClose)
            { win.addEventListener("mousedown", listeningOnClose = function () {
                if (!isMenuEvent$1(wrap)) {
                    wrap.classList.remove(prefix$1$1 + "-submenu-wrap-active");
                    win.removeEventListener("mousedown", listeningOnClose);
                    listeningOnClose = null;
                }
            }); }
    });
    function update(state) {
        var inner = items.update(state);
        wrap.style.display = inner ? "" : "none";
        return inner;
    }
    return { dom: wrap, update: update };
};
/**
Render the given, possibly nested, array of menu elements into a
document fragment, placing separators between them (and ensuring no
superfluous separators appear when some of the groups turn out to
be empty).
*/
function renderGrouped(view, content) {
    var result = document.createDocumentFragment();
    var updates = [], separators = [];
    for (var i = 0; i < content.length; i++) {
        var items = content[i], localUpdates = [], localNodes = [];
        for (var j = 0; j < items.length; j++) {
            var ref = items[j].render(view);
            var dom = ref.dom;
            var update$1 = ref.update;
            var span = crelt("span", { class: prefix$1$1 + "item" }, dom);
            result.appendChild(span);
            localNodes.push(span);
            localUpdates.push(update$1);
        }
        if (localUpdates.length) {
            updates.push(combineUpdates(localUpdates, localNodes));
            if (i < content.length - 1)
                { separators.push(result.appendChild(separator())); }
        }
    }
    function update(state) {
        var something = false, needSep = false;
        for (var i = 0; i < updates.length; i++) {
            var hasContent = updates[i](state);
            if (i)
                { separators[i - 1].style.display = needSep && hasContent ? "" : "none"; }
            needSep = hasContent;
            if (hasContent)
                { something = true; }
        }
        return something;
    }
    return { dom: result, update: update };
}
function separator() {
    return crelt("span", { class: prefix$1$1 + "separator" });
}
/**
A set of basic editor-related icons. Contains the properties
`join`, `lift`, `selectParentNode`, `undo`, `redo`, `strong`, `em`,
`code`, `link`, `bulletList`, `orderedList`, and `blockquote`, each
holding an object that can be used as the `icon` option to
`MenuItem`.
*/
var icons$1 = {
    join: {
        width: 800, height: 900,
        path: "M0 75h800v125h-800z M0 825h800v-125h-800z M250 400h100v-100h100v100h100v100h-100v100h-100v-100h-100z"
    },
    lift: {
        width: 1024, height: 1024,
        path: "M219 310v329q0 7-5 12t-12 5q-8 0-13-5l-164-164q-5-5-5-13t5-13l164-164q5-5 13-5 7 0 12 5t5 12zM1024 749v109q0 7-5 12t-12 5h-987q-7 0-12-5t-5-12v-109q0-7 5-12t12-5h987q7 0 12 5t5 12zM1024 530v109q0 7-5 12t-12 5h-621q-7 0-12-5t-5-12v-109q0-7 5-12t12-5h621q7 0 12 5t5 12zM1024 310v109q0 7-5 12t-12 5h-621q-7 0-12-5t-5-12v-109q0-7 5-12t12-5h621q7 0 12 5t5 12zM1024 91v109q0 7-5 12t-12 5h-987q-7 0-12-5t-5-12v-109q0-7 5-12t12-5h987q7 0 12 5t5 12z"
    },
    selectParentNode: { text: "\u2b1a", css: "font-weight: bold" },
    undo: {
        width: 1024, height: 1024,
        path: "M761 1024c113-206 132-520-313-509v253l-384-384 384-384v248c534-13 594 472 313 775z"
    },
    redo: {
        width: 1024, height: 1024,
        path: "M576 248v-248l384 384-384 384v-253c-446-10-427 303-313 509-280-303-221-789 313-775z"
    },
    strong: {
        width: 805, height: 1024,
        path: "M317 869q42 18 80 18 214 0 214-191 0-65-23-102-15-25-35-42t-38-26-46-14-48-6-54-1q-41 0-57 5 0 30-0 90t-0 90q0 4-0 38t-0 55 2 47 6 38zM309 442q24 4 62 4 46 0 81-7t62-25 42-51 14-81q0-40-16-70t-45-46-61-24-70-8q-28 0-74 7 0 28 2 86t2 86q0 15-0 45t-0 45q0 26 0 39zM0 950l1-53q8-2 48-9t60-15q4-6 7-15t4-19 3-18 1-21 0-19v-37q0-561-12-585-2-4-12-8t-25-6-28-4-27-2-17-1l-2-47q56-1 194-6t213-5q13 0 39 0t38 0q40 0 78 7t73 24 61 40 42 59 16 78q0 29-9 54t-22 41-36 32-41 25-48 22q88 20 146 76t58 141q0 57-20 102t-53 74-78 48-93 27-100 8q-25 0-75-1t-75-1q-60 0-175 6t-132 6z"
    },
    em: {
        width: 585, height: 1024,
        path: "M0 949l9-48q3-1 46-12t63-21q16-20 23-57 0-4 35-165t65-310 29-169v-14q-13-7-31-10t-39-4-33-3l10-58q18 1 68 3t85 4 68 1q27 0 56-1t69-4 56-3q-2 22-10 50-17 5-58 16t-62 19q-4 10-8 24t-5 22-4 26-3 24q-15 84-50 239t-44 203q-1 5-7 33t-11 51-9 47-3 32l0 10q9 2 105 17-1 25-9 56-6 0-18 0t-18 0q-16 0-49-5t-49-5q-78-1-117-1-29 0-81 5t-69 6z"
    },
    code: {
        width: 896, height: 1024,
        path: "M608 192l-96 96 224 224-224 224 96 96 288-320-288-320zM288 192l-288 320 288 320 96-96-224-224 224-224-96-96z"
    },
    link: {
        width: 951, height: 1024,
        path: "M832 694q0-22-16-38l-118-118q-16-16-38-16-24 0-41 18 1 1 10 10t12 12 8 10 7 14 2 15q0 22-16 38t-38 16q-8 0-15-2t-14-7-10-8-12-12-10-10q-18 17-18 41 0 22 16 38l117 118q15 15 38 15 22 0 38-14l84-83q16-16 16-38zM430 292q0-22-16-38l-117-118q-16-16-38-16-22 0-38 15l-84 83q-16 16-16 38 0 22 16 38l118 118q15 15 38 15 24 0 41-17-1-1-10-10t-12-12-8-10-7-14-2-15q0-22 16-38t38-16q8 0 15 2t14 7 10 8 12 12 10 10q18-17 18-41zM941 694q0 68-48 116l-84 83q-47 47-116 47-69 0-116-48l-117-118q-47-47-47-116 0-70 50-119l-50-50q-49 50-118 50-68 0-116-48l-118-118q-48-48-48-116t48-116l84-83q47-47 116-47 69 0 116 48l117 118q47 47 47 116 0 70-50 119l50 50q49-50 118-50 68 0 116 48l118 118q48 48 48 116z"
    },
    bulletList: {
        width: 768, height: 896,
        path: "M0 512h128v-128h-128v128zM0 256h128v-128h-128v128zM0 768h128v-128h-128v128zM256 512h512v-128h-512v128zM256 256h512v-128h-512v128zM256 768h512v-128h-512v128z"
    },
    orderedList: {
        width: 768, height: 896,
        path: "M320 512h448v-128h-448v128zM320 768h448v-128h-448v128zM320 128v128h448v-128h-448zM79 384h78v-256h-36l-85 23v50l43-2v185zM189 590c0-36-12-78-96-78-33 0-64 6-83 16l1 66c21-10 42-15 67-15s32 11 32 28c0 26-30 58-110 112v50h192v-67l-91 2c49-30 87-66 87-113l1-1z"
    },
    blockquote: {
        width: 640, height: 896,
        path: "M0 448v256h256v-256h-128c0 0 0-128 128-128v-128c0 0-256 0-256 256zM640 320v-128c0 0-256 0-256 256v256h256v-256h-128c0 0 0-128 128-128z"
    }
};
/**
Menu item for the `joinUp` command.
*/
var joinUpItem$1 = new MenuItem$1({
    title: "Join with above block",
    run: joinUp,
    select: function (state) { return joinUp(state); },
    icon: icons$1.join
});
/**
Menu item for the `lift` command.
*/
var liftItem$1 = new MenuItem$1({
    title: "Lift out of enclosing block",
    run: lift$1,
    select: function (state) { return lift$1(state); },
    icon: icons$1.lift
});
/**
Menu item for the `selectParentNode` command.
*/
var selectParentNodeItem$1 = new MenuItem$1({
    title: "Select parent node",
    run: selectParentNode,
    select: function (state) { return selectParentNode(state); },
    icon: icons$1.selectParentNode
});
/**
Menu item for the `undo` command.
*/
var undoItem$1 = new MenuItem$1({
    title: "Undo last change",
    run: undo,
    enable: function (state) { return undo(state); },
    icon: icons$1.undo
});
/**
Menu item for the `redo` command.
*/
var redoItem$1 = new MenuItem$1({
    title: "Redo last undone change",
    run: redo,
    enable: function (state) { return redo(state); },
    icon: icons$1.redo
});
/**
Build a menu item for wrapping the selection in a given node type.
Adds `run` and `select` properties to the ones present in
`options`. `options.attrs` may be an object that provides
attributes for the wrapping node.
*/
function wrapItem$1(nodeType, options) {
    var passedOptions = {
        run: function run(state, dispatch) {
            return wrapIn(nodeType, options.attrs)(state, dispatch);
        },
        select: function select(state) {
            return wrapIn(nodeType, options.attrs)(state);
        }
    };
    for (var prop in options)
        { passedOptions[prop] = options[prop]; }
    return new MenuItem$1(passedOptions);
}
/**
Build a menu item for changing the type of the textblock around the
selection to the given type. Provides `run`, `active`, and `select`
properties. Others must be given in `options`. `options.attrs` may
be an object to provide the attributes for the textblock node.
*/
function blockTypeItem$1(nodeType, options) {
    var command = setBlockType(nodeType, options.attrs);
    var passedOptions = {
        run: command,
        enable: function enable(state) { return command(state); },
        active: function active(state) {
            var ref = state.selection;
            var $from = ref.$from;
            var to = ref.to;
            var node = ref.node;
            if (node)
                { return node.hasMarkup(nodeType, options.attrs); }
            return to <= $from.end() && $from.parent.hasMarkup(nodeType, options.attrs);
        }
    };
    for (var prop in options)
        { passedOptions[prop] = options[prop]; }
    return new MenuItem$1(passedOptions);
}
// Work around classList.toggle being broken in IE11
function setClass$1(dom, cls, on) {
    if (on)
        { dom.classList.add(cls); }
    else
        { dom.classList.remove(cls); }
}

var prefix$3 = "ProseMirror-menubar";
function isIOS$1() {
    if (typeof navigator == "undefined")
        { return false; }
    var agent = navigator.userAgent;
    return !/Edge\/\d/.test(agent) && /AppleWebKit/.test(agent) && /Mobile\/\w+/.test(agent);
}
/**
A plugin that will place a menu bar above the editor. Note that
this involves wrapping the editor in an additional `<div>`.
*/
function menuBar$1(options) {
    return new Plugin({
        view: function view(editorView) { return new MenuBarView$1(editorView, options); }
    });
}
var MenuBarView$1 = function MenuBarView(editorView, options) {
    var this$1$1 = this;

    this.editorView = editorView;
    this.options = options;
    this.spacer = null;
    this.maxHeight = 0;
    this.widthForMaxHeight = 0;
    this.floating = false;
    this.scrollHandler = null;
    this.wrapper = crelt("div", { class: prefix$3 + "-wrapper" });
    this.menu = this.wrapper.appendChild(crelt("div", { class: prefix$3 }));
    this.menu.className = prefix$3;
    if (editorView.dom.parentNode)
        { editorView.dom.parentNode.replaceChild(this.wrapper, editorView.dom); }
    this.wrapper.appendChild(editorView.dom);
    var ref = renderGrouped(this.editorView, this.options.content);
    var dom = ref.dom;
    var update = ref.update;
    this.contentUpdate = update;
    this.menu.appendChild(dom);
    this.update();
    if (options.floating && !isIOS$1()) {
        this.updateFloat();
        var potentialScrollers = getAllWrapping(this.wrapper);
        this.scrollHandler = function (e) {
            var root = this$1$1.editorView.root;
            if (!(root.body || root).contains(this$1$1.wrapper))
                { potentialScrollers.forEach(function (el) { return el.removeEventListener("scroll", this$1$1.scrollHandler); }); }
            else
                { this$1$1.updateFloat(e.target.getBoundingClientRect ? e.target : undefined); }
        };
        potentialScrollers.forEach(function (el) { return el.addEventListener('scroll', this$1$1.scrollHandler); });
    }
};
MenuBarView$1.prototype.update = function update () {
    this.contentUpdate(this.editorView.state);
    if (this.floating) {
        this.updateScrollCursor();
    }
    else {
        if (this.menu.offsetWidth != this.widthForMaxHeight) {
            this.widthForMaxHeight = this.menu.offsetWidth;
            this.maxHeight = 0;
        }
        if (this.menu.offsetHeight > this.maxHeight) {
            this.maxHeight = this.menu.offsetHeight;
            this.menu.style.minHeight = this.maxHeight + "px";
        }
    }
};
MenuBarView$1.prototype.updateScrollCursor = function updateScrollCursor () {
    var selection = this.editorView.root.getSelection();
    if (!selection.focusNode)
        { return; }
    var rects = selection.getRangeAt(0).getClientRects();
    var selRect = rects[selectionIsInverted$1(selection) ? 0 : rects.length - 1];
    if (!selRect)
        { return; }
    var menuRect = this.menu.getBoundingClientRect();
    if (selRect.top < menuRect.bottom && selRect.bottom > menuRect.top) {
        var scrollable = findWrappingScrollable$1(this.wrapper);
        if (scrollable)
            { scrollable.scrollTop -= (menuRect.bottom - selRect.top); }
    }
};
MenuBarView$1.prototype.updateFloat = function updateFloat (scrollAncestor) {
    var parent = this.wrapper, editorRect = parent.getBoundingClientRect(), top = scrollAncestor ? Math.max(0, scrollAncestor.getBoundingClientRect().top) : 0;
    if (this.floating) {
        if (editorRect.top >= top || editorRect.bottom < this.menu.offsetHeight + 10) {
            this.floating = false;
            this.menu.style.position = this.menu.style.left = this.menu.style.top = this.menu.style.width = "";
            this.menu.style.display = "";
            this.spacer.parentNode.removeChild(this.spacer);
            this.spacer = null;
        }
        else {
            var border = (parent.offsetWidth - parent.clientWidth) / 2;
            this.menu.style.left = (editorRect.left + border) + "px";
            this.menu.style.display = editorRect.top > (this.editorView.dom.ownerDocument.defaultView || window).innerHeight
                ? "none" : "";
            if (scrollAncestor)
                { this.menu.style.top = top + "px"; }
        }
    }
    else {
        if (editorRect.top < top && editorRect.bottom >= this.menu.offsetHeight + 10) {
            this.floating = true;
            var menuRect = this.menu.getBoundingClientRect();
            this.menu.style.left = menuRect.left + "px";
            this.menu.style.width = menuRect.width + "px";
            if (scrollAncestor)
                { this.menu.style.top = top + "px"; }
            this.menu.style.position = "fixed";
            this.spacer = crelt("div", { class: prefix$3 + "-spacer", style: ("height: " + (menuRect.height) + "px") });
            parent.insertBefore(this.spacer, this.menu);
        }
    }
};
MenuBarView$1.prototype.destroy = function destroy () {
    if (this.wrapper.parentNode)
        { this.wrapper.parentNode.replaceChild(this.editorView.dom, this.wrapper); }
};
// Not precise, but close enough
function selectionIsInverted$1(selection) {
    if (selection.anchorNode == selection.focusNode)
        { return selection.anchorOffset > selection.focusOffset; }
    return selection.anchorNode.compareDocumentPosition(selection.focusNode) == Node.DOCUMENT_POSITION_FOLLOWING;
}
function findWrappingScrollable$1(node) {
    for (var cur = node.parentNode; cur; cur = cur.parentNode)
        { if (cur.scrollHeight > cur.clientHeight)
            { return cur; } }
}
function getAllWrapping(node) {
    var res = [node.ownerDocument.defaultView || window];
    for (var cur = node.parentNode; cur; cur = cur.parentNode)
        { res.push(cur); }
    return res;
}var pmmenu=/*#__PURE__*/Object.freeze({__proto__:null,Dropdown:Dropdown$1,DropdownSubmenu:DropdownSubmenu$1,MenuItem:MenuItem$1,blockTypeItem:blockTypeItem$1,icons:icons$1,joinUpItem:joinUpItem$1,liftItem:liftItem$1,menuBar:menuBar$1,redoItem:redoItem$1,renderGrouped:renderGrouped,selectParentNodeItem:selectParentNodeItem$1,undoItem:undoItem$1,wrapItem:wrapItem$1});// src/index.ts

// src/tablemap.ts
var readFromCache;
var addToCache;
if (typeof WeakMap != "undefined") {
  var cache$1 = /* @__PURE__ */ new WeakMap();
  readFromCache = function (key) { return cache$1.get(key); };
  addToCache = function (key, value) {
    cache$1.set(key, value);
    return value;
  };
} else {
  var cache$1$1 = [];
  var cacheSize = 10;
  var cachePos = 0;
  readFromCache = function (key) {
    for (var i = 0; i < cache$1$1.length; i += 2)
      { if (cache$1$1[i] == key)
        { return cache$1$1[i + 1]; } }
  };
  addToCache = function (key, value) {
    if (cachePos == cacheSize)
      { cachePos = 0; }
    cache$1$1[cachePos++] = key;
    return cache$1$1[cachePos++] = value;
  };
}
var TableMap = /*@__PURE__*/(function () {
  function TableMap(width, height, map, problems) {
    this.width = width;
    this.height = height;
    this.map = map;
    this.problems = problems;
  }
  // Find the dimensions of the cell at the given position.
  TableMap.prototype.findCell = function findCell (pos) {
    for (var i = 0; i < this.map.length; i++) {
      var curPos = this.map[i];
      if (curPos != pos)
        { continue; }
      var left = i % this.width;
      var top = i / this.width | 0;
      var right = left + 1;
      var bottom = top + 1;
      for (var j = 1; right < this.width && this.map[i + j] == curPos; j++) {
        right++;
      }
      for (var j$1 = 1; bottom < this.height && this.map[i + this.width * j$1] == curPos; j$1++) {
        bottom++;
      }
      return { left: left, top: top, right: right, bottom: bottom };
    }
    throw new RangeError(("No cell with offset " + pos + " found"));
  };
  // Find the left side of the cell at the given position.
  TableMap.prototype.colCount = function colCount (pos) {
    for (var i = 0; i < this.map.length; i++) {
      if (this.map[i] == pos) {
        return i % this.width;
      }
    }
    throw new RangeError(("No cell with offset " + pos + " found"));
  };
  // Find the next cell in the given direction, starting from the cell
  // at `pos`, if any.
  TableMap.prototype.nextCell = function nextCell (pos, axis, dir) {
    var ref = this.findCell(pos);
    var left = ref.left;
    var right = ref.right;
    var top = ref.top;
    var bottom = ref.bottom;
    if (axis == "horiz") {
      if (dir < 0 ? left == 0 : right == this.width)
        { return null; }
      return this.map[top * this.width + (dir < 0 ? left - 1 : right)];
    } else {
      if (dir < 0 ? top == 0 : bottom == this.height)
        { return null; }
      return this.map[left + this.width * (dir < 0 ? top - 1 : bottom)];
    }
  };
  // Get the rectangle spanning the two given cells.
  TableMap.prototype.rectBetween = function rectBetween (a, b) {
    var ref = this.findCell(a);
    var leftA = ref.left;
    var rightA = ref.right;
    var topA = ref.top;
    var bottomA = ref.bottom;
    var ref$1 = this.findCell(b);
    var leftB = ref$1.left;
    var rightB = ref$1.right;
    var topB = ref$1.top;
    var bottomB = ref$1.bottom;
    return {
      left: Math.min(leftA, leftB),
      top: Math.min(topA, topB),
      right: Math.max(rightA, rightB),
      bottom: Math.max(bottomA, bottomB)
    };
  };
  // Return the position of all cells that have the top left corner in
  // the given rectangle.
  TableMap.prototype.cellsInRect = function cellsInRect (rect) {
    var result = [];
    var seen = {};
    for (var row = rect.top; row < rect.bottom; row++) {
      for (var col = rect.left; col < rect.right; col++) {
        var index = row * this.width + col;
        var pos = this.map[index];
        if (seen[pos])
          { continue; }
        seen[pos] = true;
        if (col == rect.left && col && this.map[index - 1] == pos || row == rect.top && row && this.map[index - this.width] == pos) {
          continue;
        }
        result.push(pos);
      }
    }
    return result;
  };
  // Return the position at which the cell at the given row and column
  // starts, or would start, if a cell started there.
  TableMap.prototype.positionAt = function positionAt (row, col, table) {
    for (var i = 0, rowStart = 0; ; i++) {
      var rowEnd = rowStart + table.child(i).nodeSize;
      if (i == row) {
        var index = col + row * this.width;
        var rowEndIndex = (row + 1) * this.width;
        while (index < rowEndIndex && this.map[index] < rowStart)
          { index++; }
        return index == rowEndIndex ? rowEnd - 1 : this.map[index];
      }
      rowStart = rowEnd;
    }
  };
  // Find the table map for the given table node.
  TableMap.get = function get (table) {
    return readFromCache(table) || addToCache(table, computeMap(table));
  };

  return TableMap;
}());
function computeMap(table) {
  if (table.type.spec.tableRole != "table")
    { throw new RangeError("Not a table node: " + table.type.name); }
  var width = findWidth(table), height = table.childCount;
  var map = [];
  var mapPos = 0;
  var problems = null;
  var colWidths = [];
  for (var i = 0, e = width * height; i < e; i++)
    { map[i] = 0; }
  for (var row = 0, pos = 0; row < height; row++) {
    var rowNode = table.child(row);
    pos++;
    for (var i$1 = 0; ; i$1++) {
      while (mapPos < map.length && map[mapPos] != 0)
        { mapPos++; }
      if (i$1 == rowNode.childCount)
        { break; }
      var cellNode = rowNode.child(i$1);
      var ref = cellNode.attrs;
      var colspan = ref.colspan;
      var rowspan = ref.rowspan;
      var colwidth = ref.colwidth;
      for (var h = 0; h < rowspan; h++) {
        if (h + row >= height) {
          (problems || (problems = [])).push({
            type: "overlong_rowspan",
            pos: pos,
            n: rowspan - h
          });
          break;
        }
        var start = mapPos + h * width;
        for (var w = 0; w < colspan; w++) {
          if (map[start + w] == 0)
            { map[start + w] = pos; }
          else
            { (problems || (problems = [])).push({
              type: "collision",
              row: row,
              pos: pos,
              n: colspan - w
            }); }
          var colW = colwidth && colwidth[w];
          if (colW) {
            var widthIndex = (start + w) % width * 2, prev = colWidths[widthIndex];
            if (prev == null || prev != colW && colWidths[widthIndex + 1] == 1) {
              colWidths[widthIndex] = colW;
              colWidths[widthIndex + 1] = 1;
            } else if (prev == colW) {
              colWidths[widthIndex + 1]++;
            }
          }
        }
      }
      mapPos += colspan;
      pos += cellNode.nodeSize;
    }
    var expectedPos = (row + 1) * width;
    var missing = 0;
    while (mapPos < expectedPos)
      { if (map[mapPos++] == 0)
        { missing++; } }
    if (missing)
      { (problems || (problems = [])).push({ type: "missing", row: row, n: missing }); }
    pos++;
  }
  var tableMap = new TableMap(width, height, map, problems);
  var badWidths = false;
  for (var i$2 = 0; !badWidths && i$2 < colWidths.length; i$2 += 2)
    { if (colWidths[i$2] != null && colWidths[i$2 + 1] < height)
      { badWidths = true; } }
  if (badWidths)
    { findBadColWidths(tableMap, colWidths, table); }
  return tableMap;
}
function findWidth(table) {
  var width = -1;
  var hasRowSpan = false;
  for (var row = 0; row < table.childCount; row++) {
    var rowNode = table.child(row);
    var rowWidth = 0;
    if (hasRowSpan)
      { for (var j = 0; j < row; j++) {
        var prevRow = table.child(j);
        for (var i = 0; i < prevRow.childCount; i++) {
          var cell = prevRow.child(i);
          if (j + cell.attrs.rowspan > row)
            { rowWidth += cell.attrs.colspan; }
        }
      } }
    for (var i$1 = 0; i$1 < rowNode.childCount; i$1++) {
      var cell$1 = rowNode.child(i$1);
      rowWidth += cell$1.attrs.colspan;
      if (cell$1.attrs.rowspan > 1)
        { hasRowSpan = true; }
    }
    if (width == -1)
      { width = rowWidth; }
    else if (width != rowWidth)
      { width = Math.max(width, rowWidth); }
  }
  return width;
}
function findBadColWidths(map, colWidths, table) {
  if (!map.problems)
    { map.problems = []; }
  var seen = {};
  for (var i = 0; i < map.map.length; i++) {
    var pos = map.map[i];
    if (seen[pos])
      { continue; }
    seen[pos] = true;
    var node = table.nodeAt(pos);
    if (!node) {
      throw new RangeError(("No cell with offset " + pos + " found"));
    }
    var updated = null;
    var attrs = node.attrs;
    for (var j = 0; j < attrs.colspan; j++) {
      var col = (i + j) % map.width;
      var colWidth = colWidths[col * 2];
      if (colWidth != null && (!attrs.colwidth || attrs.colwidth[j] != colWidth))
        { (updated || (updated = freshColWidth(attrs)))[j] = colWidth; }
    }
    if (updated)
      { map.problems.unshift({
        type: "colwidth mismatch",
        pos: pos,
        colwidth: updated
      }); }
  }
}
function freshColWidth(attrs) {
  if (attrs.colwidth)
    { return attrs.colwidth.slice(); }
  var result = [];
  for (var i = 0; i < attrs.colspan; i++)
    { result.push(0); }
  return result;
}

// src/schema.ts
function getCellAttrs(dom, extraAttrs) {
  if (typeof dom === "string") {
    return {};
  }
  var widthAttr = dom.getAttribute("data-colwidth");
  var widths = widthAttr && /^\d+(,\d+)*$/.test(widthAttr) ? widthAttr.split(",").map(function (s) { return Number(s); }) : null;
  var colspan = Number(dom.getAttribute("colspan") || 1);
  var result = {
    colspan: colspan,
    rowspan: Number(dom.getAttribute("rowspan") || 1),
    colwidth: widths && widths.length == colspan ? widths : null
  };
  for (var prop in extraAttrs) {
    var getter = extraAttrs[prop].getFromDOM;
    var value = getter && getter(dom);
    if (value != null) {
      result[prop] = value;
    }
  }
  return result;
}
function setCellAttrs(node, extraAttrs) {
  var attrs = {};
  if (node.attrs.colspan != 1)
    { attrs.colspan = node.attrs.colspan; }
  if (node.attrs.rowspan != 1)
    { attrs.rowspan = node.attrs.rowspan; }
  if (node.attrs.colwidth)
    { attrs["data-colwidth"] = node.attrs.colwidth.join(","); }
  for (var prop in extraAttrs) {
    var setter = extraAttrs[prop].setDOMAttr;
    if (setter)
      { setter(node.attrs[prop], attrs); }
  }
  return attrs;
}
function tableNodes(options) {
  var extraAttrs = options.cellAttributes || {};
  var cellAttrs = {
    colspan: { default: 1 },
    rowspan: { default: 1 },
    colwidth: { default: null }
  };
  for (var prop in extraAttrs)
    { cellAttrs[prop] = { default: extraAttrs[prop].default }; }
  return {
    table: {
      content: "table_row+",
      tableRole: "table",
      isolating: true,
      group: options.tableGroup,
      parseDOM: [{ tag: "table" }],
      toDOM: function toDOM() {
        return ["table", ["tbody", 0]];
      }
    },
    table_row: {
      content: "(table_cell | table_header)*",
      tableRole: "row",
      parseDOM: [{ tag: "tr" }],
      toDOM: function toDOM() {
        return ["tr", 0];
      }
    },
    table_cell: {
      content: options.cellContent,
      attrs: cellAttrs,
      tableRole: "cell",
      isolating: true,
      parseDOM: [
        { tag: "td", getAttrs: function (dom) { return getCellAttrs(dom, extraAttrs); } }
      ],
      toDOM: function toDOM(node) {
        return ["td", setCellAttrs(node, extraAttrs), 0];
      }
    },
    table_header: {
      content: options.cellContent,
      attrs: cellAttrs,
      tableRole: "header_cell",
      isolating: true,
      parseDOM: [
        { tag: "th", getAttrs: function (dom) { return getCellAttrs(dom, extraAttrs); } }
      ],
      toDOM: function toDOM(node) {
        return ["th", setCellAttrs(node, extraAttrs), 0];
      }
    }
  };
}
function tableNodeTypes(schema) {
  var result = schema.cached.tableNodeTypes;
  if (!result) {
    result = schema.cached.tableNodeTypes = {};
    for (var name in schema.nodes) {
      var type = schema.nodes[name], role = type.spec.tableRole;
      if (role)
        { result[role] = type; }
    }
  }
  return result;
}

// src/util.ts
var tableEditingKey = new PluginKey("selectingCells");
function cellAround($pos) {
  for (var d = $pos.depth - 1; d > 0; d--)
    { if ($pos.node(d).type.spec.tableRole == "row")
      { return $pos.node(0).resolve($pos.before(d + 1)); } }
  return null;
}
function isInTable(state) {
  var $head = state.selection.$head;
  for (var d = $head.depth; d > 0; d--)
    { if ($head.node(d).type.spec.tableRole == "row")
      { return true; } }
  return false;
}
function selectionCell(state) {
  var sel = state.selection;
  if ("$anchorCell" in sel && sel.$anchorCell) {
    return sel.$anchorCell.pos > sel.$headCell.pos ? sel.$anchorCell : sel.$headCell;
  } else if ("node" in sel && sel.node && sel.node.type.spec.tableRole == "cell") {
    return sel.$anchor;
  }
  var $cell = cellAround(sel.$head) || cellNear(sel.$head);
  if ($cell) {
    return $cell;
  }
  throw new RangeError(("No cell found around position " + (sel.head)));
}
function cellNear($pos) {
  for (var after = $pos.nodeAfter, pos = $pos.pos; after; after = after.firstChild, pos++) {
    var role = after.type.spec.tableRole;
    if (role == "cell" || role == "header_cell")
      { return $pos.doc.resolve(pos); }
  }
  for (var before = $pos.nodeBefore, pos$1 = $pos.pos; before; before = before.lastChild, pos$1--) {
    var role$1 = before.type.spec.tableRole;
    if (role$1 == "cell" || role$1 == "header_cell")
      { return $pos.doc.resolve(pos$1 - before.nodeSize); }
  }
}
function pointsAtCell($pos) {
  return $pos.parent.type.spec.tableRole == "row" && !!$pos.nodeAfter;
}
function moveCellForward($pos) {
  return $pos.node(0).resolve($pos.pos + $pos.nodeAfter.nodeSize);
}
function inSameTable($cellA, $cellB) {
  return $cellA.depth == $cellB.depth && $cellA.pos >= $cellB.start(-1) && $cellA.pos <= $cellB.end(-1);
}
function nextCell($pos, axis, dir) {
  var table = $pos.node(-1);
  var map = TableMap.get(table);
  var tableStart = $pos.start(-1);
  var moved = map.nextCell($pos.pos - tableStart, axis, dir);
  return moved == null ? null : $pos.node(0).resolve(tableStart + moved);
}
function removeColSpan(attrs, pos, n) {
  if ( n === void 0 ) n = 1;

  var result = Object.assign({}, attrs, {colspan: attrs.colspan - n});
  if (result.colwidth) {
    result.colwidth = result.colwidth.slice();
    result.colwidth.splice(pos, n);
    if (!result.colwidth.some(function (w) { return w > 0; }))
      { result.colwidth = null; }
  }
  return result;
}
function addColSpan(attrs, pos, n) {
  if ( n === void 0 ) n = 1;

  var result = Object.assign({}, attrs, {colspan: attrs.colspan + n});
  if (result.colwidth) {
    result.colwidth = result.colwidth.slice();
    for (var i = 0; i < n; i++)
      { result.colwidth.splice(pos, 0, 0); }
  }
  return result;
}
function columnIsHeader(map, table, col) {
  var headerCell = tableNodeTypes(table.type.schema).header_cell;
  for (var row = 0; row < map.height; row++)
    { if (table.nodeAt(map.map[col + row * map.width]).type != headerCell)
      { return false; } }
  return true;
}

// src/cellselection.ts
var CellSelection = /*@__PURE__*/(function (Selection) {
  function _CellSelection($anchorCell, $headCell) {
    if ( $headCell === void 0 ) $headCell = $anchorCell;

    var table = $anchorCell.node(-1);
    var map = TableMap.get(table);
    var tableStart = $anchorCell.start(-1);
    var rect = map.rectBetween(
      $anchorCell.pos - tableStart,
      $headCell.pos - tableStart
    );
    var doc = $anchorCell.node(0);
    var cells = map.cellsInRect(rect).filter(function (p) { return p != $headCell.pos - tableStart; });
    cells.unshift($headCell.pos - tableStart);
    var ranges = cells.map(function (pos) {
      var cell = table.nodeAt(pos);
      if (!cell) {
        throw RangeError(("No cell with offset " + pos + " found"));
      }
      var from = tableStart + pos + 1;
      return new SelectionRange$1(
        doc.resolve(from),
        doc.resolve(from + cell.content.size)
      );
    });
    Selection.call(this, ranges[0].$from, ranges[0].$to, ranges);
    this.$anchorCell = $anchorCell;
    this.$headCell = $headCell;
  }

  if ( Selection ) _CellSelection.__proto__ = Selection;
  _CellSelection.prototype = Object.create( Selection && Selection.prototype );
  _CellSelection.prototype.constructor = _CellSelection;
  _CellSelection.prototype.map = function map (doc, mapping) {
    var $anchorCell = doc.resolve(mapping.map(this.$anchorCell.pos));
    var $headCell = doc.resolve(mapping.map(this.$headCell.pos));
    if (pointsAtCell($anchorCell) && pointsAtCell($headCell) && inSameTable($anchorCell, $headCell)) {
      var tableChanged = this.$anchorCell.node(-1) != $anchorCell.node(-1);
      if (tableChanged && this.isRowSelection())
        { return _CellSelection.rowSelection($anchorCell, $headCell); }
      else if (tableChanged && this.isColSelection())
        { return _CellSelection.colSelection($anchorCell, $headCell); }
      else
        { return new _CellSelection($anchorCell, $headCell); }
    }
    return TextSelection.between($anchorCell, $headCell);
  };
  // Returns a rectangular slice of table rows containing the selected
  // cells.
  _CellSelection.prototype.content = function content () {
    var table = this.$anchorCell.node(-1);
    var map = TableMap.get(table);
    var tableStart = this.$anchorCell.start(-1);
    var rect = map.rectBetween(
      this.$anchorCell.pos - tableStart,
      this.$headCell.pos - tableStart
    );
    var seen = {};
    var rows = [];
    for (var row = rect.top; row < rect.bottom; row++) {
      var rowContent = [];
      for (var index = row * map.width + rect.left, col = rect.left; col < rect.right; col++, index++) {
        var pos = map.map[index];
        if (seen[pos])
          { continue; }
        seen[pos] = true;
        var cellRect = map.findCell(pos);
        var cell = table.nodeAt(pos);
        if (!cell) {
          throw RangeError(("No cell with offset " + pos + " found"));
        }
        var extraLeft = rect.left - cellRect.left;
        var extraRight = cellRect.right - rect.right;
        if (extraLeft > 0 || extraRight > 0) {
          var attrs = cell.attrs;
          if (extraLeft > 0) {
            attrs = removeColSpan(attrs, 0, extraLeft);
          }
          if (extraRight > 0) {
            attrs = removeColSpan(
              attrs,
              attrs.colspan - extraRight,
              extraRight
            );
          }
          if (cellRect.left < rect.left) {
            cell = cell.type.createAndFill(attrs);
            if (!cell) {
              throw RangeError(
                ("Could not create cell with attrs " + (JSON.stringify(attrs)))
              );
            }
          } else {
            cell = cell.type.create(attrs, cell.content);
          }
        }
        if (cellRect.top < rect.top || cellRect.bottom > rect.bottom) {
          var attrs$1 = Object.assign({}, cell.attrs,
            {rowspan: Math.min(cellRect.bottom, rect.bottom) - Math.max(cellRect.top, rect.top)});
          if (cellRect.top < rect.top) {
            cell = cell.type.createAndFill(attrs$1);
          } else {
            cell = cell.type.create(attrs$1, cell.content);
          }
        }
        rowContent.push(cell);
      }
      rows.push(table.child(row).copy(Fragment.from(rowContent)));
    }
    var fragment = this.isColSelection() && this.isRowSelection() ? table : rows;
    return new Slice(Fragment.from(fragment), 1, 1);
  };
  _CellSelection.prototype.replace = function replace (tr, content) {
    if ( content === void 0 ) content = Slice.empty;

    var mapFrom = tr.steps.length, ranges = this.ranges;
    for (var i = 0; i < ranges.length; i++) {
      var ref = ranges[i];
      var $from = ref.$from;
      var $to = ref.$to;
      var mapping = tr.mapping.slice(mapFrom);
      tr.replace(
        mapping.map($from.pos),
        mapping.map($to.pos),
        i ? Slice.empty : content
      );
    }
    var sel = Selection.findFrom(
      tr.doc.resolve(tr.mapping.slice(mapFrom).map(this.to)),
      -1
    );
    if (sel)
      { tr.setSelection(sel); }
  };
  _CellSelection.prototype.replaceWith = function replaceWith (tr, node) {
    this.replace(tr, new Slice(Fragment.from(node), 0, 0));
  };
  _CellSelection.prototype.forEachCell = function forEachCell (f) {
    var table = this.$anchorCell.node(-1);
    var map = TableMap.get(table);
    var tableStart = this.$anchorCell.start(-1);
    var cells = map.cellsInRect(
      map.rectBetween(
        this.$anchorCell.pos - tableStart,
        this.$headCell.pos - tableStart
      )
    );
    for (var i = 0; i < cells.length; i++) {
      f(table.nodeAt(cells[i]), tableStart + cells[i]);
    }
  };
  // True if this selection goes all the way from the top to the
  // bottom of the table.
  _CellSelection.prototype.isColSelection = function isColSelection () {
    var anchorTop = this.$anchorCell.index(-1);
    var headTop = this.$headCell.index(-1);
    if (Math.min(anchorTop, headTop) > 0)
      { return false; }
    var anchorBottom = anchorTop + this.$anchorCell.nodeAfter.attrs.rowspan;
    var headBottom = headTop + this.$headCell.nodeAfter.attrs.rowspan;
    return Math.max(anchorBottom, headBottom) == this.$headCell.node(-1).childCount;
  };
  // Returns the smallest column selection that covers the given anchor
  // and head cell.
  _CellSelection.colSelection = function colSelection ($anchorCell, $headCell) {
    if ( $headCell === void 0 ) $headCell = $anchorCell;

    var table = $anchorCell.node(-1);
    var map = TableMap.get(table);
    var tableStart = $anchorCell.start(-1);
    var anchorRect = map.findCell($anchorCell.pos - tableStart);
    var headRect = map.findCell($headCell.pos - tableStart);
    var doc = $anchorCell.node(0);
    if (anchorRect.top <= headRect.top) {
      if (anchorRect.top > 0)
        { $anchorCell = doc.resolve(tableStart + map.map[anchorRect.left]); }
      if (headRect.bottom < map.height)
        { $headCell = doc.resolve(
          tableStart + map.map[map.width * (map.height - 1) + headRect.right - 1]
        ); }
    } else {
      if (headRect.top > 0)
        { $headCell = doc.resolve(tableStart + map.map[headRect.left]); }
      if (anchorRect.bottom < map.height)
        { $anchorCell = doc.resolve(
          tableStart + map.map[map.width * (map.height - 1) + anchorRect.right - 1]
        ); }
    }
    return new _CellSelection($anchorCell, $headCell);
  };
  // True if this selection goes all the way from the left to the
  // right of the table.
  _CellSelection.prototype.isRowSelection = function isRowSelection () {
    var table = this.$anchorCell.node(-1);
    var map = TableMap.get(table);
    var tableStart = this.$anchorCell.start(-1);
    var anchorLeft = map.colCount(this.$anchorCell.pos - tableStart);
    var headLeft = map.colCount(this.$headCell.pos - tableStart);
    if (Math.min(anchorLeft, headLeft) > 0)
      { return false; }
    var anchorRight = anchorLeft + this.$anchorCell.nodeAfter.attrs.colspan;
    var headRight = headLeft + this.$headCell.nodeAfter.attrs.colspan;
    return Math.max(anchorRight, headRight) == map.width;
  };
  _CellSelection.prototype.eq = function eq (other) {
    return other instanceof _CellSelection && other.$anchorCell.pos == this.$anchorCell.pos && other.$headCell.pos == this.$headCell.pos;
  };
  // Returns the smallest row selection that covers the given anchor
  // and head cell.
  _CellSelection.rowSelection = function rowSelection ($anchorCell, $headCell) {
    if ( $headCell === void 0 ) $headCell = $anchorCell;

    var table = $anchorCell.node(-1);
    var map = TableMap.get(table);
    var tableStart = $anchorCell.start(-1);
    var anchorRect = map.findCell($anchorCell.pos - tableStart);
    var headRect = map.findCell($headCell.pos - tableStart);
    var doc = $anchorCell.node(0);
    if (anchorRect.left <= headRect.left) {
      if (anchorRect.left > 0)
        { $anchorCell = doc.resolve(
          tableStart + map.map[anchorRect.top * map.width]
        ); }
      if (headRect.right < map.width)
        { $headCell = doc.resolve(
          tableStart + map.map[map.width * (headRect.top + 1) - 1]
        ); }
    } else {
      if (headRect.left > 0)
        { $headCell = doc.resolve(tableStart + map.map[headRect.top * map.width]); }
      if (anchorRect.right < map.width)
        { $anchorCell = doc.resolve(
          tableStart + map.map[map.width * (anchorRect.top + 1) - 1]
        ); }
    }
    return new _CellSelection($anchorCell, $headCell);
  };
  _CellSelection.prototype.toJSON = function toJSON () {
    return {
      type: "cell",
      anchor: this.$anchorCell.pos,
      head: this.$headCell.pos
    };
  };
  _CellSelection.fromJSON = function fromJSON (doc, json) {
    return new _CellSelection(doc.resolve(json.anchor), doc.resolve(json.head));
  };
  _CellSelection.create = function create (doc, anchorCell, headCell) {
    if ( headCell === void 0 ) headCell = anchorCell;

    return new _CellSelection(doc.resolve(anchorCell), doc.resolve(headCell));
  };
  _CellSelection.prototype.getBookmark = function getBookmark () {
    return new CellBookmark(this.$anchorCell.pos, this.$headCell.pos);
  };

  return _CellSelection;
}(Selection));
CellSelection.prototype.visible = false;
Selection.jsonID("cell", CellSelection);
var CellBookmark = /*@__PURE__*/(function () {
  function _CellBookmark(anchor, head) {
    this.anchor = anchor;
    this.head = head;
  }
  _CellBookmark.prototype.map = function map (mapping) {
    return new _CellBookmark(mapping.map(this.anchor), mapping.map(this.head));
  };
  _CellBookmark.prototype.resolve = function resolve (doc) {
    var $anchorCell = doc.resolve(this.anchor), $headCell = doc.resolve(this.head);
    if ($anchorCell.parent.type.spec.tableRole == "row" && $headCell.parent.type.spec.tableRole == "row" && $anchorCell.index() < $anchorCell.parent.childCount && $headCell.index() < $headCell.parent.childCount && inSameTable($anchorCell, $headCell))
      { return new CellSelection($anchorCell, $headCell); }
    else
      { return Selection.near($headCell, 1); }
  };

  return _CellBookmark;
}());
function drawCellSelection(state) {
  if (!(state.selection instanceof CellSelection))
    { return null; }
  var cells = [];
  state.selection.forEachCell(function (node, pos) {
    cells.push(
      Decoration$1.node(pos, pos + node.nodeSize, { class: "selectedCell" })
    );
  });
  return DecorationSet.create(state.doc, cells);
}
function isCellBoundarySelection(ref) {
  var $from = ref.$from;
  var $to = ref.$to;

  if ($from.pos == $to.pos || $from.pos < $from.pos - 6)
    { return false; }
  var afterFrom = $from.pos;
  var beforeTo = $to.pos;
  var depth = $from.depth;
  for (; depth >= 0; depth--, afterFrom++)
    { if ($from.after(depth + 1) < $from.end(depth))
      { break; } }
  for (var d = $to.depth; d >= 0; d--, beforeTo--)
    { if ($to.before(d + 1) > $to.start(d))
      { break; } }
  return afterFrom == beforeTo && /row|table/.test($from.node(depth).type.spec.tableRole);
}
function isTextSelectionAcrossCells(ref) {
  var $from = ref.$from;
  var $to = ref.$to;

  var fromCellBoundaryNode;
  var toCellBoundaryNode;
  for (var i = $from.depth; i > 0; i--) {
    var node = $from.node(i);
    if (node.type.spec.tableRole === "cell" || node.type.spec.tableRole === "header_cell") {
      fromCellBoundaryNode = node;
      break;
    }
  }
  for (var i$1 = $to.depth; i$1 > 0; i$1--) {
    var node$1 = $to.node(i$1);
    if (node$1.type.spec.tableRole === "cell" || node$1.type.spec.tableRole === "header_cell") {
      toCellBoundaryNode = node$1;
      break;
    }
  }
  return fromCellBoundaryNode !== toCellBoundaryNode && $to.parentOffset === 0;
}
function normalizeSelection(state, tr, allowTableNodeSelection) {
  var sel = (tr || state).selection;
  var doc = (tr || state).doc;
  var normalize;
  var role;
  if (sel instanceof NodeSelection && (role = sel.node.type.spec.tableRole)) {
    if (role == "cell" || role == "header_cell") {
      normalize = CellSelection.create(doc, sel.from);
    } else if (role == "row") {
      var $cell = doc.resolve(sel.from + 1);
      normalize = CellSelection.rowSelection($cell, $cell);
    } else if (!allowTableNodeSelection) {
      var map = TableMap.get(sel.node);
      var start = sel.from + 1;
      var lastCell = start + map.map[map.width * map.height - 1];
      normalize = CellSelection.create(doc, start + 1, lastCell);
    }
  } else if (sel instanceof TextSelection && isCellBoundarySelection(sel)) {
    normalize = TextSelection.create(doc, sel.from);
  } else if (sel instanceof TextSelection && isTextSelectionAcrossCells(sel)) {
    normalize = TextSelection.create(doc, sel.$from.start(), sel.$from.end());
  }
  if (normalize)
    { (tr || (tr = state.tr)).setSelection(normalize); }
  return tr;
}
var fixTablesKey = new PluginKey("fix-tables");
function changedDescendants(old, cur, offset, f) {
  var oldSize = old.childCount, curSize = cur.childCount;
  outer:
    for (var i = 0, j = 0; i < curSize; i++) {
      var child = cur.child(i);
      for (var scan = j, e = Math.min(oldSize, i + 3); scan < e; scan++) {
        if (old.child(scan) == child) {
          j = scan + 1;
          offset += child.nodeSize;
          continue outer;
        }
      }
      f(child, offset);
      if (j < oldSize && old.child(j).sameMarkup(child))
        { changedDescendants(old.child(j), child, offset + 1, f); }
      else
        { child.nodesBetween(0, child.content.size, f, offset + 1); }
      offset += child.nodeSize;
    }
}
function fixTables(state, oldState) {
  var tr;
  var check = function (node, pos) {
    if (node.type.spec.tableRole == "table")
      { tr = fixTable(state, node, pos, tr); }
  };
  if (!oldState)
    { state.doc.descendants(check); }
  else if (oldState.doc != state.doc)
    { changedDescendants(oldState.doc, state.doc, 0, check); }
  return tr;
}
function fixTable(state, table, tablePos, tr) {
  var map = TableMap.get(table);
  if (!map.problems)
    { return tr; }
  if (!tr)
    { tr = state.tr; }
  var mustAdd = [];
  for (var i = 0; i < map.height; i++)
    { mustAdd.push(0); }
  for (var i$1 = 0; i$1 < map.problems.length; i$1++) {
    var prob = map.problems[i$1];
    if (prob.type == "collision") {
      var cell = table.nodeAt(prob.pos);
      if (!cell)
        { continue; }
      var attrs = cell.attrs;
      for (var j = 0; j < attrs.rowspan; j++)
        { mustAdd[prob.row + j] += prob.n; }
      tr.setNodeMarkup(
        tr.mapping.map(tablePos + 1 + prob.pos),
        null,
        removeColSpan(attrs, attrs.colspan - prob.n, prob.n)
      );
    } else if (prob.type == "missing") {
      mustAdd[prob.row] += prob.n;
    } else if (prob.type == "overlong_rowspan") {
      var cell$1 = table.nodeAt(prob.pos);
      if (!cell$1)
        { continue; }
      tr.setNodeMarkup(tr.mapping.map(tablePos + 1 + prob.pos), null, Object.assign({}, cell$1.attrs,
        {rowspan: cell$1.attrs.rowspan - prob.n}));
    } else if (prob.type == "colwidth mismatch") {
      var cell$2 = table.nodeAt(prob.pos);
      if (!cell$2)
        { continue; }
      tr.setNodeMarkup(tr.mapping.map(tablePos + 1 + prob.pos), null, Object.assign({}, cell$2.attrs,
        {colwidth: prob.colwidth}));
    }
  }
  var first, last;
  for (var i$2 = 0; i$2 < mustAdd.length; i$2++)
    { if (mustAdd[i$2]) {
      if (first == null)
        { first = i$2; }
      last = i$2;
    } }
  for (var i$3 = 0, pos = tablePos + 1; i$3 < map.height; i$3++) {
    var row = table.child(i$3);
    var end = pos + row.nodeSize;
    var add = mustAdd[i$3];
    if (add > 0) {
      var role = "cell";
      if (row.firstChild) {
        role = row.firstChild.type.spec.tableRole;
      }
      var nodes = [];
      for (var j$1 = 0; j$1 < add; j$1++) {
        var node = tableNodeTypes(state.schema)[role].createAndFill();
        if (node)
          { nodes.push(node); }
      }
      var side = (i$3 == 0 || first == i$3 - 1) && last == i$3 ? pos + 1 : end - 1;
      tr.insert(tr.mapping.map(side), nodes);
    }
    pos = end;
  }
  return tr.setMeta(fixTablesKey, { fixTables: true });
}
function selectedRect(state) {
  var sel = state.selection;
  var $pos = selectionCell(state);
  var table = $pos.node(-1);
  var tableStart = $pos.start(-1);
  var map = TableMap.get(table);
  var rect = sel instanceof CellSelection ? map.rectBetween(
    sel.$anchorCell.pos - tableStart,
    sel.$headCell.pos - tableStart
  ) : map.findCell($pos.pos - tableStart);
  return Object.assign({}, rect, {tableStart: tableStart, map: map, table: table});
}
function addColumn(tr, ref, col) {
  var map = ref.map;
  var tableStart = ref.tableStart;
  var table = ref.table;

  var refColumn = col > 0 ? -1 : 0;
  if (columnIsHeader(map, table, col + refColumn)) {
    refColumn = col == 0 || col == map.width ? null : 0;
  }
  for (var row = 0; row < map.height; row++) {
    var index = row * map.width + col;
    if (col > 0 && col < map.width && map.map[index - 1] == map.map[index]) {
      var pos = map.map[index];
      var cell = table.nodeAt(pos);
      tr.setNodeMarkup(
        tr.mapping.map(tableStart + pos),
        null,
        addColSpan(cell.attrs, col - map.colCount(pos))
      );
      row += cell.attrs.rowspan - 1;
    } else {
      var type = refColumn == null ? tableNodeTypes(table.type.schema).cell : table.nodeAt(map.map[index + refColumn]).type;
      var pos$1 = map.positionAt(row, col, table);
      tr.insert(tr.mapping.map(tableStart + pos$1), type.createAndFill());
    }
  }
  return tr;
}
function addColumnBefore(state, dispatch) {
  if (!isInTable(state))
    { return false; }
  if (dispatch) {
    var rect = selectedRect(state);
    dispatch(addColumn(state.tr, rect, rect.left));
  }
  return true;
}
function addColumnAfter(state, dispatch) {
  if (!isInTable(state))
    { return false; }
  if (dispatch) {
    var rect = selectedRect(state);
    dispatch(addColumn(state.tr, rect, rect.right));
  }
  return true;
}
function removeColumn(tr, ref, col) {
  var map = ref.map;
  var table = ref.table;
  var tableStart = ref.tableStart;

  var mapStart = tr.mapping.maps.length;
  for (var row = 0; row < map.height; ) {
    var index = row * map.width + col;
    var pos = map.map[index];
    var cell = table.nodeAt(pos);
    var attrs = cell.attrs;
    if (col > 0 && map.map[index - 1] == pos || col < map.width - 1 && map.map[index + 1] == pos) {
      tr.setNodeMarkup(
        tr.mapping.slice(mapStart).map(tableStart + pos),
        null,
        removeColSpan(attrs, col - map.colCount(pos))
      );
    } else {
      var start = tr.mapping.slice(mapStart).map(tableStart + pos);
      tr.delete(start, start + cell.nodeSize);
    }
    row += attrs.rowspan;
  }
}
function deleteColumn(state, dispatch) {
  if (!isInTable(state))
    { return false; }
  if (dispatch) {
    var rect = selectedRect(state);
    var tr = state.tr;
    if (rect.left == 0 && rect.right == rect.map.width)
      { return false; }
    for (var i = rect.right - 1; ; i--) {
      removeColumn(tr, rect, i);
      if (i == rect.left)
        { break; }
      var table = rect.tableStart ? tr.doc.nodeAt(rect.tableStart - 1) : tr.doc;
      if (!table) {
        throw RangeError("No table found");
      }
      rect.table = table;
      rect.map = TableMap.get(table);
    }
    dispatch(tr);
  }
  return true;
}
function rowIsHeader(map, table, row) {
  var _a;
  var headerCell = tableNodeTypes(table.type.schema).header_cell;
  for (var col = 0; col < map.width; col++)
    { if (((_a = table.nodeAt(map.map[col + row * map.width])) == null ? void 0 : _a.type) != headerCell)
      { return false; } }
  return true;
}
function addRow(tr, ref, row) {
  var map = ref.map;
  var tableStart = ref.tableStart;
  var table = ref.table;

  var _a;
  var rowPos = tableStart;
  for (var i = 0; i < row; i++)
    { rowPos += table.child(i).nodeSize; }
  var cells = [];
  var refRow = row > 0 ? -1 : 0;
  if (rowIsHeader(map, table, row + refRow))
    { refRow = row == 0 || row == map.height ? null : 0; }
  for (var col = 0, index = map.width * row; col < map.width; col++, index++) {
    if (row > 0 && row < map.height && map.map[index] == map.map[index - map.width]) {
      var pos = map.map[index];
      var attrs = table.nodeAt(pos).attrs;
      tr.setNodeMarkup(tableStart + pos, null, Object.assign({}, attrs,
        {rowspan: attrs.rowspan + 1}));
      col += attrs.colspan - 1;
    } else {
      var type = refRow == null ? tableNodeTypes(table.type.schema).cell : (_a = table.nodeAt(map.map[index + refRow * map.width])) == null ? void 0 : _a.type;
      var node = type == null ? void 0 : type.createAndFill();
      if (node)
        { cells.push(node); }
    }
  }
  tr.insert(rowPos, tableNodeTypes(table.type.schema).row.create(null, cells));
  return tr;
}
function addRowBefore(state, dispatch) {
  if (!isInTable(state))
    { return false; }
  if (dispatch) {
    var rect = selectedRect(state);
    dispatch(addRow(state.tr, rect, rect.top));
  }
  return true;
}
function addRowAfter(state, dispatch) {
  if (!isInTable(state))
    { return false; }
  if (dispatch) {
    var rect = selectedRect(state);
    dispatch(addRow(state.tr, rect, rect.bottom));
  }
  return true;
}
function removeRow(tr, ref, row) {
  var map = ref.map;
  var table = ref.table;
  var tableStart = ref.tableStart;

  var rowPos = 0;
  for (var i = 0; i < row; i++)
    { rowPos += table.child(i).nodeSize; }
  var nextRow = rowPos + table.child(row).nodeSize;
  var mapFrom = tr.mapping.maps.length;
  tr.delete(rowPos + tableStart, nextRow + tableStart);
  var seen = /* @__PURE__ */ new Set();
  for (var col = 0, index = row * map.width; col < map.width; col++, index++) {
    var pos = map.map[index];
    if (seen.has(pos))
      { continue; }
    seen.add(pos);
    if (row > 0 && pos == map.map[index - map.width]) {
      var attrs = table.nodeAt(pos).attrs;
      tr.setNodeMarkup(tr.mapping.slice(mapFrom).map(pos + tableStart), null, Object.assign({}, attrs,
        {rowspan: attrs.rowspan - 1}));
      col += attrs.colspan - 1;
    } else if (row < map.height && pos == map.map[index + map.width]) {
      var cell = table.nodeAt(pos);
      var attrs$1 = cell.attrs;
      var copy = cell.type.create(
        Object.assign({}, attrs$1, {rowspan: cell.attrs.rowspan - 1}),
        cell.content
      );
      var newPos = map.positionAt(row + 1, col, table);
      tr.insert(tr.mapping.slice(mapFrom).map(tableStart + newPos), copy);
      col += attrs$1.colspan - 1;
    }
  }
}
function deleteRow(state, dispatch) {
  if (!isInTable(state))
    { return false; }
  if (dispatch) {
    var rect = selectedRect(state), tr = state.tr;
    if (rect.top == 0 && rect.bottom == rect.map.height)
      { return false; }
    for (var i = rect.bottom - 1; ; i--) {
      removeRow(tr, rect, i);
      if (i == rect.top)
        { break; }
      var table = rect.tableStart ? tr.doc.nodeAt(rect.tableStart - 1) : tr.doc;
      if (!table) {
        throw RangeError("No table found");
      }
      rect.table = table;
      rect.map = TableMap.get(rect.table);
    }
    dispatch(tr);
  }
  return true;
}
function deprecated_toggleHeader(type) {
  return function(state, dispatch) {
    if (!isInTable(state))
      { return false; }
    if (dispatch) {
      var types = tableNodeTypes(state.schema);
      var rect = selectedRect(state), tr = state.tr;
      var cells = rect.map.cellsInRect(
        type == "column" ? {
          left: rect.left,
          top: 0,
          right: rect.right,
          bottom: rect.map.height
        } : type == "row" ? {
          left: 0,
          top: rect.top,
          right: rect.map.width,
          bottom: rect.bottom
        } : rect
      );
      var nodes = cells.map(function (pos) { return rect.table.nodeAt(pos); });
      for (var i = 0; i < cells.length; i++)
        { if (nodes[i].type == types.header_cell)
          { tr.setNodeMarkup(
            rect.tableStart + cells[i],
            types.cell,
            nodes[i].attrs
          ); } }
      if (tr.steps.length == 0)
        { for (var i$1 = 0; i$1 < cells.length; i$1++)
          { tr.setNodeMarkup(
            rect.tableStart + cells[i$1],
            types.header_cell,
            nodes[i$1].attrs
          ); } }
      dispatch(tr);
    }
    return true;
  };
}
function isHeaderEnabledByType(type, rect, types) {
  var cellPositions = rect.map.cellsInRect({
    left: 0,
    top: 0,
    right: type == "row" ? rect.map.width : 1,
    bottom: type == "column" ? rect.map.height : 1
  });
  for (var i = 0; i < cellPositions.length; i++) {
    var cell = rect.table.nodeAt(cellPositions[i]);
    if (cell && cell.type !== types.header_cell) {
      return false;
    }
  }
  return true;
}
function toggleHeader(type, options) {
  options = options || { useDeprecatedLogic: false };
  if (options.useDeprecatedLogic)
    { return deprecated_toggleHeader(type); }
  return function(state, dispatch) {
    if (!isInTable(state))
      { return false; }
    if (dispatch) {
      var types = tableNodeTypes(state.schema);
      var rect = selectedRect(state), tr = state.tr;
      var isHeaderRowEnabled = isHeaderEnabledByType("row", rect, types);
      var isHeaderColumnEnabled = isHeaderEnabledByType(
        "column",
        rect,
        types
      );
      var isHeaderEnabled = type === "column" ? isHeaderRowEnabled : type === "row" ? isHeaderColumnEnabled : false;
      var selectionStartsAt = isHeaderEnabled ? 1 : 0;
      var cellsRect = type == "column" ? {
        left: 0,
        top: selectionStartsAt,
        right: 1,
        bottom: rect.map.height
      } : type == "row" ? {
        left: selectionStartsAt,
        top: 0,
        right: rect.map.width,
        bottom: 1
      } : rect;
      var newType = type == "column" ? isHeaderColumnEnabled ? types.cell : types.header_cell : type == "row" ? isHeaderRowEnabled ? types.cell : types.header_cell : types.cell;
      rect.map.cellsInRect(cellsRect).forEach(function (relativeCellPos) {
        var cellPos = relativeCellPos + rect.tableStart;
        var cell = tr.doc.nodeAt(cellPos);
        if (cell) {
          tr.setNodeMarkup(cellPos, newType, cell.attrs);
        }
      });
      dispatch(tr);
    }
    return true;
  };
}
var toggleHeaderRow = toggleHeader("row", {
  useDeprecatedLogic: true
});
toggleHeader("column", {
  useDeprecatedLogic: true
});
toggleHeader("cell", {
  useDeprecatedLogic: true
});
function findNextCell($cell, dir) {
  if (dir < 0) {
    var before = $cell.nodeBefore;
    if (before)
      { return $cell.pos - before.nodeSize; }
    for (var row = $cell.index(-1) - 1, rowEnd = $cell.before(); row >= 0; row--) {
      var rowNode = $cell.node(-1).child(row);
      var lastChild = rowNode.lastChild;
      if (lastChild) {
        return rowEnd - 1 - lastChild.nodeSize;
      }
      rowEnd -= rowNode.nodeSize;
    }
  } else {
    if ($cell.index() < $cell.parent.childCount - 1) {
      return $cell.pos + $cell.nodeAfter.nodeSize;
    }
    var table = $cell.node(-1);
    for (var row$1 = $cell.indexAfter(-1), rowStart = $cell.after(); row$1 < table.childCount; row$1++) {
      var rowNode$1 = table.child(row$1);
      if (rowNode$1.childCount)
        { return rowStart + 1; }
      rowStart += rowNode$1.nodeSize;
    }
  }
  return null;
}
function goToNextCell(direction) {
  return function(state, dispatch) {
    if (!isInTable(state))
      { return false; }
    var cell = findNextCell(selectionCell(state), direction);
    if (cell == null)
      { return false; }
    if (dispatch) {
      var $cell = state.doc.resolve(cell);
      dispatch(
        state.tr.setSelection(TextSelection.between($cell, moveCellForward($cell))).scrollIntoView()
      );
    }
    return true;
  };
}
function deleteTable(state, dispatch) {
  var $pos = state.selection.$anchor;
  for (var d = $pos.depth; d > 0; d--) {
    var node = $pos.node(d);
    if (node.type.spec.tableRole == "table") {
      if (dispatch)
        { dispatch(
          state.tr.delete($pos.before(d), $pos.after(d)).scrollIntoView()
        ); }
      return true;
    }
  }
  return false;
}
function deleteCellSelection(state, dispatch) {
  var sel = state.selection;
  if (!(sel instanceof CellSelection))
    { return false; }
  if (dispatch) {
    var tr = state.tr;
    var baseContent = tableNodeTypes(state.schema).cell.createAndFill().content;
    sel.forEachCell(function (cell, pos) {
      if (!cell.content.eq(baseContent))
        { tr.replace(
          tr.mapping.map(pos + 1),
          tr.mapping.map(pos + cell.nodeSize - 1),
          new Slice(baseContent, 0, 0)
        ); }
    });
    if (tr.docChanged)
      { dispatch(tr); }
  }
  return true;
}
function pastedCells(slice) {
  if (!slice.size)
    { return null; }
  var content = slice.content;
  var openStart = slice.openStart;
  var openEnd = slice.openEnd;
  while (content.childCount == 1 && (openStart > 0 && openEnd > 0 || content.child(0).type.spec.tableRole == "table")) {
    openStart--;
    openEnd--;
    content = content.child(0).content;
  }
  var first = content.child(0);
  var role = first.type.spec.tableRole;
  var schema = first.type.schema, rows = [];
  if (role == "row") {
    for (var i = 0; i < content.childCount; i++) {
      var cells = content.child(i).content;
      var left = i ? 0 : Math.max(0, openStart - 1);
      var right = i < content.childCount - 1 ? 0 : Math.max(0, openEnd - 1);
      if (left || right)
        { cells = fitSlice(
          tableNodeTypes(schema).row,
          new Slice(cells, left, right)
        ).content; }
      rows.push(cells);
    }
  } else if (role == "cell" || role == "header_cell") {
    rows.push(
      openStart || openEnd ? fitSlice(
        tableNodeTypes(schema).row,
        new Slice(content, openStart, openEnd)
      ).content : content
    );
  } else {
    return null;
  }
  return ensureRectangular(schema, rows);
}
function ensureRectangular(schema, rows) {
  var widths = [];
  for (var i = 0; i < rows.length; i++) {
    var row = rows[i];
    for (var j = row.childCount - 1; j >= 0; j--) {
      var ref = row.child(j).attrs;
      var rowspan = ref.rowspan;
      var colspan = ref.colspan;
      for (var r = i; r < i + rowspan; r++)
        { widths[r] = (widths[r] || 0) + colspan; }
    }
  }
  var width = 0;
  for (var r$1 = 0; r$1 < widths.length; r$1++)
    { width = Math.max(width, widths[r$1]); }
  for (var r$2 = 0; r$2 < widths.length; r$2++) {
    if (r$2 >= rows.length)
      { rows.push(Fragment.empty); }
    if (widths[r$2] < width) {
      var empty = tableNodeTypes(schema).cell.createAndFill();
      var cells = [];
      for (var i$1 = widths[r$2]; i$1 < width; i$1++) {
        cells.push(empty);
      }
      rows[r$2] = rows[r$2].append(Fragment.from(cells));
    }
  }
  return { height: rows.length, width: width, rows: rows };
}
function fitSlice(nodeType, slice) {
  var node = nodeType.createAndFill();
  var tr = new Transform(node).replace(0, node.content.size, slice);
  return tr.doc;
}
function clipCells(ref, newWidth, newHeight) {
  var width = ref.width;
  var height = ref.height;
  var rows = ref.rows;

  if (width != newWidth) {
    var added = [];
    var newRows = [];
    for (var row = 0; row < rows.length; row++) {
      var frag = rows[row], cells = [];
      for (var col = added[row] || 0, i = 0; col < newWidth; i++) {
        var cell = frag.child(i % frag.childCount);
        if (col + cell.attrs.colspan > newWidth)
          { cell = cell.type.createChecked(
            removeColSpan(
              cell.attrs,
              cell.attrs.colspan,
              col + cell.attrs.colspan - newWidth
            ),
            cell.content
          ); }
        cells.push(cell);
        col += cell.attrs.colspan;
        for (var j = 1; j < cell.attrs.rowspan; j++)
          { added[row + j] = (added[row + j] || 0) + cell.attrs.colspan; }
      }
      newRows.push(Fragment.from(cells));
    }
    rows = newRows;
    width = newWidth;
  }
  if (height != newHeight) {
    var newRows$1 = [];
    for (var row$1 = 0, i$1 = 0; row$1 < newHeight; row$1++, i$1++) {
      var cells$1 = [], source = rows[i$1 % height];
      for (var j$1 = 0; j$1 < source.childCount; j$1++) {
        var cell$1 = source.child(j$1);
        if (row$1 + cell$1.attrs.rowspan > newHeight)
          { cell$1 = cell$1.type.create(
            Object.assign({}, cell$1.attrs,
              {rowspan: Math.max(1, newHeight - cell$1.attrs.rowspan)}),
            cell$1.content
          ); }
        cells$1.push(cell$1);
      }
      newRows$1.push(Fragment.from(cells$1));
    }
    rows = newRows$1;
    height = newHeight;
  }
  return { width: width, height: height, rows: rows };
}
function growTable(tr, map, table, start, width, height, mapFrom) {
  var schema = tr.doc.type.schema;
  var types = tableNodeTypes(schema);
  var empty;
  var emptyHead;
  if (width > map.width) {
    for (var row = 0, rowEnd = 0; row < map.height; row++) {
      var rowNode = table.child(row);
      rowEnd += rowNode.nodeSize;
      var cells = [];
      var add = (void 0);
      if (rowNode.lastChild == null || rowNode.lastChild.type == types.cell)
        { add = empty || (empty = types.cell.createAndFill()); }
      else
        { add = emptyHead || (emptyHead = types.header_cell.createAndFill()); }
      for (var i = map.width; i < width; i++)
        { cells.push(add); }
      tr.insert(tr.mapping.slice(mapFrom).map(rowEnd - 1 + start), cells);
    }
  }
  if (height > map.height) {
    var cells$1 = [];
    for (var i$1 = 0, start2 = (map.height - 1) * map.width; i$1 < Math.max(map.width, width); i$1++) {
      var header = i$1 >= map.width ? false : table.nodeAt(map.map[start2 + i$1]).type == types.header_cell;
      cells$1.push(
        header ? emptyHead || (emptyHead = types.header_cell.createAndFill()) : empty || (empty = types.cell.createAndFill())
      );
    }
    var emptyRow = types.row.create(null, Fragment.from(cells$1)), rows = [];
    for (var i$2 = map.height; i$2 < height; i$2++)
      { rows.push(emptyRow); }
    tr.insert(tr.mapping.slice(mapFrom).map(start + table.nodeSize - 2), rows);
  }
  return !!(empty || emptyHead);
}
function isolateHorizontal(tr, map, table, start, left, right, top, mapFrom) {
  if (top == 0 || top == map.height)
    { return false; }
  var found = false;
  for (var col = left; col < right; col++) {
    var index = top * map.width + col, pos = map.map[index];
    if (map.map[index - map.width] == pos) {
      found = true;
      var cell = table.nodeAt(pos);
      var ref = map.findCell(pos);
      var cellTop = ref.top;
      var cellLeft = ref.left;
      tr.setNodeMarkup(tr.mapping.slice(mapFrom).map(pos + start), null, Object.assign({}, cell.attrs,
        {rowspan: top - cellTop}));
      tr.insert(
        tr.mapping.slice(mapFrom).map(map.positionAt(top, cellLeft, table)),
        cell.type.createAndFill(Object.assign({}, cell.attrs,
          {rowspan: cellTop + cell.attrs.rowspan - top}))
      );
      col += cell.attrs.colspan - 1;
    }
  }
  return found;
}
function isolateVertical(tr, map, table, start, top, bottom, left, mapFrom) {
  if (left == 0 || left == map.width)
    { return false; }
  var found = false;
  for (var row = top; row < bottom; row++) {
    var index = row * map.width + left, pos = map.map[index];
    if (map.map[index - 1] == pos) {
      found = true;
      var cell = table.nodeAt(pos);
      var cellLeft = map.colCount(pos);
      var updatePos = tr.mapping.slice(mapFrom).map(pos + start);
      tr.setNodeMarkup(
        updatePos,
        null,
        removeColSpan(
          cell.attrs,
          left - cellLeft,
          cell.attrs.colspan - (left - cellLeft)
        )
      );
      tr.insert(
        updatePos + cell.nodeSize,
        cell.type.createAndFill(
          removeColSpan(cell.attrs, 0, left - cellLeft)
        )
      );
      row += cell.attrs.rowspan - 1;
    }
  }
  return found;
}
function insertCells(state, dispatch, tableStart, rect, cells) {
  var table = tableStart ? state.doc.nodeAt(tableStart - 1) : state.doc;
  if (!table) {
    throw new Error("No table found");
  }
  var map = TableMap.get(table);
  var top = rect.top;
  var left = rect.left;
  var right = left + cells.width, bottom = top + cells.height;
  var tr = state.tr;
  var mapFrom = 0;
  function recomp() {
    table = tableStart ? tr.doc.nodeAt(tableStart - 1) : tr.doc;
    if (!table) {
      throw new Error("No table found");
    }
    map = TableMap.get(table);
    mapFrom = tr.mapping.maps.length;
  }
  if (growTable(tr, map, table, tableStart, right, bottom, mapFrom))
    { recomp(); }
  if (isolateHorizontal(tr, map, table, tableStart, left, right, top, mapFrom))
    { recomp(); }
  if (isolateHorizontal(tr, map, table, tableStart, left, right, bottom, mapFrom))
    { recomp(); }
  if (isolateVertical(tr, map, table, tableStart, top, bottom, left, mapFrom))
    { recomp(); }
  if (isolateVertical(tr, map, table, tableStart, top, bottom, right, mapFrom))
    { recomp(); }
  for (var row = top; row < bottom; row++) {
    var from = map.positionAt(row, left, table), to = map.positionAt(row, right, table);
    tr.replace(
      tr.mapping.slice(mapFrom).map(from + tableStart),
      tr.mapping.slice(mapFrom).map(to + tableStart),
      new Slice(cells.rows[row - top], 0, 0)
    );
  }
  recomp();
  tr.setSelection(
    new CellSelection(
      tr.doc.resolve(tableStart + map.positionAt(top, left, table)),
      tr.doc.resolve(tableStart + map.positionAt(bottom - 1, right - 1, table))
    )
  );
  dispatch(tr);
}

// src/input.ts
var handleKeyDown$1 = keydownHandler({
  ArrowLeft: arrow$1("horiz", -1),
  ArrowRight: arrow$1("horiz", 1),
  ArrowUp: arrow$1("vert", -1),
  ArrowDown: arrow$1("vert", 1),
  "Shift-ArrowLeft": shiftArrow("horiz", -1),
  "Shift-ArrowRight": shiftArrow("horiz", 1),
  "Shift-ArrowUp": shiftArrow("vert", -1),
  "Shift-ArrowDown": shiftArrow("vert", 1),
  Backspace: deleteCellSelection,
  "Mod-Backspace": deleteCellSelection,
  Delete: deleteCellSelection,
  "Mod-Delete": deleteCellSelection
});
function maybeSetSelection(state, dispatch, selection) {
  if (selection.eq(state.selection))
    { return false; }
  if (dispatch)
    { dispatch(state.tr.setSelection(selection).scrollIntoView()); }
  return true;
}
function arrow$1(axis, dir) {
  return function (state, dispatch, view) {
    if (!view)
      { return false; }
    var sel = state.selection;
    if (sel instanceof CellSelection) {
      return maybeSetSelection(
        state,
        dispatch,
        Selection.near(sel.$headCell, dir)
      );
    }
    if (axis != "horiz" && !sel.empty)
      { return false; }
    var end = atEndOfCell(view, axis, dir);
    if (end == null)
      { return false; }
    if (axis == "horiz") {
      return maybeSetSelection(
        state,
        dispatch,
        Selection.near(state.doc.resolve(sel.head + dir), dir)
      );
    } else {
      var $cell = state.doc.resolve(end);
      var $next = nextCell($cell, axis, dir);
      var newSel;
      if ($next)
        { newSel = Selection.near($next, 1); }
      else if (dir < 0)
        { newSel = Selection.near(state.doc.resolve($cell.before(-1)), -1); }
      else
        { newSel = Selection.near(state.doc.resolve($cell.after(-1)), 1); }
      return maybeSetSelection(state, dispatch, newSel);
    }
  };
}
function shiftArrow(axis, dir) {
  return function (state, dispatch, view) {
    if (!view)
      { return false; }
    var sel = state.selection;
    var cellSel;
    if (sel instanceof CellSelection) {
      cellSel = sel;
    } else {
      var end = atEndOfCell(view, axis, dir);
      if (end == null)
        { return false; }
      cellSel = new CellSelection(state.doc.resolve(end));
    }
    var $head = nextCell(cellSel.$headCell, axis, dir);
    if (!$head)
      { return false; }
    return maybeSetSelection(
      state,
      dispatch,
      new CellSelection(cellSel.$anchorCell, $head)
    );
  };
}
function handleTripleClick(view, pos) {
  var doc = view.state.doc, $cell = cellAround(doc.resolve(pos));
  if (!$cell)
    { return false; }
  view.dispatch(view.state.tr.setSelection(new CellSelection($cell)));
  return true;
}
function handlePaste(view, _, slice) {
  if (!isInTable(view.state))
    { return false; }
  var cells = pastedCells(slice);
  var sel = view.state.selection;
  if (sel instanceof CellSelection) {
    if (!cells)
      { cells = {
        width: 1,
        height: 1,
        rows: [
          Fragment.from(
            fitSlice(tableNodeTypes(view.state.schema).cell, slice)
          )
        ]
      }; }
    var table = sel.$anchorCell.node(-1);
    var start = sel.$anchorCell.start(-1);
    var rect = TableMap.get(table).rectBetween(
      sel.$anchorCell.pos - start,
      sel.$headCell.pos - start
    );
    cells = clipCells(cells, rect.right - rect.left, rect.bottom - rect.top);
    insertCells(view.state, view.dispatch, start, rect, cells);
    return true;
  } else if (cells) {
    var $cell = selectionCell(view.state);
    var start$1 = $cell.start(-1);
    insertCells(
      view.state,
      view.dispatch,
      start$1,
      TableMap.get($cell.node(-1)).findCell($cell.pos - start$1),
      cells
    );
    return true;
  } else {
    return false;
  }
}
function handleMouseDown(view, startEvent) {
  var _a;
  if (startEvent.ctrlKey || startEvent.metaKey)
    { return; }
  var startDOMCell = domInCell(view, startEvent.target);
  var $anchor;
  if (startEvent.shiftKey && view.state.selection instanceof CellSelection) {
    setCellSelection(view.state.selection.$anchorCell, startEvent);
    startEvent.preventDefault();
  } else if (startEvent.shiftKey && startDOMCell && ($anchor = cellAround(view.state.selection.$anchor)) != null && ((_a = cellUnderMouse(view, startEvent)) == null ? void 0 : _a.pos) != $anchor.pos) {
    setCellSelection($anchor, startEvent);
    startEvent.preventDefault();
  } else if (!startDOMCell) {
    return;
  }
  function setCellSelection($anchor2, event) {
    var $head = cellUnderMouse(view, event);
    var starting = tableEditingKey.getState(view.state) == null;
    if (!$head || !inSameTable($anchor2, $head)) {
      if (starting)
        { $head = $anchor2; }
      else
        { return; }
    }
    var selection = new CellSelection($anchor2, $head);
    if (starting || !view.state.selection.eq(selection)) {
      var tr = view.state.tr.setSelection(selection);
      if (starting)
        { tr.setMeta(tableEditingKey, $anchor2.pos); }
      view.dispatch(tr);
    }
  }
  function stop() {
    view.root.removeEventListener("mouseup", stop);
    view.root.removeEventListener("dragstart", stop);
    view.root.removeEventListener("mousemove", move);
    if (tableEditingKey.getState(view.state) != null)
      { view.dispatch(view.state.tr.setMeta(tableEditingKey, -1)); }
  }
  function move(_event) {
    var event = _event;
    var anchor = tableEditingKey.getState(view.state);
    var $anchor2;
    if (anchor != null) {
      $anchor2 = view.state.doc.resolve(anchor);
    } else if (domInCell(view, event.target) != startDOMCell) {
      $anchor2 = cellUnderMouse(view, startEvent);
      if (!$anchor2)
        { return stop(); }
    }
    if ($anchor2)
      { setCellSelection($anchor2, event); }
  }
  view.root.addEventListener("mouseup", stop);
  view.root.addEventListener("dragstart", stop);
  view.root.addEventListener("mousemove", move);
}
function atEndOfCell(view, axis, dir) {
  if (!(view.state.selection instanceof TextSelection))
    { return null; }
  var ref = view.state.selection;
  var $head = ref.$head;
  for (var d = $head.depth - 1; d >= 0; d--) {
    var parent = $head.node(d), index = dir < 0 ? $head.index(d) : $head.indexAfter(d);
    if (index != (dir < 0 ? 0 : parent.childCount))
      { return null; }
    if (parent.type.spec.tableRole == "cell" || parent.type.spec.tableRole == "header_cell") {
      var cellPos = $head.before(d);
      var dirStr = axis == "vert" ? dir > 0 ? "down" : "up" : dir > 0 ? "right" : "left";
      return view.endOfTextblock(dirStr) ? cellPos : null;
    }
  }
  return null;
}
function domInCell(view, dom) {
  for (; dom && dom != view.dom; dom = dom.parentNode) {
    if (dom.nodeName == "TD" || dom.nodeName == "TH") {
      return dom;
    }
  }
  return null;
}
function cellUnderMouse(view, event) {
  var mousePos = view.posAtCoords({
    left: event.clientX,
    top: event.clientY
  });
  if (!mousePos)
    { return null; }
  return mousePos ? cellAround(view.state.doc.resolve(mousePos.pos)) : null;
}

// src/columnresizing.ts
new PluginKey(
  "tableColumnResizing"
);

// src/index.ts
function tableEditing(ref) {
  if ( ref === void 0 ) ref = {};
  var allowTableNodeSelection = ref.allowTableNodeSelection; if ( allowTableNodeSelection === void 0 ) allowTableNodeSelection = false;

  return new Plugin({
    key: tableEditingKey,
    // This piece of state is used to remember when a mouse-drag
    // cell-selection is happening, so that it can continue even as
    // transactions (which might move its anchor cell) come in.
    state: {
      init: function init() {
        return null;
      },
      apply: function apply(tr, cur) {
        var set = tr.getMeta(tableEditingKey);
        if (set != null)
          { return set == -1 ? null : set; }
        if (cur == null || !tr.docChanged)
          { return cur; }
        var ref = tr.mapping.mapResult(cur);
        var deleted = ref.deleted;
        var pos = ref.pos;
        return deleted ? null : pos;
      }
    },
    props: {
      decorations: drawCellSelection,
      handleDOMEvents: {
        mousedown: handleMouseDown
      },
      createSelectionBetween: function createSelectionBetween(view) {
        return tableEditingKey.getState(view.state) != null ? view.state.selection : null;
      },
      handleTripleClick: handleTripleClick,
      handleKeyDown: handleKeyDown$1,
      handlePaste: handlePaste
    },
    appendTransaction: function appendTransaction(_, oldState, state) {
      return normalizeSelection(
        state,
        fixTables(state, oldState),
        allowTableNodeSelection
      );
    }
  });
}/**
Returns a command function that wraps the selection in a list with
the given type an attributes. If `dispatch` is null, only return a
value to indicate whether this is possible, but don't actually
perform the change.
*/
function wrapInList(listType, attrs) {
    if ( attrs === void 0 ) attrs = null;

    return function (state, dispatch) {
        var ref = state.selection;
        var $from = ref.$from;
        var $to = ref.$to;
        var range = $from.blockRange($to), doJoin = false, outerRange = range;
        if (!range)
            { return false; }
        // This is at the top of an existing list item
        if (range.depth >= 2 && $from.node(range.depth - 1).type.compatibleContent(listType) && range.startIndex == 0) {
            // Don't do anything if this is the top of the list
            if ($from.index(range.depth - 1) == 0)
                { return false; }
            var $insert = state.doc.resolve(range.start - 2);
            outerRange = new NodeRange($insert, $insert, range.depth);
            if (range.endIndex < range.parent.childCount)
                { range = new NodeRange($from, state.doc.resolve($to.end(range.depth)), range.depth); }
            doJoin = true;
        }
        var wrap = findWrapping(outerRange, listType, attrs, range);
        if (!wrap)
            { return false; }
        if (dispatch)
            { dispatch(doWrapInList(state.tr, range, wrap, doJoin, listType).scrollIntoView()); }
        return true;
    };
}
function doWrapInList(tr, range, wrappers, joinBefore, listType) {
    var content = Fragment.empty;
    for (var i = wrappers.length - 1; i >= 0; i--)
        { content = Fragment.from(wrappers[i].type.create(wrappers[i].attrs, content)); }
    tr.step(new ReplaceAroundStep(range.start - (joinBefore ? 2 : 0), range.end, range.start, range.end, new Slice(content, 0, 0), wrappers.length, true));
    var found = 0;
    for (var i$1 = 0; i$1 < wrappers.length; i$1++)
        { if (wrappers[i$1].type == listType)
            { found = i$1 + 1; } }
    var splitDepth = wrappers.length - found;
    var splitPos = range.start + wrappers.length - (joinBefore ? 2 : 0), parent = range.parent;
    for (var i$2 = range.startIndex, e = range.endIndex, first = true; i$2 < e; i$2++, first = false) {
        if (!first && canSplit(tr.doc, splitPos, splitDepth)) {
            tr.split(splitPos, splitDepth);
            splitPos += 2 * splitDepth;
        }
        splitPos += parent.child(i$2).nodeSize;
    }
    return tr;
}
/**
Build a command that splits a non-empty textblock at the top level
of a list item by also splitting that list item.
*/
function splitListItem(itemType, itemAttrs) {
    return function (state, dispatch) {
        var ref = state.selection;
        var $from = ref.$from;
        var $to = ref.$to;
        var node = ref.node;
        if ((node && node.isBlock) || $from.depth < 2 || !$from.sameParent($to))
            { return false; }
        var grandParent = $from.node(-1);
        if (grandParent.type != itemType)
            { return false; }
        if ($from.parent.content.size == 0 && $from.node(-1).childCount == $from.indexAfter(-1)) {
            // In an empty block. If this is a nested list, the wrapping
            // list item should be split. Otherwise, bail out and let next
            // command handle lifting.
            if ($from.depth == 3 || $from.node(-3).type != itemType ||
                $from.index(-2) != $from.node(-2).childCount - 1)
                { return false; }
            if (dispatch) {
                var wrap = Fragment.empty;
                var depthBefore = $from.index(-1) ? 1 : $from.index(-2) ? 2 : 3;
                // Build a fragment containing empty versions of the structure
                // from the outer list item to the parent node of the cursor
                for (var d = $from.depth - depthBefore; d >= $from.depth - 3; d--)
                    { wrap = Fragment.from($from.node(d).copy(wrap)); }
                var depthAfter = $from.indexAfter(-1) < $from.node(-2).childCount ? 1
                    : $from.indexAfter(-2) < $from.node(-3).childCount ? 2 : 3;
                // Add a second list item with an empty default start node
                wrap = wrap.append(Fragment.from(itemType.createAndFill()));
                var start = $from.before($from.depth - (depthBefore - 1));
                var tr$1 = state.tr.replace(start, $from.after(-depthAfter), new Slice(wrap, 4 - depthBefore, 0));
                var sel = -1;
                tr$1.doc.nodesBetween(start, tr$1.doc.content.size, function (node, pos) {
                    if (sel > -1)
                        { return false; }
                    if (node.isTextblock && node.content.size == 0)
                        { sel = pos + 1; }
                });
                if (sel > -1)
                    { tr$1.setSelection(Selection.near(tr$1.doc.resolve(sel))); }
                dispatch(tr$1.scrollIntoView());
            }
            return true;
        }
        var nextType = $to.pos == $from.end() ? grandParent.contentMatchAt(0).defaultType : null;
        var tr = state.tr.delete($from.pos, $to.pos);
        var types = nextType ? [itemAttrs ? { type: itemType, attrs: itemAttrs } : null, { type: nextType }] : undefined;
        if (!canSplit(tr.doc, $from.pos, 2, types))
            { return false; }
        if (dispatch)
            { dispatch(tr.split($from.pos, 2, types).scrollIntoView()); }
        return true;
    };
}
/**
Create a command to lift the list item around the selection up into
a wrapping list.
*/
function liftListItem(itemType) {
    return function (state, dispatch) {
        var ref = state.selection;
        var $from = ref.$from;
        var $to = ref.$to;
        var range = $from.blockRange($to, function (node) { return node.childCount > 0 && node.firstChild.type == itemType; });
        if (!range)
            { return false; }
        if (!dispatch)
            { return true; }
        if ($from.node(range.depth - 1).type == itemType) // Inside a parent list
            { return liftToOuterList(state, dispatch, itemType, range); }
        else // Outer list node
            { return liftOutOfList(state, dispatch, range); }
    };
}
function liftToOuterList(state, dispatch, itemType, range) {
    var tr = state.tr, end = range.end, endOfList = range.$to.end(range.depth);
    if (end < endOfList) {
        // There are siblings after the lifted items, which must become
        // children of the last item
        tr.step(new ReplaceAroundStep(end - 1, endOfList, end, endOfList, new Slice(Fragment.from(itemType.create(null, range.parent.copy())), 1, 0), 1, true));
        range = new NodeRange(tr.doc.resolve(range.$from.pos), tr.doc.resolve(endOfList), range.depth);
    }
    var target = liftTarget(range);
    if (target == null)
        { return false; }
    tr.lift(range, target);
    var after = tr.mapping.map(end, -1) - 1;
    if (canJoin(tr.doc, after))
        { tr.join(after); }
    dispatch(tr.scrollIntoView());
    return true;
}
function liftOutOfList(state, dispatch, range) {
    var tr = state.tr, list = range.parent;
    // Merge the list items into a single big item
    for (var pos = range.end, i = range.endIndex - 1, e = range.startIndex; i > e; i--) {
        pos -= list.child(i).nodeSize;
        tr.delete(pos - 1, pos + 1);
    }
    var $start = tr.doc.resolve(range.start), item = $start.nodeAfter;
    if (tr.mapping.map(range.end) != range.start + $start.nodeAfter.nodeSize)
        { return false; }
    var atStart = range.startIndex == 0, atEnd = range.endIndex == list.childCount;
    var parent = $start.node(-1), indexBefore = $start.index(-1);
    if (!parent.canReplace(indexBefore + (atStart ? 0 : 1), indexBefore + 1, item.content.append(atEnd ? Fragment.empty : Fragment.from(list))))
        { return false; }
    var start = $start.pos, end = start + item.nodeSize;
    // Strip off the surrounding list. At the sides where we're not at
    // the end of the list, the existing list is closed. At sides where
    // this is the end, it is overwritten to its end.
    tr.step(new ReplaceAroundStep(start - (atStart ? 1 : 0), end + (atEnd ? 1 : 0), start + 1, end - 1, new Slice((atStart ? Fragment.empty : Fragment.from(list.copy(Fragment.empty)))
        .append(atEnd ? Fragment.empty : Fragment.from(list.copy(Fragment.empty))), atStart ? 0 : 1, atEnd ? 0 : 1), atStart ? 0 : 1));
    dispatch(tr.scrollIntoView());
    return true;
}
/**
Create a command to sink the list item around the selection down
into an inner list.
*/
function sinkListItem(itemType) {
    return function (state, dispatch) {
        var ref = state.selection;
        var $from = ref.$from;
        var $to = ref.$to;
        var range = $from.blockRange($to, function (node) { return node.childCount > 0 && node.firstChild.type == itemType; });
        if (!range)
            { return false; }
        var startIndex = range.startIndex;
        if (startIndex == 0)
            { return false; }
        var parent = range.parent, nodeBefore = parent.child(startIndex - 1);
        if (nodeBefore.type != itemType)
            { return false; }
        if (dispatch) {
            var nestedBefore = nodeBefore.lastChild && nodeBefore.lastChild.type == parent.type;
            var inner = Fragment.from(nestedBefore ? itemType.create() : null);
            var slice = new Slice(Fragment.from(itemType.create(null, Fragment.from(parent.type.create(null, inner)))), nestedBefore ? 3 : 1, 0);
            var before = range.start, after = range.end;
            dispatch(state.tr.step(new ReplaceAroundStep(before - (nestedBefore ? 3 : 1), after, before, after, slice, 1, true))
                .scrollIntoView());
        }
        return true;
    };
}var SVG = "http://www.w3.org/2000/svg";
var XLINK = "http://www.w3.org/1999/xlink";

var prefix$2 = "ProseMirror-icon";

var getIconSize = function (name) {
    var veryBigIcons = ['table', 'enlarge', 'shrink'];
    var biggerIcons = ['emoji'];
    var bigIcons = ['headline', 'join', 'image', 'undo', 'redo', 'markdown', 'angleDoubleRight', 'angleDoubleLeft'];
    var smallIcons = ['bulletList', 'orderedList', 'indent', 'outdent'];

    return smallIcons.includes(name)
        ? '18' : bigIcons.includes(name)
            ? '16' : biggerIcons.includes(name)
                ? '15' : veryBigIcons.includes(name) ? '14' : '17';
};

function getIcon(icon, htmlNode) {
    htmlNode = htmlNode || 'div';
    var node = document.createElement(htmlNode);
    node.className = prefix$2;

    if (htmlNode === "button") {
        node.setAttribute("type", "button");
    }

    if (icon.path) {
        var name = "pm-icon-" + icon.name;
        if (!document.getElementById(name)) { buildSVG(name, icon); }
        var svg = node.appendChild(document.createElementNS(SVG, "svg"));
        var iconSize = getIconSize(icon.name);
        svg.setAttribute('height', iconSize /*icon.height*/);
        svg.setAttribute('width', iconSize /*icon.width*/);
        var use = svg.appendChild(document.createElementNS(SVG, "use"));
        use.setAttributeNS(XLINK, "href", /([^#]*)/.exec(document.location)[1] + "#" + name);
    } else if (icon.dom) {
        node.appendChild(icon.dom.cloneNode(true));
    } else {
        node.appendChild(document.createElement("span")).textContent = icon.text || '';
        if (icon.css) { node.firstChild.style.cssText = icon.css; }
    }
    return node;
}

function buildSVG(name, data) {
    var collection = document.getElementById(prefix$2 + "-collection");
    if (!collection) {
        collection = document.createElementNS(SVG, "svg");
        collection.id = prefix$2 + "-collection";
        collection.style.display = "none";
        document.body.insertBefore(collection, document.body.firstChild);
    }
    var sym = document.createElementNS(SVG, "symbol");
    sym.id = name;
    sym.setAttribute("viewBox", "0 0 " + data.width + " " + data.height);

    var pathData = Array.isArray(data.path) ? data.path : [data.path];

    pathData.forEach(function (path) {
        var pathDom = sym.appendChild(document.createElementNS(SVG, "path"));
        pathDom.setAttribute("d", path);
        collection.appendChild(sym);
    });
}

// :: Object
// A set of basic editor-related icons. Contains the properties
// `join`, `lift`, `selectParentNode`, `undo`, `redo`, `strong`, `em`,
// `code`, `link`, `bulletList`, `orderedList`, and `blockquote`, each
// holding an object that can be used as the `icon` option to
// `MenuItem`.
var icons = {
    headline: {
        name: 'headline',
        width: 27, height: 27,
        path: "M26.281 26c-1.375 0-2.766-0.109-4.156-0.109-1.375 0-2.75 0.109-4.125 0.109-0.531 0-0.781-0.578-0.781-1.031 0-1.391 1.563-0.797 2.375-1.328 0.516-0.328 0.516-1.641 0.516-2.188l-0.016-6.109c0-0.172 0-0.328-0.016-0.484-0.25-0.078-0.531-0.063-0.781-0.063h-10.547c-0.266 0-0.547-0.016-0.797 0.063-0.016 0.156-0.016 0.313-0.016 0.484l-0.016 5.797c0 0.594 0 2.219 0.578 2.562 0.812 0.5 2.656-0.203 2.656 1.203 0 0.469-0.219 1.094-0.766 1.094-1.453 0-2.906-0.109-4.344-0.109-1.328 0-2.656 0.109-3.984 0.109-0.516 0-0.75-0.594-0.75-1.031 0-1.359 1.437-0.797 2.203-1.328 0.5-0.344 0.516-1.687 0.516-2.234l-0.016-0.891v-12.703c0-0.75 0.109-3.156-0.594-3.578-0.781-0.484-2.453 0.266-2.453-1.141 0-0.453 0.203-1.094 0.75-1.094 1.437 0 2.891 0.109 4.328 0.109 1.313 0 2.641-0.109 3.953-0.109 0.562 0 0.781 0.625 0.781 1.094 0 1.344-1.547 0.688-2.312 1.172-0.547 0.328-0.547 1.937-0.547 2.5l0.016 5c0 0.172 0 0.328 0.016 0.5 0.203 0.047 0.406 0.047 0.609 0.047h10.922c0.187 0 0.391 0 0.594-0.047 0.016-0.172 0.016-0.328 0.016-0.5l0.016-5c0-0.578 0-2.172-0.547-2.5-0.781-0.469-2.344 0.156-2.344-1.172 0-0.469 0.219-1.094 0.781-1.094 1.375 0 2.75 0.109 4.125 0.109 1.344 0 2.688-0.109 4.031-0.109 0.562 0 0.781 0.625 0.781 1.094 0 1.359-1.609 0.672-2.391 1.156-0.531 0.344-0.547 1.953-0.547 2.516l0.016 14.734c0 0.516 0.031 1.875 0.531 2.188 0.797 0.5 2.484-0.141 2.484 1.219 0 0.453-0.203 1.094-0.75 1.094z"
    },
    plus: {
        name: 'plus',
        width: 16, height: 16,
        path: "M8 2a.5.5 0 0 1 .5.5v5h5a.5.5 0 0 1 0 1h-5v5a.5.5 0 0 1-1 0v-5h-5a.5.5 0 0 1 0-1h5v-5A.5.5 0 0 1 8 2Z"
    },
    add: {
        name: 'add',
        width: 16, height: 16,
        path: [
            "M14 1a1 1 0 0 1 1 1v12a1 1 0 0 1-1 1H2a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1h12zM2 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2H2z",
            "M8 4a.5.5 0 0 1 .5.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3A.5.5 0 0 1 8 4z"
        ]
    },
    join: {
        name: 'join',
        width: 800, height: 900,
        path: "M0 75h800v125h-800z M0 825h800v-125h-800z M250 400h100v-100h100v100h100v100h-100v100h-100v-100h-100z"
    },
    text: {
        name: 'text',
        width: 16, height: 16,
        path: 'm2.244 13.081.943-2.803H6.66l.944 2.803H8.86L5.54 3.75H4.322L1 13.081h1.244zm2.7-7.923L6.34 9.314H3.51l1.4-4.156h.034zm9.146 7.027h.035v.896h1.128V8.125c0-1.51-1.114-2.345-2.646-2.345-1.736 0-2.59.916-2.666 2.174h1.108c.068-.718.595-1.19 1.517-1.19.971 0 1.518.52 1.518 1.464v.731H12.19c-1.647.007-2.522.8-2.522 2.058 0 1.319.957 2.18 2.345 2.18 1.06 0 1.716-.43 2.078-1.011zm-1.763.035c-.752 0-1.456-.397-1.456-1.244 0-.65.424-1.115 1.408-1.115h1.805v.834c0 .896-.752 1.525-1.757 1.525z'
    },
    strong: {
        name: 'strong',
        width: 16, height: 16,
        path: "M8.21 13c2.106 0 3.412-1.087 3.412-2.823 0-1.306-.984-2.283-2.324-2.386v-.055a2.176 2.176 0 0 0 1.852-2.14c0-1.51-1.162-2.46-3.014-2.46H3.843V13H8.21zM5.908 4.674h1.696c.963 0 1.517.451 1.517 1.244 0 .834-.629 1.32-1.73 1.32H5.908V4.673zm0 6.788V8.598h1.73c1.217 0 1.88.492 1.88 1.415 0 .943-.643 1.449-1.832 1.449H5.907z"
    },
    em: {
        name: 'em',
        width: 16, height: 16,
        path: "M7.991 11.674 9.53 4.455c.123-.595.246-.71 1.347-.807l.11-.52H7.211l-.11.52c1.06.096 1.128.212 1.005.807L6.57 11.674c-.123.595-.246.71-1.346.806l-.11.52h3.774l.11-.52c-1.06-.095-1.129-.211-1.006-.806z"
    },
    strikethrough: {
        name: 'strikethrough',
        width: 16, height: 16,
        path: "M6.333 5.686c0 .31.083.581.27.814H5.166a2.776 2.776 0 0 1-.099-.76c0-1.627 1.436-2.768 3.48-2.768 1.969 0 3.39 1.175 3.445 2.85h-1.23c-.11-1.08-.964-1.743-2.25-1.743-1.23 0-2.18.602-2.18 1.607zm2.194 7.478c-2.153 0-3.589-1.107-3.705-2.81h1.23c.144 1.06 1.129 1.703 2.544 1.703 1.34 0 2.31-.705 2.31-1.675 0-.827-.547-1.374-1.914-1.675L8.046 8.5H1v-1h14v1h-3.504c.468.437.675.994.675 1.697 0 1.826-1.436 2.967-3.644 2.967z"
    },
    code: {
        name: 'code',
        width: 16, height: 16,
        path: "M5.854 4.854a.5.5 0 1 0-.708-.708l-3.5 3.5a.5.5 0 0 0 0 .708l3.5 3.5a.5.5 0 0 0 .708-.708L2.707 8l3.147-3.146zm4.292 0a.5.5 0 0 1 .708-.708l3.5 3.5a.5.5 0 0 1 0 .708l-3.5 3.5a.5.5 0 0 1-.708-.708L13.293 8l-3.147-3.146z"
    },
    link: {
        name: 'link',
        width: 16, height: 16,
        path: [
            "M4.715 6.542 3.343 7.914a3 3 0 1 0 4.243 4.243l1.828-1.829A3 3 0 0 0 8.586 5.5L8 6.086a1.002 1.002 0 0 0-.154.199 2 2 0 0 1 .861 3.337L6.88 11.45a2 2 0 1 1-2.83-2.83l.793-.792a4.018 4.018 0 0 1-.128-1.287z",
            "M6.586 4.672A3 3 0 0 0 7.414 9.5l.775-.776a2 2 0 0 1-.896-3.346L9.12 3.55a2 2 0 1 1 2.83 2.83l-.793.792c.112.42.155.855.128 1.287l1.372-1.372a3 3 0 1 0-4.243-4.243L6.586 4.672z"
        ]
    },
    bulletList: {
        name: 'bulletList',
        width: 16, height: 16,
        path: "M5 11.5a.5.5 0 0 1 .5-.5h9a.5.5 0 0 1 0 1h-9a.5.5 0 0 1-.5-.5zm0-4a.5.5 0 0 1 .5-.5h9a.5.5 0 0 1 0 1h-9a.5.5 0 0 1-.5-.5zm0-4a.5.5 0 0 1 .5-.5h9a.5.5 0 0 1 0 1h-9a.5.5 0 0 1-.5-.5zm-3 1a1 1 0 1 0 0-2 1 1 0 0 0 0 2zm0 4a1 1 0 1 0 0-2 1 1 0 0 0 0 2zm0 4a1 1 0 1 0 0-2 1 1 0 0 0 0 2z"
    },
    orderedList: {
        name: 'orderedList',
        width: 16, height: 16,
        path: [
            "M5 11.5a.5.5 0 0 1 .5-.5h9a.5.5 0 0 1 0 1h-9a.5.5 0 0 1-.5-.5zm0-4a.5.5 0 0 1 .5-.5h9a.5.5 0 0 1 0 1h-9a.5.5 0 0 1-.5-.5zm0-4a.5.5 0 0 1 .5-.5h9a.5.5 0 0 1 0 1h-9a.5.5 0 0 1-.5-.5z",
            "M1.713 11.865v-.474H2c.217 0 .363-.137.363-.317 0-.185-.158-.31-.361-.31-.223 0-.367.152-.373.31h-.59c.016-.467.373-.787.986-.787.588-.002.954.291.957.703a.595.595 0 0 1-.492.594v.033a.615.615 0 0 1 .569.631c.003.533-.502.8-1.051.8-.656 0-1-.37-1.008-.794h.582c.008.178.186.306.422.309.254 0 .424-.145.422-.35-.002-.195-.155-.348-.414-.348h-.3zm-.004-4.699h-.604v-.035c0-.408.295-.844.958-.844.583 0 .96.326.96.756 0 .389-.257.617-.476.848l-.537.572v.03h1.054V9H1.143v-.395l.957-.99c.138-.142.293-.304.293-.508 0-.18-.147-.32-.342-.32a.33.33 0 0 0-.342.338v.041zM2.564 5h-.635V2.924h-.031l-.598.42v-.567l.629-.443h.635V5z"
        ]
    },
    indent: {
        name: 'indent',
        width: 16, height: 16,
        path: "M2 3.5a.5.5 0 0 1 .5-.5h11a.5.5 0 0 1 0 1h-11a.5.5 0 0 1-.5-.5zm.646 2.146a.5.5 0 0 1 .708 0l2 2a.5.5 0 0 1 0 .708l-2 2a.5.5 0 0 1-.708-.708L4.293 8 2.646 6.354a.5.5 0 0 1 0-.708zM7 6.5a.5.5 0 0 1 .5-.5h6a.5.5 0 0 1 0 1h-6a.5.5 0 0 1-.5-.5zm0 3a.5.5 0 0 1 .5-.5h6a.5.5 0 0 1 0 1h-6a.5.5 0 0 1-.5-.5zm-5 3a.5.5 0 0 1 .5-.5h11a.5.5 0 0 1 0 1h-11a.5.5 0 0 1-.5-.5z"
    },
    outdent: {
        name: 'outdent',
        width: 16, height: 16,
        path: "M2 3.5a.5.5 0 0 1 .5-.5h11a.5.5 0 0 1 0 1h-11a.5.5 0 0 1-.5-.5zm10.646 2.146a.5.5 0 0 1 .708.708L11.707 8l1.647 1.646a.5.5 0 0 1-.708.708l-2-2a.5.5 0 0 1 0-.708l2-2zM2 6.5a.5.5 0 0 1 .5-.5h6a.5.5 0 0 1 0 1h-6a.5.5 0 0 1-.5-.5zm0 3a.5.5 0 0 1 .5-.5h6a.5.5 0 0 1 0 1h-6a.5.5 0 0 1-.5-.5zm0 3a.5.5 0 0 1 .5-.5h11a.5.5 0 0 1 0 1h-11a.5.5 0 0 1-.5-.5z"
    },
    blockquote: {
        name: 'blockquote',
        width: 16, height: 16,
        path: "M12 12a1 1 0 0 0 1-1V8.558a1 1 0 0 0-1-1h-1.388c0-.351.021-.703.062-1.054.062-.372.166-.703.31-.992.145-.29.331-.517.559-.683.227-.186.516-.279.868-.279V3c-.579 0-1.085.124-1.52.372a3.322 3.322 0 0 0-1.085.992 4.92 4.92 0 0 0-.62 1.458A7.712 7.712 0 0 0 9 7.558V11a1 1 0 0 0 1 1h2Zm-6 0a1 1 0 0 0 1-1V8.558a1 1 0 0 0-1-1H4.612c0-.351.021-.703.062-1.054.062-.372.166-.703.31-.992.145-.29.331-.517.559-.683.227-.186.516-.279.868-.279V3c-.579 0-1.085.124-1.52.372a3.322 3.322 0 0 0-1.085.992 4.92 4.92 0 0 0-.62 1.458A7.712 7.712 0 0 0 3 7.558V11a1 1 0 0 0 1 1h2Z"
    },
    table: {
        name: 'table',
        width: 18, height: 18,
        path: "M0 2a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V2zm15 2h-4v3h4V4zm0 4h-4v3h4V8zm0 4h-4v3h3a1 1 0 0 0 1-1v-2zm-5 3v-3H6v3h4zm-5 0v-3H1v2a1 1 0 0 0 1 1h3zm-4-4h4V8H1v3zm0-4h4V4H1v3zm5-3v3h4V4H6zm4 4H6v3h4V8z"
    },
    emoji: {
        name: 'emoji',
        width: 18, height: 18,
        path: [
            "M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z",
            "M4.285 9.567a.5.5 0 0 1 .683.183A3.498 3.498 0 0 0 8 11.5a3.498 3.498 0 0 0 3.032-1.75.5.5 0 1 1 .866.5A4.498 4.498 0 0 1 8 12.5a4.498 4.498 0 0 1-3.898-2.25.5.5 0 0 1 .183-.683zM7 6.5C7 7.328 6.552 8 6 8s-1-.672-1-1.5S5.448 5 6 5s1 .672 1 1.5zm4 0c0 .828-.448 1.5-1 1.5s-1-.672-1-1.5S9.448 5 10 5s1 .672 1 1.5z"
        ]
    },
    upload: {
        name: 'upload',
        width: 16, height: 16,
        path: [
            "M9.344 8.656h2l-3.344-3.313-3.344 3.313h2v2.688h2.688v-2.688zM12.906 6.688q1.281 0.094 2.188 1.047t0.906 2.266q0 1.375-0.984 2.359t-2.359 0.984h-8.656q-1.656 0-2.828-1.172t-1.172-2.828q0-1.469 1.047-2.641t2.516-1.328q0.656-1.219 1.844-1.969t2.594-0.75q1.688 0 3.141 1.188t1.766 2.844z"
        ]
    },
    undo: {
        name: 'undo',
        width: 16, height: 16,
        path: [
            "M8 3a5 5 0 1 1-4.546 2.914.5.5 0 0 0-.908-.417A6 6 0 1 0 8 2v1z",
            "M8 4.466V.534a.25.25 0 0 0-.41-.192L5.23 2.308a.25.25 0 0 0 0 .384l2.36 1.966A.25.25 0 0 0 8 4.466z"
        ]
    },
    redo: {
        name: 'redo',
        width: 16, height: 16,
        path: [
            "M8 3a5 5 0 1 0 4.546 2.914.5.5 0 0 1 .908-.417A6 6 0 1 1 8 2v1z",
            "M8 4.466V.534a.25.25 0 0 1 .41-.192l2.36 1.966c.12.1.12.284 0 .384L8.41 4.658A.25.25 0 0 1 8 4.466z"
        ]
    },
    enlarge: {
        name: 'enlarge',
        width: 16, height: 16,
        path: "M5.828 10.172a.5.5 0 0 0-.707 0l-4.096 4.096V11.5a.5.5 0 0 0-1 0v3.975a.5.5 0 0 0 .5.5H4.5a.5.5 0 0 0 0-1H1.732l4.096-4.096a.5.5 0 0 0 0-.707zm4.344-4.344a.5.5 0 0 0 .707 0l4.096-4.096V4.5a.5.5 0 1 0 1 0V.525a.5.5 0 0 0-.5-.5H11.5a.5.5 0 0 0 0 1h2.768l-4.096 4.096a.5.5 0 0 0 0 .707z"
    },
    shrink: {
        name: 'shrink',
        width: 16, height: 16,
        path: "M.172 15.828a.5.5 0 0 0 .707 0l4.096-4.096V14.5a.5.5 0 1 0 1 0v-3.975a.5.5 0 0 0-.5-.5H1.5a.5.5 0 0 0 0 1h2.768L.172 15.121a.5.5 0 0 0 0 .707zM15.828.172a.5.5 0 0 0-.707 0l-4.096 4.096V1.5a.5.5 0 1 0-1 0v3.975a.5.5 0 0 0 .5.5H14.5a.5.5 0 0 0 0-1h-2.768L15.828.879a.5.5 0 0 0 0-.707z"
    },
    angleDoubleRight: {
        name: 'angleDoubleRight',
        width: 16, height: 16,
        path: [
            "M3.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L9.293 8 3.646 2.354a.5.5 0 0 1 0-.708z",
            "M7.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L13.293 8 7.646 2.354a.5.5 0 0 1 0-.708z"
        ]
    },
    angleDoubleLeft: {
        name: 'angleDoubleLeft',
        width: 16, height: 16,
        path: [
            "M8.354 1.646a.5.5 0 0 1 0 .708L2.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z",
            "M12.354 1.646a.5.5 0 0 1 0 .708L6.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z"
        ]
    },
    markdown: {
        name: 'markdown',
        width: 16, height: 16,
        path: [
            "M14 3a1 1 0 0 1 1 1v8a1 1 0 0 1-1 1H2a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h12zM2 2a2 2 0 0 0-2 2v8a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2H2z",
            "M9.146 8.146a.5.5 0 0 1 .708 0L11.5 9.793l1.646-1.647a.5.5 0 0 1 .708.708l-2 2a.5.5 0 0 1-.708 0l-2-2a.5.5 0 0 1 0-.708z",
            "M11.5 5a.5.5 0 0 1 .5.5v4a.5.5 0 0 1-1 0v-4a.5.5 0 0 1 .5-.5z",
            "M3.56 11V7.01h.056l1.428 3.239h.774l1.42-3.24h.056V11h1.073V5.001h-1.2l-1.71 3.894h-.039l-1.71-3.894H2.5V11h1.06z"
        ]
    },
    horizontalRule: {
        name: 'horizontalRule',
        width: 16, height: 16,
        path: [
            "M0 6.5v3c0 0.276 0.224 0.5 0.5 0.5h15c0.276 0 0.5-0.224 0.5-0.5v-3c0-0.276-0.224-0.5-0.5-0.5h-15c-0.276 0-0.5 0.224-0.5 0.5z"
        ]
    },
    selectParentNode: {name: 'selectParentNode',text: "\u2b1a", css: "font-weight: bold"}
};var PREFIX = "ProseMirror-menu";

// Work around classList.toggle being broken in IE11
function setClass(dom, cls, on) {
    if (on) { dom.classList.add(cls); }
    else { dom.classList.remove(cls); }
}

function setAttribute(dom, attr, value, on) {
    if (on) { dom.setAttribute(attr, value); }
    else { dom.removeAttribute(attr); }
}

function translate$1(view, text) {
    return view._props.translate ? view._props.translate(text) : text;
}

function addClassId(dom, options) {
    if (options.id) {
        addMenuClass(dom, options);
    }
}

function initMenuItemTrigger(view, options) {
    var trigger = null;
    if (options.icon) {
        trigger = getIcon(options.icon, options.htmlNode);
    } else if (options.label) {
        trigger = document.createElement(options.htmlNode);
        trigger.innerHTML = translate$1(view, options.label).replace('</i>', '</i> ');
    } else {
        return null;
    }

    trigger.classList.add(buildMenuClass('trigger'));

    if (trigger) {
        setAttributesFromOptions(trigger, options);
    }

    return trigger;
}

function setTabindex(dom, options) {
    if (typeof options.tabindex !== 'undefined') {
        dom.setAttribute('tabindex', options.tabindex);
    }
}

function setTitle(dom, options, view) {
    if (options.title !== 'undefined') {
        var title = (typeof options.title === "function" ? options.title(view.state) : options.title);
        dom.setAttribute("title", translate$1(view, title));
    }
}

function setAttributesFromOptions(dom, options) {
    if (options.class) { dom.classList.add(options.class); }
    if (options.css) { dom.style.cssText += options.css; }
    if (options.seperator) {
        dom.classList.add('seperator');
    }
    addClassId(dom, options);
}

function buildMenuClass(suffix) {
    if (typeof suffix === 'object') {
        suffix = suffix.id;
    }

    return PREFIX + '-' + suffix;
}

function addMenuClass(dom, suffix) {
    dom.classList.add(buildMenuClass(suffix));
}

var lastMenuEvent = {time: 0, node: null};

function markMenuEvent(e) {
    lastMenuEvent.time = Date.now();
    lastMenuEvent.node = e.target;
}

function isMenuEvent(wrapper) {
    return Date.now() - 100 < lastMenuEvent.time &&
        lastMenuEvent.node && wrapper.contains(lastMenuEvent.node);
}// ::- An icon or label that, when clicked, executes a command.

// MenuItemSpec:: interface
// The configuration object passed to the `MenuItem` constructor.
//
//   run:: (EditorState, (Transaction), EditorView, dom.Event)
//   The function to execute when the menu item is activated.
//
//   select:: ?(EditorState) → bool
//   Optional function that is used to determine whether the item is
//   appropriate at the moment. Deselected items will be hidden.
//
//   enable:: ?(EditorState) → bool
//   Function that is used to determine if the item is enabled. If
//   given and returning false, the item will be given a disabled
//   styling.
//
//   active:: ?(EditorState) → bool
//   A predicate function to determine whether the item is 'active' (for
//   example, the item for toggling the strong mark might be active then
//   the cursor is in strong text).
//
//   render:: ?(EditorView) → dom.Node
//   A function that renders the item. You must provide either this,
//   [`icon`](#menu.MenuItemSpec.icon), or [`label`](#MenuItemSpec.label).
//
//   icon:: ?Object
//   Describes an icon to show for this item. The object may specify
//   an SVG icon, in which case its `path` property should be an [SVG
//   path
//   spec](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/d),
//   and `width` and `height` should provide the viewbox in which that
//   path exists. Alternatively, it may have a `text` property
//   specifying a string of text that makes up the icon, with an
//   optional `css` property giving additional CSS styling for the
//   text. _Or_ it may contain `dom` property containing a DOM node.
//
//   label:: ?string
//   Makes the item show up as a text label. Mostly useful for items
//   wrapped in a [drop-down](#menu.Dropdown) or similar menu. The object
//   should have a `label` property providing the text to display.
//
//   title:: ?union<string, (EditorState) → string>
//   Defines DOM title (mouseover) text for the item.
//
//   class:: string
//   Optionally adds a CSS class to the item's DOM representation.
//
//   css:: string
//   Optionally adds a string of inline CSS to the item's DOM
//   representation.
//
//   execEvent:: string
//   Defines which event on the command's DOM representation should
//   trigger the execution of the command. Defaults to mousedown.
var MenuItem = function MenuItem(options) {
    // :: MenuItemSpec
    // The options used to create the menu item.
    this.options = options || {};
    this.sortOrder = this.options.sortOrder;
    this.options.htmlNode = 'button';
};

// :: (EditorView) → {dom: dom.Node, update: (EditorState) → bool}
// Renders the icon according to its [display
// options](#menu.MenuItemSpec.display), and adds an event handler which
// executes the command when the representation is clicked.
MenuItem.prototype.render = function render (view, renderOptions) {
        if ( renderOptions === void 0 ) renderOptions = {};

    this.options = $.extend(this.options, renderOptions);

    if (typeof this.options.render === 'function') {
        return this.options.render.apply(this, [this.options]);
    }

    this.dom = initMenuItemTrigger(view, this.options);

    if (!this.dom) {
        throw new RangeError("MenuItem without icon or label property");
    }

    this.$ = $(this.dom);

    setAttributesFromOptions(this.dom, this.options);
    setTabindex(this.dom, renderOptions);
    setTitle(this.dom, this.options, view);
    this.initEvents(view);

    return this.dom;
};

MenuItem.prototype.initEvents = function initEvents (view) {
        var this$1$1 = this;

    var runHandler = function (e) {
        e.preventDefault();
        if (!this$1$1.$.hasClass(buildMenuClass('disabled'))) {
            this$1$1.options.run.call(this$1$1, view.state, view.dispatch, view, e);
        }
    };

    $(this.dom).on("mousedown", runHandler);
    $(this.dom).on("keydown", function (e) {
        var keyCode = e.keyCode || e.which;

        switch (keyCode) {
            case 13: // Enter
                e.preventDefault();
                runHandler(e);
                break;
        }
    });
};

MenuItem.prototype.getMenuBar = function getMenuBar () {
    if (!this.menuBar) {
        this.menuBar = $(this.dom).closest('.ProseMirror-menubar').data('menuBarInstance');
    }

    return this.menuBar;
};

MenuItem.prototype.switchIcon = function switchIcon (icon, title) {
    if (title) {
        $(this.dom).attr('title', title);
    }
    $(this.dom).find('svg').replaceWith($(getIcon(icon, this.options.htmlNode)).find('svg'));
};

MenuItem.prototype.update = function update (state) {
    this.adoptItemState(state);
    return this.selected;
};

MenuItem.prototype.adoptItemState = function adoptItemState (state, forceEnable, forceActive) {
    this.setEnabledItemState(state, forceEnable);
    this.setActiveItemState(state, forceActive);
    this.setSelectedItemState(state, forceEnable);
};

MenuItem.prototype.setActiveItemState = function setActiveItemState (state, forceActive) {
    this.active = false;
    if (this.options.active) {
        this.active = (this.options.active(state) || forceActive) || false;
        setClass(this.dom, buildMenuClass('active'), this.active);
        setAttribute(this.dom, 'aria-pressed', 'true', this.active);
    }
};

MenuItem.prototype.setEnabledItemState = function setEnabledItemState (state, forceEnable) {
    this.enabled = true;
    if (this.options.enable) {
        this.enabled = this.options.enable(state) || forceEnable || false;
        setClass(this.dom, buildMenuClass('disabled'), !this.enabled);
        setAttribute(this.dom, 'aria-disabled', 'true', !this.enabled);
    }
};

MenuItem.prototype.setSelectedItemState = function setSelectedItemState (state, forceEnable) {
    this.selected = true;
    if (this.options.select) {
        this.selected = this.options.select(state);
        this.dom.style.display = this.selected || forceEnable ? "" : "none";
        this.setHidden(!this.selected);
    }
};

MenuItem.prototype.setHidden = function setHidden (isHidden) {
    setAttribute(this.dom, 'aria-hidden', 'true', isHidden);
    setClass(this.dom, 'd-none', isHidden);

    if (this.isFocusable() && isHidden) {
        setAttribute(this.dom, 'tabindex', '-1', isHidden);
    }
};

MenuItem.prototype.isFocusable = function isFocusable () {
    return ['a', 'button', 'select', 'input'].includes(this.dom.tagName.toLocaleLowerCase());
};var MENU_SUFFIX_GROUP = 'group';

var MenuItemGroup = /*@__PURE__*/(function (MenuItem) {
    function MenuItemGroup(content, options) {
        MenuItem.call(this, options);
        this.options.htmlNode = 'div';
        this.initContent(content);
    }

    if ( MenuItem ) MenuItemGroup.__proto__ = MenuItem;
    MenuItemGroup.prototype = Object.create( MenuItem && MenuItem.prototype );
    MenuItemGroup.prototype.constructor = MenuItemGroup;

    MenuItemGroup.prototype.initContent = function initContent (content) {
        var this$1$1 = this;

        this.content = {
            items: sortItems(Array.isArray(content) ? content : [content]),
            update: function (state) {
                var result = false;

                sortItems(this$1$1.content.items).forEach(function (item, i) {
                    var updateResult = item.update(state);
                    var $item = $(item.dom);

                    if (!updateResult) {
                        $item.hide();
                    } else {
                        $item.show();
                    }

                    // Mark the last item in the group
                    if ((i === this$1$1.content.items.length - 1)) {
                        $item.addClass('last');
                    }

                    // If one item is visible the whole group is visible
                    result = result || updateResult;
                });

                return result;
            }
        };
    };

    MenuItemGroup.prototype.forEachItem = function forEachItem (callable) {
        this.content.items.forEach(callable);
    };

    MenuItemGroup.prototype.render = function render (view, renderOptions) {
        var this$1$1 = this;

        this.$ = $('<' + this.options.htmlNode + '>').addClass(buildMenuClass(MENU_SUFFIX_GROUP));
        this.dom = this.$[0];

        setAttributesFromOptions(this.dom, this.options);

        this.renderItems(view).forEach(function (itemDom) {
            this$1$1.$.append(itemDom);
        });

        return this.dom;
    };

    MenuItemGroup.prototype.update = function update (state) {
        var result = this.content.update(state);
        return result && MenuItem.prototype.update.call(this, state);
    };

    MenuItemGroup.prototype.setHidden = function setHidden (isHidden) {
        MenuItem.prototype.setHidden.call(this, isHidden);

        if (isHidden) {
            this.forEachItem(function (item) {
                item.setHidden(isHidden);
            });
        }
    };

    MenuItemGroup.prototype.renderItems = function renderItems (view) {
        var rendered = [];

        this.forEachItem(function (item) {
            var dom = item.render(view);

            // Note the PREFIX + item is here for compatibility reasons
            var itemDom = crelt("div", {class: PREFIX + 'item'}, dom);
            addMenuClass(itemDom, 'item');
            rendered.push(itemDom);
        });

        return rendered;
    };

    return MenuItemGroup;
}(MenuItem));

function sortItems(items) {
    var result = [];
    items.forEach(function (item) {
        if (item && item.type && item.type === 'dropdown') {
            result.push(new Dropdown(sortItems(item.items), item));
        } else if (item && item.type && item.type === 'group') {
            result.push(new MenuItemGroup(sortItems(item.items), item));
        } else if (item) {
            result.push(item);
        }
    });

    return result.sort(function (a, b) {
        if (typeof a.sortOrder === 'undefined') {
            return 1;
        }
        if (typeof b.sortOrder === 'undefined') {
            return -1;
        }
        return a.sortOrder - b.sortOrder;
    });
}// Holds currently opened dropdown item with close function
var opened = null;

// ::- A drop-down menu, displayed as a label with a downwards-pointing
// triangle to the right of it.
var Dropdown = /*@__PURE__*/(function (MenuItemGroup) {
    function Dropdown(content, options) {
        MenuItemGroup.call(this, content, options);
        this.options.htmlNode = 'button';
    }

    if ( MenuItemGroup ) Dropdown.__proto__ = MenuItemGroup;
    Dropdown.prototype = Object.create( MenuItemGroup && MenuItemGroup.prototype );
    Dropdown.prototype.constructor = Dropdown;

    // :: (EditorView) → {dom: dom.Node, update: (EditorState)}
    // Render the dropdown menu and sub-items.
    Dropdown.prototype.render = function render (view, renderOptions) {
        this.view = view;
        this.getContentDom(view);
        this.initTrigger(view);
        this.initWrapper(view);
        this.initEvents(view);
        return this.dom;
    };

    Dropdown.prototype.initTrigger = function initTrigger (view) {
        this.trigger = initMenuItemTrigger(view, this.options);

        if (!this.trigger) {
            throw new RangeError("Dropdown without icon or label property")
        }

        addMenuClass(this.trigger, 'dropdown');

        this.trigger.setAttribute('aria-haspopup', 'true');
        this.trigger.setAttribute('aria-expanded', 'false');

        setTitle(this.trigger, this.options, view);
    };

    Dropdown.prototype.initWrapper = function initWrapper () {
        this.dom = crelt("div", {}, this.trigger);
        addMenuClass(this.dom, 'dropdown-wrapper');
        this.$ = $(this.dom);
    };

    Dropdown.prototype.initContent = function initContent (content) {
        var this$1$1 = this;

        MenuItemGroup.prototype.initContent.call(this, content);
        this.content.update = function (state) {
            var result = false;
            this$1$1.forEachItem(function (item) {
                var updateResult = item.update(state);
                item.dom.style.display = updateResult ? "" : "none";
                result = result || updateResult;
            });
            return result;
        };
    };

    Dropdown.prototype.initEvents = function initEvents (view) {
        var this$1$1 = this;

        this.$.on('keydown', function (e) {
            var keyCode = e.keyCode || e.which;

            switch (keyCode) {
                case 9: // Enter
                    this$1$1.onTab(e);
                    break;
                case 13: // Enter
                    this$1$1.onEnter(e);
                    break;
                case 27: // Escape
                    this$1$1.onEscape(e);
                    break;
                case 40: // ArrowDown
                    this$1$1.onArrowDown(e);
                    break;
                case 38: // ArrowUp
                    this$1$1.onArrowUp(e);
                    break;
                case 37: // ArrowLeft
                    this$1$1.onArrowLeft(e);
                    break;
                case 39: // ArrowLeft
                    this$1$1.onArrowRight(e);
                    break;
            }
        });

        $(this.trigger).on('mousedown', function (e) {
            this$1$1.onClickTrigger(e);
        });
    };

    Dropdown.prototype.getContentDom = function getContentDom (view) {
        if (!this.contentDom) {
            this.contentDom = this.renderItems(view);
        }

        return this.contentDom;
    };

    Dropdown.prototype.open = function open () {
        var this$1$1 = this;

        opened = this.expand(this.dom);

        $(window).on('mousedown.richtextMenu', function () {
            if (!isMenuEvent(this$1$1.dom)) { this$1$1.close(); }
        });

        closeSubMenues();

        this.trigger.setAttribute('aria-expanded', 'true');
    };

    Dropdown.prototype.close = function close () {
        if (opened && opened.close()) {
            opened = null;
            $(window).off("mousedown.richtextMenu");
        }

        closeSubMenues();
        this.trigger.setAttribute('aria-expanded', 'false');
    };

    Dropdown.prototype.isOpen = function isOpen () {
        return this.$.find('.' + buildMenuClass('dropdown-menu')).is(':visible');
    };

    Dropdown.prototype.onTab = function onTab (e) {
        if (this.isOpen()) {
            this.close();
        }
    };

    Dropdown.prototype.onEnter = function onEnter (e) {
        e.preventDefault();
        if (!this.isOpen()) {
            if (opened) {
                this.close();
            }

            this.open();
            return;
        }

        if (this.getSubMenu().find('a:focus').length) {
            this.getMenuBar().context.editor.focus();
        }

        this.close();
    };

    Dropdown.prototype.getSubMenu = function getSubMenu () {
        return $(this.menu);
    };

    Dropdown.prototype.onEscape = function onEscape (e) {
        e.preventDefault();
        e.stopPropagation();

        var wasOpen = this.isOpen();

        this.close();

        if (wasOpen) {
            $(this.trigger).focus();
        }
    };

    Dropdown.prototype.onArrowDown = function onArrowDown (e) {
        e.preventDefault();
        e.stopPropagation();

        if (this.isOpen()) {
            this.focusNext();
        } else {
            if (opened) {
                this.close();
            }

            $(this.trigger).trigger('mousedown');
        }
    };

    Dropdown.prototype.focusNext = function focusNext () {
        var $focused = this.getFocused();
        var $parent = $focused.parent('.' + buildMenuClass('dropdown-item'));
        var $next = $parent.next();
        $next = $next.length ? $next.find('a:visible:first') : this.getFirstLink();
        $next.focus();
    };

    Dropdown.prototype.getFocused = function getFocused () {
        return this.getSubMenu().find('a:focus');
    };

    Dropdown.prototype.getFirstLink = function getFirstLink () {
        return $(this.menu).find('.' + buildMenuClass('dropdown-item') + ':first').find('a:first');
    };

    Dropdown.prototype.onArrowUp = function onArrowUp (e) {
        e.preventDefault();
        e.stopPropagation();

        if (this.isOpen()) {
            this.focusPrev();
        } else {
            if (opened) {
                this.close();
            }

            this.open();
        }
    };

    Dropdown.prototype.onArrowLeft = function onArrowLeft (e) {
        // Prevent main nav switch
        if (this.isOpen()) {
            e.preventDefault();
            e.stopPropagation();
        }
    };

    Dropdown.prototype.onArrowRight = function onArrowRight (e) {
        // Prevent main nav switch
        if (this.isOpen()) {
            e.preventDefault();
            e.stopPropagation();
        }
    };

    Dropdown.prototype.focusPrev = function focusPrev () {
        var $focused = this.getFocused();
        var $parent = $focused.closest('.' + buildMenuClass('dropdown-item'));
        var $prev = $parent.prev();
        $prev = $prev.length ? $prev.find('a:visible:first') : this.getLastLink();
        $prev.focus();
    };

    Dropdown.prototype.getLastLink = function getLastLink () {
        return $(this.menu).children('.' + buildMenuClass('dropdown-item:last')).find('a:first');
    };

    Dropdown.prototype.onClickTrigger = function onClickTrigger (e) {
        e.preventDefault();
        if (!this.selected || !this.enabled) { return; }
        markMenuEvent(e);

        var wasOpen = this.isOpen();

        if (opened) {
            this.close();
        }

        if (!wasOpen) {
            this.open();
        }
    };

    Dropdown.prototype.renderItems = function renderItems (view) {
        var rendered = [];
        this.content.items.forEach(function (item) {
            var dom = item.render(view, {htmlNode: 'a', tabindex: 0});
            var itemDom = crelt("div", {}, dom);
            addMenuClass(itemDom, 'dropdown-item');
            rendered.push(itemDom);
        });

        return rendered;
    };

    Dropdown.prototype.update = function update (state) {
        var contentUpdateResult = this.content.update(state);

        var forceEnable = false;
        var forceActive = false;

        this.content.items.forEach(function (item) {
            forceEnable = forceEnable || item.enabled;
            forceActive = forceActive || item.active;
        });

        this.adoptItemState(state, forceEnable, (forceActive && this.options.bubbleActive));
        return contentUpdateResult;
    };

    Dropdown.prototype.expand = function expand (dom) {

        var menuDOM = crelt("div", {}, this.getContentDom());
        addMenuClass(menuDOM, 'dropdown-menu');

        var done = false;

        function close() {
            closeSubMenues();
            if (done) { return; }
            done = true;
            dom.removeChild(menuDOM);
            return true;
        }

        dom.appendChild(menuDOM);

        var $menuDom = $(menuDOM);
        var right = $menuDom.offset().left + $menuDom.width();
        var rightAlignClass = buildMenuClass('dropdown-right');

        setClass($menuDom[0], rightAlignClass, (right > $(window).width() / 2));

        this.menu = menuDOM;
        return {close: close, node: menuDOM};
    };

    return Dropdown;
}(MenuItemGroup));

function closeSubMenues() {
    $('.' + buildMenuClass('submenu')).css('display', '');
}// ::- Represents a submenu wrapping a group of elements that start
// hidden and expand to the right when hovered over or tapped.
var DropdownSubmenu = /*@__PURE__*/(function (Dropdown) {
    function DropdownSubmenu(content, options) {
        Dropdown.call(this, content, options);
        this.options.bubbleActive = true;
    }

    if ( Dropdown ) DropdownSubmenu.__proto__ = Dropdown;
    DropdownSubmenu.prototype = Object.create( Dropdown && Dropdown.prototype );
    DropdownSubmenu.prototype.constructor = DropdownSubmenu;

    DropdownSubmenu.prototype.initTrigger = function initTrigger (view) {
        this.trigger = $('<a tabindex="0" aria-haspopup="listbox" aria-expanded="false"></a>')
            .text(translate$1(view, this.options.label))[0];
        setAttributesFromOptions(this.trigger, this.options);
    };

    /**
     * <div class="ProseMirror-menu-submenu-wrap">
     *     <div class="ProseMirror-menu-submenu-label">
     *         <a tabindex="0">Label</a>
     *     </div>
     *     <div class="ProseMirror-menu-submenu">
     *         <div class="ProseMirror-menu-dropdown-item"></div>
     *         <div class="ProseMirror-menu-dropdown-item"></div>
     *     </div>>
     * </div>
     */
    DropdownSubmenu.prototype.initWrapper = function initWrapper (view) {
        var label = $('<div>').addClass(buildMenuClass('submenu-label')).html(this.trigger)[0];

        this.menu = crelt("div", {class: buildMenuClass("submenu")},  this.getContentDom(view));

        this.dom = crelt("div", {class: buildMenuClass("submenu-wrap")}, label, this.menu);

        this.$ = $(this.dom);
    };

    DropdownSubmenu.prototype.onEnter = function onEnter (e) {
        if(this.getFocused().length) {
            return;
        }

        e.preventDefault();
        e.stopPropagation();

        this.getSubMenu().show();

        this.getFirstLink().focus();
    };

    DropdownSubmenu.prototype.onArrowLeft = function onArrowLeft (e) {
        if(this.isOpen()) {
            e.preventDefault();
            e.stopPropagation();
            this.close();
            $(this.trigger).focus();
        }
    };

    DropdownSubmenu.prototype.onArrowRight = function onArrowRight (e) {
        e.preventDefault();
        e.stopPropagation();
        this.getSubMenu().show();
        this.getFirstLink().focus();
    };

    DropdownSubmenu.prototype.onArrowUp = function onArrowUp (e) {
        if(!this.isOpen()) {
            // Let parent dropdown handle
            return;
        }

        Dropdown.prototype.onArrowUp.call(this, e);
    };

    DropdownSubmenu.prototype.onArrowDown = function onArrowDown (e) {
        if(!this.isOpen()) {
            // Let parent dropdown handle
            return;
        }

        Dropdown.prototype.onArrowDown.call(this, e);
    };

    DropdownSubmenu.prototype.open = function open () {
        this.getSubMenu().show();
        this.trigger.setAttribute('aria-expanded', 'true');
    };

    DropdownSubmenu.prototype.close = function close () {
        this.getSubMenu().css('display', '');
        this.trigger.setAttribute('aria-expanded', 'false');
    };

    DropdownSubmenu.prototype.getSubMenu = function getSubMenu () {
        return this.$.find('.ProseMirror-menu-submenu');
    };

    DropdownSubmenu.prototype.focusNext = function focusNext () {
        var $focused = this.getSubMenu().find('a:focus');
        var $parent = $focused.parent('.'+buildMenuClass('dropdown-item'));
        var $next = $parent.next();
        $next = $next.length ? $next.find('a:visible:first') : this.getFirstLink();
        $next.focus();
    };

    DropdownSubmenu.prototype.isOpen = function isOpen () {
        return this.getSubMenu().is(':visible');
    };

    return DropdownSubmenu;
}(Dropdown));// Helpers to create specific types of items
function cmdItem(cmd, options) {
    var passedOptions = {
        label: options.title,
        run: cmd
    };
    for (var prop in options) { passedOptions[prop] = options[prop]; }
    if ((!options.enable || options.enable === true) && !options.select)
        { passedOptions[options.enable ? "enable" : "select"] = function (state) { return cmd(state); }; }

    return new MenuItem(passedOptions)
}

function markItem(markType, options, context) {
    var passedOptions = {
        active: function active(state) {
            return markActive(state, markType)
        },
        enable: true
    };
    for (var prop in options) { passedOptions[prop] = options[prop]; }
    var menuItem = cmdItem(toggleMark(markType), passedOptions);

    if (options.runSource) {
        menuItem.runSource = options.runSource;
    } else if (context && markType.spec.toMarkdown
        && typeof markType.spec.toMarkdown.open === 'string'
        && typeof markType.spec.toMarkdown.close === 'string') {
        menuItem.runSource = wrapSourceTextMark(context, markType);
    }

    return menuItem;
}

function wrapSourceTextMark(context, markType, open, close) {
    if (!open && markType.spec.toMarkdown && markType.spec.toMarkdown.open) {
        open = markType.spec.toMarkdown.open;
    }

    if (!close && markType.spec.toMarkdown && markType.spec.toMarkdown.close) {
        close = markType.spec.toMarkdown.close;
    }

    if (!open) {
        return;
    }

    if (!close) {
        close = open;
    }

    return function () {
        var $source = context.$source;
        var length = $source.val().length;
        var start = $source[0].selectionStart;
        var selectionDirection = $source[0].selectionDirection;
        var end = $source[0].selectionEnd;
        var selectedText = $source.val().substring(start, end);

        var preSelection = $source.val().substring((start - open.length), start);
        var postSelection = $source.val().substring(end, (end + close.length));

        if (preSelection === open && postSelection === close) {
            // Revert mark
            $source.val($source.val().substring(0, start - open.length) + selectedText + $source.val().substring(end + close.length, length));
            $source[0].setSelectionRange((start - open.length), end - open.length, selectionDirection);
        } else {
            var leadingSpaceCount = Math.max(selectedText.search(/\S/), 0);
            var leadingSpaces = leadingSpaceCount > 0
                ? ' '.repeat(leadingSpaceCount)
                : '';

            var trailingSpaceCount = selectedText.search(/ +$/) > -1
                ? selectedText.length - selectedText.search(/ +$/)
                : 0;
            var trailingSpaces = trailingSpaceCount > 0
                ? ' '.repeat(trailingSpaceCount)
                : '';

            selectedText = selectedText.trim();

            var replacement = open + selectedText + close;
            $source.val($source.val().substring(0, start) + leadingSpaces + replacement + trailingSpaces + $source.val().substring(end, length));
            $source[0].setSelectionRange((start + leadingSpaceCount + open.length), (end + open.length - trailingSpaceCount), selectionDirection);
        }
    }
}

function markActive(state, type) {
    var ref = state.selection;
    var from = ref.from;
    var $from = ref.$from;
    var to = ref.to;
    var empty = ref.empty;
    if (empty) { return type.isInSet(state.storedMarks || $from.marks()) }
    else { return state.doc.rangeHasMark(from, to, type) }
}

function wrapListItem(nodeType, options) {
    return cmdItem(wrapInList(nodeType, options.attrs), options)
}

// :: MenuItem
// Menu item for the `joinUp` command.
var joinUpItem = function () {
    return new MenuItem({
        title: "Join with above block",
        run: joinUp,
        select: function (state) { return joinUp(state); },
        icon: icons.join
    });
};

// :: MenuItem
// Menu item for the `lift` command.
var liftItem = function () {
    return new MenuItem({
        title: "Lift out of enclosing block",
        run: lift,
        select: function (state) { return lift(state); },
        icon: icons.outdent
    });
};

function lift(state, dispatch) {
    var ref = state.selection;
    var $from = ref.$from;
    var $to = ref.$to;

    var inList = $from.blockRange($to, function (node) {
        return node.childCount && node.firstChild.type.name === 'list_item';
    });

    if (inList) {
        return false;
    }

    var range = $from.blockRange($to), target = range && liftTarget(range);
    if (target == null) {
        return false;
    }
    if (dispatch) {
        dispatch(state.tr.lift(range, target).scrollIntoView());
    }
    return true;
}

// :: MenuItem
// Menu item for the `selectParentNode` command.
var selectParentNodeItem = function () {
    return new MenuItem({
        title: "Select parent node",
        run: selectParentNode,
        select: function (state) { return selectParentNode(state); },
        icon: icons.selectParentNode
    });
};

// :: (Object) → MenuItem
// Menu item for the `undo` command.
var undoItem = function () {
    return new MenuItem({
        title: "Undo last change",
        run: undo,
        enable: function (state) { return undo(state); },
        icon: icons.undo
    });
};

// :: (Object) → MenuItem
// Menu item for the `redo` command.
var redoItem = function () {
    return new MenuItem({
        title: "Redo last undone change",
        run: redo,
        enable: function (state) { return redo(state); },
        icon: icons.redo
    });
};

// :: (NodeType, Object) → MenuItem
// Build a menu item for wrapping the selection in a given node type.
// Adds `run` and `select` properties to the ones present in
// `options`. `options.attrs` may be an object or a function, as in
// `toggleMarkItem`.
function wrapItem(nodeType, options) {
    var passedOptions = {
        run: function run(state, dispatch) {
            // FIXME if (options.attrs instanceof Function) options.attrs(state, attrs => wrapIn(nodeType, attrs)(state))
            return wrapIn(nodeType, options.attrs)(state, dispatch)
        },
        select: function select(state) {
            return wrapIn(nodeType, options.attrs instanceof Function ? null : options.attrs)(state)
        }
    };
    for (var prop in options) { passedOptions[prop] = options[prop]; }
    return new MenuItem(passedOptions)
}

// :: (NodeType, Object) → MenuItem
// Build a menu item for changing the type of the textblock around the
// selection to the given type. Provides `run`, `active`, and `select`
// properties. Others must be given in `options`. `options.attrs` may
// be an object to provide the attributes for the textblock node.
function blockTypeItem(nodeType, options) {
    var command = setBlockType(nodeType, options.attrs);
    var passedOptions = {
        run: command,
        enable: function enable(state) {
            return command(state)
        },
        active: function active(state) {
            var ref = state.selection;
            var $from = ref.$from;
            var to = ref.to;
            var node = ref.node;
            if (node) { return node.hasMarkup(nodeType, options.attrs) }
            return to <= $from.end() && $from.parent.hasMarkup(nodeType, options.attrs)
        }
    };
    for (var prop in options) { passedOptions[prop] = options[prop]; }
    return new MenuItem(passedOptions)
}

function canInsert(state, nodeType) {
    var $from = state.selection.$from;
    for (var d = $from.depth; d >= 0; d--) {
        var index = $from.index(d);
        if ($from.node(d).canReplaceWith(index, index, nodeType)) { return true }
    }
    return false
}

function canInsertLink(state) {
    var allowLink = true;
    state.doc.nodesBetween(state.selection.$from.pos, state.selection.$to.pos, function (node) {
        if (node.type.spec.code) {
            allowLink = false;
        } else {
            node.marks.forEach(function (mark) {
                var spec = mark.type.spec;
                if (spec.preventMarks && $.inArray('link', spec.preventMarks) >= 0) {
                    allowLink = false;
                }
            });
        }
    });

    return allowLink;
}var prefix$1 = "ProseMirror-menubar";

function buildMenuItems(context) {
    var groups = {
        types: {
            type: 'dropdown',
            id: 'type',
            toggleSelect: false,
            sortOrder: 100,
            title: context.translate("Type"),
            seperator: true,
            icon: icons.text,
            items: []
        },
        marks: {type: 'group', id: 'marks-group', sortOrder: 200, items: []},
        format: {type: 'group', id: 'format-group', sortOrder: 300, items: [liftItem()]},
        insert: {
            type: 'dropdown',
            id: 'insert-dropdown',
            sortOrder: 400,
            title: context.translate("Insert"),
            seperator: true,
            icon: icons.upload,
            items: []
        },
        helper: {
            type: 'group',
            id: 'helper-group',
            hideOnCollapse: true,
            sortOrder: 500,
            items: []
        },
        resize: {type: 'group', id: 'resize-group', sortOrder: 600, items: []},
    };

    var definitions = [groups.types, groups.marks, groups.format, groups.insert, groups.helper, groups.mode, groups.resize];

    var menuGroupPlugins = [];
    var menuWrapperPlugins = [];

    context.plugins.forEach(function (plugin) {
        if (plugin.menu) {
            plugin.menu(context).forEach(function (menuDefinition) {
                if (checkMenuDefinition(context, menuDefinition)) {
                    if (menuDefinition.type && menuDefinition.type === 'group') {
                        definitions.push(menuDefinition);
                        return;
                    }

                    if (menuDefinition.item && menuDefinition.id) {
                        // transfer the id of the definition to the item itself
                        menuDefinition.item.options.id = menuDefinition.id;
                    }

                    if (menuDefinition.group && groups[menuDefinition.group]) {
                        groups[menuDefinition.group].items.push(menuDefinition.item);
                    } else if (menuDefinition.item && !menuDefinition.group) {
                        definitions.push(menuDefinition.item);
                    }
                }
            });
        }

        if (plugin.menuGroups) {
            menuGroupPlugins.push(plugin);
        }

        if (plugin.menuWrapper) {
            menuWrapperPlugins.push(plugin);
        }
    });

    // Execute after all menu items are assembled
    menuGroupPlugins.forEach(function (plugin) {
        definitions = plugin.menuGroups(definitions, context);
    });

    context.menuWrapperPlugins = menuWrapperPlugins;

    return filterOutExcludes(context, definitions);
}

function filterOutExcludes(context, definition) {
    if (!definition) {
        return false;
    }

    if (Array.isArray(definition)) {
        return definition.filter(function (item) {
            return filterOutExcludes(context, item);
        });
    }

    if (definition instanceof MenuItemGroup) {
        definition.content.items = definition.content.items.filter(function (item) {
            return filterOutExcludes(context, item);
        });
    }

    if (typeof definition === 'object' && definition.items) {
        definition.items = definition.items.filter(function (item) {
            return filterOutExcludes(context, item);
        });
    }

    var id = definition.id;
    if (!id && definition.options) {
        id = definition.options.id;
    }

    return definition && !isExcludedMenuItem(context, id);
}

function wrapMenuItem(plugin, context, menuItem) {
    if (!menuItem) {
        return;
    }

    if (!plugin.menuWrapper) {
        return;
    }

    if ($.isArray(menuItem)) {
        menuItem.forEach(function (item) {
            wrapMenuItem(plugin, context, item);
        });
    }

    var wrapper = plugin.menuWrapper(context);

    if (menuItem instanceof MenuItem) {
        if (wrapper.run) {
            var origCallback = menuItem.options.run;
            menuItem.options.run = function (state, dispatch, view, evt) {
                var result = wrapper.run(menuItem, state, dispatch, view, evt);
                if (!result) {
                    origCallback.call(menuItem, state, dispatch, view, evt);
                }
            };
        }

        if (wrapper.active) {
            var origCallback$1 = menuItem.options.active;
            menuItem.options.active = function (state) {
                var origValue = origCallback$1 ? origCallback$1.call(menuItem, state) : false;
                return wrapper.active(menuItem, state, origValue);
            };
        }

        if (wrapper.enable) {
            var origCallback$2 = menuItem.options.enable;
            menuItem.options.enable = function (state) {
                var origValue = origCallback$2 ? origCallback$2.call(menuItem, state) : true;
                return wrapper.enable(menuItem, state, origValue);
            };
        }

        if (wrapper.select) {
            var origCallback$3 = menuItem.options.select;
            menuItem.options.select = function (state) {
                var origValue = origCallback$3 ? origCallback$3.call(menuItem, state) : true;
                return wrapper.select(menuItem, state, origValue);
            };
        }
    }

    if (menuItem.items) {
        wrapMenuItem(plugin, context, menuItem.items);
    }

    if (menuItem instanceof MenuItemGroup) {
        wrapMenuItem(plugin, context, menuItem.content.items);
    }
}

function checkMenuDefinition(context, menuDefinition) {
    if (!menuDefinition || menuDefinition.node && !context.schema.nodes[menuDefinition.node]) {
        return false;
    }

    return !(menuDefinition.mark && !context.schema.marks[menuDefinition.mark]);
}

function isExcludedMenuItem(context, id) {
    var presetOption = context.getPresetOption('menu', 'exclude', []);
    if (Array.isArray(presetOption) && presetOption.includes(id)) {
        return true;
    }

    var globalOption = context.getGlobalOption('menu', 'exclude', []);
    if (Array.isArray(globalOption) && globalOption.includes(id)) {
        return true;
    }

    var contextOption = context.getPluginOption('menu', 'exclude', []);
    return Array.isArray(contextOption) && contextOption.includes(id);
}

function buildMenuBar(context) {
    context.menu = menuBar({
        content: buildMenuItems(context),
        floating: false,
        context: context
    });

    return context.menu;
}


function isIOS() {
    if (typeof navigator == "undefined") { return false; }
    var agent = navigator.userAgent;
    return !/Edge\/\d/.test(agent) && /AppleWebKit/.test(agent) && /Mobile\/\w+/.test(agent);
}

// :: (Object) → Plugin
// A plugin that will place a menu bar above the editor. Note that
// this involves wrapping the editor in an additional `<div>`.
//
//   options::-
//   Supports the following options:
//
//     content:: [[MenuElement]]
//     Provides the content of the menu, as a nested array to be
//     passed to `renderGrouped`.
//
//     floating:: ?bool
//     Determines whether the menu floats, i.e. whether it sticks to
//     the top of the viewport when the editor is partially scrolled
//     out of view.
function menuBar(options) {
    return new Plugin({
        view: function view(editorView) {
            options.context.menu = new MenuBarView(editorView, options);
            options.context.event.trigger('afterMenuBarInit', options.context.menu);
            return options.context.menu;
        }
    })
}

function translate(view, text) {
    return view._props.translate ? view._props.translate(text) : text;
}

var lastFocusedElement = null;

var MenuBarView = function MenuBarView(editorView, options) {
    var this$1$1 = this;

    this.editorView = editorView;
    this.options = options;
    this.context = this.options.context;
    this.focusIconIndex = 0;
    var $editor = this.context.editor.$;
    this.wrapper = crelt("div", {class: prefix$1 + "-wrapper"});

    this.menu = this.wrapper.appendChild(crelt("div", {
        class: prefix$1,
        'aria-label': translate(editorView, 'Text Formatting'),
        'aria-controls': $editor.attr('id'),
        role: 'toolbar'
    }));

    this.menu.className = prefix$1;
    this.spacer = null;

    editorView.dom.parentNode.replaceChild(this.wrapper, editorView.dom);
    this.wrapper.appendChild(editorView.dom);

    this.maxHeight = 0;
    this.widthForMaxHeight = 0;
    this.floating = false;
    this.eventType = 'click';

    this.groupItem = new MenuItemGroup(this.options.content, {id: 'main-menu-group'});

    this.context.menuWrapperPlugins.forEach(function (plugin) {
        wrapMenuItem(plugin, this$1$1.context, this$1$1.groupItem);
    });

    // TODO: In case of focus menu render only on first focus
    this.menu.appendChild(this.groupItem.render(this.editorView));

    this.$ = $(this.menu);

    // Focus and blur editor handler
    if ($editor.is('.focusMenu')) {
        this.$.addClass('d-none');

        $editor.off('focus', '.ProseMirror, textarea').off('blur', '.ProseMirror, textarea')
            .on('focus', '.ProseMirror, textarea', function (event) {
                if (this$1$1.$.data('isHiding')) {
                    this$1$1.$.data('isHiding', false)
                        .addClass('d-none')
                        .stop(true, false);
                }
                if (this$1$1.$.hasClass('d-none')) {
                    this$1$1.$.removeClass('d-none');
                    var that = this$1$1;

                    $editor.on('keyup', function (e) {
                        var code = e.keyCode ? e.keyCode : e.which;
                        if (code === 9 && lastFocusedElement !== $(lastFocusedElement).closest(event.target).prevObject[0]) {
                            setTimeout(function () {
                                $(that.groupItem.dom).find('.' + buildMenuClass('trigger:first')).attr('tabindex', 0).focus();
                                $editor.off('keyup');
                            },0);
                        }
                    });
                }
            })
            .on('blur', '.ProseMirror, textarea', function (e) {
                var targetHasMenuBtn = e.relatedTarget ? e.relatedTarget.classList.contains('ProseMirror-menu-trigger') : false;
                lastFocusedElement = e.target;

                if (!$editor.is('.fullscreen') && !targetHasMenuBtn && !$(e.target).hasClass('cm-editor')) {
                    lastFocusedElement = null;
                    var that = this$1$1.$;
                    that.data('isHiding', true)
                        // Don't apply the d-none immediately to allow clicking on links which might move after hiding the toolbar
                        .hide(100, function(){that.addClass('d-none');});
                }
            });
    }

    this.$.on('mousedown', function (e) {
        // Prevent focusout if we click outside a menu item, but still inside menu container
        e.preventDefault();
    }).on("keydown", function (e) {
        var keyCode = e.keyCode || e.which;

        switch (keyCode) {
            case 39: // ArrowRight
                e.preventDefault();
                this$1$1.focusNext();
                break;
            case 37: // ArrowLeft
                e.preventDefault();
                this$1$1.focusPrev();
                break;
        }
    });

    this.$.data('menuBarInstance', this);

    this.update();

    if (options.floating && !isIOS()) {
        this.updateFloat();
        this.scrollFunc = function () {
            var root = this$1$1.editorView.root;
            if (!(root.body || root).contains(this$1$1.wrapper))
                { window.removeEventListener("scroll", this$1$1.scrollFunc); }
            else
                { this$1$1.updateFloat(); }
        };
        window.addEventListener("scroll", this.scrollFunc);
    }
};

MenuBarView.prototype.update = function update () {
    this.groupItem.update(this.editorView.state, this.context);

    if (this.floating) {
        this.updateScrollCursor();
    } else {
        if (this.menu.offsetWidth !== this.widthForMaxHeight) {
            this.widthForMaxHeight = this.menu.offsetWidth;
            this.maxHeight = 0;
        }
        if (this.menu.offsetHeight > this.maxHeight) {
            this.maxHeight = this.menu.offsetHeight;
        }
    }

    this.context.event.trigger('afterMenuBarUpdate', this);
};

MenuBarView.prototype.focusPrev = function focusPrev () {
    var $prev = null;
    var $focus = null;
    var newFocusIconIndex = 0;
    var $current = this.$.find('.' + buildMenuClass('trigger:focus'));
    var $items = this.$.find('.' + buildMenuClass('trigger'));

    $items.each(function (index) {
        var $this = $(this);

        if ($this.is($current)) {
            $focus = $prev;
            newFocusIconIndex = index - 1;
        }

        $this.attr('tabindex', -1);

        if ($this.is(':visible')) {
            $prev = $this;
        }
    });

    if (!$focus) {
        $focus = $items.last();
        newFocusIconIndex = $items.length - 1;
    }

    this.focusIconIndex = newFocusIconIndex;

    $focus.attr('tabindex', 0).focus();
};

MenuBarView.prototype.focusNext = function focusNext () {
    var $next = null;
    var newFocusIconIndex = 0;
    var focusNextItem = false;
    var $current = this.$.find('.' + buildMenuClass('trigger:focus'));

    this.$.find('.' + buildMenuClass('trigger')).each(function (index) {
        var $this = $(this);
        if (!$this.is(':visible')) {
            return;
        }

        if (focusNextItem) {
            $next = $this;
            focusNextItem = false;
            newFocusIconIndex = index;
        } else {
            $this.attr('tabindex', -1);
            focusNextItem = $this.is($current);
        }
    });

    if (!$next) {
        $next = this.$.find('.' + buildMenuClass('trigger:first'));
    }

    this.focusIconIndex = newFocusIconIndex;

    $next.attr('tabindex', 0).focus();
};

MenuBarView.prototype.updateScrollCursor = function updateScrollCursor () {
    var selection = this.editorView.root.getSelection();
    if (!selection.focusNode) { return; }
    var rects = selection.getRangeAt(0).getClientRects();
    var selRect = rects[selectionIsInverted(selection) ? 0 : rects.length - 1];
    if (!selRect) { return; }
    var menuRect = this.menu.getBoundingClientRect();
    if (selRect.top < menuRect.bottom && selRect.bottom > menuRect.top) {
        var scrollable = findWrappingScrollable(this.wrapper);
        if (scrollable) { scrollable.scrollTop -= (menuRect.bottom - selRect.top); }
    }
};

MenuBarView.prototype.updateFloat = function updateFloat () {
    var parent = this.wrapper, editorRect = parent.getBoundingClientRect();
    if (this.floating) {
        if (editorRect.top >= 0 || editorRect.bottom < this.menu.offsetHeight + 10) {
            this.floating = false;
            this.menu.style.position = this.menu.style.left = this.menu.style.width = "";
            this.menu.style.display = "";
            this.spacer.parentNode.removeChild(this.spacer);
            this.spacer = null;
        } else {
            var border = (parent.offsetWidth - parent.clientWidth) / 2;
            this.menu.style.left = (editorRect.left + border) + "px";
            this.menu.style.display = (editorRect.top > window.innerHeight ? "none" : "");
        }
    } else {
        if (editorRect.top < 0 && editorRect.bottom >= this.menu.offsetHeight + 10) {
            this.floating = true;
            var menuRect = this.menu.getBoundingClientRect();
            this.menu.style.left = menuRect.left + "px";
            this.menu.style.width = menuRect.width + "px";
            this.menu.style.position = "fixed";
            this.spacer = crel("div", {class: prefix$1 + "-spacer", style: ("height: " + (menuRect.height) + "px")});
            parent.insertBefore(this.spacer, this.menu);
        }
    }
};

MenuBarView.prototype.destroy = function destroy () {
    if (this.wrapper.parentNode)
        { this.wrapper.parentNode.replaceChild(this.editorView.dom, this.wrapper); }
};

// Not precise, but close enough
function selectionIsInverted(selection) {
    if (selection.anchorNode === selection.focusNode)
        { return selection.anchorOffset > selection.focusOffset; }
    return selection.anchorNode.compareDocumentPosition(selection.focusNode) === Node.DOCUMENT_POSITION_FOLLOWING;
}

function findWrappingScrollable(node) {
    for (var cur = node.parentNode; cur; cur = cur.parentNode)
        { if (cur.scrollHeight > cur.clientHeight) { return cur; } }
}var menu$k=/*#__PURE__*/Object.freeze({__proto__:null,Dropdown:Dropdown,DropdownSubmenu:DropdownSubmenu,MenuItem:MenuItem,MenuItemGroup:MenuItemGroup,blockTypeItem:blockTypeItem,canInsert:canInsert,canInsertLink:canInsertLink,cmdItem:cmdItem,icons:icons,joinUpItem:joinUpItem,liftItem:liftItem,markActive:markActive,markItem:markItem,menuBar:menuBar,redoItem:redoItem,selectParentNodeItem:selectParentNodeItem,undoItem:undoItem,wrapItem:wrapItem,wrapListItem:wrapListItem,wrapSourceTextMark:wrapSourceTextMark});var prefix = "ProseMirror-prompt";

var Promt = function Promt(options) {
    this.options = options;
    this.render();
};

Promt.prototype.render = function render () {
    $('.ProseMirror-prompt').remove();
    this.$wrapper = $('<div>').addClass(prefix).appendTo($('body'));
    this.buildForm();
    this.initEvents();
    this.initWrapper();
};

Promt.prototype.initWrapper = function initWrapper () {
    var box = this.$wrapper[0].getBoundingClientRect();
    this.$wrapper.css({
        top: ((window.innerHeight - box.height) / 2) + "px",
        left: ((window.innerWidth - box.width) / 2) + "px"
    });

    this.$wrapper.find('select:visible, input[type="text"]:visible, textarea:visible, [contenteditable="true"]:visible').first().focus();
};

Promt.prototype.buildForm = function buildForm () {
        var this$1$1 = this;

    this.$form = $('<form>').appendTo(this.$wrapper);

    if (this.options.title) {
        this.$form.append('<h5>' + this.options.title + '</h5>');
    }

    this.buildFormFields();

    this.domFields.forEach(function (field) {
        this$1$1.$form.append(field);
    });

    this.$form.on('submit', function (e) {
        e.preventDefault();
        this$1$1.submit();
    });

    this.buildButtons();
};

Promt.prototype.buildFormFields = function buildFormFields () {
    this.domFields = [];
    for (var name in this.options.fields) {
        var field = this.options.fields[name];
        var $field = $('<div>').append('<label>' + (field.options.label || name) + ':</label><br>').append(this.options.fields[name].render());
        this.domFields.push($field[0]);
    }
};

Promt.prototype.buildButtons = function buildButtons () {
        var this$1$1 = this;

    this.$buttons = $('<div>').addClass(prefix + "-buttons");
    // TODO: translate text!
    $('<button type="submit" class="btn btn-primary">').addClass(prefix + "-submit").text('OK').appendTo(this.$buttons);

    this.$buttons.append(document.createTextNode(' '));

    $('<button type="button" class="btn btn-secondary">').addClass(prefix + "-cancel")
        .text('Cancel').appendTo(this.$buttons)
        .on('click', function () { return this$1$1.close(); });

    this.$form.append(this.$buttons);
};

Promt.prototype.close = function close () {
    this.$wrapper.remove();
};

Promt.prototype.submit = function submit () {
    var params = this.getValues();
    if (params) {
        this.close();
        this.options.callback(params);
    }
};

Promt.prototype.getValues = function getValues () {
    var result = Object.create(null);
    var i = 0;

    for (var name in this.options.fields) {
        var field = this.options.fields[name];
        var dom = this.domFields[i++];

        var value = field.read(dom);
        var bad = field.validate(value);

        if (bad) {
            this.reportInvalid(dom, bad);
            return null;
        }
        result[name] = field.clean(value);
    }

    return result;
};

Promt.prototype.reportInvalid = function reportInvalid (dom, message) {
    // FIXME this is awful and needs a lot more work
    var parent = dom.parentNode;
    var msg = parent.appendChild(document.createElement("div"));
    msg.style.left = (dom.offsetLeft + dom.offsetWidth + 2) + "px";
    msg.style.top = (dom.offsetTop - 5) + "px";
    msg.className = "ProseMirror-invalid";
    msg.textContent = message;
    setTimeout(function () { return parent.removeChild(msg); }, 1500);
};

Promt.prototype.initEvents = function initEvents () {
        var this$1$1 = this;

    this.$form.on("keydown", function (e) {
        if (e.keyCode === 27) {
            e.preventDefault();
            this$1$1.close();
        } else if (e.keyCode === 13 && !(e.ctrlKey || e.metaKey || e.shiftKey)) {
            e.preventDefault();
            this$1$1.submit();
        } else if (e.keyCode === 9) {
            window.setTimeout(function () {
                if (!$.contains(this$1$1.$wrapper[0], document.activeElement)) {
                    this$1$1.close();
                }
            }, 500);
        }
    }).on('mousedown', function (e) {
        if (!$.contains(this$1$1.$wrapper[0], e.target)) {
            this$1$1.close();
        }
    });
};

function openPrompt(options) {
    return new Promt(options);
}

// ::- The type of field that `FieldPrompt` expects to be passed to it.
var Field = function Field(options) {
    this.options = options;
};

// render:: (state: EditorState, props: Object) → dom.Node
// Render the field to the DOM. Should be implemented by all subclasses.

// :: (dom.Node) → any
// Read the field's value from its DOM node.
Field.prototype.read = function read (dom) {
    if (dom.value) {
        return dom.value;
    } else {
        return $(dom).find('input, select')[0].value;
    }
};

// :: (any) → ?string
// A field-type-specific validation function.
Field.prototype.validateType = function validateType (_value) {
};

Field.prototype.validate = function validate (value) {
    if (!value && this.options.required)
        { return "Required field"; }
    return this.validateType(value) || (this.options.validate && this.options.validate(value));
};

Field.prototype.clean = function clean (value) {
    return this.options.clean ? this.options.clean(value) : value;
};

// ::- A field class for single-line text fields.
var TextField = /*@__PURE__*/(function (Field) {
    function TextField () {
        Field.apply(this, arguments);
    }

    if ( Field ) TextField.__proto__ = Field;
    TextField.prototype = Object.create( Field && Field.prototype );
    TextField.prototype.constructor = TextField;

    TextField.prototype.render = function render () {
        var input = document.createElement("input");
        input.type = "text";
        input.className = 'form-control';
        input.value = this.options.value || "";
        input.autocomplete = "off";
        return input;
    };

    return TextField;
}(Field));


// ::- A field class for dropdown fields based on a plain `<select>`
// tag. Expects an option `options`, which should be an array of
// `{value: string, label: string}` objects, or a function taking a
// `ProseMirror` instance and returning such an array.
var SelectField = /*@__PURE__*/(function (Field) {
    function SelectField () {
        Field.apply(this, arguments);
    }

    if ( Field ) SelectField.__proto__ = Field;
    SelectField.prototype = Object.create( Field && Field.prototype );
    SelectField.prototype.constructor = SelectField;

    SelectField.prototype.render = function render () {
        var this$1$1 = this;

        var select = document.createElement("select");
        select.className = 'form-control';

        this.options.options.forEach(function (o) {
            var opt = select.appendChild(document.createElement("option"));
            opt.value = o.value;
            opt.selected = o.value === this$1$1.options.value;
            opt.label = o.label;
        });
        return select;
    };

    return SelectField;
}(Field));

// ::- A field class for checkbox fields.
var CheckboxField = /*@__PURE__*/(function (Field) {
    function CheckboxField () {
        Field.apply(this, arguments);
    }

    if ( Field ) CheckboxField.__proto__ = Field;
    CheckboxField.prototype = Object.create( Field && Field.prototype );
    CheckboxField.prototype.constructor = CheckboxField;

    CheckboxField.prototype.render = function render () {
        var input = document.createElement("input");
        input.type = "checkbox";
        input.className = "form-check-input";
        input.checked = !!this.options.value;
        return input;
    };

    CheckboxField.prototype.read = function read (dom) {
        if (typeof dom.checked !== "undefined") {
            return !!dom.checked;
        }

        var input = $(dom).find('input[type="checkbox"]')[0];
        return !!(input && input.checked);
    };

    CheckboxField.prototype.clean = function clean (value) {
        return !!value;
    };

    return CheckboxField;
}(Field));var prompt=/*#__PURE__*/Object.freeze({__proto__:null,CheckboxField:CheckboxField,Field:Field,SelectField:SelectField,TextField:TextField,openPrompt:openPrompt});// TODO: enable global default config e.g. for emoji, locale, etc

var isHumhub = function () {
    return humhub && humhub.modules;
};

var showSuccessNotify = function (message) {
    if (isHumhub) {
        humhub.modules.ui.status.success(message);
    }
};

function getEmojiConfig() {
    if (!window.humhub || !window.humhub.config) {
        return {};
    }

    return humhub.config.get('ui.richtext.prosemirror', 'emoji', {twemoji: {}});
}

function isSmallView() {
    if (!window.humhub) {
        return getClientWidth() <= 767;
    }

    return isHumhub() ? humhub.modules.ui.view.isSmall() : null;
}

var getClientWidth = function () {
    return window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
};

function getUserLocale() {
    if (!window.humhub) {
        return (navigator.languages && navigator.languages.length) ? navigator.languages[0] : navigator.language;
    }

    return isHumhub() ? humhub.modules.user.config.locale.split("-")[0] : null;
}

function filterFileUrl(url, mode) {
    if (!window.humhub) {
        return {url: url, guid: null};
    }

    return isHumhub() ? humhub.modules.file.filterFileUrl(url, mode) : url;
}

function getLoaderWidget() {
    if (!window.humhub) {
        return $('<div class="loader">loading...</div>');
    }

    return humhub.require('ui.loader').set($('<span class="ProseMirror-placeholder">'), {
        span: true,
        size: '8px',
        css: {
            padding: '0px',
            width: '60px'
        }
    });
}

function encode$4(str) {
    if (!window.humhub) {
        return $('<div/>').text(str).html();
    }

    return isHumhub() ? humhub.modules.util.string.encode(str) : str;
}

// TODO: Implement oembed provider interface
function loadOembeds(urls) {
    if (!window.humhub) {
        return Promise.resolve([]);
    }

    return humhub.require('oembed').load(urls);
}

function getOembed(url) {
    if (!window.humhub) {
        return null;
    }

    return humhub.require('oembed').get(url);
}/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 *
 */



var loaderPlugin = function (context) {
    return new Plugin({
        state: {
            init: function init() {
                return DecorationSet.empty
            },
            apply: function apply(tr, set) {
                // Adjust decoration positions to changes made by the transaction
                set = set.map(tr.mapping, tr.doc);
                // See if the transaction adds or removes any placeholders
                var action = tr.getMeta(this);
                if (action && action.add) {
                    var deco = Decoration$1.widget(action.add.pos, getLoaderWidget()[0], {id: action.add.id, content: true});
                    set = set.add(tr.doc, [deco]);
                    context.addContentDecoration('loader');
                } else if (action && action.remove) {
                    set = set.remove(set.find(null, null, function (spec) { return spec.id === action.remove.id; }));
                    context.removeContentDecoration('loader');
                }
                return set
            }
        },
        props: {
            decorations: function decorations(state) {
                return this.getState(state)
            }
        }
    });
};

function findLoader(context, id) {
    var decos = context.getProsemirrorPlugins('loader')[0].getState(context.editor.view.state);
    var found = decos.find(null, null, function (spec) { return spec.id === id; });
    return found.length ? found[0].from : null
}

function loaderStart(context, id, dispatch) {
    var view = context.editor.view;
    var tr = view.state.tr;

    if (!tr.selection.empty) {
        tr.deleteSelection();
    }

    tr.setMeta(context.getProsemirrorPlugins('loader')[0], {add: {id: id, pos: tr.selection.from}});

    if(dispatch) {
        view.dispatch(tr);
    }

    return tr;
}

function replaceLoader(context, id, content, dispatch) {
    var view = context.editor.view;
    var pos = findLoader(context, id);

    // If the content around the placeholder has been deleted, drop the image
    if (pos === null) {
        return;
    }

    var tr = view.state.tr.replaceWith(pos, pos, content).setMeta(context.getProsemirrorPlugins('loader')[0], {remove: {id: id}});

    if(dispatch) {
        view.dispatch(tr);
    }

    return tr;
}

function removeLoader(context, id, dispatch) {
    var view = context.editor.view;
    var pos = findLoader(context, id);

    // Focus the editor in order to synchronized changes into hidden textarea
    // for case when before file uploading the editor was not focused
    view.focus();

    // If the content around the placeholder has been deleted, drop the image
    if (pos === null) {
        return;
    }

    var tr = view.state.tr.setMeta(context.getProsemirrorPlugins('loader')[0], {remove: {id: id}});

    if(dispatch) {
        view.dispatch(tr);
    }

    return tr;
}var loader$1=/*#__PURE__*/Object.freeze({__proto__:null,loaderPlugin:loaderPlugin,loaderStart:loaderStart,removeLoader:removeLoader,replaceLoader:replaceLoader});/* eslint-disable no-bitwise */

var decodeCache$1 = {};

function getDecodeCache$1 (exclude) {
  var cache = decodeCache$1[exclude];
  if (cache) { return cache }

  cache = decodeCache$1[exclude] = [];

  for (var i = 0; i < 128; i++) {
    var ch = String.fromCharCode(i);
    cache.push(ch);
  }

  for (var i$1 = 0; i$1 < exclude.length; i$1++) {
    var ch$1 = exclude.charCodeAt(i$1);
    cache[ch$1] = '%' + ('0' + ch$1.toString(16).toUpperCase()).slice(-2);
  }

  return cache
}

// Decode percent-encoded string.
//
function decode$3 (string, exclude) {
  if (typeof exclude !== 'string') {
    exclude = decode$3.defaultChars;
  }

  var cache = getDecodeCache$1(exclude);

  return string.replace(/(%[a-f0-9]{2})+/gi, function (seq) {
    var result = '';

    for (var i = 0, l = seq.length; i < l; i += 3) {
      var b1 = parseInt(seq.slice(i + 1, i + 3), 16);

      if (b1 < 0x80) {
        result += cache[b1];
        continue
      }

      if ((b1 & 0xE0) === 0xC0 && (i + 3 < l)) {
        // 110xxxxx 10xxxxxx
        var b2 = parseInt(seq.slice(i + 4, i + 6), 16);

        if ((b2 & 0xC0) === 0x80) {
          var chr = ((b1 << 6) & 0x7C0) | (b2 & 0x3F);

          if (chr < 0x80) {
            result += '\ufffd\ufffd';
          } else {
            result += String.fromCharCode(chr);
          }

          i += 3;
          continue
        }
      }

      if ((b1 & 0xF0) === 0xE0 && (i + 6 < l)) {
        // 1110xxxx 10xxxxxx 10xxxxxx
        var b2$1 = parseInt(seq.slice(i + 4, i + 6), 16);
        var b3 = parseInt(seq.slice(i + 7, i + 9), 16);

        if ((b2$1 & 0xC0) === 0x80 && (b3 & 0xC0) === 0x80) {
          var chr$1 = ((b1 << 12) & 0xF000) | ((b2$1 << 6) & 0xFC0) | (b3 & 0x3F);

          if (chr$1 < 0x800 || (chr$1 >= 0xD800 && chr$1 <= 0xDFFF)) {
            result += '\ufffd\ufffd\ufffd';
          } else {
            result += String.fromCharCode(chr$1);
          }

          i += 6;
          continue
        }
      }

      if ((b1 & 0xF8) === 0xF0 && (i + 9 < l)) {
        // 111110xx 10xxxxxx 10xxxxxx 10xxxxxx
        var b2$2 = parseInt(seq.slice(i + 4, i + 6), 16);
        var b3$1 = parseInt(seq.slice(i + 7, i + 9), 16);
        var b4 = parseInt(seq.slice(i + 10, i + 12), 16);

        if ((b2$2 & 0xC0) === 0x80 && (b3$1 & 0xC0) === 0x80 && (b4 & 0xC0) === 0x80) {
          var chr$2 = ((b1 << 18) & 0x1C0000) | ((b2$2 << 12) & 0x3F000) | ((b3$1 << 6) & 0xFC0) | (b4 & 0x3F);

          if (chr$2 < 0x10000 || chr$2 > 0x10FFFF) {
            result += '\ufffd\ufffd\ufffd\ufffd';
          } else {
            chr$2 -= 0x10000;
            result += String.fromCharCode(0xD800 + (chr$2 >> 10), 0xDC00 + (chr$2 & 0x3FF));
          }

          i += 9;
          continue
        }
      }

      result += '\ufffd';
    }

    return result
  })
}

decode$3.defaultChars = ';/?:@&=+$,#';
decode$3.componentChars = '';var encodeCache$1 = {};

// Create a lookup array where anything but characters in `chars` string
// and alphanumeric chars is percent-encoded.
//
function getEncodeCache$1 (exclude) {
  var cache = encodeCache$1[exclude];
  if (cache) { return cache }

  cache = encodeCache$1[exclude] = [];

  for (var i = 0; i < 128; i++) {
    var ch = String.fromCharCode(i);

    if (/^[0-9a-z]$/i.test(ch)) {
      // always allow unencoded alphanumeric characters
      cache.push(ch);
    } else {
      cache.push('%' + ('0' + i.toString(16).toUpperCase()).slice(-2));
    }
  }

  for (var i$1 = 0; i$1 < exclude.length; i$1++) {
    cache[exclude.charCodeAt(i$1)] = exclude[i$1];
  }

  return cache
}

// Encode unsafe characters with percent-encoding, skipping already
// encoded sequences.
//
//  - string       - string to encode
//  - exclude      - list of characters to ignore (in addition to a-zA-Z0-9)
//  - keepEscaped  - don't encode '%' in a correct escape sequence (default: true)
//
function encode$3 (string, exclude, keepEscaped) {
  if (typeof exclude !== 'string') {
    // encode(string, keepEscaped)
    keepEscaped = exclude;
    exclude = encode$3.defaultChars;
  }

  if (typeof keepEscaped === 'undefined') {
    keepEscaped = true;
  }

  var cache = getEncodeCache$1(exclude);
  var result = '';

  for (var i = 0, l = string.length; i < l; i++) {
    var code = string.charCodeAt(i);

    if (keepEscaped && code === 0x25 /* % */ && i + 2 < l) {
      if (/^[0-9a-f]{2}$/i.test(string.slice(i + 1, i + 3))) {
        result += string.slice(i, i + 3);
        i += 2;
        continue
      }
    }

    if (code < 128) {
      result += cache[code];
      continue
    }

    if (code >= 0xD800 && code <= 0xDFFF) {
      if (code >= 0xD800 && code <= 0xDBFF && i + 1 < l) {
        var nextCode = string.charCodeAt(i + 1);
        if (nextCode >= 0xDC00 && nextCode <= 0xDFFF) {
          result += encodeURIComponent(string[i] + string[i + 1]);
          i++;
          continue
        }
      }
      result += '%EF%BF%BD';
      continue
    }

    result += encodeURIComponent(string[i]);
  }

  return result
}

encode$3.defaultChars = ";/?:@&=+$,-_.!~*'()#";
encode$3.componentChars = "-_.!~*'()";function format$1 (url) {
  var result = '';

  result += url.protocol || '';
  result += url.slashes ? '//' : '';
  result += url.auth ? url.auth + '@' : '';

  if (url.hostname && url.hostname.indexOf(':') !== -1) {
    // ipv6 address
    result += '[' + url.hostname + ']';
  } else {
    result += url.hostname || '';
  }

  result += url.port ? ':' + url.port : '';
  result += url.pathname || '';
  result += url.search || '';
  result += url.hash || '';

  return result
}// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.

//
// Changes from joyent/node:
//
// 1. No leading slash in paths,
//    e.g. in `url.parse('http://foo?bar')` pathname is ``, not `/`
//
// 2. Backslashes are not replaced with slashes,
//    so `http:\\example.org\` is treated like a relative path
//
// 3. Trailing colon is treated like a part of the path,
//    i.e. in `http://example.org:foo` pathname is `:foo`
//
// 4. Nothing is URL-encoded in the resulting object,
//    (in joyent/node some chars in auth and paths are encoded)
//
// 5. `url.parse()` does not have `parseQueryString` argument
//
// 6. Removed extraneous result properties: `host`, `path`, `query`, etc.,
//    which can be constructed using other parts of the url.
//

function Url$1 () {
  this.protocol = null;
  this.slashes = null;
  this.auth = null;
  this.port = null;
  this.hostname = null;
  this.hash = null;
  this.search = null;
  this.pathname = null;
}

// Reference: RFC 3986, RFC 1808, RFC 2396

// define these here so at least they only have to be
// compiled once on the first module load.
var protocolPattern$1 = /^([a-z0-9.+-]+:)/i;
var portPattern$1 = /:[0-9]*$/;

// Special case for a simple path URL
/* eslint-disable-next-line no-useless-escape */
var simplePathPattern$1 = /^(\/\/?(?!\/)[^\?\s]*)(\?[^\s]*)?$/;

// RFC 2396: characters reserved for delimiting URLs.
// We actually just auto-escape these.
var delims$1 = ['<', '>', '"', '`', ' ', '\r', '\n', '\t'];

// RFC 2396: characters not allowed for various reasons.
var unwise$1 = ['{', '}', '|', '\\', '^', '`'].concat(delims$1);

// Allowed by RFCs, but cause of XSS attacks.  Always escape these.
var autoEscape$1 = ['\''].concat(unwise$1);
// Characters that are never ever allowed in a hostname.
// Note that any invalid chars are also handled, but these
// are the ones that are *expected* to be seen, so we fast-path
// them.
var nonHostChars$1 = ['%', '/', '?', ';', '#'].concat(autoEscape$1);
var hostEndingChars$1 = ['/', '?', '#'];
var hostnameMaxLen$1 = 255;
var hostnamePartPattern$1 = /^[+a-z0-9A-Z_-]{0,63}$/;
var hostnamePartStart$1 = /^([+a-z0-9A-Z_-]{0,63})(.*)$/;
// protocols that can allow "unsafe" and "unwise" chars.
// protocols that never have a hostname.
var hostlessProtocol$1 = {
  javascript: true,
  'javascript:': true
};
// protocols that always contain a // bit.
var slashedProtocol$1 = {
  http: true,
  https: true,
  ftp: true,
  gopher: true,
  file: true,
  'http:': true,
  'https:': true,
  'ftp:': true,
  'gopher:': true,
  'file:': true
};

function urlParse$1 (url, slashesDenoteHost) {
  if (url && url instanceof Url$1) { return url }

  var u = new Url$1();
  u.parse(url, slashesDenoteHost);
  return u
}

Url$1.prototype.parse = function (url, slashesDenoteHost) {
  var lowerProto, hec, slashes;
  var rest = url;

  // trim before proceeding.
  // This is to support parse stuff like "  http://foo.com  \n"
  rest = rest.trim();

  if (!slashesDenoteHost && url.split('#').length === 1) {
    // Try fast path regexp
    var simplePath = simplePathPattern$1.exec(rest);
    if (simplePath) {
      this.pathname = simplePath[1];
      if (simplePath[2]) {
        this.search = simplePath[2];
      }
      return this
    }
  }

  var proto = protocolPattern$1.exec(rest);
  if (proto) {
    proto = proto[0];
    lowerProto = proto.toLowerCase();
    this.protocol = proto;
    rest = rest.substr(proto.length);
  }

  // figure out if it's got a host
  // user@server is *always* interpreted as a hostname, and url
  // resolution will treat //foo/bar as host=foo,path=bar because that's
  // how the browser resolves relative URLs.
  /* eslint-disable-next-line no-useless-escape */
  if (slashesDenoteHost || proto || rest.match(/^\/\/[^@\/]+@[^@\/]+/)) {
    slashes = rest.substr(0, 2) === '//';
    if (slashes && !(proto && hostlessProtocol$1[proto])) {
      rest = rest.substr(2);
      this.slashes = true;
    }
  }

  if (!hostlessProtocol$1[proto] &&
      (slashes || (proto && !slashedProtocol$1[proto]))) {
    // there's a hostname.
    // the first instance of /, ?, ;, or # ends the host.
    //
    // If there is an @ in the hostname, then non-host chars *are* allowed
    // to the left of the last @ sign, unless some host-ending character
    // comes *before* the @-sign.
    // URLs are obnoxious.
    //
    // ex:
    // http://a@b@c/ => user:a@b host:c
    // http://a@b?@c => user:a host:c path:/?@c

    // v0.12 TODO(isaacs): This is not quite how Chrome does things.
    // Review our test case against browsers more comprehensively.

    // find the first instance of any hostEndingChars
    var hostEnd = -1;
    for (var i = 0; i < hostEndingChars$1.length; i++) {
      hec = rest.indexOf(hostEndingChars$1[i]);
      if (hec !== -1 && (hostEnd === -1 || hec < hostEnd)) {
        hostEnd = hec;
      }
    }

    // at this point, either we have an explicit point where the
    // auth portion cannot go past, or the last @ char is the decider.
    var auth, atSign;
    if (hostEnd === -1) {
      // atSign can be anywhere.
      atSign = rest.lastIndexOf('@');
    } else {
      // atSign must be in auth portion.
      // http://a@b/c@d => host:b auth:a path:/c@d
      atSign = rest.lastIndexOf('@', hostEnd);
    }

    // Now we have a portion which is definitely the auth.
    // Pull that off.
    if (atSign !== -1) {
      auth = rest.slice(0, atSign);
      rest = rest.slice(atSign + 1);
      this.auth = auth;
    }

    // the host is the remaining to the left of the first non-host char
    hostEnd = -1;
    for (var i$1 = 0; i$1 < nonHostChars$1.length; i$1++) {
      hec = rest.indexOf(nonHostChars$1[i$1]);
      if (hec !== -1 && (hostEnd === -1 || hec < hostEnd)) {
        hostEnd = hec;
      }
    }
    // if we still have not hit it, then the entire thing is a host.
    if (hostEnd === -1) {
      hostEnd = rest.length;
    }

    if (rest[hostEnd - 1] === ':') { hostEnd--; }
    var host = rest.slice(0, hostEnd);
    rest = rest.slice(hostEnd);

    // pull out port.
    this.parseHost(host);

    // we've indicated that there is a hostname,
    // so even if it's empty, it has to be present.
    this.hostname = this.hostname || '';

    // if hostname begins with [ and ends with ]
    // assume that it's an IPv6 address.
    var ipv6Hostname = this.hostname[0] === '[' &&
        this.hostname[this.hostname.length - 1] === ']';

    // validate a little.
    if (!ipv6Hostname) {
      var hostparts = this.hostname.split(/\./);
      for (var i$2 = 0, l = hostparts.length; i$2 < l; i$2++) {
        var part = hostparts[i$2];
        if (!part) { continue }
        if (!part.match(hostnamePartPattern$1)) {
          var newpart = '';
          for (var j = 0, k = part.length; j < k; j++) {
            if (part.charCodeAt(j) > 127) {
              // we replace non-ASCII char with a temporary placeholder
              // we need this to make sure size of hostname is not
              // broken by replacing non-ASCII by nothing
              newpart += 'x';
            } else {
              newpart += part[j];
            }
          }
          // we test again with ASCII char only
          if (!newpart.match(hostnamePartPattern$1)) {
            var validParts = hostparts.slice(0, i$2);
            var notHost = hostparts.slice(i$2 + 1);
            var bit = part.match(hostnamePartStart$1);
            if (bit) {
              validParts.push(bit[1]);
              notHost.unshift(bit[2]);
            }
            if (notHost.length) {
              rest = notHost.join('.') + rest;
            }
            this.hostname = validParts.join('.');
            break
          }
        }
      }
    }

    if (this.hostname.length > hostnameMaxLen$1) {
      this.hostname = '';
    }

    // strip [ and ] from the hostname
    // the host field still retains them, though
    if (ipv6Hostname) {
      this.hostname = this.hostname.substr(1, this.hostname.length - 2);
    }
  }

  // chop off from the tail first.
  var hash = rest.indexOf('#');
  if (hash !== -1) {
    // got a fragment string.
    this.hash = rest.substr(hash);
    rest = rest.slice(0, hash);
  }
  var qm = rest.indexOf('?');
  if (qm !== -1) {
    this.search = rest.substr(qm);
    rest = rest.slice(0, qm);
  }
  if (rest) { this.pathname = rest; }
  if (slashedProtocol$1[lowerProto] &&
      this.hostname && !this.pathname) {
    this.pathname = '';
  }

  return this
};

Url$1.prototype.parseHost = function (host) {
  var port = portPattern$1.exec(host);
  if (port) {
    port = port[0];
    if (port !== ':') {
      this.port = port.substr(1);
    }
    host = host.substr(0, host.length - port.length);
  }
  if (host) { this.hostname = host; }
};var mdurl$2=/*#__PURE__*/Object.freeze({__proto__:null,decode:decode$3,encode:encode$3,format:format$1,parse:urlParse$1});var Any = /[\0-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]/;var Cc = /[\0-\x1F\x7F-\x9F]/;var regex$6 = /[\xAD\u0600-\u0605\u061C\u06DD\u070F\u0890\u0891\u08E2\u180E\u200B-\u200F\u202A-\u202E\u2060-\u2064\u2066-\u206F\uFEFF\uFFF9-\uFFFB]|\uD804[\uDCBD\uDCCD]|\uD80D[\uDC30-\uDC3F]|\uD82F[\uDCA0-\uDCA3]|\uD834[\uDD73-\uDD7A]|\uDB40[\uDC01\uDC20-\uDC7F]/;var P = /[!-#%-\*,-\/:;\?@\[-\]_\{\}\xA1\xA7\xAB\xB6\xB7\xBB\xBF\u037E\u0387\u055A-\u055F\u0589\u058A\u05BE\u05C0\u05C3\u05C6\u05F3\u05F4\u0609\u060A\u060C\u060D\u061B\u061D-\u061F\u066A-\u066D\u06D4\u0700-\u070D\u07F7-\u07F9\u0830-\u083E\u085E\u0964\u0965\u0970\u09FD\u0A76\u0AF0\u0C77\u0C84\u0DF4\u0E4F\u0E5A\u0E5B\u0F04-\u0F12\u0F14\u0F3A-\u0F3D\u0F85\u0FD0-\u0FD4\u0FD9\u0FDA\u104A-\u104F\u10FB\u1360-\u1368\u1400\u166E\u169B\u169C\u16EB-\u16ED\u1735\u1736\u17D4-\u17D6\u17D8-\u17DA\u1800-\u180A\u1944\u1945\u1A1E\u1A1F\u1AA0-\u1AA6\u1AA8-\u1AAD\u1B5A-\u1B60\u1B7D\u1B7E\u1BFC-\u1BFF\u1C3B-\u1C3F\u1C7E\u1C7F\u1CC0-\u1CC7\u1CD3\u2010-\u2027\u2030-\u2043\u2045-\u2051\u2053-\u205E\u207D\u207E\u208D\u208E\u2308-\u230B\u2329\u232A\u2768-\u2775\u27C5\u27C6\u27E6-\u27EF\u2983-\u2998\u29D8-\u29DB\u29FC\u29FD\u2CF9-\u2CFC\u2CFE\u2CFF\u2D70\u2E00-\u2E2E\u2E30-\u2E4F\u2E52-\u2E5D\u3001-\u3003\u3008-\u3011\u3014-\u301F\u3030\u303D\u30A0\u30FB\uA4FE\uA4FF\uA60D-\uA60F\uA673\uA67E\uA6F2-\uA6F7\uA874-\uA877\uA8CE\uA8CF\uA8F8-\uA8FA\uA8FC\uA92E\uA92F\uA95F\uA9C1-\uA9CD\uA9DE\uA9DF\uAA5C-\uAA5F\uAADE\uAADF\uAAF0\uAAF1\uABEB\uFD3E\uFD3F\uFE10-\uFE19\uFE30-\uFE52\uFE54-\uFE61\uFE63\uFE68\uFE6A\uFE6B\uFF01-\uFF03\uFF05-\uFF0A\uFF0C-\uFF0F\uFF1A\uFF1B\uFF1F\uFF20\uFF3B-\uFF3D\uFF3F\uFF5B\uFF5D\uFF5F-\uFF65]|\uD800[\uDD00-\uDD02\uDF9F\uDFD0]|\uD801\uDD6F|\uD802[\uDC57\uDD1F\uDD3F\uDE50-\uDE58\uDE7F\uDEF0-\uDEF6\uDF39-\uDF3F\uDF99-\uDF9C]|\uD803[\uDEAD\uDF55-\uDF59\uDF86-\uDF89]|\uD804[\uDC47-\uDC4D\uDCBB\uDCBC\uDCBE-\uDCC1\uDD40-\uDD43\uDD74\uDD75\uDDC5-\uDDC8\uDDCD\uDDDB\uDDDD-\uDDDF\uDE38-\uDE3D\uDEA9]|\uD805[\uDC4B-\uDC4F\uDC5A\uDC5B\uDC5D\uDCC6\uDDC1-\uDDD7\uDE41-\uDE43\uDE60-\uDE6C\uDEB9\uDF3C-\uDF3E]|\uD806[\uDC3B\uDD44-\uDD46\uDDE2\uDE3F-\uDE46\uDE9A-\uDE9C\uDE9E-\uDEA2\uDF00-\uDF09]|\uD807[\uDC41-\uDC45\uDC70\uDC71\uDEF7\uDEF8\uDF43-\uDF4F\uDFFF]|\uD809[\uDC70-\uDC74]|\uD80B[\uDFF1\uDFF2]|\uD81A[\uDE6E\uDE6F\uDEF5\uDF37-\uDF3B\uDF44]|\uD81B[\uDE97-\uDE9A\uDFE2]|\uD82F\uDC9F|\uD836[\uDE87-\uDE8B]|\uD83A[\uDD5E\uDD5F]/;var regex$5 = /[\$\+<->\^`\|~\xA2-\xA6\xA8\xA9\xAC\xAE-\xB1\xB4\xB8\xD7\xF7\u02C2-\u02C5\u02D2-\u02DF\u02E5-\u02EB\u02ED\u02EF-\u02FF\u0375\u0384\u0385\u03F6\u0482\u058D-\u058F\u0606-\u0608\u060B\u060E\u060F\u06DE\u06E9\u06FD\u06FE\u07F6\u07FE\u07FF\u0888\u09F2\u09F3\u09FA\u09FB\u0AF1\u0B70\u0BF3-\u0BFA\u0C7F\u0D4F\u0D79\u0E3F\u0F01-\u0F03\u0F13\u0F15-\u0F17\u0F1A-\u0F1F\u0F34\u0F36\u0F38\u0FBE-\u0FC5\u0FC7-\u0FCC\u0FCE\u0FCF\u0FD5-\u0FD8\u109E\u109F\u1390-\u1399\u166D\u17DB\u1940\u19DE-\u19FF\u1B61-\u1B6A\u1B74-\u1B7C\u1FBD\u1FBF-\u1FC1\u1FCD-\u1FCF\u1FDD-\u1FDF\u1FED-\u1FEF\u1FFD\u1FFE\u2044\u2052\u207A-\u207C\u208A-\u208C\u20A0-\u20C0\u2100\u2101\u2103-\u2106\u2108\u2109\u2114\u2116-\u2118\u211E-\u2123\u2125\u2127\u2129\u212E\u213A\u213B\u2140-\u2144\u214A-\u214D\u214F\u218A\u218B\u2190-\u2307\u230C-\u2328\u232B-\u2426\u2440-\u244A\u249C-\u24E9\u2500-\u2767\u2794-\u27C4\u27C7-\u27E5\u27F0-\u2982\u2999-\u29D7\u29DC-\u29FB\u29FE-\u2B73\u2B76-\u2B95\u2B97-\u2BFF\u2CE5-\u2CEA\u2E50\u2E51\u2E80-\u2E99\u2E9B-\u2EF3\u2F00-\u2FD5\u2FF0-\u2FFF\u3004\u3012\u3013\u3020\u3036\u3037\u303E\u303F\u309B\u309C\u3190\u3191\u3196-\u319F\u31C0-\u31E3\u31EF\u3200-\u321E\u322A-\u3247\u3250\u3260-\u327F\u328A-\u32B0\u32C0-\u33FF\u4DC0-\u4DFF\uA490-\uA4C6\uA700-\uA716\uA720\uA721\uA789\uA78A\uA828-\uA82B\uA836-\uA839\uAA77-\uAA79\uAB5B\uAB6A\uAB6B\uFB29\uFBB2-\uFBC2\uFD40-\uFD4F\uFDCF\uFDFC-\uFDFF\uFE62\uFE64-\uFE66\uFE69\uFF04\uFF0B\uFF1C-\uFF1E\uFF3E\uFF40\uFF5C\uFF5E\uFFE0-\uFFE6\uFFE8-\uFFEE\uFFFC\uFFFD]|\uD800[\uDD37-\uDD3F\uDD79-\uDD89\uDD8C-\uDD8E\uDD90-\uDD9C\uDDA0\uDDD0-\uDDFC]|\uD802[\uDC77\uDC78\uDEC8]|\uD805\uDF3F|\uD807[\uDFD5-\uDFF1]|\uD81A[\uDF3C-\uDF3F\uDF45]|\uD82F\uDC9C|\uD833[\uDF50-\uDFC3]|\uD834[\uDC00-\uDCF5\uDD00-\uDD26\uDD29-\uDD64\uDD6A-\uDD6C\uDD83\uDD84\uDD8C-\uDDA9\uDDAE-\uDDEA\uDE00-\uDE41\uDE45\uDF00-\uDF56]|\uD835[\uDEC1\uDEDB\uDEFB\uDF15\uDF35\uDF4F\uDF6F\uDF89\uDFA9\uDFC3]|\uD836[\uDC00-\uDDFF\uDE37-\uDE3A\uDE6D-\uDE74\uDE76-\uDE83\uDE85\uDE86]|\uD838[\uDD4F\uDEFF]|\uD83B[\uDCAC\uDCB0\uDD2E\uDEF0\uDEF1]|\uD83C[\uDC00-\uDC2B\uDC30-\uDC93\uDCA0-\uDCAE\uDCB1-\uDCBF\uDCC1-\uDCCF\uDCD1-\uDCF5\uDD0D-\uDDAD\uDDE6-\uDE02\uDE10-\uDE3B\uDE40-\uDE48\uDE50\uDE51\uDE60-\uDE65\uDF00-\uDFFF]|\uD83D[\uDC00-\uDED7\uDEDC-\uDEEC\uDEF0-\uDEFC\uDF00-\uDF76\uDF7B-\uDFD9\uDFE0-\uDFEB\uDFF0]|\uD83E[\uDC00-\uDC0B\uDC10-\uDC47\uDC50-\uDC59\uDC60-\uDC87\uDC90-\uDCAD\uDCB0\uDCB1\uDD00-\uDE53\uDE60-\uDE6D\uDE70-\uDE7C\uDE80-\uDE88\uDE90-\uDEBD\uDEBF-\uDEC5\uDECE-\uDEDB\uDEE0-\uDEE8\uDEF0-\uDEF8\uDF00-\uDF92\uDF94-\uDFCA]/;var Z = /[ \xA0\u1680\u2000-\u200A\u2028\u2029\u202F\u205F\u3000]/;var ucmicro=/*#__PURE__*/Object.freeze({__proto__:null,Any:Any,Cc:Cc,Cf:regex$6,P:P,S:regex$5,Z:Z});// Generated using scripts/write-decode-map.ts
var htmlDecodeTree = new Uint16Array(
// prettier-ignore
"\u1d41<\xd5\u0131\u028a\u049d\u057b\u05d0\u0675\u06de\u07a2\u07d6\u080f\u0a4a\u0a91\u0da1\u0e6d\u0f09\u0f26\u10ca\u1228\u12e1\u1415\u149d\u14c3\u14df\u1525\0\0\0\0\0\0\u156b\u16cd\u198d\u1c12\u1ddd\u1f7e\u2060\u21b0\u228d\u23c0\u23fb\u2442\u2824\u2912\u2d08\u2e48\u2fce\u3016\u32ba\u3639\u37ac\u38fe\u3a28\u3a71\u3ae0\u3b2e\u0800EMabcfglmnoprstu\\bfms\x7f\x84\x8b\x90\x95\x98\xa6\xb3\xb9\xc8\xcflig\u803b\xc6\u40c6P\u803b&\u4026cute\u803b\xc1\u40c1reve;\u4102\u0100iyx}rc\u803b\xc2\u40c2;\u4410r;\uc000\ud835\udd04rave\u803b\xc0\u40c0pha;\u4391acr;\u4100d;\u6a53\u0100gp\x9d\xa1on;\u4104f;\uc000\ud835\udd38plyFunction;\u6061ing\u803b\xc5\u40c5\u0100cs\xbe\xc3r;\uc000\ud835\udc9cign;\u6254ilde\u803b\xc3\u40c3ml\u803b\xc4\u40c4\u0400aceforsu\xe5\xfb\xfe\u0117\u011c\u0122\u0127\u012a\u0100cr\xea\xf2kslash;\u6216\u0176\xf6\xf8;\u6ae7ed;\u6306y;\u4411\u0180crt\u0105\u010b\u0114ause;\u6235noullis;\u612ca;\u4392r;\uc000\ud835\udd05pf;\uc000\ud835\udd39eve;\u42d8c\xf2\u0113mpeq;\u624e\u0700HOacdefhilorsu\u014d\u0151\u0156\u0180\u019e\u01a2\u01b5\u01b7\u01ba\u01dc\u0215\u0273\u0278\u027ecy;\u4427PY\u803b\xa9\u40a9\u0180cpy\u015d\u0162\u017aute;\u4106\u0100;i\u0167\u0168\u62d2talDifferentialD;\u6145leys;\u612d\u0200aeio\u0189\u018e\u0194\u0198ron;\u410cdil\u803b\xc7\u40c7rc;\u4108nint;\u6230ot;\u410a\u0100dn\u01a7\u01adilla;\u40b8terDot;\u40b7\xf2\u017fi;\u43a7rcle\u0200DMPT\u01c7\u01cb\u01d1\u01d6ot;\u6299inus;\u6296lus;\u6295imes;\u6297o\u0100cs\u01e2\u01f8kwiseContourIntegral;\u6232eCurly\u0100DQ\u0203\u020foubleQuote;\u601duote;\u6019\u0200lnpu\u021e\u0228\u0247\u0255on\u0100;e\u0225\u0226\u6237;\u6a74\u0180git\u022f\u0236\u023aruent;\u6261nt;\u622fourIntegral;\u622e\u0100fr\u024c\u024e;\u6102oduct;\u6210nterClockwiseContourIntegral;\u6233oss;\u6a2fcr;\uc000\ud835\udc9ep\u0100;C\u0284\u0285\u62d3ap;\u624d\u0580DJSZacefios\u02a0\u02ac\u02b0\u02b4\u02b8\u02cb\u02d7\u02e1\u02e6\u0333\u048d\u0100;o\u0179\u02a5trahd;\u6911cy;\u4402cy;\u4405cy;\u440f\u0180grs\u02bf\u02c4\u02c7ger;\u6021r;\u61a1hv;\u6ae4\u0100ay\u02d0\u02d5ron;\u410e;\u4414l\u0100;t\u02dd\u02de\u6207a;\u4394r;\uc000\ud835\udd07\u0100af\u02eb\u0327\u0100cm\u02f0\u0322ritical\u0200ADGT\u0300\u0306\u0316\u031ccute;\u40b4o\u0174\u030b\u030d;\u42d9bleAcute;\u42ddrave;\u4060ilde;\u42dcond;\u62c4ferentialD;\u6146\u0470\u033d\0\0\0\u0342\u0354\0\u0405f;\uc000\ud835\udd3b\u0180;DE\u0348\u0349\u034d\u40a8ot;\u60dcqual;\u6250ble\u0300CDLRUV\u0363\u0372\u0382\u03cf\u03e2\u03f8ontourIntegra\xec\u0239o\u0274\u0379\0\0\u037b\xbb\u0349nArrow;\u61d3\u0100eo\u0387\u03a4ft\u0180ART\u0390\u0396\u03a1rrow;\u61d0ightArrow;\u61d4e\xe5\u02cang\u0100LR\u03ab\u03c4eft\u0100AR\u03b3\u03b9rrow;\u67f8ightArrow;\u67faightArrow;\u67f9ight\u0100AT\u03d8\u03derrow;\u61d2ee;\u62a8p\u0241\u03e9\0\0\u03efrrow;\u61d1ownArrow;\u61d5erticalBar;\u6225n\u0300ABLRTa\u0412\u042a\u0430\u045e\u047f\u037crrow\u0180;BU\u041d\u041e\u0422\u6193ar;\u6913pArrow;\u61f5reve;\u4311eft\u02d2\u043a\0\u0446\0\u0450ightVector;\u6950eeVector;\u695eector\u0100;B\u0459\u045a\u61bdar;\u6956ight\u01d4\u0467\0\u0471eeVector;\u695fector\u0100;B\u047a\u047b\u61c1ar;\u6957ee\u0100;A\u0486\u0487\u62a4rrow;\u61a7\u0100ct\u0492\u0497r;\uc000\ud835\udc9frok;\u4110\u0800NTacdfglmopqstux\u04bd\u04c0\u04c4\u04cb\u04de\u04e2\u04e7\u04ee\u04f5\u0521\u052f\u0536\u0552\u055d\u0560\u0565G;\u414aH\u803b\xd0\u40d0cute\u803b\xc9\u40c9\u0180aiy\u04d2\u04d7\u04dcron;\u411arc\u803b\xca\u40ca;\u442dot;\u4116r;\uc000\ud835\udd08rave\u803b\xc8\u40c8ement;\u6208\u0100ap\u04fa\u04fecr;\u4112ty\u0253\u0506\0\0\u0512mallSquare;\u65fberySmallSquare;\u65ab\u0100gp\u0526\u052aon;\u4118f;\uc000\ud835\udd3csilon;\u4395u\u0100ai\u053c\u0549l\u0100;T\u0542\u0543\u6a75ilde;\u6242librium;\u61cc\u0100ci\u0557\u055ar;\u6130m;\u6a73a;\u4397ml\u803b\xcb\u40cb\u0100ip\u056a\u056fsts;\u6203onentialE;\u6147\u0280cfios\u0585\u0588\u058d\u05b2\u05ccy;\u4424r;\uc000\ud835\udd09lled\u0253\u0597\0\0\u05a3mallSquare;\u65fcerySmallSquare;\u65aa\u0370\u05ba\0\u05bf\0\0\u05c4f;\uc000\ud835\udd3dAll;\u6200riertrf;\u6131c\xf2\u05cb\u0600JTabcdfgorst\u05e8\u05ec\u05ef\u05fa\u0600\u0612\u0616\u061b\u061d\u0623\u066c\u0672cy;\u4403\u803b>\u403emma\u0100;d\u05f7\u05f8\u4393;\u43dcreve;\u411e\u0180eiy\u0607\u060c\u0610dil;\u4122rc;\u411c;\u4413ot;\u4120r;\uc000\ud835\udd0a;\u62d9pf;\uc000\ud835\udd3eeater\u0300EFGLST\u0635\u0644\u064e\u0656\u065b\u0666qual\u0100;L\u063e\u063f\u6265ess;\u62dbullEqual;\u6267reater;\u6aa2ess;\u6277lantEqual;\u6a7eilde;\u6273cr;\uc000\ud835\udca2;\u626b\u0400Aacfiosu\u0685\u068b\u0696\u069b\u069e\u06aa\u06be\u06caRDcy;\u442a\u0100ct\u0690\u0694ek;\u42c7;\u405eirc;\u4124r;\u610clbertSpace;\u610b\u01f0\u06af\0\u06b2f;\u610dizontalLine;\u6500\u0100ct\u06c3\u06c5\xf2\u06a9rok;\u4126mp\u0144\u06d0\u06d8ownHum\xf0\u012fqual;\u624f\u0700EJOacdfgmnostu\u06fa\u06fe\u0703\u0707\u070e\u071a\u071e\u0721\u0728\u0744\u0778\u078b\u078f\u0795cy;\u4415lig;\u4132cy;\u4401cute\u803b\xcd\u40cd\u0100iy\u0713\u0718rc\u803b\xce\u40ce;\u4418ot;\u4130r;\u6111rave\u803b\xcc\u40cc\u0180;ap\u0720\u072f\u073f\u0100cg\u0734\u0737r;\u412ainaryI;\u6148lie\xf3\u03dd\u01f4\u0749\0\u0762\u0100;e\u074d\u074e\u622c\u0100gr\u0753\u0758ral;\u622bsection;\u62c2isible\u0100CT\u076c\u0772omma;\u6063imes;\u6062\u0180gpt\u077f\u0783\u0788on;\u412ef;\uc000\ud835\udd40a;\u4399cr;\u6110ilde;\u4128\u01eb\u079a\0\u079ecy;\u4406l\u803b\xcf\u40cf\u0280cfosu\u07ac\u07b7\u07bc\u07c2\u07d0\u0100iy\u07b1\u07b5rc;\u4134;\u4419r;\uc000\ud835\udd0dpf;\uc000\ud835\udd41\u01e3\u07c7\0\u07ccr;\uc000\ud835\udca5rcy;\u4408kcy;\u4404\u0380HJacfos\u07e4\u07e8\u07ec\u07f1\u07fd\u0802\u0808cy;\u4425cy;\u440cppa;\u439a\u0100ey\u07f6\u07fbdil;\u4136;\u441ar;\uc000\ud835\udd0epf;\uc000\ud835\udd42cr;\uc000\ud835\udca6\u0580JTaceflmost\u0825\u0829\u082c\u0850\u0863\u09b3\u09b8\u09c7\u09cd\u0a37\u0a47cy;\u4409\u803b<\u403c\u0280cmnpr\u0837\u083c\u0841\u0844\u084dute;\u4139bda;\u439bg;\u67ealacetrf;\u6112r;\u619e\u0180aey\u0857\u085c\u0861ron;\u413ddil;\u413b;\u441b\u0100fs\u0868\u0970t\u0500ACDFRTUVar\u087e\u08a9\u08b1\u08e0\u08e6\u08fc\u092f\u095b\u0390\u096a\u0100nr\u0883\u088fgleBracket;\u67e8row\u0180;BR\u0899\u089a\u089e\u6190ar;\u61e4ightArrow;\u61c6eiling;\u6308o\u01f5\u08b7\0\u08c3bleBracket;\u67e6n\u01d4\u08c8\0\u08d2eeVector;\u6961ector\u0100;B\u08db\u08dc\u61c3ar;\u6959loor;\u630aight\u0100AV\u08ef\u08f5rrow;\u6194ector;\u694e\u0100er\u0901\u0917e\u0180;AV\u0909\u090a\u0910\u62a3rrow;\u61a4ector;\u695aiangle\u0180;BE\u0924\u0925\u0929\u62b2ar;\u69cfqual;\u62b4p\u0180DTV\u0937\u0942\u094cownVector;\u6951eeVector;\u6960ector\u0100;B\u0956\u0957\u61bfar;\u6958ector\u0100;B\u0965\u0966\u61bcar;\u6952ight\xe1\u039cs\u0300EFGLST\u097e\u098b\u0995\u099d\u09a2\u09adqualGreater;\u62daullEqual;\u6266reater;\u6276ess;\u6aa1lantEqual;\u6a7dilde;\u6272r;\uc000\ud835\udd0f\u0100;e\u09bd\u09be\u62d8ftarrow;\u61daidot;\u413f\u0180npw\u09d4\u0a16\u0a1bg\u0200LRlr\u09de\u09f7\u0a02\u0a10eft\u0100AR\u09e6\u09ecrrow;\u67f5ightArrow;\u67f7ightArrow;\u67f6eft\u0100ar\u03b3\u0a0aight\xe1\u03bfight\xe1\u03caf;\uc000\ud835\udd43er\u0100LR\u0a22\u0a2ceftArrow;\u6199ightArrow;\u6198\u0180cht\u0a3e\u0a40\u0a42\xf2\u084c;\u61b0rok;\u4141;\u626a\u0400acefiosu\u0a5a\u0a5d\u0a60\u0a77\u0a7c\u0a85\u0a8b\u0a8ep;\u6905y;\u441c\u0100dl\u0a65\u0a6fiumSpace;\u605flintrf;\u6133r;\uc000\ud835\udd10nusPlus;\u6213pf;\uc000\ud835\udd44c\xf2\u0a76;\u439c\u0480Jacefostu\u0aa3\u0aa7\u0aad\u0ac0\u0b14\u0b19\u0d91\u0d97\u0d9ecy;\u440acute;\u4143\u0180aey\u0ab4\u0ab9\u0aberon;\u4147dil;\u4145;\u441d\u0180gsw\u0ac7\u0af0\u0b0eative\u0180MTV\u0ad3\u0adf\u0ae8ediumSpace;\u600bhi\u0100cn\u0ae6\u0ad8\xeb\u0ad9eryThi\xee\u0ad9ted\u0100GL\u0af8\u0b06reaterGreate\xf2\u0673essLes\xf3\u0a48Line;\u400ar;\uc000\ud835\udd11\u0200Bnpt\u0b22\u0b28\u0b37\u0b3areak;\u6060BreakingSpace;\u40a0f;\u6115\u0680;CDEGHLNPRSTV\u0b55\u0b56\u0b6a\u0b7c\u0ba1\u0beb\u0c04\u0c5e\u0c84\u0ca6\u0cd8\u0d61\u0d85\u6aec\u0100ou\u0b5b\u0b64ngruent;\u6262pCap;\u626doubleVerticalBar;\u6226\u0180lqx\u0b83\u0b8a\u0b9bement;\u6209ual\u0100;T\u0b92\u0b93\u6260ilde;\uc000\u2242\u0338ists;\u6204reater\u0380;EFGLST\u0bb6\u0bb7\u0bbd\u0bc9\u0bd3\u0bd8\u0be5\u626fqual;\u6271ullEqual;\uc000\u2267\u0338reater;\uc000\u226b\u0338ess;\u6279lantEqual;\uc000\u2a7e\u0338ilde;\u6275ump\u0144\u0bf2\u0bfdownHump;\uc000\u224e\u0338qual;\uc000\u224f\u0338e\u0100fs\u0c0a\u0c27tTriangle\u0180;BE\u0c1a\u0c1b\u0c21\u62eaar;\uc000\u29cf\u0338qual;\u62ecs\u0300;EGLST\u0c35\u0c36\u0c3c\u0c44\u0c4b\u0c58\u626equal;\u6270reater;\u6278ess;\uc000\u226a\u0338lantEqual;\uc000\u2a7d\u0338ilde;\u6274ested\u0100GL\u0c68\u0c79reaterGreater;\uc000\u2aa2\u0338essLess;\uc000\u2aa1\u0338recedes\u0180;ES\u0c92\u0c93\u0c9b\u6280qual;\uc000\u2aaf\u0338lantEqual;\u62e0\u0100ei\u0cab\u0cb9verseElement;\u620cghtTriangle\u0180;BE\u0ccb\u0ccc\u0cd2\u62ebar;\uc000\u29d0\u0338qual;\u62ed\u0100qu\u0cdd\u0d0cuareSu\u0100bp\u0ce8\u0cf9set\u0100;E\u0cf0\u0cf3\uc000\u228f\u0338qual;\u62e2erset\u0100;E\u0d03\u0d06\uc000\u2290\u0338qual;\u62e3\u0180bcp\u0d13\u0d24\u0d4eset\u0100;E\u0d1b\u0d1e\uc000\u2282\u20d2qual;\u6288ceeds\u0200;EST\u0d32\u0d33\u0d3b\u0d46\u6281qual;\uc000\u2ab0\u0338lantEqual;\u62e1ilde;\uc000\u227f\u0338erset\u0100;E\u0d58\u0d5b\uc000\u2283\u20d2qual;\u6289ilde\u0200;EFT\u0d6e\u0d6f\u0d75\u0d7f\u6241qual;\u6244ullEqual;\u6247ilde;\u6249erticalBar;\u6224cr;\uc000\ud835\udca9ilde\u803b\xd1\u40d1;\u439d\u0700Eacdfgmoprstuv\u0dbd\u0dc2\u0dc9\u0dd5\u0ddb\u0de0\u0de7\u0dfc\u0e02\u0e20\u0e22\u0e32\u0e3f\u0e44lig;\u4152cute\u803b\xd3\u40d3\u0100iy\u0dce\u0dd3rc\u803b\xd4\u40d4;\u441eblac;\u4150r;\uc000\ud835\udd12rave\u803b\xd2\u40d2\u0180aei\u0dee\u0df2\u0df6cr;\u414cga;\u43a9cron;\u439fpf;\uc000\ud835\udd46enCurly\u0100DQ\u0e0e\u0e1aoubleQuote;\u601cuote;\u6018;\u6a54\u0100cl\u0e27\u0e2cr;\uc000\ud835\udcaaash\u803b\xd8\u40d8i\u016c\u0e37\u0e3cde\u803b\xd5\u40d5es;\u6a37ml\u803b\xd6\u40d6er\u0100BP\u0e4b\u0e60\u0100ar\u0e50\u0e53r;\u603eac\u0100ek\u0e5a\u0e5c;\u63deet;\u63b4arenthesis;\u63dc\u0480acfhilors\u0e7f\u0e87\u0e8a\u0e8f\u0e92\u0e94\u0e9d\u0eb0\u0efcrtialD;\u6202y;\u441fr;\uc000\ud835\udd13i;\u43a6;\u43a0usMinus;\u40b1\u0100ip\u0ea2\u0eadncareplan\xe5\u069df;\u6119\u0200;eio\u0eb9\u0eba\u0ee0\u0ee4\u6abbcedes\u0200;EST\u0ec8\u0ec9\u0ecf\u0eda\u627aqual;\u6aaflantEqual;\u627cilde;\u627eme;\u6033\u0100dp\u0ee9\u0eeeuct;\u620fortion\u0100;a\u0225\u0ef9l;\u621d\u0100ci\u0f01\u0f06r;\uc000\ud835\udcab;\u43a8\u0200Ufos\u0f11\u0f16\u0f1b\u0f1fOT\u803b\"\u4022r;\uc000\ud835\udd14pf;\u611acr;\uc000\ud835\udcac\u0600BEacefhiorsu\u0f3e\u0f43\u0f47\u0f60\u0f73\u0fa7\u0faa\u0fad\u1096\u10a9\u10b4\u10bearr;\u6910G\u803b\xae\u40ae\u0180cnr\u0f4e\u0f53\u0f56ute;\u4154g;\u67ebr\u0100;t\u0f5c\u0f5d\u61a0l;\u6916\u0180aey\u0f67\u0f6c\u0f71ron;\u4158dil;\u4156;\u4420\u0100;v\u0f78\u0f79\u611cerse\u0100EU\u0f82\u0f99\u0100lq\u0f87\u0f8eement;\u620builibrium;\u61cbpEquilibrium;\u696fr\xbb\u0f79o;\u43a1ght\u0400ACDFTUVa\u0fc1\u0feb\u0ff3\u1022\u1028\u105b\u1087\u03d8\u0100nr\u0fc6\u0fd2gleBracket;\u67e9row\u0180;BL\u0fdc\u0fdd\u0fe1\u6192ar;\u61e5eftArrow;\u61c4eiling;\u6309o\u01f5\u0ff9\0\u1005bleBracket;\u67e7n\u01d4\u100a\0\u1014eeVector;\u695dector\u0100;B\u101d\u101e\u61c2ar;\u6955loor;\u630b\u0100er\u102d\u1043e\u0180;AV\u1035\u1036\u103c\u62a2rrow;\u61a6ector;\u695biangle\u0180;BE\u1050\u1051\u1055\u62b3ar;\u69d0qual;\u62b5p\u0180DTV\u1063\u106e\u1078ownVector;\u694feeVector;\u695cector\u0100;B\u1082\u1083\u61bear;\u6954ector\u0100;B\u1091\u1092\u61c0ar;\u6953\u0100pu\u109b\u109ef;\u611dndImplies;\u6970ightarrow;\u61db\u0100ch\u10b9\u10bcr;\u611b;\u61b1leDelayed;\u69f4\u0680HOacfhimoqstu\u10e4\u10f1\u10f7\u10fd\u1119\u111e\u1151\u1156\u1161\u1167\u11b5\u11bb\u11bf\u0100Cc\u10e9\u10eeHcy;\u4429y;\u4428FTcy;\u442ccute;\u415a\u0280;aeiy\u1108\u1109\u110e\u1113\u1117\u6abcron;\u4160dil;\u415erc;\u415c;\u4421r;\uc000\ud835\udd16ort\u0200DLRU\u112a\u1134\u113e\u1149ownArrow\xbb\u041eeftArrow\xbb\u089aightArrow\xbb\u0fddpArrow;\u6191gma;\u43a3allCircle;\u6218pf;\uc000\ud835\udd4a\u0272\u116d\0\0\u1170t;\u621aare\u0200;ISU\u117b\u117c\u1189\u11af\u65a1ntersection;\u6293u\u0100bp\u118f\u119eset\u0100;E\u1197\u1198\u628fqual;\u6291erset\u0100;E\u11a8\u11a9\u6290qual;\u6292nion;\u6294cr;\uc000\ud835\udcaear;\u62c6\u0200bcmp\u11c8\u11db\u1209\u120b\u0100;s\u11cd\u11ce\u62d0et\u0100;E\u11cd\u11d5qual;\u6286\u0100ch\u11e0\u1205eeds\u0200;EST\u11ed\u11ee\u11f4\u11ff\u627bqual;\u6ab0lantEqual;\u627dilde;\u627fTh\xe1\u0f8c;\u6211\u0180;es\u1212\u1213\u1223\u62d1rset\u0100;E\u121c\u121d\u6283qual;\u6287et\xbb\u1213\u0580HRSacfhiors\u123e\u1244\u1249\u1255\u125e\u1271\u1276\u129f\u12c2\u12c8\u12d1ORN\u803b\xde\u40deADE;\u6122\u0100Hc\u124e\u1252cy;\u440by;\u4426\u0100bu\u125a\u125c;\u4009;\u43a4\u0180aey\u1265\u126a\u126fron;\u4164dil;\u4162;\u4422r;\uc000\ud835\udd17\u0100ei\u127b\u1289\u01f2\u1280\0\u1287efore;\u6234a;\u4398\u0100cn\u128e\u1298kSpace;\uc000\u205f\u200aSpace;\u6009lde\u0200;EFT\u12ab\u12ac\u12b2\u12bc\u623cqual;\u6243ullEqual;\u6245ilde;\u6248pf;\uc000\ud835\udd4bipleDot;\u60db\u0100ct\u12d6\u12dbr;\uc000\ud835\udcafrok;\u4166\u0ae1\u12f7\u130e\u131a\u1326\0\u132c\u1331\0\0\0\0\0\u1338\u133d\u1377\u1385\0\u13ff\u1404\u140a\u1410\u0100cr\u12fb\u1301ute\u803b\xda\u40dar\u0100;o\u1307\u1308\u619fcir;\u6949r\u01e3\u1313\0\u1316y;\u440eve;\u416c\u0100iy\u131e\u1323rc\u803b\xdb\u40db;\u4423blac;\u4170r;\uc000\ud835\udd18rave\u803b\xd9\u40d9acr;\u416a\u0100di\u1341\u1369er\u0100BP\u1348\u135d\u0100ar\u134d\u1350r;\u405fac\u0100ek\u1357\u1359;\u63dfet;\u63b5arenthesis;\u63ddon\u0100;P\u1370\u1371\u62c3lus;\u628e\u0100gp\u137b\u137fon;\u4172f;\uc000\ud835\udd4c\u0400ADETadps\u1395\u13ae\u13b8\u13c4\u03e8\u13d2\u13d7\u13f3rrow\u0180;BD\u1150\u13a0\u13a4ar;\u6912ownArrow;\u61c5ownArrow;\u6195quilibrium;\u696eee\u0100;A\u13cb\u13cc\u62a5rrow;\u61a5own\xe1\u03f3er\u0100LR\u13de\u13e8eftArrow;\u6196ightArrow;\u6197i\u0100;l\u13f9\u13fa\u43d2on;\u43a5ing;\u416ecr;\uc000\ud835\udcb0ilde;\u4168ml\u803b\xdc\u40dc\u0480Dbcdefosv\u1427\u142c\u1430\u1433\u143e\u1485\u148a\u1490\u1496ash;\u62abar;\u6aeby;\u4412ash\u0100;l\u143b\u143c\u62a9;\u6ae6\u0100er\u1443\u1445;\u62c1\u0180bty\u144c\u1450\u147aar;\u6016\u0100;i\u144f\u1455cal\u0200BLST\u1461\u1465\u146a\u1474ar;\u6223ine;\u407ceparator;\u6758ilde;\u6240ThinSpace;\u600ar;\uc000\ud835\udd19pf;\uc000\ud835\udd4dcr;\uc000\ud835\udcb1dash;\u62aa\u0280cefos\u14a7\u14ac\u14b1\u14b6\u14bcirc;\u4174dge;\u62c0r;\uc000\ud835\udd1apf;\uc000\ud835\udd4ecr;\uc000\ud835\udcb2\u0200fios\u14cb\u14d0\u14d2\u14d8r;\uc000\ud835\udd1b;\u439epf;\uc000\ud835\udd4fcr;\uc000\ud835\udcb3\u0480AIUacfosu\u14f1\u14f5\u14f9\u14fd\u1504\u150f\u1514\u151a\u1520cy;\u442fcy;\u4407cy;\u442ecute\u803b\xdd\u40dd\u0100iy\u1509\u150drc;\u4176;\u442br;\uc000\ud835\udd1cpf;\uc000\ud835\udd50cr;\uc000\ud835\udcb4ml;\u4178\u0400Hacdefos\u1535\u1539\u153f\u154b\u154f\u155d\u1560\u1564cy;\u4416cute;\u4179\u0100ay\u1544\u1549ron;\u417d;\u4417ot;\u417b\u01f2\u1554\0\u155boWidt\xe8\u0ad9a;\u4396r;\u6128pf;\u6124cr;\uc000\ud835\udcb5\u0be1\u1583\u158a\u1590\0\u15b0\u15b6\u15bf\0\0\0\0\u15c6\u15db\u15eb\u165f\u166d\0\u1695\u169b\u16b2\u16b9\0\u16becute\u803b\xe1\u40e1reve;\u4103\u0300;Ediuy\u159c\u159d\u15a1\u15a3\u15a8\u15ad\u623e;\uc000\u223e\u0333;\u623frc\u803b\xe2\u40e2te\u80bb\xb4\u0306;\u4430lig\u803b\xe6\u40e6\u0100;r\xb2\u15ba;\uc000\ud835\udd1erave\u803b\xe0\u40e0\u0100ep\u15ca\u15d6\u0100fp\u15cf\u15d4sym;\u6135\xe8\u15d3ha;\u43b1\u0100ap\u15dfc\u0100cl\u15e4\u15e7r;\u4101g;\u6a3f\u0264\u15f0\0\0\u160a\u0280;adsv\u15fa\u15fb\u15ff\u1601\u1607\u6227nd;\u6a55;\u6a5clope;\u6a58;\u6a5a\u0380;elmrsz\u1618\u1619\u161b\u161e\u163f\u164f\u1659\u6220;\u69a4e\xbb\u1619sd\u0100;a\u1625\u1626\u6221\u0461\u1630\u1632\u1634\u1636\u1638\u163a\u163c\u163e;\u69a8;\u69a9;\u69aa;\u69ab;\u69ac;\u69ad;\u69ae;\u69aft\u0100;v\u1645\u1646\u621fb\u0100;d\u164c\u164d\u62be;\u699d\u0100pt\u1654\u1657h;\u6222\xbb\xb9arr;\u637c\u0100gp\u1663\u1667on;\u4105f;\uc000\ud835\udd52\u0380;Eaeiop\u12c1\u167b\u167d\u1682\u1684\u1687\u168a;\u6a70cir;\u6a6f;\u624ad;\u624bs;\u4027rox\u0100;e\u12c1\u1692\xf1\u1683ing\u803b\xe5\u40e5\u0180cty\u16a1\u16a6\u16a8r;\uc000\ud835\udcb6;\u402amp\u0100;e\u12c1\u16af\xf1\u0288ilde\u803b\xe3\u40e3ml\u803b\xe4\u40e4\u0100ci\u16c2\u16c8onin\xf4\u0272nt;\u6a11\u0800Nabcdefiklnoprsu\u16ed\u16f1\u1730\u173c\u1743\u1748\u1778\u177d\u17e0\u17e6\u1839\u1850\u170d\u193d\u1948\u1970ot;\u6aed\u0100cr\u16f6\u171ek\u0200ceps\u1700\u1705\u170d\u1713ong;\u624cpsilon;\u43f6rime;\u6035im\u0100;e\u171a\u171b\u623dq;\u62cd\u0176\u1722\u1726ee;\u62bded\u0100;g\u172c\u172d\u6305e\xbb\u172drk\u0100;t\u135c\u1737brk;\u63b6\u0100oy\u1701\u1741;\u4431quo;\u601e\u0280cmprt\u1753\u175b\u1761\u1764\u1768aus\u0100;e\u010a\u0109ptyv;\u69b0s\xe9\u170cno\xf5\u0113\u0180ahw\u176f\u1771\u1773;\u43b2;\u6136een;\u626cr;\uc000\ud835\udd1fg\u0380costuvw\u178d\u179d\u17b3\u17c1\u17d5\u17db\u17de\u0180aiu\u1794\u1796\u179a\xf0\u0760rc;\u65efp\xbb\u1371\u0180dpt\u17a4\u17a8\u17adot;\u6a00lus;\u6a01imes;\u6a02\u0271\u17b9\0\0\u17becup;\u6a06ar;\u6605riangle\u0100du\u17cd\u17d2own;\u65bdp;\u65b3plus;\u6a04e\xe5\u1444\xe5\u14adarow;\u690d\u0180ako\u17ed\u1826\u1835\u0100cn\u17f2\u1823k\u0180lst\u17fa\u05ab\u1802ozenge;\u69ebriangle\u0200;dlr\u1812\u1813\u1818\u181d\u65b4own;\u65beeft;\u65c2ight;\u65b8k;\u6423\u01b1\u182b\0\u1833\u01b2\u182f\0\u1831;\u6592;\u65914;\u6593ck;\u6588\u0100eo\u183e\u184d\u0100;q\u1843\u1846\uc000=\u20e5uiv;\uc000\u2261\u20e5t;\u6310\u0200ptwx\u1859\u185e\u1867\u186cf;\uc000\ud835\udd53\u0100;t\u13cb\u1863om\xbb\u13cctie;\u62c8\u0600DHUVbdhmptuv\u1885\u1896\u18aa\u18bb\u18d7\u18db\u18ec\u18ff\u1905\u190a\u1910\u1921\u0200LRlr\u188e\u1890\u1892\u1894;\u6557;\u6554;\u6556;\u6553\u0280;DUdu\u18a1\u18a2\u18a4\u18a6\u18a8\u6550;\u6566;\u6569;\u6564;\u6567\u0200LRlr\u18b3\u18b5\u18b7\u18b9;\u655d;\u655a;\u655c;\u6559\u0380;HLRhlr\u18ca\u18cb\u18cd\u18cf\u18d1\u18d3\u18d5\u6551;\u656c;\u6563;\u6560;\u656b;\u6562;\u655fox;\u69c9\u0200LRlr\u18e4\u18e6\u18e8\u18ea;\u6555;\u6552;\u6510;\u650c\u0280;DUdu\u06bd\u18f7\u18f9\u18fb\u18fd;\u6565;\u6568;\u652c;\u6534inus;\u629flus;\u629eimes;\u62a0\u0200LRlr\u1919\u191b\u191d\u191f;\u655b;\u6558;\u6518;\u6514\u0380;HLRhlr\u1930\u1931\u1933\u1935\u1937\u1939\u193b\u6502;\u656a;\u6561;\u655e;\u653c;\u6524;\u651c\u0100ev\u0123\u1942bar\u803b\xa6\u40a6\u0200ceio\u1951\u1956\u195a\u1960r;\uc000\ud835\udcb7mi;\u604fm\u0100;e\u171a\u171cl\u0180;bh\u1968\u1969\u196b\u405c;\u69c5sub;\u67c8\u016c\u1974\u197el\u0100;e\u1979\u197a\u6022t\xbb\u197ap\u0180;Ee\u012f\u1985\u1987;\u6aae\u0100;q\u06dc\u06db\u0ce1\u19a7\0\u19e8\u1a11\u1a15\u1a32\0\u1a37\u1a50\0\0\u1ab4\0\0\u1ac1\0\0\u1b21\u1b2e\u1b4d\u1b52\0\u1bfd\0\u1c0c\u0180cpr\u19ad\u19b2\u19ddute;\u4107\u0300;abcds\u19bf\u19c0\u19c4\u19ca\u19d5\u19d9\u6229nd;\u6a44rcup;\u6a49\u0100au\u19cf\u19d2p;\u6a4bp;\u6a47ot;\u6a40;\uc000\u2229\ufe00\u0100eo\u19e2\u19e5t;\u6041\xee\u0693\u0200aeiu\u19f0\u19fb\u1a01\u1a05\u01f0\u19f5\0\u19f8s;\u6a4don;\u410ddil\u803b\xe7\u40e7rc;\u4109ps\u0100;s\u1a0c\u1a0d\u6a4cm;\u6a50ot;\u410b\u0180dmn\u1a1b\u1a20\u1a26il\u80bb\xb8\u01adptyv;\u69b2t\u8100\xa2;e\u1a2d\u1a2e\u40a2r\xe4\u01b2r;\uc000\ud835\udd20\u0180cei\u1a3d\u1a40\u1a4dy;\u4447ck\u0100;m\u1a47\u1a48\u6713ark\xbb\u1a48;\u43c7r\u0380;Ecefms\u1a5f\u1a60\u1a62\u1a6b\u1aa4\u1aaa\u1aae\u65cb;\u69c3\u0180;el\u1a69\u1a6a\u1a6d\u42c6q;\u6257e\u0261\u1a74\0\0\u1a88rrow\u0100lr\u1a7c\u1a81eft;\u61baight;\u61bb\u0280RSacd\u1a92\u1a94\u1a96\u1a9a\u1a9f\xbb\u0f47;\u64c8st;\u629birc;\u629aash;\u629dnint;\u6a10id;\u6aefcir;\u69c2ubs\u0100;u\u1abb\u1abc\u6663it\xbb\u1abc\u02ec\u1ac7\u1ad4\u1afa\0\u1b0aon\u0100;e\u1acd\u1ace\u403a\u0100;q\xc7\xc6\u026d\u1ad9\0\0\u1ae2a\u0100;t\u1ade\u1adf\u402c;\u4040\u0180;fl\u1ae8\u1ae9\u1aeb\u6201\xee\u1160e\u0100mx\u1af1\u1af6ent\xbb\u1ae9e\xf3\u024d\u01e7\u1afe\0\u1b07\u0100;d\u12bb\u1b02ot;\u6a6dn\xf4\u0246\u0180fry\u1b10\u1b14\u1b17;\uc000\ud835\udd54o\xe4\u0254\u8100\xa9;s\u0155\u1b1dr;\u6117\u0100ao\u1b25\u1b29rr;\u61b5ss;\u6717\u0100cu\u1b32\u1b37r;\uc000\ud835\udcb8\u0100bp\u1b3c\u1b44\u0100;e\u1b41\u1b42\u6acf;\u6ad1\u0100;e\u1b49\u1b4a\u6ad0;\u6ad2dot;\u62ef\u0380delprvw\u1b60\u1b6c\u1b77\u1b82\u1bac\u1bd4\u1bf9arr\u0100lr\u1b68\u1b6a;\u6938;\u6935\u0270\u1b72\0\0\u1b75r;\u62dec;\u62dfarr\u0100;p\u1b7f\u1b80\u61b6;\u693d\u0300;bcdos\u1b8f\u1b90\u1b96\u1ba1\u1ba5\u1ba8\u622arcap;\u6a48\u0100au\u1b9b\u1b9ep;\u6a46p;\u6a4aot;\u628dr;\u6a45;\uc000\u222a\ufe00\u0200alrv\u1bb5\u1bbf\u1bde\u1be3rr\u0100;m\u1bbc\u1bbd\u61b7;\u693cy\u0180evw\u1bc7\u1bd4\u1bd8q\u0270\u1bce\0\0\u1bd2re\xe3\u1b73u\xe3\u1b75ee;\u62ceedge;\u62cfen\u803b\xa4\u40a4earrow\u0100lr\u1bee\u1bf3eft\xbb\u1b80ight\xbb\u1bbde\xe4\u1bdd\u0100ci\u1c01\u1c07onin\xf4\u01f7nt;\u6231lcty;\u632d\u0980AHabcdefhijlorstuwz\u1c38\u1c3b\u1c3f\u1c5d\u1c69\u1c75\u1c8a\u1c9e\u1cac\u1cb7\u1cfb\u1cff\u1d0d\u1d7b\u1d91\u1dab\u1dbb\u1dc6\u1dcdr\xf2\u0381ar;\u6965\u0200glrs\u1c48\u1c4d\u1c52\u1c54ger;\u6020eth;\u6138\xf2\u1133h\u0100;v\u1c5a\u1c5b\u6010\xbb\u090a\u016b\u1c61\u1c67arow;\u690fa\xe3\u0315\u0100ay\u1c6e\u1c73ron;\u410f;\u4434\u0180;ao\u0332\u1c7c\u1c84\u0100gr\u02bf\u1c81r;\u61catseq;\u6a77\u0180glm\u1c91\u1c94\u1c98\u803b\xb0\u40b0ta;\u43b4ptyv;\u69b1\u0100ir\u1ca3\u1ca8sht;\u697f;\uc000\ud835\udd21ar\u0100lr\u1cb3\u1cb5\xbb\u08dc\xbb\u101e\u0280aegsv\u1cc2\u0378\u1cd6\u1cdc\u1ce0m\u0180;os\u0326\u1cca\u1cd4nd\u0100;s\u0326\u1cd1uit;\u6666amma;\u43ddin;\u62f2\u0180;io\u1ce7\u1ce8\u1cf8\u40f7de\u8100\xf7;o\u1ce7\u1cf0ntimes;\u62c7n\xf8\u1cf7cy;\u4452c\u026f\u1d06\0\0\u1d0arn;\u631eop;\u630d\u0280lptuw\u1d18\u1d1d\u1d22\u1d49\u1d55lar;\u4024f;\uc000\ud835\udd55\u0280;emps\u030b\u1d2d\u1d37\u1d3d\u1d42q\u0100;d\u0352\u1d33ot;\u6251inus;\u6238lus;\u6214quare;\u62a1blebarwedg\xe5\xfan\u0180adh\u112e\u1d5d\u1d67ownarrow\xf3\u1c83arpoon\u0100lr\u1d72\u1d76ef\xf4\u1cb4igh\xf4\u1cb6\u0162\u1d7f\u1d85karo\xf7\u0f42\u026f\u1d8a\0\0\u1d8ern;\u631fop;\u630c\u0180cot\u1d98\u1da3\u1da6\u0100ry\u1d9d\u1da1;\uc000\ud835\udcb9;\u4455l;\u69f6rok;\u4111\u0100dr\u1db0\u1db4ot;\u62f1i\u0100;f\u1dba\u1816\u65bf\u0100ah\u1dc0\u1dc3r\xf2\u0429a\xf2\u0fa6angle;\u69a6\u0100ci\u1dd2\u1dd5y;\u445fgrarr;\u67ff\u0900Dacdefglmnopqrstux\u1e01\u1e09\u1e19\u1e38\u0578\u1e3c\u1e49\u1e61\u1e7e\u1ea5\u1eaf\u1ebd\u1ee1\u1f2a\u1f37\u1f44\u1f4e\u1f5a\u0100Do\u1e06\u1d34o\xf4\u1c89\u0100cs\u1e0e\u1e14ute\u803b\xe9\u40e9ter;\u6a6e\u0200aioy\u1e22\u1e27\u1e31\u1e36ron;\u411br\u0100;c\u1e2d\u1e2e\u6256\u803b\xea\u40ealon;\u6255;\u444dot;\u4117\u0100Dr\u1e41\u1e45ot;\u6252;\uc000\ud835\udd22\u0180;rs\u1e50\u1e51\u1e57\u6a9aave\u803b\xe8\u40e8\u0100;d\u1e5c\u1e5d\u6a96ot;\u6a98\u0200;ils\u1e6a\u1e6b\u1e72\u1e74\u6a99nters;\u63e7;\u6113\u0100;d\u1e79\u1e7a\u6a95ot;\u6a97\u0180aps\u1e85\u1e89\u1e97cr;\u4113ty\u0180;sv\u1e92\u1e93\u1e95\u6205et\xbb\u1e93p\u01001;\u1e9d\u1ea4\u0133\u1ea1\u1ea3;\u6004;\u6005\u6003\u0100gs\u1eaa\u1eac;\u414bp;\u6002\u0100gp\u1eb4\u1eb8on;\u4119f;\uc000\ud835\udd56\u0180als\u1ec4\u1ece\u1ed2r\u0100;s\u1eca\u1ecb\u62d5l;\u69e3us;\u6a71i\u0180;lv\u1eda\u1edb\u1edf\u43b5on\xbb\u1edb;\u43f5\u0200csuv\u1eea\u1ef3\u1f0b\u1f23\u0100io\u1eef\u1e31rc\xbb\u1e2e\u0269\u1ef9\0\0\u1efb\xed\u0548ant\u0100gl\u1f02\u1f06tr\xbb\u1e5dess\xbb\u1e7a\u0180aei\u1f12\u1f16\u1f1als;\u403dst;\u625fv\u0100;D\u0235\u1f20D;\u6a78parsl;\u69e5\u0100Da\u1f2f\u1f33ot;\u6253rr;\u6971\u0180cdi\u1f3e\u1f41\u1ef8r;\u612fo\xf4\u0352\u0100ah\u1f49\u1f4b;\u43b7\u803b\xf0\u40f0\u0100mr\u1f53\u1f57l\u803b\xeb\u40ebo;\u60ac\u0180cip\u1f61\u1f64\u1f67l;\u4021s\xf4\u056e\u0100eo\u1f6c\u1f74ctatio\xee\u0559nential\xe5\u0579\u09e1\u1f92\0\u1f9e\0\u1fa1\u1fa7\0\0\u1fc6\u1fcc\0\u1fd3\0\u1fe6\u1fea\u2000\0\u2008\u205allingdotse\xf1\u1e44y;\u4444male;\u6640\u0180ilr\u1fad\u1fb3\u1fc1lig;\u8000\ufb03\u0269\u1fb9\0\0\u1fbdg;\u8000\ufb00ig;\u8000\ufb04;\uc000\ud835\udd23lig;\u8000\ufb01lig;\uc000fj\u0180alt\u1fd9\u1fdc\u1fe1t;\u666dig;\u8000\ufb02ns;\u65b1of;\u4192\u01f0\u1fee\0\u1ff3f;\uc000\ud835\udd57\u0100ak\u05bf\u1ff7\u0100;v\u1ffc\u1ffd\u62d4;\u6ad9artint;\u6a0d\u0100ao\u200c\u2055\u0100cs\u2011\u2052\u03b1\u201a\u2030\u2038\u2045\u2048\0\u2050\u03b2\u2022\u2025\u2027\u202a\u202c\0\u202e\u803b\xbd\u40bd;\u6153\u803b\xbc\u40bc;\u6155;\u6159;\u615b\u01b3\u2034\0\u2036;\u6154;\u6156\u02b4\u203e\u2041\0\0\u2043\u803b\xbe\u40be;\u6157;\u615c5;\u6158\u01b6\u204c\0\u204e;\u615a;\u615d8;\u615el;\u6044wn;\u6322cr;\uc000\ud835\udcbb\u0880Eabcdefgijlnorstv\u2082\u2089\u209f\u20a5\u20b0\u20b4\u20f0\u20f5\u20fa\u20ff\u2103\u2112\u2138\u0317\u213e\u2152\u219e\u0100;l\u064d\u2087;\u6a8c\u0180cmp\u2090\u2095\u209dute;\u41f5ma\u0100;d\u209c\u1cda\u43b3;\u6a86reve;\u411f\u0100iy\u20aa\u20aerc;\u411d;\u4433ot;\u4121\u0200;lqs\u063e\u0642\u20bd\u20c9\u0180;qs\u063e\u064c\u20c4lan\xf4\u0665\u0200;cdl\u0665\u20d2\u20d5\u20e5c;\u6aa9ot\u0100;o\u20dc\u20dd\u6a80\u0100;l\u20e2\u20e3\u6a82;\u6a84\u0100;e\u20ea\u20ed\uc000\u22db\ufe00s;\u6a94r;\uc000\ud835\udd24\u0100;g\u0673\u061bmel;\u6137cy;\u4453\u0200;Eaj\u065a\u210c\u210e\u2110;\u6a92;\u6aa5;\u6aa4\u0200Eaes\u211b\u211d\u2129\u2134;\u6269p\u0100;p\u2123\u2124\u6a8arox\xbb\u2124\u0100;q\u212e\u212f\u6a88\u0100;q\u212e\u211bim;\u62e7pf;\uc000\ud835\udd58\u0100ci\u2143\u2146r;\u610am\u0180;el\u066b\u214e\u2150;\u6a8e;\u6a90\u8300>;cdlqr\u05ee\u2160\u216a\u216e\u2173\u2179\u0100ci\u2165\u2167;\u6aa7r;\u6a7aot;\u62d7Par;\u6995uest;\u6a7c\u0280adels\u2184\u216a\u2190\u0656\u219b\u01f0\u2189\0\u218epro\xf8\u209er;\u6978q\u0100lq\u063f\u2196les\xf3\u2088i\xed\u066b\u0100en\u21a3\u21adrtneqq;\uc000\u2269\ufe00\xc5\u21aa\u0500Aabcefkosy\u21c4\u21c7\u21f1\u21f5\u21fa\u2218\u221d\u222f\u2268\u227dr\xf2\u03a0\u0200ilmr\u21d0\u21d4\u21d7\u21dbrs\xf0\u1484f\xbb\u2024il\xf4\u06a9\u0100dr\u21e0\u21e4cy;\u444a\u0180;cw\u08f4\u21eb\u21efir;\u6948;\u61adar;\u610firc;\u4125\u0180alr\u2201\u220e\u2213rts\u0100;u\u2209\u220a\u6665it\xbb\u220alip;\u6026con;\u62b9r;\uc000\ud835\udd25s\u0100ew\u2223\u2229arow;\u6925arow;\u6926\u0280amopr\u223a\u223e\u2243\u225e\u2263rr;\u61fftht;\u623bk\u0100lr\u2249\u2253eftarrow;\u61a9ightarrow;\u61aaf;\uc000\ud835\udd59bar;\u6015\u0180clt\u226f\u2274\u2278r;\uc000\ud835\udcbdas\xe8\u21f4rok;\u4127\u0100bp\u2282\u2287ull;\u6043hen\xbb\u1c5b\u0ae1\u22a3\0\u22aa\0\u22b8\u22c5\u22ce\0\u22d5\u22f3\0\0\u22f8\u2322\u2367\u2362\u237f\0\u2386\u23aa\u23b4cute\u803b\xed\u40ed\u0180;iy\u0771\u22b0\u22b5rc\u803b\xee\u40ee;\u4438\u0100cx\u22bc\u22bfy;\u4435cl\u803b\xa1\u40a1\u0100fr\u039f\u22c9;\uc000\ud835\udd26rave\u803b\xec\u40ec\u0200;ino\u073e\u22dd\u22e9\u22ee\u0100in\u22e2\u22e6nt;\u6a0ct;\u622dfin;\u69dcta;\u6129lig;\u4133\u0180aop\u22fe\u231a\u231d\u0180cgt\u2305\u2308\u2317r;\u412b\u0180elp\u071f\u230f\u2313in\xe5\u078ear\xf4\u0720h;\u4131f;\u62b7ed;\u41b5\u0280;cfot\u04f4\u232c\u2331\u233d\u2341are;\u6105in\u0100;t\u2338\u2339\u621eie;\u69dddo\xf4\u2319\u0280;celp\u0757\u234c\u2350\u235b\u2361al;\u62ba\u0100gr\u2355\u2359er\xf3\u1563\xe3\u234darhk;\u6a17rod;\u6a3c\u0200cgpt\u236f\u2372\u2376\u237by;\u4451on;\u412ff;\uc000\ud835\udd5aa;\u43b9uest\u803b\xbf\u40bf\u0100ci\u238a\u238fr;\uc000\ud835\udcben\u0280;Edsv\u04f4\u239b\u239d\u23a1\u04f3;\u62f9ot;\u62f5\u0100;v\u23a6\u23a7\u62f4;\u62f3\u0100;i\u0777\u23aelde;\u4129\u01eb\u23b8\0\u23bccy;\u4456l\u803b\xef\u40ef\u0300cfmosu\u23cc\u23d7\u23dc\u23e1\u23e7\u23f5\u0100iy\u23d1\u23d5rc;\u4135;\u4439r;\uc000\ud835\udd27ath;\u4237pf;\uc000\ud835\udd5b\u01e3\u23ec\0\u23f1r;\uc000\ud835\udcbfrcy;\u4458kcy;\u4454\u0400acfghjos\u240b\u2416\u2422\u2427\u242d\u2431\u2435\u243bppa\u0100;v\u2413\u2414\u43ba;\u43f0\u0100ey\u241b\u2420dil;\u4137;\u443ar;\uc000\ud835\udd28reen;\u4138cy;\u4445cy;\u445cpf;\uc000\ud835\udd5ccr;\uc000\ud835\udcc0\u0b80ABEHabcdefghjlmnoprstuv\u2470\u2481\u2486\u248d\u2491\u250e\u253d\u255a\u2580\u264e\u265e\u2665\u2679\u267d\u269a\u26b2\u26d8\u275d\u2768\u278b\u27c0\u2801\u2812\u0180art\u2477\u247a\u247cr\xf2\u09c6\xf2\u0395ail;\u691barr;\u690e\u0100;g\u0994\u248b;\u6a8bar;\u6962\u0963\u24a5\0\u24aa\0\u24b1\0\0\0\0\0\u24b5\u24ba\0\u24c6\u24c8\u24cd\0\u24f9ute;\u413amptyv;\u69b4ra\xee\u084cbda;\u43bbg\u0180;dl\u088e\u24c1\u24c3;\u6991\xe5\u088e;\u6a85uo\u803b\xab\u40abr\u0400;bfhlpst\u0899\u24de\u24e6\u24e9\u24eb\u24ee\u24f1\u24f5\u0100;f\u089d\u24e3s;\u691fs;\u691d\xeb\u2252p;\u61abl;\u6939im;\u6973l;\u61a2\u0180;ae\u24ff\u2500\u2504\u6aabil;\u6919\u0100;s\u2509\u250a\u6aad;\uc000\u2aad\ufe00\u0180abr\u2515\u2519\u251drr;\u690crk;\u6772\u0100ak\u2522\u252cc\u0100ek\u2528\u252a;\u407b;\u405b\u0100es\u2531\u2533;\u698bl\u0100du\u2539\u253b;\u698f;\u698d\u0200aeuy\u2546\u254b\u2556\u2558ron;\u413e\u0100di\u2550\u2554il;\u413c\xec\u08b0\xe2\u2529;\u443b\u0200cqrs\u2563\u2566\u256d\u257da;\u6936uo\u0100;r\u0e19\u1746\u0100du\u2572\u2577har;\u6967shar;\u694bh;\u61b2\u0280;fgqs\u258b\u258c\u0989\u25f3\u25ff\u6264t\u0280ahlrt\u2598\u25a4\u25b7\u25c2\u25e8rrow\u0100;t\u0899\u25a1a\xe9\u24f6arpoon\u0100du\u25af\u25b4own\xbb\u045ap\xbb\u0966eftarrows;\u61c7ight\u0180ahs\u25cd\u25d6\u25derrow\u0100;s\u08f4\u08a7arpoon\xf3\u0f98quigarro\xf7\u21f0hreetimes;\u62cb\u0180;qs\u258b\u0993\u25falan\xf4\u09ac\u0280;cdgs\u09ac\u260a\u260d\u261d\u2628c;\u6aa8ot\u0100;o\u2614\u2615\u6a7f\u0100;r\u261a\u261b\u6a81;\u6a83\u0100;e\u2622\u2625\uc000\u22da\ufe00s;\u6a93\u0280adegs\u2633\u2639\u263d\u2649\u264bppro\xf8\u24c6ot;\u62d6q\u0100gq\u2643\u2645\xf4\u0989gt\xf2\u248c\xf4\u099bi\xed\u09b2\u0180ilr\u2655\u08e1\u265asht;\u697c;\uc000\ud835\udd29\u0100;E\u099c\u2663;\u6a91\u0161\u2669\u2676r\u0100du\u25b2\u266e\u0100;l\u0965\u2673;\u696alk;\u6584cy;\u4459\u0280;acht\u0a48\u2688\u268b\u2691\u2696r\xf2\u25c1orne\xf2\u1d08ard;\u696bri;\u65fa\u0100io\u269f\u26a4dot;\u4140ust\u0100;a\u26ac\u26ad\u63b0che\xbb\u26ad\u0200Eaes\u26bb\u26bd\u26c9\u26d4;\u6268p\u0100;p\u26c3\u26c4\u6a89rox\xbb\u26c4\u0100;q\u26ce\u26cf\u6a87\u0100;q\u26ce\u26bbim;\u62e6\u0400abnoptwz\u26e9\u26f4\u26f7\u271a\u272f\u2741\u2747\u2750\u0100nr\u26ee\u26f1g;\u67ecr;\u61fdr\xeb\u08c1g\u0180lmr\u26ff\u270d\u2714eft\u0100ar\u09e6\u2707ight\xe1\u09f2apsto;\u67fcight\xe1\u09fdparrow\u0100lr\u2725\u2729ef\xf4\u24edight;\u61ac\u0180afl\u2736\u2739\u273dr;\u6985;\uc000\ud835\udd5dus;\u6a2dimes;\u6a34\u0161\u274b\u274fst;\u6217\xe1\u134e\u0180;ef\u2757\u2758\u1800\u65cange\xbb\u2758ar\u0100;l\u2764\u2765\u4028t;\u6993\u0280achmt\u2773\u2776\u277c\u2785\u2787r\xf2\u08a8orne\xf2\u1d8car\u0100;d\u0f98\u2783;\u696d;\u600eri;\u62bf\u0300achiqt\u2798\u279d\u0a40\u27a2\u27ae\u27bbquo;\u6039r;\uc000\ud835\udcc1m\u0180;eg\u09b2\u27aa\u27ac;\u6a8d;\u6a8f\u0100bu\u252a\u27b3o\u0100;r\u0e1f\u27b9;\u601arok;\u4142\u8400<;cdhilqr\u082b\u27d2\u2639\u27dc\u27e0\u27e5\u27ea\u27f0\u0100ci\u27d7\u27d9;\u6aa6r;\u6a79re\xe5\u25f2mes;\u62c9arr;\u6976uest;\u6a7b\u0100Pi\u27f5\u27f9ar;\u6996\u0180;ef\u2800\u092d\u181b\u65c3r\u0100du\u2807\u280dshar;\u694ahar;\u6966\u0100en\u2817\u2821rtneqq;\uc000\u2268\ufe00\xc5\u281e\u0700Dacdefhilnopsu\u2840\u2845\u2882\u288e\u2893\u28a0\u28a5\u28a8\u28da\u28e2\u28e4\u0a83\u28f3\u2902Dot;\u623a\u0200clpr\u284e\u2852\u2863\u287dr\u803b\xaf\u40af\u0100et\u2857\u2859;\u6642\u0100;e\u285e\u285f\u6720se\xbb\u285f\u0100;s\u103b\u2868to\u0200;dlu\u103b\u2873\u2877\u287bow\xee\u048cef\xf4\u090f\xf0\u13d1ker;\u65ae\u0100oy\u2887\u288cmma;\u6a29;\u443cash;\u6014asuredangle\xbb\u1626r;\uc000\ud835\udd2ao;\u6127\u0180cdn\u28af\u28b4\u28c9ro\u803b\xb5\u40b5\u0200;acd\u1464\u28bd\u28c0\u28c4s\xf4\u16a7ir;\u6af0ot\u80bb\xb7\u01b5us\u0180;bd\u28d2\u1903\u28d3\u6212\u0100;u\u1d3c\u28d8;\u6a2a\u0163\u28de\u28e1p;\u6adb\xf2\u2212\xf0\u0a81\u0100dp\u28e9\u28eeels;\u62a7f;\uc000\ud835\udd5e\u0100ct\u28f8\u28fdr;\uc000\ud835\udcc2pos\xbb\u159d\u0180;lm\u2909\u290a\u290d\u43bctimap;\u62b8\u0c00GLRVabcdefghijlmoprstuvw\u2942\u2953\u297e\u2989\u2998\u29da\u29e9\u2a15\u2a1a\u2a58\u2a5d\u2a83\u2a95\u2aa4\u2aa8\u2b04\u2b07\u2b44\u2b7f\u2bae\u2c34\u2c67\u2c7c\u2ce9\u0100gt\u2947\u294b;\uc000\u22d9\u0338\u0100;v\u2950\u0bcf\uc000\u226b\u20d2\u0180elt\u295a\u2972\u2976ft\u0100ar\u2961\u2967rrow;\u61cdightarrow;\u61ce;\uc000\u22d8\u0338\u0100;v\u297b\u0c47\uc000\u226a\u20d2ightarrow;\u61cf\u0100Dd\u298e\u2993ash;\u62afash;\u62ae\u0280bcnpt\u29a3\u29a7\u29ac\u29b1\u29ccla\xbb\u02deute;\u4144g;\uc000\u2220\u20d2\u0280;Eiop\u0d84\u29bc\u29c0\u29c5\u29c8;\uc000\u2a70\u0338d;\uc000\u224b\u0338s;\u4149ro\xf8\u0d84ur\u0100;a\u29d3\u29d4\u666el\u0100;s\u29d3\u0b38\u01f3\u29df\0\u29e3p\u80bb\xa0\u0b37mp\u0100;e\u0bf9\u0c00\u0280aeouy\u29f4\u29fe\u2a03\u2a10\u2a13\u01f0\u29f9\0\u29fb;\u6a43on;\u4148dil;\u4146ng\u0100;d\u0d7e\u2a0aot;\uc000\u2a6d\u0338p;\u6a42;\u443dash;\u6013\u0380;Aadqsx\u0b92\u2a29\u2a2d\u2a3b\u2a41\u2a45\u2a50rr;\u61d7r\u0100hr\u2a33\u2a36k;\u6924\u0100;o\u13f2\u13f0ot;\uc000\u2250\u0338ui\xf6\u0b63\u0100ei\u2a4a\u2a4ear;\u6928\xed\u0b98ist\u0100;s\u0ba0\u0b9fr;\uc000\ud835\udd2b\u0200Eest\u0bc5\u2a66\u2a79\u2a7c\u0180;qs\u0bbc\u2a6d\u0be1\u0180;qs\u0bbc\u0bc5\u2a74lan\xf4\u0be2i\xed\u0bea\u0100;r\u0bb6\u2a81\xbb\u0bb7\u0180Aap\u2a8a\u2a8d\u2a91r\xf2\u2971rr;\u61aear;\u6af2\u0180;sv\u0f8d\u2a9c\u0f8c\u0100;d\u2aa1\u2aa2\u62fc;\u62facy;\u445a\u0380AEadest\u2ab7\u2aba\u2abe\u2ac2\u2ac5\u2af6\u2af9r\xf2\u2966;\uc000\u2266\u0338rr;\u619ar;\u6025\u0200;fqs\u0c3b\u2ace\u2ae3\u2aeft\u0100ar\u2ad4\u2ad9rro\xf7\u2ac1ightarro\xf7\u2a90\u0180;qs\u0c3b\u2aba\u2aealan\xf4\u0c55\u0100;s\u0c55\u2af4\xbb\u0c36i\xed\u0c5d\u0100;r\u0c35\u2afei\u0100;e\u0c1a\u0c25i\xe4\u0d90\u0100pt\u2b0c\u2b11f;\uc000\ud835\udd5f\u8180\xac;in\u2b19\u2b1a\u2b36\u40acn\u0200;Edv\u0b89\u2b24\u2b28\u2b2e;\uc000\u22f9\u0338ot;\uc000\u22f5\u0338\u01e1\u0b89\u2b33\u2b35;\u62f7;\u62f6i\u0100;v\u0cb8\u2b3c\u01e1\u0cb8\u2b41\u2b43;\u62fe;\u62fd\u0180aor\u2b4b\u2b63\u2b69r\u0200;ast\u0b7b\u2b55\u2b5a\u2b5flle\xec\u0b7bl;\uc000\u2afd\u20e5;\uc000\u2202\u0338lint;\u6a14\u0180;ce\u0c92\u2b70\u2b73u\xe5\u0ca5\u0100;c\u0c98\u2b78\u0100;e\u0c92\u2b7d\xf1\u0c98\u0200Aait\u2b88\u2b8b\u2b9d\u2ba7r\xf2\u2988rr\u0180;cw\u2b94\u2b95\u2b99\u619b;\uc000\u2933\u0338;\uc000\u219d\u0338ghtarrow\xbb\u2b95ri\u0100;e\u0ccb\u0cd6\u0380chimpqu\u2bbd\u2bcd\u2bd9\u2b04\u0b78\u2be4\u2bef\u0200;cer\u0d32\u2bc6\u0d37\u2bc9u\xe5\u0d45;\uc000\ud835\udcc3ort\u026d\u2b05\0\0\u2bd6ar\xe1\u2b56m\u0100;e\u0d6e\u2bdf\u0100;q\u0d74\u0d73su\u0100bp\u2beb\u2bed\xe5\u0cf8\xe5\u0d0b\u0180bcp\u2bf6\u2c11\u2c19\u0200;Ees\u2bff\u2c00\u0d22\u2c04\u6284;\uc000\u2ac5\u0338et\u0100;e\u0d1b\u2c0bq\u0100;q\u0d23\u2c00c\u0100;e\u0d32\u2c17\xf1\u0d38\u0200;Ees\u2c22\u2c23\u0d5f\u2c27\u6285;\uc000\u2ac6\u0338et\u0100;e\u0d58\u2c2eq\u0100;q\u0d60\u2c23\u0200gilr\u2c3d\u2c3f\u2c45\u2c47\xec\u0bd7lde\u803b\xf1\u40f1\xe7\u0c43iangle\u0100lr\u2c52\u2c5ceft\u0100;e\u0c1a\u2c5a\xf1\u0c26ight\u0100;e\u0ccb\u2c65\xf1\u0cd7\u0100;m\u2c6c\u2c6d\u43bd\u0180;es\u2c74\u2c75\u2c79\u4023ro;\u6116p;\u6007\u0480DHadgilrs\u2c8f\u2c94\u2c99\u2c9e\u2ca3\u2cb0\u2cb6\u2cd3\u2ce3ash;\u62adarr;\u6904p;\uc000\u224d\u20d2ash;\u62ac\u0100et\u2ca8\u2cac;\uc000\u2265\u20d2;\uc000>\u20d2nfin;\u69de\u0180Aet\u2cbd\u2cc1\u2cc5rr;\u6902;\uc000\u2264\u20d2\u0100;r\u2cca\u2ccd\uc000<\u20d2ie;\uc000\u22b4\u20d2\u0100At\u2cd8\u2cdcrr;\u6903rie;\uc000\u22b5\u20d2im;\uc000\u223c\u20d2\u0180Aan\u2cf0\u2cf4\u2d02rr;\u61d6r\u0100hr\u2cfa\u2cfdk;\u6923\u0100;o\u13e7\u13e5ear;\u6927\u1253\u1a95\0\0\0\0\0\0\0\0\0\0\0\0\0\u2d2d\0\u2d38\u2d48\u2d60\u2d65\u2d72\u2d84\u1b07\0\0\u2d8d\u2dab\0\u2dc8\u2dce\0\u2ddc\u2e19\u2e2b\u2e3e\u2e43\u0100cs\u2d31\u1a97ute\u803b\xf3\u40f3\u0100iy\u2d3c\u2d45r\u0100;c\u1a9e\u2d42\u803b\xf4\u40f4;\u443e\u0280abios\u1aa0\u2d52\u2d57\u01c8\u2d5alac;\u4151v;\u6a38old;\u69bclig;\u4153\u0100cr\u2d69\u2d6dir;\u69bf;\uc000\ud835\udd2c\u036f\u2d79\0\0\u2d7c\0\u2d82n;\u42dbave\u803b\xf2\u40f2;\u69c1\u0100bm\u2d88\u0df4ar;\u69b5\u0200acit\u2d95\u2d98\u2da5\u2da8r\xf2\u1a80\u0100ir\u2d9d\u2da0r;\u69beoss;\u69bbn\xe5\u0e52;\u69c0\u0180aei\u2db1\u2db5\u2db9cr;\u414dga;\u43c9\u0180cdn\u2dc0\u2dc5\u01cdron;\u43bf;\u69b6pf;\uc000\ud835\udd60\u0180ael\u2dd4\u2dd7\u01d2r;\u69b7rp;\u69b9\u0380;adiosv\u2dea\u2deb\u2dee\u2e08\u2e0d\u2e10\u2e16\u6228r\xf2\u1a86\u0200;efm\u2df7\u2df8\u2e02\u2e05\u6a5dr\u0100;o\u2dfe\u2dff\u6134f\xbb\u2dff\u803b\xaa\u40aa\u803b\xba\u40bagof;\u62b6r;\u6a56lope;\u6a57;\u6a5b\u0180clo\u2e1f\u2e21\u2e27\xf2\u2e01ash\u803b\xf8\u40f8l;\u6298i\u016c\u2e2f\u2e34de\u803b\xf5\u40f5es\u0100;a\u01db\u2e3as;\u6a36ml\u803b\xf6\u40f6bar;\u633d\u0ae1\u2e5e\0\u2e7d\0\u2e80\u2e9d\0\u2ea2\u2eb9\0\0\u2ecb\u0e9c\0\u2f13\0\0\u2f2b\u2fbc\0\u2fc8r\u0200;ast\u0403\u2e67\u2e72\u0e85\u8100\xb6;l\u2e6d\u2e6e\u40b6le\xec\u0403\u0269\u2e78\0\0\u2e7bm;\u6af3;\u6afdy;\u443fr\u0280cimpt\u2e8b\u2e8f\u2e93\u1865\u2e97nt;\u4025od;\u402eil;\u6030enk;\u6031r;\uc000\ud835\udd2d\u0180imo\u2ea8\u2eb0\u2eb4\u0100;v\u2ead\u2eae\u43c6;\u43d5ma\xf4\u0a76ne;\u660e\u0180;tv\u2ebf\u2ec0\u2ec8\u43c0chfork\xbb\u1ffd;\u43d6\u0100au\u2ecf\u2edfn\u0100ck\u2ed5\u2eddk\u0100;h\u21f4\u2edb;\u610e\xf6\u21f4s\u0480;abcdemst\u2ef3\u2ef4\u1908\u2ef9\u2efd\u2f04\u2f06\u2f0a\u2f0e\u402bcir;\u6a23ir;\u6a22\u0100ou\u1d40\u2f02;\u6a25;\u6a72n\u80bb\xb1\u0e9dim;\u6a26wo;\u6a27\u0180ipu\u2f19\u2f20\u2f25ntint;\u6a15f;\uc000\ud835\udd61nd\u803b\xa3\u40a3\u0500;Eaceinosu\u0ec8\u2f3f\u2f41\u2f44\u2f47\u2f81\u2f89\u2f92\u2f7e\u2fb6;\u6ab3p;\u6ab7u\xe5\u0ed9\u0100;c\u0ece\u2f4c\u0300;acens\u0ec8\u2f59\u2f5f\u2f66\u2f68\u2f7eppro\xf8\u2f43urlye\xf1\u0ed9\xf1\u0ece\u0180aes\u2f6f\u2f76\u2f7approx;\u6ab9qq;\u6ab5im;\u62e8i\xed\u0edfme\u0100;s\u2f88\u0eae\u6032\u0180Eas\u2f78\u2f90\u2f7a\xf0\u2f75\u0180dfp\u0eec\u2f99\u2faf\u0180als\u2fa0\u2fa5\u2faalar;\u632eine;\u6312urf;\u6313\u0100;t\u0efb\u2fb4\xef\u0efbrel;\u62b0\u0100ci\u2fc0\u2fc5r;\uc000\ud835\udcc5;\u43c8ncsp;\u6008\u0300fiopsu\u2fda\u22e2\u2fdf\u2fe5\u2feb\u2ff1r;\uc000\ud835\udd2epf;\uc000\ud835\udd62rime;\u6057cr;\uc000\ud835\udcc6\u0180aeo\u2ff8\u3009\u3013t\u0100ei\u2ffe\u3005rnion\xf3\u06b0nt;\u6a16st\u0100;e\u3010\u3011\u403f\xf1\u1f19\xf4\u0f14\u0a80ABHabcdefhilmnoprstux\u3040\u3051\u3055\u3059\u30e0\u310e\u312b\u3147\u3162\u3172\u318e\u3206\u3215\u3224\u3229\u3258\u326e\u3272\u3290\u32b0\u32b7\u0180art\u3047\u304a\u304cr\xf2\u10b3\xf2\u03ddail;\u691car\xf2\u1c65ar;\u6964\u0380cdenqrt\u3068\u3075\u3078\u307f\u308f\u3094\u30cc\u0100eu\u306d\u3071;\uc000\u223d\u0331te;\u4155i\xe3\u116emptyv;\u69b3g\u0200;del\u0fd1\u3089\u308b\u308d;\u6992;\u69a5\xe5\u0fd1uo\u803b\xbb\u40bbr\u0580;abcfhlpstw\u0fdc\u30ac\u30af\u30b7\u30b9\u30bc\u30be\u30c0\u30c3\u30c7\u30cap;\u6975\u0100;f\u0fe0\u30b4s;\u6920;\u6933s;\u691e\xeb\u225d\xf0\u272el;\u6945im;\u6974l;\u61a3;\u619d\u0100ai\u30d1\u30d5il;\u691ao\u0100;n\u30db\u30dc\u6236al\xf3\u0f1e\u0180abr\u30e7\u30ea\u30eer\xf2\u17e5rk;\u6773\u0100ak\u30f3\u30fdc\u0100ek\u30f9\u30fb;\u407d;\u405d\u0100es\u3102\u3104;\u698cl\u0100du\u310a\u310c;\u698e;\u6990\u0200aeuy\u3117\u311c\u3127\u3129ron;\u4159\u0100di\u3121\u3125il;\u4157\xec\u0ff2\xe2\u30fa;\u4440\u0200clqs\u3134\u3137\u313d\u3144a;\u6937dhar;\u6969uo\u0100;r\u020e\u020dh;\u61b3\u0180acg\u314e\u315f\u0f44l\u0200;ips\u0f78\u3158\u315b\u109cn\xe5\u10bbar\xf4\u0fa9t;\u65ad\u0180ilr\u3169\u1023\u316esht;\u697d;\uc000\ud835\udd2f\u0100ao\u3177\u3186r\u0100du\u317d\u317f\xbb\u047b\u0100;l\u1091\u3184;\u696c\u0100;v\u318b\u318c\u43c1;\u43f1\u0180gns\u3195\u31f9\u31fcht\u0300ahlrst\u31a4\u31b0\u31c2\u31d8\u31e4\u31eerrow\u0100;t\u0fdc\u31ada\xe9\u30c8arpoon\u0100du\u31bb\u31bfow\xee\u317ep\xbb\u1092eft\u0100ah\u31ca\u31d0rrow\xf3\u0feaarpoon\xf3\u0551ightarrows;\u61c9quigarro\xf7\u30cbhreetimes;\u62ccg;\u42daingdotse\xf1\u1f32\u0180ahm\u320d\u3210\u3213r\xf2\u0feaa\xf2\u0551;\u600foust\u0100;a\u321e\u321f\u63b1che\xbb\u321fmid;\u6aee\u0200abpt\u3232\u323d\u3240\u3252\u0100nr\u3237\u323ag;\u67edr;\u61fer\xeb\u1003\u0180afl\u3247\u324a\u324er;\u6986;\uc000\ud835\udd63us;\u6a2eimes;\u6a35\u0100ap\u325d\u3267r\u0100;g\u3263\u3264\u4029t;\u6994olint;\u6a12ar\xf2\u31e3\u0200achq\u327b\u3280\u10bc\u3285quo;\u603ar;\uc000\ud835\udcc7\u0100bu\u30fb\u328ao\u0100;r\u0214\u0213\u0180hir\u3297\u329b\u32a0re\xe5\u31f8mes;\u62cai\u0200;efl\u32aa\u1059\u1821\u32ab\u65b9tri;\u69celuhar;\u6968;\u611e\u0d61\u32d5\u32db\u32df\u332c\u3338\u3371\0\u337a\u33a4\0\0\u33ec\u33f0\0\u3428\u3448\u345a\u34ad\u34b1\u34ca\u34f1\0\u3616\0\0\u3633cute;\u415bqu\xef\u27ba\u0500;Eaceinpsy\u11ed\u32f3\u32f5\u32ff\u3302\u330b\u330f\u331f\u3326\u3329;\u6ab4\u01f0\u32fa\0\u32fc;\u6ab8on;\u4161u\xe5\u11fe\u0100;d\u11f3\u3307il;\u415frc;\u415d\u0180Eas\u3316\u3318\u331b;\u6ab6p;\u6abaim;\u62e9olint;\u6a13i\xed\u1204;\u4441ot\u0180;be\u3334\u1d47\u3335\u62c5;\u6a66\u0380Aacmstx\u3346\u334a\u3357\u335b\u335e\u3363\u336drr;\u61d8r\u0100hr\u3350\u3352\xeb\u2228\u0100;o\u0a36\u0a34t\u803b\xa7\u40a7i;\u403bwar;\u6929m\u0100in\u3369\xf0nu\xf3\xf1t;\u6736r\u0100;o\u3376\u2055\uc000\ud835\udd30\u0200acoy\u3382\u3386\u3391\u33a0rp;\u666f\u0100hy\u338b\u338fcy;\u4449;\u4448rt\u026d\u3399\0\0\u339ci\xe4\u1464ara\xec\u2e6f\u803b\xad\u40ad\u0100gm\u33a8\u33b4ma\u0180;fv\u33b1\u33b2\u33b2\u43c3;\u43c2\u0400;deglnpr\u12ab\u33c5\u33c9\u33ce\u33d6\u33de\u33e1\u33e6ot;\u6a6a\u0100;q\u12b1\u12b0\u0100;E\u33d3\u33d4\u6a9e;\u6aa0\u0100;E\u33db\u33dc\u6a9d;\u6a9fe;\u6246lus;\u6a24arr;\u6972ar\xf2\u113d\u0200aeit\u33f8\u3408\u340f\u3417\u0100ls\u33fd\u3404lsetm\xe9\u336ahp;\u6a33parsl;\u69e4\u0100dl\u1463\u3414e;\u6323\u0100;e\u341c\u341d\u6aaa\u0100;s\u3422\u3423\u6aac;\uc000\u2aac\ufe00\u0180flp\u342e\u3433\u3442tcy;\u444c\u0100;b\u3438\u3439\u402f\u0100;a\u343e\u343f\u69c4r;\u633ff;\uc000\ud835\udd64a\u0100dr\u344d\u0402es\u0100;u\u3454\u3455\u6660it\xbb\u3455\u0180csu\u3460\u3479\u349f\u0100au\u3465\u346fp\u0100;s\u1188\u346b;\uc000\u2293\ufe00p\u0100;s\u11b4\u3475;\uc000\u2294\ufe00u\u0100bp\u347f\u348f\u0180;es\u1197\u119c\u3486et\u0100;e\u1197\u348d\xf1\u119d\u0180;es\u11a8\u11ad\u3496et\u0100;e\u11a8\u349d\xf1\u11ae\u0180;af\u117b\u34a6\u05b0r\u0165\u34ab\u05b1\xbb\u117car\xf2\u1148\u0200cemt\u34b9\u34be\u34c2\u34c5r;\uc000\ud835\udcc8tm\xee\xf1i\xec\u3415ar\xe6\u11be\u0100ar\u34ce\u34d5r\u0100;f\u34d4\u17bf\u6606\u0100an\u34da\u34edight\u0100ep\u34e3\u34eapsilo\xee\u1ee0h\xe9\u2eafs\xbb\u2852\u0280bcmnp\u34fb\u355e\u1209\u358b\u358e\u0480;Edemnprs\u350e\u350f\u3511\u3515\u351e\u3523\u352c\u3531\u3536\u6282;\u6ac5ot;\u6abd\u0100;d\u11da\u351aot;\u6ac3ult;\u6ac1\u0100Ee\u3528\u352a;\u6acb;\u628alus;\u6abfarr;\u6979\u0180eiu\u353d\u3552\u3555t\u0180;en\u350e\u3545\u354bq\u0100;q\u11da\u350feq\u0100;q\u352b\u3528m;\u6ac7\u0100bp\u355a\u355c;\u6ad5;\u6ad3c\u0300;acens\u11ed\u356c\u3572\u3579\u357b\u3326ppro\xf8\u32faurlye\xf1\u11fe\xf1\u11f3\u0180aes\u3582\u3588\u331bppro\xf8\u331aq\xf1\u3317g;\u666a\u0680123;Edehlmnps\u35a9\u35ac\u35af\u121c\u35b2\u35b4\u35c0\u35c9\u35d5\u35da\u35df\u35e8\u35ed\u803b\xb9\u40b9\u803b\xb2\u40b2\u803b\xb3\u40b3;\u6ac6\u0100os\u35b9\u35bct;\u6abeub;\u6ad8\u0100;d\u1222\u35c5ot;\u6ac4s\u0100ou\u35cf\u35d2l;\u67c9b;\u6ad7arr;\u697bult;\u6ac2\u0100Ee\u35e4\u35e6;\u6acc;\u628blus;\u6ac0\u0180eiu\u35f4\u3609\u360ct\u0180;en\u121c\u35fc\u3602q\u0100;q\u1222\u35b2eq\u0100;q\u35e7\u35e4m;\u6ac8\u0100bp\u3611\u3613;\u6ad4;\u6ad6\u0180Aan\u361c\u3620\u362drr;\u61d9r\u0100hr\u3626\u3628\xeb\u222e\u0100;o\u0a2b\u0a29war;\u692alig\u803b\xdf\u40df\u0be1\u3651\u365d\u3660\u12ce\u3673\u3679\0\u367e\u36c2\0\0\0\0\0\u36db\u3703\0\u3709\u376c\0\0\0\u3787\u0272\u3656\0\0\u365bget;\u6316;\u43c4r\xeb\u0e5f\u0180aey\u3666\u366b\u3670ron;\u4165dil;\u4163;\u4442lrec;\u6315r;\uc000\ud835\udd31\u0200eiko\u3686\u369d\u36b5\u36bc\u01f2\u368b\0\u3691e\u01004f\u1284\u1281a\u0180;sv\u3698\u3699\u369b\u43b8ym;\u43d1\u0100cn\u36a2\u36b2k\u0100as\u36a8\u36aeppro\xf8\u12c1im\xbb\u12acs\xf0\u129e\u0100as\u36ba\u36ae\xf0\u12c1rn\u803b\xfe\u40fe\u01ec\u031f\u36c6\u22e7es\u8180\xd7;bd\u36cf\u36d0\u36d8\u40d7\u0100;a\u190f\u36d5r;\u6a31;\u6a30\u0180eps\u36e1\u36e3\u3700\xe1\u2a4d\u0200;bcf\u0486\u36ec\u36f0\u36f4ot;\u6336ir;\u6af1\u0100;o\u36f9\u36fc\uc000\ud835\udd65rk;\u6ada\xe1\u3362rime;\u6034\u0180aip\u370f\u3712\u3764d\xe5\u1248\u0380adempst\u3721\u374d\u3740\u3751\u3757\u375c\u375fngle\u0280;dlqr\u3730\u3731\u3736\u3740\u3742\u65b5own\xbb\u1dbbeft\u0100;e\u2800\u373e\xf1\u092e;\u625cight\u0100;e\u32aa\u374b\xf1\u105aot;\u65ecinus;\u6a3alus;\u6a39b;\u69cdime;\u6a3bezium;\u63e2\u0180cht\u3772\u377d\u3781\u0100ry\u3777\u377b;\uc000\ud835\udcc9;\u4446cy;\u445brok;\u4167\u0100io\u378b\u378ex\xf4\u1777head\u0100lr\u3797\u37a0eftarro\xf7\u084fightarrow\xbb\u0f5d\u0900AHabcdfghlmoprstuw\u37d0\u37d3\u37d7\u37e4\u37f0\u37fc\u380e\u381c\u3823\u3834\u3851\u385d\u386b\u38a9\u38cc\u38d2\u38ea\u38f6r\xf2\u03edar;\u6963\u0100cr\u37dc\u37e2ute\u803b\xfa\u40fa\xf2\u1150r\u01e3\u37ea\0\u37edy;\u445eve;\u416d\u0100iy\u37f5\u37farc\u803b\xfb\u40fb;\u4443\u0180abh\u3803\u3806\u380br\xf2\u13adlac;\u4171a\xf2\u13c3\u0100ir\u3813\u3818sht;\u697e;\uc000\ud835\udd32rave\u803b\xf9\u40f9\u0161\u3827\u3831r\u0100lr\u382c\u382e\xbb\u0957\xbb\u1083lk;\u6580\u0100ct\u3839\u384d\u026f\u383f\0\0\u384arn\u0100;e\u3845\u3846\u631cr\xbb\u3846op;\u630fri;\u65f8\u0100al\u3856\u385acr;\u416b\u80bb\xa8\u0349\u0100gp\u3862\u3866on;\u4173f;\uc000\ud835\udd66\u0300adhlsu\u114b\u3878\u387d\u1372\u3891\u38a0own\xe1\u13b3arpoon\u0100lr\u3888\u388cef\xf4\u382digh\xf4\u382fi\u0180;hl\u3899\u389a\u389c\u43c5\xbb\u13faon\xbb\u389aparrows;\u61c8\u0180cit\u38b0\u38c4\u38c8\u026f\u38b6\0\0\u38c1rn\u0100;e\u38bc\u38bd\u631dr\xbb\u38bdop;\u630eng;\u416fri;\u65f9cr;\uc000\ud835\udcca\u0180dir\u38d9\u38dd\u38e2ot;\u62f0lde;\u4169i\u0100;f\u3730\u38e8\xbb\u1813\u0100am\u38ef\u38f2r\xf2\u38a8l\u803b\xfc\u40fcangle;\u69a7\u0780ABDacdeflnoprsz\u391c\u391f\u3929\u392d\u39b5\u39b8\u39bd\u39df\u39e4\u39e8\u39f3\u39f9\u39fd\u3a01\u3a20r\xf2\u03f7ar\u0100;v\u3926\u3927\u6ae8;\u6ae9as\xe8\u03e1\u0100nr\u3932\u3937grt;\u699c\u0380eknprst\u34e3\u3946\u394b\u3952\u395d\u3964\u3996app\xe1\u2415othin\xe7\u1e96\u0180hir\u34eb\u2ec8\u3959op\xf4\u2fb5\u0100;h\u13b7\u3962\xef\u318d\u0100iu\u3969\u396dgm\xe1\u33b3\u0100bp\u3972\u3984setneq\u0100;q\u397d\u3980\uc000\u228a\ufe00;\uc000\u2acb\ufe00setneq\u0100;q\u398f\u3992\uc000\u228b\ufe00;\uc000\u2acc\ufe00\u0100hr\u399b\u399fet\xe1\u369ciangle\u0100lr\u39aa\u39afeft\xbb\u0925ight\xbb\u1051y;\u4432ash\xbb\u1036\u0180elr\u39c4\u39d2\u39d7\u0180;be\u2dea\u39cb\u39cfar;\u62bbq;\u625alip;\u62ee\u0100bt\u39dc\u1468a\xf2\u1469r;\uc000\ud835\udd33tr\xe9\u39aesu\u0100bp\u39ef\u39f1\xbb\u0d1c\xbb\u0d59pf;\uc000\ud835\udd67ro\xf0\u0efbtr\xe9\u39b4\u0100cu\u3a06\u3a0br;\uc000\ud835\udccb\u0100bp\u3a10\u3a18n\u0100Ee\u3980\u3a16\xbb\u397en\u0100Ee\u3992\u3a1e\xbb\u3990igzag;\u699a\u0380cefoprs\u3a36\u3a3b\u3a56\u3a5b\u3a54\u3a61\u3a6airc;\u4175\u0100di\u3a40\u3a51\u0100bg\u3a45\u3a49ar;\u6a5fe\u0100;q\u15fa\u3a4f;\u6259erp;\u6118r;\uc000\ud835\udd34pf;\uc000\ud835\udd68\u0100;e\u1479\u3a66at\xe8\u1479cr;\uc000\ud835\udccc\u0ae3\u178e\u3a87\0\u3a8b\0\u3a90\u3a9b\0\0\u3a9d\u3aa8\u3aab\u3aaf\0\0\u3ac3\u3ace\0\u3ad8\u17dc\u17dftr\xe9\u17d1r;\uc000\ud835\udd35\u0100Aa\u3a94\u3a97r\xf2\u03c3r\xf2\u09f6;\u43be\u0100Aa\u3aa1\u3aa4r\xf2\u03b8r\xf2\u09eba\xf0\u2713is;\u62fb\u0180dpt\u17a4\u3ab5\u3abe\u0100fl\u3aba\u17a9;\uc000\ud835\udd69im\xe5\u17b2\u0100Aa\u3ac7\u3acar\xf2\u03cer\xf2\u0a01\u0100cq\u3ad2\u17b8r;\uc000\ud835\udccd\u0100pt\u17d6\u3adcr\xe9\u17d4\u0400acefiosu\u3af0\u3afd\u3b08\u3b0c\u3b11\u3b15\u3b1b\u3b21c\u0100uy\u3af6\u3afbte\u803b\xfd\u40fd;\u444f\u0100iy\u3b02\u3b06rc;\u4177;\u444bn\u803b\xa5\u40a5r;\uc000\ud835\udd36cy;\u4457pf;\uc000\ud835\udd6acr;\uc000\ud835\udcce\u0100cm\u3b26\u3b29y;\u444el\u803b\xff\u40ff\u0500acdefhiosw\u3b42\u3b48\u3b54\u3b58\u3b64\u3b69\u3b6d\u3b74\u3b7a\u3b80cute;\u417a\u0100ay\u3b4d\u3b52ron;\u417e;\u4437ot;\u417c\u0100et\u3b5d\u3b61tr\xe6\u155fa;\u43b6r;\uc000\ud835\udd37cy;\u4436grarr;\u61ddpf;\uc000\ud835\udd6bcr;\uc000\ud835\udccf\u0100jn\u3b85\u3b87;\u600dj;\u600c"
    .split("")
    .map(function (c) { return c.charCodeAt(0); }));// Generated using scripts/write-decode-map.ts
var xmlDecodeTree = new Uint16Array(
// prettier-ignore
"\u0200aglq\t\x15\x18\x1b\u026d\x0f\0\0\x12p;\u4026os;\u4027t;\u403et;\u403cuot;\u4022"
    .split("")
    .map(function (c) { return c.charCodeAt(0); }));// Adapted from https://github.com/mathiasbynens/he/blob/36afe179392226cf1b6ccdb16ebbb7a5a844d93a/src/he.js#L106-L134
var _a$1;
var decodeMap = new Map([
    [0, 65533],
    // C1 Unicode control character reference replacements
    [128, 8364],
    [130, 8218],
    [131, 402],
    [132, 8222],
    [133, 8230],
    [134, 8224],
    [135, 8225],
    [136, 710],
    [137, 8240],
    [138, 352],
    [139, 8249],
    [140, 338],
    [142, 381],
    [145, 8216],
    [146, 8217],
    [147, 8220],
    [148, 8221],
    [149, 8226],
    [150, 8211],
    [151, 8212],
    [152, 732],
    [153, 8482],
    [154, 353],
    [155, 8250],
    [156, 339],
    [158, 382],
    [159, 376] ]);
/**
 * Polyfill for `String.fromCodePoint`. It is used to create a string from a Unicode code point.
 */
var fromCodePoint$3 = 
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition, node/no-unsupported-features/es-builtins
(_a$1 = String.fromCodePoint) !== null && _a$1 !== void 0 ? _a$1 : function (codePoint) {
    var output = "";
    if (codePoint > 0xffff) {
        codePoint -= 0x10000;
        output += String.fromCharCode(((codePoint >>> 10) & 0x3ff) | 0xd800);
        codePoint = 0xdc00 | (codePoint & 0x3ff);
    }
    output += String.fromCharCode(codePoint);
    return output;
};
/**
 * Replace the given code point with a replacement character if it is a
 * surrogate or is outside the valid range. Otherwise return the code
 * point unchanged.
 */
function replaceCodePoint(codePoint) {
    var _a;
    if ((codePoint >= 0xd800 && codePoint <= 0xdfff) || codePoint > 0x10ffff) {
        return 0xfffd;
    }
    return (_a = decodeMap.get(codePoint)) !== null && _a !== void 0 ? _a : codePoint;
}var CharCodes;
(function (CharCodes) {
    CharCodes[CharCodes["NUM"] = 35] = "NUM";
    CharCodes[CharCodes["SEMI"] = 59] = "SEMI";
    CharCodes[CharCodes["EQUALS"] = 61] = "EQUALS";
    CharCodes[CharCodes["ZERO"] = 48] = "ZERO";
    CharCodes[CharCodes["NINE"] = 57] = "NINE";
    CharCodes[CharCodes["LOWER_A"] = 97] = "LOWER_A";
    CharCodes[CharCodes["LOWER_F"] = 102] = "LOWER_F";
    CharCodes[CharCodes["LOWER_X"] = 120] = "LOWER_X";
    CharCodes[CharCodes["LOWER_Z"] = 122] = "LOWER_Z";
    CharCodes[CharCodes["UPPER_A"] = 65] = "UPPER_A";
    CharCodes[CharCodes["UPPER_F"] = 70] = "UPPER_F";
    CharCodes[CharCodes["UPPER_Z"] = 90] = "UPPER_Z";
})(CharCodes || (CharCodes = {}));
/** Bit that needs to be set to convert an upper case ASCII character to lower case */
var TO_LOWER_BIT = 32;
var BinTrieFlags;
(function (BinTrieFlags) {
    BinTrieFlags[BinTrieFlags["VALUE_LENGTH"] = 49152] = "VALUE_LENGTH";
    BinTrieFlags[BinTrieFlags["BRANCH_LENGTH"] = 16256] = "BRANCH_LENGTH";
    BinTrieFlags[BinTrieFlags["JUMP_TABLE"] = 127] = "JUMP_TABLE";
})(BinTrieFlags || (BinTrieFlags = {}));
function isNumber(code) {
    return code >= CharCodes.ZERO && code <= CharCodes.NINE;
}
function isHexadecimalCharacter(code) {
    return ((code >= CharCodes.UPPER_A && code <= CharCodes.UPPER_F) ||
        (code >= CharCodes.LOWER_A && code <= CharCodes.LOWER_F));
}
function isAsciiAlphaNumeric(code) {
    return ((code >= CharCodes.UPPER_A && code <= CharCodes.UPPER_Z) ||
        (code >= CharCodes.LOWER_A && code <= CharCodes.LOWER_Z) ||
        isNumber(code));
}
/**
 * Checks if the given character is a valid end character for an entity in an attribute.
 *
 * Attribute values that aren't terminated properly aren't parsed, and shouldn't lead to a parser error.
 * See the example in https://html.spec.whatwg.org/multipage/parsing.html#named-character-reference-state
 */
function isEntityInAttributeInvalidEnd(code) {
    return code === CharCodes.EQUALS || isAsciiAlphaNumeric(code);
}
var EntityDecoderState;
(function (EntityDecoderState) {
    EntityDecoderState[EntityDecoderState["EntityStart"] = 0] = "EntityStart";
    EntityDecoderState[EntityDecoderState["NumericStart"] = 1] = "NumericStart";
    EntityDecoderState[EntityDecoderState["NumericDecimal"] = 2] = "NumericDecimal";
    EntityDecoderState[EntityDecoderState["NumericHex"] = 3] = "NumericHex";
    EntityDecoderState[EntityDecoderState["NamedEntity"] = 4] = "NamedEntity";
})(EntityDecoderState || (EntityDecoderState = {}));
var DecodingMode;
(function (DecodingMode) {
    /** Entities in text nodes that can end with any character. */
    DecodingMode[DecodingMode["Legacy"] = 0] = "Legacy";
    /** Only allow entities terminated with a semicolon. */
    DecodingMode[DecodingMode["Strict"] = 1] = "Strict";
    /** Entities in attributes have limitations on ending characters. */
    DecodingMode[DecodingMode["Attribute"] = 2] = "Attribute";
})(DecodingMode || (DecodingMode = {}));
/**
 * Token decoder with support of writing partial entities.
 */
var EntityDecoder = function EntityDecoder(
/** The tree used to decode entities. */
decodeTree, 
/**
 * The function that is called when a codepoint is decoded.
 *
 * For multi-byte named entities, this will be called multiple times,
 * with the second codepoint, and the same `consumed` value.
 *
 * @param codepoint The decoded codepoint.
 * @param consumed The number of bytes consumed by the decoder.
 */
emitCodePoint, 
/** An object that is used to produce errors. */
errors) {
    this.decodeTree = decodeTree;
    this.emitCodePoint = emitCodePoint;
    this.errors = errors;
    /** The current state of the decoder. */
    this.state = EntityDecoderState.EntityStart;
    /** Characters that were consumed while parsing an entity. */
    this.consumed = 1;
    /**
     * The result of the entity.
     *
     * Either the result index of a numeric entity, or the codepoint of a
     * numeric entity.
     */
    this.result = 0;
    /** The current index in the decode tree. */
    this.treeIndex = 0;
    /** The number of characters that were consumed in excess. */
    this.excess = 1;
    /** The mode in which the decoder is operating. */
    this.decodeMode = DecodingMode.Strict;
};
/** Resets the instance to make it reusable. */
EntityDecoder.prototype.startEntity = function startEntity (decodeMode) {
    this.decodeMode = decodeMode;
    this.state = EntityDecoderState.EntityStart;
    this.result = 0;
    this.treeIndex = 0;
    this.excess = 1;
    this.consumed = 1;
};
/**
 * Write an entity to the decoder. This can be called multiple times with partial entities.
 * If the entity is incomplete, the decoder will return -1.
 *
 * Mirrors the implementation of `getDecoder`, but with the ability to stop decoding if the
 * entity is incomplete, and resume when the next string is written.
 *
 * @param string The string containing the entity (or a continuation of the entity).
 * @param offset The offset at which the entity begins. Should be 0 if this is not the first call.
 * @returns The number of characters that were consumed, or -1 if the entity is incomplete.
 */
EntityDecoder.prototype.write = function write (str, offset) {
    switch (this.state) {
        case EntityDecoderState.EntityStart: {
            if (str.charCodeAt(offset) === CharCodes.NUM) {
                this.state = EntityDecoderState.NumericStart;
                this.consumed += 1;
                return this.stateNumericStart(str, offset + 1);
            }
            this.state = EntityDecoderState.NamedEntity;
            return this.stateNamedEntity(str, offset);
        }
        case EntityDecoderState.NumericStart: {
            return this.stateNumericStart(str, offset);
        }
        case EntityDecoderState.NumericDecimal: {
            return this.stateNumericDecimal(str, offset);
        }
        case EntityDecoderState.NumericHex: {
            return this.stateNumericHex(str, offset);
        }
        case EntityDecoderState.NamedEntity: {
            return this.stateNamedEntity(str, offset);
        }
    }
};
/**
 * Switches between the numeric decimal and hexadecimal states.
 *
 * Equivalent to the `Numeric character reference state` in the HTML spec.
 *
 * @param str The string containing the entity (or a continuation of the entity).
 * @param offset The current offset.
 * @returns The number of characters that were consumed, or -1 if the entity is incomplete.
 */
EntityDecoder.prototype.stateNumericStart = function stateNumericStart (str, offset) {
    if (offset >= str.length) {
        return -1;
    }
    if ((str.charCodeAt(offset) | TO_LOWER_BIT) === CharCodes.LOWER_X) {
        this.state = EntityDecoderState.NumericHex;
        this.consumed += 1;
        return this.stateNumericHex(str, offset + 1);
    }
    this.state = EntityDecoderState.NumericDecimal;
    return this.stateNumericDecimal(str, offset);
};
EntityDecoder.prototype.addToNumericResult = function addToNumericResult (str, start, end, base) {
    if (start !== end) {
        var digitCount = end - start;
        this.result =
            this.result * Math.pow(base, digitCount) +
                parseInt(str.substr(start, digitCount), base);
        this.consumed += digitCount;
    }
};
/**
 * Parses a hexadecimal numeric entity.
 *
 * Equivalent to the `Hexademical character reference state` in the HTML spec.
 *
 * @param str The string containing the entity (or a continuation of the entity).
 * @param offset The current offset.
 * @returns The number of characters that were consumed, or -1 if the entity is incomplete.
 */
EntityDecoder.prototype.stateNumericHex = function stateNumericHex (str, offset) {
    var startIdx = offset;
    while (offset < str.length) {
        var char = str.charCodeAt(offset);
        if (isNumber(char) || isHexadecimalCharacter(char)) {
            offset += 1;
        }
        else {
            this.addToNumericResult(str, startIdx, offset, 16);
            return this.emitNumericEntity(char, 3);
        }
    }
    this.addToNumericResult(str, startIdx, offset, 16);
    return -1;
};
/**
 * Parses a decimal numeric entity.
 *
 * Equivalent to the `Decimal character reference state` in the HTML spec.
 *
 * @param str The string containing the entity (or a continuation of the entity).
 * @param offset The current offset.
 * @returns The number of characters that were consumed, or -1 if the entity is incomplete.
 */
EntityDecoder.prototype.stateNumericDecimal = function stateNumericDecimal (str, offset) {
    var startIdx = offset;
    while (offset < str.length) {
        var char = str.charCodeAt(offset);
        if (isNumber(char)) {
            offset += 1;
        }
        else {
            this.addToNumericResult(str, startIdx, offset, 10);
            return this.emitNumericEntity(char, 2);
        }
    }
    this.addToNumericResult(str, startIdx, offset, 10);
    return -1;
};
/**
 * Validate and emit a numeric entity.
 *
 * Implements the logic from the `Hexademical character reference start
 * state` and `Numeric character reference end state` in the HTML spec.
 *
 * @param lastCp The last code point of the entity. Used to see if the
 *           entity was terminated with a semicolon.
 * @param expectedLength The minimum number of characters that should be
 *                   consumed. Used to validate that at least one digit
 *                   was consumed.
 * @returns The number of characters that were consumed.
 */
EntityDecoder.prototype.emitNumericEntity = function emitNumericEntity (lastCp, expectedLength) {
    var _a;
    // Ensure we consumed at least one digit.
    if (this.consumed <= expectedLength) {
        (_a = this.errors) === null || _a === void 0 ? void 0 : _a.absenceOfDigitsInNumericCharacterReference(this.consumed);
        return 0;
    }
    // Figure out if this is a legit end of the entity
    if (lastCp === CharCodes.SEMI) {
        this.consumed += 1;
    }
    else if (this.decodeMode === DecodingMode.Strict) {
        return 0;
    }
    this.emitCodePoint(replaceCodePoint(this.result), this.consumed);
    if (this.errors) {
        if (lastCp !== CharCodes.SEMI) {
            this.errors.missingSemicolonAfterCharacterReference();
        }
        this.errors.validateNumericCharacterReference(this.result);
    }
    return this.consumed;
};
/**
 * Parses a named entity.
 *
 * Equivalent to the `Named character reference state` in the HTML spec.
 *
 * @param str The string containing the entity (or a continuation of the entity).
 * @param offset The current offset.
 * @returns The number of characters that were consumed, or -1 if the entity is incomplete.
 */
EntityDecoder.prototype.stateNamedEntity = function stateNamedEntity (str, offset) {
    var ref = this;
        var decodeTree = ref.decodeTree;
    var current = decodeTree[this.treeIndex];
    // The mask is the number of bytes of the value, including the current byte.
    var valueLength = (current & BinTrieFlags.VALUE_LENGTH) >> 14;
    for (; offset < str.length; offset++, this.excess++) {
        var char = str.charCodeAt(offset);
        this.treeIndex = determineBranch(decodeTree, current, this.treeIndex + Math.max(1, valueLength), char);
        if (this.treeIndex < 0) {
            return this.result === 0 ||
                // If we are parsing an attribute
                (this.decodeMode === DecodingMode.Attribute &&
                    // We shouldn't have consumed any characters after the entity,
                    (valueLength === 0 ||
                        // And there should be no invalid characters.
                        isEntityInAttributeInvalidEnd(char)))
                ? 0
                : this.emitNotTerminatedNamedEntity();
        }
        current = decodeTree[this.treeIndex];
        valueLength = (current & BinTrieFlags.VALUE_LENGTH) >> 14;
        // If the branch is a value, store it and continue
        if (valueLength !== 0) {
            // If the entity is terminated by a semicolon, we are done.
            if (char === CharCodes.SEMI) {
                return this.emitNamedEntityData(this.treeIndex, valueLength, this.consumed + this.excess);
            }
            // If we encounter a non-terminated (legacy) entity while parsing strictly, then ignore it.
            if (this.decodeMode !== DecodingMode.Strict) {
                this.result = this.treeIndex;
                this.consumed += this.excess;
                this.excess = 0;
            }
        }
    }
    return -1;
};
/**
 * Emit a named entity that was not terminated with a semicolon.
 *
 * @returns The number of characters consumed.
 */
EntityDecoder.prototype.emitNotTerminatedNamedEntity = function emitNotTerminatedNamedEntity () {
    var _a;
    var ref = this;
        var result = ref.result;
        var decodeTree = ref.decodeTree;
    var valueLength = (decodeTree[result] & BinTrieFlags.VALUE_LENGTH) >> 14;
    this.emitNamedEntityData(result, valueLength, this.consumed);
    (_a = this.errors) === null || _a === void 0 ? void 0 : _a.missingSemicolonAfterCharacterReference();
    return this.consumed;
};
/**
 * Emit a named entity.
 *
 * @param result The index of the entity in the decode tree.
 * @param valueLength The number of bytes in the entity.
 * @param consumed The number of characters consumed.
 *
 * @returns The number of characters consumed.
 */
EntityDecoder.prototype.emitNamedEntityData = function emitNamedEntityData (result, valueLength, consumed) {
    var ref = this;
        var decodeTree = ref.decodeTree;
    this.emitCodePoint(valueLength === 1
        ? decodeTree[result] & ~BinTrieFlags.VALUE_LENGTH
        : decodeTree[result + 1], consumed);
    if (valueLength === 3) {
        // For multi-byte values, we need to emit the second byte.
        this.emitCodePoint(decodeTree[result + 2], consumed);
    }
    return consumed;
};
/**
 * Signal to the parser that the end of the input was reached.
 *
 * Remaining data will be emitted and relevant errors will be produced.
 *
 * @returns The number of characters consumed.
 */
EntityDecoder.prototype.end = function end () {
    var _a;
    switch (this.state) {
        case EntityDecoderState.NamedEntity: {
            // Emit a named entity if we have one.
            return this.result !== 0 &&
                (this.decodeMode !== DecodingMode.Attribute ||
                    this.result === this.treeIndex)
                ? this.emitNotTerminatedNamedEntity()
                : 0;
        }
        // Otherwise, emit a numeric entity if we have one.
        case EntityDecoderState.NumericDecimal: {
            return this.emitNumericEntity(0, 2);
        }
        case EntityDecoderState.NumericHex: {
            return this.emitNumericEntity(0, 3);
        }
        case EntityDecoderState.NumericStart: {
            (_a = this.errors) === null || _a === void 0 ? void 0 : _a.absenceOfDigitsInNumericCharacterReference(this.consumed);
            return 0;
        }
        case EntityDecoderState.EntityStart: {
            // Return 0 if we have no entity.
            return 0;
        }
    }
};
/**
 * Creates a function that decodes entities in a string.
 *
 * @param decodeTree The decode tree.
 * @returns A function that decodes entities in a string.
 */
function getDecoder(decodeTree) {
    var ret = "";
    var decoder = new EntityDecoder(decodeTree, function (str) { return (ret += fromCodePoint$3(str)); });
    return function decodeWithTrie(str, decodeMode) {
        var lastIndex = 0;
        var offset = 0;
        while ((offset = str.indexOf("&", offset)) >= 0) {
            ret += str.slice(lastIndex, offset);
            decoder.startEntity(decodeMode);
            var len = decoder.write(str, 
            // Skip the "&"
            offset + 1);
            if (len < 0) {
                lastIndex = offset + decoder.end();
                break;
            }
            lastIndex = offset + len;
            // If `len` is 0, skip the current `&` and continue.
            offset = len === 0 ? lastIndex + 1 : lastIndex;
        }
        var result = ret + str.slice(lastIndex);
        // Make sure we don't keep a reference to the final string.
        ret = "";
        return result;
    };
}
/**
 * Determines the branch of the current node that is taken given the current
 * character. This function is used to traverse the trie.
 *
 * @param decodeTree The trie.
 * @param current The current node.
 * @param nodeIdx The index right after the current node and its value.
 * @param char The current character.
 * @returns The index of the next node, or -1 if no branch is taken.
 */
function determineBranch(decodeTree, current, nodeIdx, char) {
    var branchCount = (current & BinTrieFlags.BRANCH_LENGTH) >> 7;
    var jumpOffset = current & BinTrieFlags.JUMP_TABLE;
    // Case 1: Single branch encoded in jump offset
    if (branchCount === 0) {
        return jumpOffset !== 0 && char === jumpOffset ? nodeIdx : -1;
    }
    // Case 2: Multiple branches encoded in jump table
    if (jumpOffset) {
        var value = char - jumpOffset;
        return value < 0 || value >= branchCount
            ? -1
            : decodeTree[nodeIdx + value] - 1;
    }
    // Case 3: Multiple branches encoded in dictionary
    // Binary search for the character.
    var lo = nodeIdx;
    var hi = lo + branchCount - 1;
    while (lo <= hi) {
        var mid = (lo + hi) >>> 1;
        var midVal = decodeTree[mid];
        if (midVal < char) {
            lo = mid + 1;
        }
        else if (midVal > char) {
            hi = mid - 1;
        }
        else {
            return decodeTree[mid + branchCount];
        }
    }
    return -1;
}
var htmlDecoder = getDecoder(htmlDecodeTree);
getDecoder(xmlDecodeTree);
/**
 * Decodes an HTML string.
 *
 * @param str The string to decode.
 * @param mode The decoding mode.
 * @returns The decoded string.
 */
function decodeHTML(str, mode) {
    if ( mode === void 0 ) mode = DecodingMode.Legacy;

    return htmlDecoder(str, mode);
}// Utilities
//


function _class$2 (obj) { return Object.prototype.toString.call(obj) }

function isString$2 (obj) { return _class$2(obj) === '[object String]' }

var _hasOwnProperty = Object.prototype.hasOwnProperty;

function has$1 (object, key) {
  return _hasOwnProperty.call(object, key)
}

// Merge objects
//
function assign$3 (obj /* from1, from2, from3, ... */) {
  var sources = Array.prototype.slice.call(arguments, 1);

  sources.forEach(function (source) {
    if (!source) { return }

    if (typeof source !== 'object') {
      throw new TypeError(source + 'must be object')
    }

    Object.keys(source).forEach(function (key) {
      obj[key] = source[key];
    });
  });

  return obj
}

// Remove element from array and put another array at those position.
// Useful for some operations with tokens
function arrayReplaceAt$1 (src, pos, newElements) {
  return [].concat(src.slice(0, pos), newElements, src.slice(pos + 1))
}

function isValidEntityCode$1 (c) {
  /* eslint no-bitwise:0 */
  // broken sequence
  if (c >= 0xD800 && c <= 0xDFFF) { return false }
  // never used
  if (c >= 0xFDD0 && c <= 0xFDEF) { return false }
  if ((c & 0xFFFF) === 0xFFFF || (c & 0xFFFF) === 0xFFFE) { return false }
  // control codes
  if (c >= 0x00 && c <= 0x08) { return false }
  if (c === 0x0B) { return false }
  if (c >= 0x0E && c <= 0x1F) { return false }
  if (c >= 0x7F && c <= 0x9F) { return false }
  // out of range
  if (c > 0x10FFFF) { return false }
  return true
}

function fromCodePoint$2 (c) {
  /* eslint no-bitwise:0 */
  if (c > 0xffff) {
    c -= 0x10000;
    var surrogate1 = 0xd800 + (c >> 10);
    var surrogate2 = 0xdc00 + (c & 0x3ff);

    return String.fromCharCode(surrogate1, surrogate2)
  }
  return String.fromCharCode(c)
}

var UNESCAPE_MD_RE  = /\\([!"#$%&'()*+,\-./:;<=>?@[\\\]^_`{|}~])/g;
var ENTITY_RE       = /&([a-z#][a-z0-9]{1,31});/gi;
var UNESCAPE_ALL_RE = new RegExp(UNESCAPE_MD_RE.source + '|' + ENTITY_RE.source, 'gi');

var DIGITAL_ENTITY_TEST_RE = /^#((?:x[a-f0-9]{1,8}|[0-9]{1,8}))$/i;

function replaceEntityPattern (match, name) {
  if (name.charCodeAt(0) === 0x23/* # */ && DIGITAL_ENTITY_TEST_RE.test(name)) {
    var code = name[1].toLowerCase() === 'x'
      ? parseInt(name.slice(2), 16)
      : parseInt(name.slice(1), 10);

    if (isValidEntityCode$1(code)) {
      return fromCodePoint$2(code)
    }

    return match
  }

  var decoded = decodeHTML(match);
  if (decoded !== match) {
    return decoded
  }

  return match
}

/* function replaceEntities(str) {
  if (str.indexOf('&') < 0) { return str; }

  return str.replace(ENTITY_RE, replaceEntityPattern);
} */

function unescapeMd (str) {
  if (str.indexOf('\\') < 0) { return str }
  return str.replace(UNESCAPE_MD_RE, '$1')
}

function unescapeAll$3 (str) {
  if (str.indexOf('\\') < 0 && str.indexOf('&') < 0) { return str }

  return str.replace(UNESCAPE_ALL_RE, function (match, escaped, entity) {
    if (escaped) { return escaped }
    return replaceEntityPattern(match, entity)
  })
}

var HTML_ESCAPE_TEST_RE = /[&<>"]/;
var HTML_ESCAPE_REPLACE_RE = /[&<>"]/g;
var HTML_REPLACEMENTS = {
  '&': '&amp;',
  '<': '&lt;',
  '>': '&gt;',
  '"': '&quot;'
};

function replaceUnsafeChar (ch) {
  return HTML_REPLACEMENTS[ch]
}

function escapeHtml$1 (str) {
  if (HTML_ESCAPE_TEST_RE.test(str)) {
    return str.replace(HTML_ESCAPE_REPLACE_RE, replaceUnsafeChar)
  }
  return str
}

var REGEXP_ESCAPE_RE = /[.?*+^$[\]\\(){}|-]/g;

function escapeRE$2 (str) {
  return str.replace(REGEXP_ESCAPE_RE, '\\$&')
}

function isSpace$e (code) {
  switch (code) {
    case 0x09:
    case 0x20:
      return true
  }
  return false
}

// Zs (unicode class) || [\t\f\v\r\n]
function isWhiteSpace$2 (code) {
  if (code >= 0x2000 && code <= 0x200A) { return true }
  switch (code) {
    case 0x09: // \t
    case 0x0A: // \n
    case 0x0B: // \v
    case 0x0C: // \f
    case 0x0D: // \r
    case 0x20:
    case 0xA0:
    case 0x1680:
    case 0x202F:
    case 0x205F:
    case 0x3000:
      return true
  }
  return false
}

/* eslint-disable max-len */

// Currently without astral characters support.
function isPunctChar$2 (ch) {
  return P.test(ch) || regex$5.test(ch)
}

// Markdown ASCII punctuation characters.
//
// !, ", #, $, %, &, ', (, ), *, +, ,, -, ., /, :, ;, <, =, >, ?, @, [, \, ], ^, _, `, {, |, }, or ~
// http://spec.commonmark.org/0.15/#ascii-punctuation-character
//
// Don't confuse with unicode punctuation !!! It lacks some chars in ascii range.
//
function isMdAsciiPunct$2 (ch) {
  switch (ch) {
    case 0x21/* ! */:
    case 0x22/* " */:
    case 0x23/* # */:
    case 0x24/* $ */:
    case 0x25/* % */:
    case 0x26/* & */:
    case 0x27/* ' */:
    case 0x28/* ( */:
    case 0x29/* ) */:
    case 0x2A/* * */:
    case 0x2B/* + */:
    case 0x2C/* , */:
    case 0x2D/* - */:
    case 0x2E/* . */:
    case 0x2F/* / */:
    case 0x3A/* : */:
    case 0x3B/* ; */:
    case 0x3C/* < */:
    case 0x3D/* = */:
    case 0x3E/* > */:
    case 0x3F/* ? */:
    case 0x40/* @ */:
    case 0x5B/* [ */:
    case 0x5C/* \ */:
    case 0x5D/* ] */:
    case 0x5E/* ^ */:
    case 0x5F/* _ */:
    case 0x60/* ` */:
    case 0x7B/* { */:
    case 0x7C/* | */:
    case 0x7D/* } */:
    case 0x7E/* ~ */:
      return true
    default:
      return false
  }
}

// Hepler to unify [reference labels].
//
function normalizeReference$3 (str) {
  // Trim and collapse whitespace
  //
  str = str.trim().replace(/\s+/g, ' ');

  // In node v10 'ẞ'.toLowerCase() === 'Ṿ', which is presumed to be a bug
  // fixed in v12 (couldn't find any details).
  //
  // So treat this one as a special case
  // (remove this when node v10 is no longer supported).
  //
  if ('ẞ'.toLowerCase() === 'Ṿ') {
    str = str.replace(/ẞ/g, 'ß');
  }

  // .toLowerCase().toUpperCase() should get rid of all differences
  // between letter variants.
  //
  // Simple .toLowerCase() doesn't normalize 125 code points correctly,
  // and .toUpperCase doesn't normalize 6 of them (list of exceptions:
  // İ, ϴ, ẞ, Ω, K, Å - those are already uppercased, but have differently
  // uppercased versions).
  //
  // Here's an example showing how it happens. Lets take greek letter omega:
  // uppercase U+0398 (Θ), U+03f4 (ϴ) and lowercase U+03b8 (θ), U+03d1 (ϑ)
  //
  // Unicode entries:
  // 0398;GREEK CAPITAL LETTER THETA;Lu;0;L;;;;;N;;;;03B8;
  // 03B8;GREEK SMALL LETTER THETA;Ll;0;L;;;;;N;;;0398;;0398
  // 03D1;GREEK THETA SYMBOL;Ll;0;L;<compat> 03B8;;;;N;GREEK SMALL LETTER SCRIPT THETA;;0398;;0398
  // 03F4;GREEK CAPITAL THETA SYMBOL;Lu;0;L;<compat> 0398;;;;N;;;;03B8;
  //
  // Case-insensitive comparison should treat all of them as equivalent.
  //
  // But .toLowerCase() doesn't change ϑ (it's already lowercase),
  // and .toUpperCase() doesn't change ϴ (already uppercase).
  //
  // Applying first lower then upper case normalizes any character:
  // '\u0398\u03f4\u03b8\u03d1'.toLowerCase().toUpperCase() === '\u0398\u0398\u0398\u0398'
  //
  // Note: this is equivalent to unicode case folding; unicode normalization
  // is a different step that is not required here.
  //
  // Final result should be uppercased, because it's later stored in an object
  // (this avoid a conflict with Object.prototype members,
  // most notably, `__proto__`)
  //
  return str.toLowerCase().toUpperCase()
}

// Re-export libraries commonly used in both markdown-it and its plugins,
// so plugins won't have to depend on them explicitly, which reduces their
// bundled size (e.g. a browser build).
//
var lib$4 = { mdurl: mdurl$2, ucmicro: ucmicro };var utils$2=/*#__PURE__*/Object.freeze({__proto__:null,arrayReplaceAt:arrayReplaceAt$1,assign:assign$3,escapeHtml:escapeHtml$1,escapeRE:escapeRE$2,fromCodePoint:fromCodePoint$2,has:has$1,isMdAsciiPunct:isMdAsciiPunct$2,isPunctChar:isPunctChar$2,isSpace:isSpace$e,isString:isString$2,isValidEntityCode:isValidEntityCode$1,isWhiteSpace:isWhiteSpace$2,lib:lib$4,normalizeReference:normalizeReference$3,unescapeAll:unescapeAll$3,unescapeMd:unescapeMd});// Parse link label
//
// this function assumes that first character ("[") already matches;
// returns the end of the label
//

function parseLinkLabel (state, start, disableNested) {
  var level, found, marker, prevPos;

  var max = state.posMax;
  var oldPos = state.pos;

  state.pos = start + 1;
  level = 1;

  while (state.pos < max) {
    marker = state.src.charCodeAt(state.pos);
    if (marker === 0x5D /* ] */) {
      level--;
      if (level === 0) {
        found = true;
        break
      }
    }

    prevPos = state.pos;
    state.md.inline.skipToken(state);
    if (marker === 0x5B /* [ */) {
      if (prevPos === state.pos - 1) {
        // increase level if we find text `[`, which is not a part of any token
        level++;
      } else if (disableNested) {
        state.pos = oldPos;
        return -1
      }
    }
  }

  var labelEnd = -1;

  if (found) {
    labelEnd = state.pos;
  }

  // restore old state
  state.pos = oldPos;

  return labelEnd
}// Parse link destination
//


function parseLinkDestination (str, start, max) {
  var code;
  var pos = start;

  var result = {
    ok: false,
    pos: 0,
    str: ''
  };

  if (str.charCodeAt(pos) === 0x3C /* < */) {
    pos++;
    while (pos < max) {
      code = str.charCodeAt(pos);
      if (code === 0x0A /* \n */) { return result }
      if (code === 0x3C /* < */) { return result }
      if (code === 0x3E /* > */) {
        result.pos = pos + 1;
        result.str = unescapeAll$3(str.slice(start + 1, pos));
        result.ok = true;
        return result
      }
      if (code === 0x5C /* \ */ && pos + 1 < max) {
        pos += 2;
        continue
      }

      pos++;
    }

    // no closing '>'
    return result
  }

  // this should be ... } else { ... branch

  var level = 0;
  while (pos < max) {
    code = str.charCodeAt(pos);

    if (code === 0x20) { break }

    // ascii control characters
    if (code < 0x20 || code === 0x7F) { break }

    if (code === 0x5C /* \ */ && pos + 1 < max) {
      if (str.charCodeAt(pos + 1) === 0x20) { break }
      pos += 2;
      continue
    }

    if (code === 0x28 /* ( */) {
      level++;
      if (level > 32) { return result }
    }

    if (code === 0x29 /* ) */) {
      if (level === 0) { break }
      level--;
    }

    pos++;
  }

  if (start === pos) { return result }
  if (level !== 0) { return result }

  result.str = unescapeAll$3(str.slice(start, pos));
  result.pos = pos;
  result.ok = true;
  return result
}// Parse link title
//


// Parse link title within `str` in [start, max] range,
// or continue previous parsing if `prev_state` is defined (equal to result of last execution).
//
function parseLinkTitle (str, start, max, prev_state) {
  var code;
  var pos = start;

  var state = {
    // if `true`, this is a valid link title
    ok: false,
    // if `true`, this link can be continued on the next line
    can_continue: false,
    // if `ok`, it's the position of the first character after the closing marker
    pos: 0,
    // if `ok`, it's the unescaped title
    str: '',
    // expected closing marker character code
    marker: 0
  };

  if (prev_state) {
    // this is a continuation of a previous parseLinkTitle call on the next line,
    // used in reference links only
    state.str = prev_state.str;
    state.marker = prev_state.marker;
  } else {
    if (pos >= max) { return state }

    var marker = str.charCodeAt(pos);
    if (marker !== 0x22 /* " */ && marker !== 0x27 /* ' */ && marker !== 0x28 /* ( */) { return state }

    start++;
    pos++;

    // if opening marker is "(", switch it to closing marker ")"
    if (marker === 0x28) { marker = 0x29; }

    state.marker = marker;
  }

  while (pos < max) {
    code = str.charCodeAt(pos);
    if (code === state.marker) {
      state.pos = pos + 1;
      state.str += unescapeAll$3(str.slice(start, pos));
      state.ok = true;
      return state
    } else if (code === 0x28 /* ( */ && state.marker === 0x29 /* ) */) {
      return state
    } else if (code === 0x5C /* \ */ && pos + 1 < max) {
      pos++;
    }

    pos++;
  }

  // no closing marker found, but this link title may continue on the next line (for references)
  state.can_continue = true;
  state.str += unescapeAll$3(str.slice(start, pos));
  return state
}// Just a shortcut for bulk export
var helpers$2=/*#__PURE__*/Object.freeze({__proto__:null,parseLinkDestination:parseLinkDestination,parseLinkLabel:parseLinkLabel,parseLinkTitle:parseLinkTitle});/**
 * class Renderer
 *
 * Generates HTML from parsed token stream. Each instance has independent
 * copy of rules. Those can be rewritten with ease. Also, you can add new
 * rules if you create plugin and adds new token types.
 **/


var default_rules$1 = {};

default_rules$1.code_inline = function (tokens, idx, options, env, slf) {
  var token = tokens[idx];

  return  '<code' + slf.renderAttrs(token) + '>' +
          escapeHtml$1(token.content) +
          '</code>'
};

default_rules$1.code_block = function (tokens, idx, options, env, slf) {
  var token = tokens[idx];

  return  '<pre' + slf.renderAttrs(token) + '><code>' +
          escapeHtml$1(tokens[idx].content) +
          '</code></pre>\n'
};

default_rules$1.fence = function (tokens, idx, options, env, slf) {
  var token = tokens[idx];
  var info = token.info ? unescapeAll$3(token.info).trim() : '';
  var langName = '';
  var langAttrs = '';

  if (info) {
    var arr = info.split(/(\s+)/g);
    langName = arr[0];
    langAttrs = arr.slice(2).join('');
  }

  var highlighted;
  if (options.highlight) {
    highlighted = options.highlight(token.content, langName, langAttrs) || escapeHtml$1(token.content);
  } else {
    highlighted = escapeHtml$1(token.content);
  }

  if (highlighted.indexOf('<pre') === 0) {
    return highlighted + '\n'
  }

  // If language exists, inject class gently, without modifying original token.
  // May be, one day we will add .deepClone() for token and simplify this part, but
  // now we prefer to keep things local.
  if (info) {
    var i = token.attrIndex('class');
    var tmpAttrs = token.attrs ? token.attrs.slice() : [];

    if (i < 0) {
      tmpAttrs.push(['class', options.langPrefix + langName]);
    } else {
      tmpAttrs[i] = tmpAttrs[i].slice();
      tmpAttrs[i][1] += ' ' + options.langPrefix + langName;
    }

    // Fake token just to render attributes
    var tmpToken = {
      attrs: tmpAttrs
    };

    return ("<pre><code" + (slf.renderAttrs(tmpToken)) + ">" + highlighted + "</code></pre>\n")
  }

  return ("<pre><code" + (slf.renderAttrs(token)) + ">" + highlighted + "</code></pre>\n")
};

default_rules$1.image = function (tokens, idx, options, env, slf) {
  var token = tokens[idx];

  // "alt" attr MUST be set, even if empty. Because it's mandatory and
  // should be placed on proper position for tests.
  //
  // Replace content with actual value

  token.attrs[token.attrIndex('alt')][1] =
    slf.renderInlineAsText(token.children, options, env);

  return slf.renderToken(tokens, idx, options)
};

default_rules$1.hardbreak = function (tokens, idx, options /*, env */) {
  return options.xhtmlOut ? '<br />\n' : '<br>\n'
};
default_rules$1.softbreak = function (tokens, idx, options /*, env */) {
  return options.breaks ? (options.xhtmlOut ? '<br />\n' : '<br>\n') : '\n'
};

default_rules$1.text = function (tokens, idx /*, options, env */) {
  return escapeHtml$1(tokens[idx].content)
};

default_rules$1.html_block = function (tokens, idx /*, options, env */) {
  return tokens[idx].content
};
default_rules$1.html_inline = function (tokens, idx /*, options, env */) {
  return tokens[idx].content
};

/**
 * new Renderer()
 *
 * Creates new [[Renderer]] instance and fill [[Renderer#rules]] with defaults.
 **/
function Renderer$2 () {
  /**
   * Renderer#rules -> Object
   *
   * Contains render rules for tokens. Can be updated and extended.
   *
   * ##### Example
   *
   * ```javascript
   * var md = require('markdown-it')();
   *
   * md.renderer.rules.strong_open  = function () { return '<b>'; };
   * md.renderer.rules.strong_close = function () { return '</b>'; };
   *
   * var result = md.renderInline(...);
   * ```
   *
   * Each rule is called as independent static function with fixed signature:
   *
   * ```javascript
   * function my_token_render(tokens, idx, options, env, renderer) {
   *   // ...
   *   return renderedHTML;
   * }
   * ```
   *
   * See [source code](https://github.com/markdown-it/markdown-it/blob/master/lib/renderer.mjs)
   * for more details and examples.
   **/
  this.rules = assign$3({}, default_rules$1);
}

/**
 * Renderer.renderAttrs(token) -> String
 *
 * Render token attributes to string.
 **/
Renderer$2.prototype.renderAttrs = function renderAttrs (token) {
  var i, l, result;

  if (!token.attrs) { return '' }

  result = '';

  for (i = 0, l = token.attrs.length; i < l; i++) {
    result += ' ' + escapeHtml$1(token.attrs[i][0]) + '="' + escapeHtml$1(token.attrs[i][1]) + '"';
  }

  return result
};

/**
 * Renderer.renderToken(tokens, idx, options) -> String
 * - tokens (Array): list of tokens
 * - idx (Numbed): token index to render
 * - options (Object): params of parser instance
 *
 * Default token renderer. Can be overriden by custom function
 * in [[Renderer#rules]].
 **/
Renderer$2.prototype.renderToken = function renderToken (tokens, idx, options) {
  var token = tokens[idx];
  var result = '';

  // Tight list paragraphs
  if (token.hidden) {
    return ''
  }

  // Insert a newline between hidden paragraph and subsequent opening
  // block-level tag.
  //
  // For example, here we should insert a newline before blockquote:
  //  - a
  //    >
  //
  if (token.block && token.nesting !== -1 && idx && tokens[idx - 1].hidden) {
    result += '\n';
  }

  // Add token name, e.g. `<img`
  result += (token.nesting === -1 ? '</' : '<') + token.tag;

  // Encode attributes, e.g. `<img src="foo"`
  result += this.renderAttrs(token);

  // Add a slash for self-closing tags, e.g. `<img src="foo" /`
  if (token.nesting === 0 && options.xhtmlOut) {
    result += ' /';
  }

  // Check if we need to add a newline after this tag
  var needLf = false;
  if (token.block) {
    needLf = true;

    if (token.nesting === 1) {
      if (idx + 1 < tokens.length) {
        var nextToken = tokens[idx + 1];

        if (nextToken.type === 'inline' || nextToken.hidden) {
          // Block-level tag containing an inline tag.
          //
          needLf = false;
        } else if (nextToken.nesting === -1 && nextToken.tag === token.tag) {
          // Opening tag + closing tag of the same type. E.g. `<li></li>`.
          //
          needLf = false;
        }
      }
    }
  }

  result += needLf ? '>\n' : '>';

  return result
};

/**
 * Renderer.renderInline(tokens, options, env) -> String
 * - tokens (Array): list on block tokens to render
 * - options (Object): params of parser instance
 * - env (Object): additional data from parsed input (references, for example)
 *
 * The same as [[Renderer.render]], but for single token of `inline` type.
 **/
Renderer$2.prototype.renderInline = function (tokens, options, env) {
  var result = '';
  var rules = this.rules;

  for (var i = 0, len = tokens.length; i < len; i++) {
    var type = tokens[i].type;

    if (typeof rules[type] !== 'undefined') {
      result += rules[type](tokens, i, options, env, this);
    } else {
      result += this.renderToken(tokens, i, options);
    }
  }

  return result
};

/** internal
 * Renderer.renderInlineAsText(tokens, options, env) -> String
 * - tokens (Array): list on block tokens to render
 * - options (Object): params of parser instance
 * - env (Object): additional data from parsed input (references, for example)
 *
 * Special kludge for image `alt` attributes to conform CommonMark spec.
 * Don't try to use it! Spec requires to show `alt` content with stripped markup,
 * instead of simple escaping.
 **/
Renderer$2.prototype.renderInlineAsText = function (tokens, options, env) {
  var result = '';

  for (var i = 0, len = tokens.length; i < len; i++) {
    switch (tokens[i].type) {
      case 'text':
        result += tokens[i].content;
        break
      case 'image':
        result += this.renderInlineAsText(tokens[i].children, options, env);
        break
      case 'html_inline':
      case 'html_block':
        result += tokens[i].content;
        break
      case 'softbreak':
      case 'hardbreak':
        result += '\n';
        break
        // all other tokens are skipped
    }
  }

  return result
};

/**
 * Renderer.render(tokens, options, env) -> String
 * - tokens (Array): list on block tokens to render
 * - options (Object): params of parser instance
 * - env (Object): additional data from parsed input (references, for example)
 *
 * Takes token stream and generates HTML. Probably, you will never need to call
 * this method directly.
 **/
Renderer$2.prototype.render = function (tokens, options, env) {
  var result = '';
  var rules = this.rules;

  for (var i = 0, len = tokens.length; i < len; i++) {
    var type = tokens[i].type;

    if (type === 'inline') {
      result += this.renderInline(tokens[i].children, options, env);
    } else if (typeof rules[type] !== 'undefined') {
      result += rules[type](tokens, i, options, env, this);
    } else {
      result += this.renderToken(tokens, i, options, env);
    }
  }

  return result
};/**
 * class Ruler
 *
 * Helper class, used by [[MarkdownIt#core]], [[MarkdownIt#block]] and
 * [[MarkdownIt#inline]] to manage sequences of functions (rules):
 *
 * - keep rules in defined order
 * - assign the name to each rule
 * - enable/disable rules
 * - add/replace rules
 * - allow assign rules to additional named chains (in the same)
 * - cacheing lists of active rules
 *
 * You will not need use this class directly until write plugins. For simple
 * rules control use [[MarkdownIt.disable]], [[MarkdownIt.enable]] and
 * [[MarkdownIt.use]].
 **/

/**
 * new Ruler()
 **/
function Ruler$4 () {
  // List of added rules. Each element is:
  //
  // {
  //   name: XXX,
  //   enabled: Boolean,
  //   fn: Function(),
  //   alt: [ name2, name3 ]
  // }
  //
  this.__rules__ = [];

  // Cached rule chains.
  //
  // First level - chain name, '' for default.
  // Second level - diginal anchor for fast filtering by charcodes.
  //
  this.__cache__ = null;
}

// Helper methods, should not be used directly

// Find rule index by name
//
Ruler$4.prototype.__find__ = function (name) {
  for (var i = 0; i < this.__rules__.length; i++) {
    if (this.__rules__[i].name === name) {
      return i
    }
  }
  return -1
};

// Build rules lookup cache
//
Ruler$4.prototype.__compile__ = function () {
  var self = this;
  var chains = [''];

  // collect unique names
  self.__rules__.forEach(function (rule) {
    if (!rule.enabled) { return }

    rule.alt.forEach(function (altName) {
      if (chains.indexOf(altName) < 0) {
        chains.push(altName);
      }
    });
  });

  self.__cache__ = {};

  chains.forEach(function (chain) {
    self.__cache__[chain] = [];
    self.__rules__.forEach(function (rule) {
      if (!rule.enabled) { return }

      if (chain && rule.alt.indexOf(chain) < 0) { return }

      self.__cache__[chain].push(rule.fn);
    });
  });
};

/**
 * Ruler.at(name, fn [, options])
 * - name (String): rule name to replace.
 * - fn (Function): new rule function.
 * - options (Object): new rule options (not mandatory).
 *
 * Replace rule by name with new function & options. Throws error if name not
 * found.
 *
 * ##### Options:
 *
 * - __alt__ - array with names of "alternate" chains.
 *
 * ##### Example
 *
 * Replace existing typographer replacement rule with new one:
 *
 * ```javascript
 * var md = require('markdown-it')();
 *
 * md.core.ruler.at('replacements', function replace(state) {
 *   //...
 * });
 * ```
 **/
Ruler$4.prototype.at = function (name, fn, options) {
  var index = this.__find__(name);
  var opt = options || {};

  if (index === -1) { throw new Error('Parser rule not found: ' + name) }

  this.__rules__[index].fn = fn;
  this.__rules__[index].alt = opt.alt || [];
  this.__cache__ = null;
};

/**
 * Ruler.before(beforeName, ruleName, fn [, options])
 * - beforeName (String): new rule will be added before this one.
 * - ruleName (String): name of added rule.
 * - fn (Function): rule function.
 * - options (Object): rule options (not mandatory).
 *
 * Add new rule to chain before one with given name. See also
 * [[Ruler.after]], [[Ruler.push]].
 *
 * ##### Options:
 *
 * - __alt__ - array with names of "alternate" chains.
 *
 * ##### Example
 *
 * ```javascript
 * var md = require('markdown-it')();
 *
 * md.block.ruler.before('paragraph', 'my_rule', function replace(state) {
 *   //...
 * });
 * ```
 **/
Ruler$4.prototype.before = function (beforeName, ruleName, fn, options) {
  var index = this.__find__(beforeName);
  var opt = options || {};

  if (index === -1) { throw new Error('Parser rule not found: ' + beforeName) }

  this.__rules__.splice(index, 0, {
    name: ruleName,
    enabled: true,
    fn: fn,
    alt: opt.alt || []
  });

  this.__cache__ = null;
};

/**
 * Ruler.after(afterName, ruleName, fn [, options])
 * - afterName (String): new rule will be added after this one.
 * - ruleName (String): name of added rule.
 * - fn (Function): rule function.
 * - options (Object): rule options (not mandatory).
 *
 * Add new rule to chain after one with given name. See also
 * [[Ruler.before]], [[Ruler.push]].
 *
 * ##### Options:
 *
 * - __alt__ - array with names of "alternate" chains.
 *
 * ##### Example
 *
 * ```javascript
 * var md = require('markdown-it')();
 *
 * md.inline.ruler.after('text', 'my_rule', function replace(state) {
 *   //...
 * });
 * ```
 **/
Ruler$4.prototype.after = function (afterName, ruleName, fn, options) {
  var index = this.__find__(afterName);
  var opt = options || {};

  if (index === -1) { throw new Error('Parser rule not found: ' + afterName) }

  this.__rules__.splice(index + 1, 0, {
    name: ruleName,
    enabled: true,
    fn: fn,
    alt: opt.alt || []
  });

  this.__cache__ = null;
};

/**
 * Ruler.push(ruleName, fn [, options])
 * - ruleName (String): name of added rule.
 * - fn (Function): rule function.
 * - options (Object): rule options (not mandatory).
 *
 * Push new rule to the end of chain. See also
 * [[Ruler.before]], [[Ruler.after]].
 *
 * ##### Options:
 *
 * - __alt__ - array with names of "alternate" chains.
 *
 * ##### Example
 *
 * ```javascript
 * var md = require('markdown-it')();
 *
 * md.core.ruler.push('my_rule', function replace(state) {
 *   //...
 * });
 * ```
 **/
Ruler$4.prototype.push = function (ruleName, fn, options) {
  var opt = options || {};

  this.__rules__.push({
    name: ruleName,
    enabled: true,
    fn: fn,
    alt: opt.alt || []
  });

  this.__cache__ = null;
};

/**
 * Ruler.enable(list [, ignoreInvalid]) -> Array
 * - list (String|Array): list of rule names to enable.
 * - ignoreInvalid (Boolean): set `true` to ignore errors when rule not found.
 *
 * Enable rules with given names. If any rule name not found - throw Error.
 * Errors can be disabled by second param.
 *
 * Returns list of found rule names (if no exception happened).
 *
 * See also [[Ruler.disable]], [[Ruler.enableOnly]].
 **/
Ruler$4.prototype.enable = function (list, ignoreInvalid) {
  if (!Array.isArray(list)) { list = [list]; }

  var result = [];

  // Search by name and enable
  list.forEach(function (name) {
    var idx = this.__find__(name);

    if (idx < 0) {
      if (ignoreInvalid) { return }
      throw new Error('Rules manager: invalid rule name ' + name)
    }
    this.__rules__[idx].enabled = true;
    result.push(name);
  }, this);

  this.__cache__ = null;
  return result
};

/**
 * Ruler.enableOnly(list [, ignoreInvalid])
 * - list (String|Array): list of rule names to enable (whitelist).
 * - ignoreInvalid (Boolean): set `true` to ignore errors when rule not found.
 *
 * Enable rules with given names, and disable everything else. If any rule name
 * not found - throw Error. Errors can be disabled by second param.
 *
 * See also [[Ruler.disable]], [[Ruler.enable]].
 **/
Ruler$4.prototype.enableOnly = function (list, ignoreInvalid) {
  if (!Array.isArray(list)) { list = [list]; }

  this.__rules__.forEach(function (rule) { rule.enabled = false; });

  this.enable(list, ignoreInvalid);
};

/**
 * Ruler.disable(list [, ignoreInvalid]) -> Array
 * - list (String|Array): list of rule names to disable.
 * - ignoreInvalid (Boolean): set `true` to ignore errors when rule not found.
 *
 * Disable rules with given names. If any rule name not found - throw Error.
 * Errors can be disabled by second param.
 *
 * Returns list of found rule names (if no exception happened).
 *
 * See also [[Ruler.enable]], [[Ruler.enableOnly]].
 **/
Ruler$4.prototype.disable = function (list, ignoreInvalid) {
  if (!Array.isArray(list)) { list = [list]; }

  var result = [];

  // Search by name and disable
  list.forEach(function (name) {
    var idx = this.__find__(name);

    if (idx < 0) {
      if (ignoreInvalid) { return }
      throw new Error('Rules manager: invalid rule name ' + name)
    }
    this.__rules__[idx].enabled = false;
    result.push(name);
  }, this);

  this.__cache__ = null;
  return result
};

/**
 * Ruler.getRules(chainName) -> Array
 *
 * Return array of active functions (rules) for given chain name. It analyzes
 * rules configuration, compiles caches if not exists and returns result.
 *
 * Default chain name is `''` (empty string). It can't be skipped. That's
 * done intentionally, to keep signature monomorphic for high speed.
 **/
Ruler$4.prototype.getRules = function (chainName) {
  if (this.__cache__ === null) {
    this.__compile__();
  }

  // Chain can be empty, if rules disabled. But we still have to return Array.
  return this.__cache__[chainName] || []
};// Token class

/**
 * class Token
 **/

/**
 * new Token(type, tag, nesting)
 *
 * Create new token and fill passed properties.
 **/
function Token$4 (type, tag, nesting) {
  /**
   * Token#type -> String
   *
   * Type of the token (string, e.g. "paragraph_open")
   **/
  this.type     = type;

  /**
   * Token#tag -> String
   *
   * html tag name, e.g. "p"
   **/
  this.tag      = tag;

  /**
   * Token#attrs -> Array
   *
   * Html attributes. Format: `[ [ name1, value1 ], [ name2, value2 ] ]`
   **/
  this.attrs    = null;

  /**
   * Token#map -> Array
   *
   * Source map info. Format: `[ line_begin, line_end ]`
   **/
  this.map      = null;

  /**
   * Token#nesting -> Number
   *
   * Level change (number in {-1, 0, 1} set), where:
   *
   * -  `1` means the tag is opening
   * -  `0` means the tag is self-closing
   * - `-1` means the tag is closing
   **/
  this.nesting  = nesting;

  /**
   * Token#level -> Number
   *
   * nesting level, the same as `state.level`
   **/
  this.level    = 0;

  /**
   * Token#children -> Array
   *
   * An array of child nodes (inline and img tokens)
   **/
  this.children = null;

  /**
   * Token#content -> String
   *
   * In a case of self-closing tag (code, html, fence, etc.),
   * it has contents of this tag.
   **/
  this.content  = '';

  /**
   * Token#markup -> String
   *
   * '*' or '_' for emphasis, fence string for fence, etc.
   **/
  this.markup   = '';

  /**
   * Token#info -> String
   *
   * Additional information:
   *
   * - Info string for "fence" tokens
   * - The value "auto" for autolink "link_open" and "link_close" tokens
   * - The string value of the item marker for ordered-list "list_item_open" tokens
   **/
  this.info     = '';

  /**
   * Token#meta -> Object
   *
   * A place for plugins to store an arbitrary data
   **/
  this.meta     = null;

  /**
   * Token#block -> Boolean
   *
   * True for block-level tokens, false for inline tokens.
   * Used in renderer to calculate line breaks
   **/
  this.block    = false;

  /**
   * Token#hidden -> Boolean
   *
   * If it's true, ignore this element when rendering. Used for tight lists
   * to hide paragraphs.
   **/
  this.hidden   = false;
}

/**
 * Token.attrIndex(name) -> Number
 *
 * Search attribute index by name.
 **/
Token$4.prototype.attrIndex = function attrIndex (name) {
  if (!this.attrs) { return -1 }

  var attrs = this.attrs;

  for (var i = 0, len = attrs.length; i < len; i++) {
    if (attrs[i][0] === name) { return i }
  }
  return -1
};

/**
 * Token.attrPush(attrData)
 *
 * Add `[ name, value ]` attribute to list. Init attrs if necessary
 **/
Token$4.prototype.attrPush = function attrPush (attrData) {
  if (this.attrs) {
    this.attrs.push(attrData);
  } else {
    this.attrs = [attrData];
  }
};

/**
 * Token.attrSet(name, value)
 *
 * Set `name` attribute to `value`. Override old value if exists.
 **/
Token$4.prototype.attrSet = function attrSet (name, value) {
  var idx = this.attrIndex(name);
  var attrData = [name, value];

  if (idx < 0) {
    this.attrPush(attrData);
  } else {
    this.attrs[idx] = attrData;
  }
};

/**
 * Token.attrGet(name)
 *
 * Get the value of attribute `name`, or null if it does not exist.
 **/
Token$4.prototype.attrGet = function attrGet (name) {
  var idx = this.attrIndex(name);
  var value = null;
  if (idx >= 0) {
    value = this.attrs[idx][1];
  }
  return value
};

/**
 * Token.attrJoin(name, value)
 *
 * Join value to existing attribute via space. Or create new attribute if not
 * exists. Useful to operate with token classes.
 **/
Token$4.prototype.attrJoin = function attrJoin (name, value) {
  var idx = this.attrIndex(name);

  if (idx < 0) {
    this.attrPush([name, value]);
  } else {
    this.attrs[idx][1] = this.attrs[idx][1] + ' ' + value;
  }
};// Core state object
//


function StateCore$1 (src, md, env) {
  this.src = src;
  this.env = env;
  this.tokens = [];
  this.inlineMode = false;
  this.md = md; // link to parser instance
}

// re-export Token class to use in core rules
StateCore$1.prototype.Token = Token$4;// Normalize input string

// https://spec.commonmark.org/0.29/#line-ending
var NEWLINES_RE$1  = /\r\n?|\n/g;
var NULL_RE$1      = /\0/g;

function normalize$1 (state) {
  var str;

  // Normalize newlines
  str = state.src.replace(NEWLINES_RE$1, '\n');

  // Replace NULL characters
  str = str.replace(NULL_RE$1, '\uFFFD');

  state.src = str;
}function block$2 (state) {
  var token;

  if (state.inlineMode) {
    token          = new state.Token('inline', '', 0);
    token.content  = state.src;
    token.map      = [0, 1];
    token.children = [];
    state.tokens.push(token);
  } else {
    state.md.block.parse(state.src, state.md, state.env, state.tokens);
  }
}function inline$1 (state) {
  var tokens = state.tokens;

  // Parse inlines
  for (var i = 0, l = tokens.length; i < l; i++) {
    var tok = tokens[i];
    if (tok.type === 'inline') {
      state.md.inline.parse(tok.content, state.md, state.env, tok.children);
    }
  }
}// Replace link-like texts with link nodes.
//
// Currently restricted by `md.validateLink()` to http/https/ftp
//


function isLinkOpen$3 (str) {
  return /^<a[>\s]/i.test(str)
}
function isLinkClose$3 (str) {
  return /^<\/a\s*>/i.test(str)
}

function linkify$4 (state) {
  var blockTokens = state.tokens;

  if (!state.md.options.linkify) { return }

  for (var j = 0, l = blockTokens.length; j < l; j++) {
    if (blockTokens[j].type !== 'inline' ||
        !state.md.linkify.pretest(blockTokens[j].content)) {
      continue
    }

    var tokens = blockTokens[j].children;

    var htmlLinkLevel = 0;

    // We scan from the end, to keep position when new tags added.
    // Use reversed logic in links start/end match
    for (var i = tokens.length - 1; i >= 0; i--) {
      var currentToken = tokens[i];

      // Skip content of markdown links
      if (currentToken.type === 'link_close') {
        i--;
        while (tokens[i].level !== currentToken.level && tokens[i].type !== 'link_open') {
          i--;
        }
        continue
      }

      // Skip content of html tag links
      if (currentToken.type === 'html_inline') {
        if (isLinkOpen$3(currentToken.content) && htmlLinkLevel > 0) {
          htmlLinkLevel--;
        }
        if (isLinkClose$3(currentToken.content)) {
          htmlLinkLevel++;
        }
      }
      if (htmlLinkLevel > 0) { continue }

      if (currentToken.type === 'text' && state.md.linkify.test(currentToken.content)) {
        var text = currentToken.content;
        var links = state.md.linkify.match(text);

        // Now split string to nodes
        var nodes = [];
        var level = currentToken.level;
        var lastPos = 0;

        // forbid escape sequence at the start of the string,
        // this avoids http\://example.com/ from being linkified as
        // http:<a href="//example.com/">//example.com/</a>
        if (links.length > 0 &&
            links[0].index === 0 &&
            i > 0 &&
            tokens[i - 1].type === 'text_special') {
          links = links.slice(1);
        }

        for (var ln = 0; ln < links.length; ln++) {
          var url = links[ln].url;
          var fullUrl = state.md.normalizeLink(url);
          if (!state.md.validateLink(fullUrl)) { continue }

          var urlText = links[ln].text;

          // Linkifier might send raw hostnames like "example.com", where url
          // starts with domain name. So we prepend http:// in those cases,
          // and remove it afterwards.
          //
          if (!links[ln].schema) {
            urlText = state.md.normalizeLinkText('http://' + urlText).replace(/^http:\/\//, '');
          } else if (links[ln].schema === 'mailto:' && !/^mailto:/i.test(urlText)) {
            urlText = state.md.normalizeLinkText('mailto:' + urlText).replace(/^mailto:/, '');
          } else {
            urlText = state.md.normalizeLinkText(urlText);
          }

          var pos = links[ln].index;

          if (pos > lastPos) {
            var token   = new state.Token('text', '', 0);
            token.content = text.slice(lastPos, pos);
            token.level   = level;
            nodes.push(token);
          }

          var token_o   = new state.Token('link_open', 'a', 1);
          token_o.attrs   = [['href', fullUrl]];
          token_o.level   = level++;
          token_o.markup  = 'linkify';
          token_o.info    = 'auto';
          nodes.push(token_o);

          var token_t   = new state.Token('text', '', 0);
          token_t.content = urlText;
          token_t.level   = level;
          nodes.push(token_t);

          var token_c   = new state.Token('link_close', 'a', -1);
          token_c.level   = --level;
          token_c.markup  = 'linkify';
          token_c.info    = 'auto';
          nodes.push(token_c);

          lastPos = links[ln].lastIndex;
        }
        if (lastPos < text.length) {
          var token$1   = new state.Token('text', '', 0);
          token$1.content = text.slice(lastPos);
          token$1.level   = level;
          nodes.push(token$1);
        }

        // replace current node
        blockTokens[j].children = tokens = arrayReplaceAt$1(tokens, i, nodes);
      }
    }
  }
}// Simple typographic replacements
//
// (c) (C) → ©
// (tm) (TM) → ™
// (r) (R) → ®
// +- → ±
// ... → … (also ?.... → ?.., !.... → !..)
// ???????? → ???, !!!!! → !!!, `,,` → `,`
// -- → &ndash;, --- → &mdash;
//

// TODO:
// - fractionals 1/2, 1/4, 3/4 -> ½, ¼, ¾
// - multiplications 2 x 4 -> 2 × 4

var RARE_RE$1 = /\+-|\.\.|\?\?\?\?|!!!!|,,|--/;

// Workaround for phantomjs - need regex without /g flag,
// or root check will fail every second time
var SCOPED_ABBR_TEST_RE$1 = /\((c|tm|r)\)/i;

var SCOPED_ABBR_RE$1 = /\((c|tm|r)\)/ig;
var SCOPED_ABBR$1 = {
  c: '©',
  r: '®',
  tm: '™'
};

function replaceFn$1 (match, name) {
  return SCOPED_ABBR$1[name.toLowerCase()]
}

function replace_scoped$1 (inlineTokens) {
  var inside_autolink = 0;

  for (var i = inlineTokens.length - 1; i >= 0; i--) {
    var token = inlineTokens[i];

    if (token.type === 'text' && !inside_autolink) {
      token.content = token.content.replace(SCOPED_ABBR_RE$1, replaceFn$1);
    }

    if (token.type === 'link_open' && token.info === 'auto') {
      inside_autolink--;
    }

    if (token.type === 'link_close' && token.info === 'auto') {
      inside_autolink++;
    }
  }
}

function replace_rare$1 (inlineTokens) {
  var inside_autolink = 0;

  for (var i = inlineTokens.length - 1; i >= 0; i--) {
    var token = inlineTokens[i];

    if (token.type === 'text' && !inside_autolink) {
      if (RARE_RE$1.test(token.content)) {
        token.content = token.content
          .replace(/\+-/g, '±')
          // .., ..., ....... -> …
          // but ?..... & !..... -> ?.. & !..
          .replace(/\.{2,}/g, '…').replace(/([?!])…/g, '$1..')
          .replace(/([?!]){4,}/g, '$1$1$1').replace(/,{2,}/g, ',')
          // em-dash
          .replace(/(^|[^-])---(?=[^-]|$)/mg, '$1\u2014')
          // en-dash
          .replace(/(^|\s)--(?=\s|$)/mg, '$1\u2013')
          .replace(/(^|[^-\s])--(?=[^-\s]|$)/mg, '$1\u2013');
      }
    }

    if (token.type === 'link_open' && token.info === 'auto') {
      inside_autolink--;
    }

    if (token.type === 'link_close' && token.info === 'auto') {
      inside_autolink++;
    }
  }
}

function replace$2 (state) {
  var blkIdx;

  if (!state.md.options.typographer) { return }

  for (blkIdx = state.tokens.length - 1; blkIdx >= 0; blkIdx--) {
    if (state.tokens[blkIdx].type !== 'inline') { continue }

    if (SCOPED_ABBR_TEST_RE$1.test(state.tokens[blkIdx].content)) {
      replace_scoped$1(state.tokens[blkIdx].children);
    }

    if (RARE_RE$1.test(state.tokens[blkIdx].content)) {
      replace_rare$1(state.tokens[blkIdx].children);
    }
  }
}// Convert straight quotation marks to typographic ones
//


var QUOTE_TEST_RE$1 = /['"]/;
var QUOTE_RE$1 = /['"]/g;
var APOSTROPHE$1 = '\u2019'; /* ’ */

function replaceAt$1 (str, index, ch) {
  return str.slice(0, index) + ch + str.slice(index + 1)
}

function process_inlines$1 (tokens, state) {
  var j;

  var stack = [];

  for (var i = 0; i < tokens.length; i++) {
    var token = tokens[i];

    var thisLevel = tokens[i].level;

    for (j = stack.length - 1; j >= 0; j--) {
      if (stack[j].level <= thisLevel) { break }
    }
    stack.length = j + 1;

    if (token.type !== 'text') { continue }

    var text = token.content;
    var pos = 0;
    var max = text.length;

    /* eslint no-labels:0,block-scoped-var:0 */
    OUTER:
    while (pos < max) {
      QUOTE_RE$1.lastIndex = pos;
      var t = QUOTE_RE$1.exec(text);
      if (!t) { break }

      var canOpen = true;
      var canClose = true;
      pos = t.index + 1;
      var isSingle = (t[0] === "'");

      // Find previous character,
      // default to space if it's the beginning of the line
      //
      var lastChar = 0x20;

      if (t.index - 1 >= 0) {
        lastChar = text.charCodeAt(t.index - 1);
      } else {
        for (j = i - 1; j >= 0; j--) {
          if (tokens[j].type === 'softbreak' || tokens[j].type === 'hardbreak') { break } // lastChar defaults to 0x20
          if (!tokens[j].content) { continue } // should skip all tokens except 'text', 'html_inline' or 'code_inline'

          lastChar = tokens[j].content.charCodeAt(tokens[j].content.length - 1);
          break
        }
      }

      // Find next character,
      // default to space if it's the end of the line
      //
      var nextChar = 0x20;

      if (pos < max) {
        nextChar = text.charCodeAt(pos);
      } else {
        for (j = i + 1; j < tokens.length; j++) {
          if (tokens[j].type === 'softbreak' || tokens[j].type === 'hardbreak') { break } // nextChar defaults to 0x20
          if (!tokens[j].content) { continue } // should skip all tokens except 'text', 'html_inline' or 'code_inline'

          nextChar = tokens[j].content.charCodeAt(0);
          break
        }
      }

      var isLastPunctChar = isMdAsciiPunct$2(lastChar) || isPunctChar$2(String.fromCharCode(lastChar));
      var isNextPunctChar = isMdAsciiPunct$2(nextChar) || isPunctChar$2(String.fromCharCode(nextChar));

      var isLastWhiteSpace = isWhiteSpace$2(lastChar);
      var isNextWhiteSpace = isWhiteSpace$2(nextChar);

      if (isNextWhiteSpace) {
        canOpen = false;
      } else if (isNextPunctChar) {
        if (!(isLastWhiteSpace || isLastPunctChar)) {
          canOpen = false;
        }
      }

      if (isLastWhiteSpace) {
        canClose = false;
      } else if (isLastPunctChar) {
        if (!(isNextWhiteSpace || isNextPunctChar)) {
          canClose = false;
        }
      }

      if (nextChar === 0x22 /* " */ && t[0] === '"') {
        if (lastChar >= 0x30 /* 0 */ && lastChar <= 0x39 /* 9 */) {
          // special case: 1"" - count first quote as an inch
          canClose = canOpen = false;
        }
      }

      if (canOpen && canClose) {
        // Replace quotes in the middle of punctuation sequence, but not
        // in the middle of the words, i.e.:
        //
        // 1. foo " bar " baz - not replaced
        // 2. foo-"-bar-"-baz - replaced
        // 3. foo"bar"baz     - not replaced
        //
        canOpen = isLastPunctChar;
        canClose = isNextPunctChar;
      }

      if (!canOpen && !canClose) {
        // middle of word
        if (isSingle) {
          token.content = replaceAt$1(token.content, t.index, APOSTROPHE$1);
        }
        continue
      }

      if (canClose) {
        // this could be a closing quote, rewind the stack to get a match
        for (j = stack.length - 1; j >= 0; j--) {
          var item = stack[j];
          if (stack[j].level < thisLevel) { break }
          if (item.single === isSingle && stack[j].level === thisLevel) {
            item = stack[j];

            var openQuote = (void 0);
            var closeQuote = (void 0);
            if (isSingle) {
              openQuote = state.md.options.quotes[2];
              closeQuote = state.md.options.quotes[3];
            } else {
              openQuote = state.md.options.quotes[0];
              closeQuote = state.md.options.quotes[1];
            }

            // replace token.content *before* tokens[item.token].content,
            // because, if they are pointing at the same token, replaceAt
            // could mess up indices when quote length != 1
            token.content = replaceAt$1(token.content, t.index, closeQuote);
            tokens[item.token].content = replaceAt$1(
              tokens[item.token].content, item.pos, openQuote);

            pos += closeQuote.length - 1;
            if (item.token === i) { pos += openQuote.length - 1; }

            text = token.content;
            max = text.length;

            stack.length = j;
            continue OUTER
          }
        }
      }

      if (canOpen) {
        stack.push({
          token: i,
          pos: t.index,
          single: isSingle,
          level: thisLevel
        });
      } else if (canClose && isSingle) {
        token.content = replaceAt$1(token.content, t.index, APOSTROPHE$1);
      }
    }
  }
}

function smartquotes$1 (state) {
  /* eslint max-depth:0 */
  if (!state.md.options.typographer) { return }

  for (var blkIdx = state.tokens.length - 1; blkIdx >= 0; blkIdx--) {
    if (state.tokens[blkIdx].type !== 'inline' ||
        !QUOTE_TEST_RE$1.test(state.tokens[blkIdx].content)) {
      continue
    }

    process_inlines$1(state.tokens[blkIdx].children, state);
  }
}// Join raw text tokens with the rest of the text
//
// This is set as a separate rule to provide an opportunity for plugins
// to run text replacements after text join, but before escape join.
//
// For example, `\:)` shouldn't be replaced with an emoji.
//

function text_join$1 (state) {
  var curr, last;
  var blockTokens = state.tokens;
  var l = blockTokens.length;

  for (var j = 0; j < l; j++) {
    if (blockTokens[j].type !== 'inline') { continue }

    var tokens = blockTokens[j].children;
    var max = tokens.length;

    for (curr = 0; curr < max; curr++) {
      if (tokens[curr].type === 'text_special') {
        tokens[curr].type = 'text';
      }
    }

    for (curr = last = 0; curr < max; curr++) {
      if (tokens[curr].type === 'text' &&
          curr + 1 < max &&
          tokens[curr + 1].type === 'text') {
        // collapse two adjacent text nodes
        tokens[curr + 1].content = tokens[curr].content + tokens[curr + 1].content;
      } else {
        if (curr !== last) { tokens[last] = tokens[curr]; }

        last++;
      }
    }

    if (curr !== last) {
      tokens.length = last;
    }
  }
}/** internal
 * class Core
 *
 * Top-level rules executor. Glues block/inline parsers and does intermediate
 * transformations.
 **/


var _rules$5 = [
  ['normalize',      normalize$1],
  ['block',          block$2],
  ['inline',         inline$1],
  ['linkify',        linkify$4],
  ['replacements',   replace$2],
  ['smartquotes',    smartquotes$1],
  // `text_join` finds `text_special` tokens (for escape sequences)
  // and joins them with the rest of the text
  ['text_join',      text_join$1]
];

/**
 * new Core()
 **/
function Core$1 () {
  /**
   * Core#ruler -> Ruler
   *
   * [[Ruler]] instance. Keep configuration of core rules.
   **/
  this.ruler = new Ruler$4();

  for (var i = 0; i < _rules$5.length; i++) {
    this.ruler.push(_rules$5[i][0], _rules$5[i][1]);
  }
}

/**
 * Core.process(state)
 *
 * Executes core chain rules.
 **/
Core$1.prototype.process = function (state) {
  var rules = this.ruler.getRules('');

  for (var i = 0, l = rules.length; i < l; i++) {
    rules[i](state);
  }
};

Core$1.prototype.State = StateCore$1;// Parser state class


function StateBlock$1 (src, md, env, tokens) {
  this.src = src;

  // link to parser instance
  this.md     = md;

  this.env = env;

  //
  // Internal state vartiables
  //

  this.tokens = tokens;

  this.bMarks = [];  // line begin offsets for fast jumps
  this.eMarks = [];  // line end offsets for fast jumps
  this.tShift = [];  // offsets of the first non-space characters (tabs not expanded)
  this.sCount = [];  // indents for each line (tabs expanded)

  // An amount of virtual spaces (tabs expanded) between beginning
  // of each line (bMarks) and real beginning of that line.
  //
  // It exists only as a hack because blockquotes override bMarks
  // losing information in the process.
  //
  // It's used only when expanding tabs, you can think about it as
  // an initial tab length, e.g. bsCount=21 applied to string `\t123`
  // means first tab should be expanded to 4-21%4 === 3 spaces.
  //
  this.bsCount = [];

  // block parser variables

  // required block content indent (for example, if we are
  // inside a list, it would be positioned after list marker)
  this.blkIndent  = 0;
  this.line       = 0; // line index in src
  this.lineMax    = 0; // lines count
  this.tight      = false;  // loose/tight mode for lists
  this.ddIndent   = -1; // indent of the current dd block (-1 if there isn't any)
  this.listIndent = -1; // indent of the current list block (-1 if there isn't any)

  // can be 'blockquote', 'list', 'root', 'paragraph' or 'reference'
  // used in lists to determine if they interrupt a paragraph
  this.parentType = 'root';

  this.level = 0;

  // Create caches
  // Generate markers.
  var s = this.src;

  for (var start = 0, pos = 0, indent = 0, offset = 0, len = s.length, indent_found = false; pos < len; pos++) {
    var ch = s.charCodeAt(pos);

    if (!indent_found) {
      if (isSpace$e(ch)) {
        indent++;

        if (ch === 0x09) {
          offset += 4 - offset % 4;
        } else {
          offset++;
        }
        continue
      } else {
        indent_found = true;
      }
    }

    if (ch === 0x0A || pos === len - 1) {
      if (ch !== 0x0A) { pos++; }
      this.bMarks.push(start);
      this.eMarks.push(pos);
      this.tShift.push(indent);
      this.sCount.push(offset);
      this.bsCount.push(0);

      indent_found = false;
      indent = 0;
      offset = 0;
      start = pos + 1;
    }
  }

  // Push fake entry to simplify cache bounds checks
  this.bMarks.push(s.length);
  this.eMarks.push(s.length);
  this.tShift.push(0);
  this.sCount.push(0);
  this.bsCount.push(0);

  this.lineMax = this.bMarks.length - 1; // don't count last fake line
}

// Push new token to "stream".
//
StateBlock$1.prototype.push = function (type, tag, nesting) {
  var token = new Token$4(type, tag, nesting);
  token.block = true;

  if (nesting < 0) { this.level--; } // closing tag
  token.level = this.level;
  if (nesting > 0) { this.level++; } // opening tag

  this.tokens.push(token);
  return token
};

StateBlock$1.prototype.isEmpty = function isEmpty (line) {
  return this.bMarks[line] + this.tShift[line] >= this.eMarks[line]
};

StateBlock$1.prototype.skipEmptyLines = function skipEmptyLines (from) {
  for (var max = this.lineMax; from < max; from++) {
    if (this.bMarks[from] + this.tShift[from] < this.eMarks[from]) {
      break
    }
  }
  return from
};

// Skip spaces from given position.
StateBlock$1.prototype.skipSpaces = function skipSpaces (pos) {
  for (var max = this.src.length; pos < max; pos++) {
    var ch = this.src.charCodeAt(pos);
    if (!isSpace$e(ch)) { break }
  }
  return pos
};

// Skip spaces from given position in reverse.
StateBlock$1.prototype.skipSpacesBack = function skipSpacesBack (pos, min) {
  if (pos <= min) { return pos }

  while (pos > min) {
    if (!isSpace$e(this.src.charCodeAt(--pos))) { return pos + 1 }
  }
  return pos
};

// Skip char codes from given position
StateBlock$1.prototype.skipChars = function skipChars (pos, code) {
  for (var max = this.src.length; pos < max; pos++) {
    if (this.src.charCodeAt(pos) !== code) { break }
  }
  return pos
};

// Skip char codes reverse from given position - 1
StateBlock$1.prototype.skipCharsBack = function skipCharsBack (pos, code, min) {
  if (pos <= min) { return pos }

  while (pos > min) {
    if (code !== this.src.charCodeAt(--pos)) { return pos + 1 }
  }
  return pos
};

// cut lines range from source.
StateBlock$1.prototype.getLines = function getLines (begin, end, indent, keepLastLF) {
  if (begin >= end) {
    return ''
  }

  var queue = new Array(end - begin);

  for (var i = 0, line = begin; line < end; line++, i++) {
    var lineIndent = 0;
    var lineStart = this.bMarks[line];
    var first = lineStart;
    var last = (void 0);

    if (line + 1 < end || keepLastLF) {
      // No need for bounds check because we have fake entry on tail.
      last = this.eMarks[line] + 1;
    } else {
      last = this.eMarks[line];
    }

    while (first < last && lineIndent < indent) {
      var ch = this.src.charCodeAt(first);

      if (isSpace$e(ch)) {
        if (ch === 0x09) {
          lineIndent += 4 - (lineIndent + this.bsCount[line]) % 4;
        } else {
          lineIndent++;
        }
      } else if (first - lineStart < this.tShift[line]) {
        // patched tShift masked characters to look like spaces (blockquotes, list markers)
        lineIndent++;
      } else {
        break
      }

      first++;
    }

    if (lineIndent > indent) {
      // partially expanding tabs in code blocks, e.g '\t\tfoobar'
      // with indent=2 becomes '  \tfoobar'
      queue[i] = new Array(lineIndent - indent + 1).join(' ') + this.src.slice(first, last);
    } else {
      queue[i] = this.src.slice(first, last);
    }
  }

  return queue.join('')
};

// re-export Token class to use in block rules
StateBlock$1.prototype.Token = Token$4;// GFM table, https://github.github.com/gfm/#tables-extension-


// Limit the amount of empty autocompleted cells in a table,
// see https://github.com/markdown-it/markdown-it/issues/1000,
//
// Both pulldown-cmark and commonmark-hs limit the number of cells this way to ~200k.
// We set it to 65k, which can expand user input by a factor of x370
// (256x256 square is 1.8kB expanded into 650kB).
var MAX_AUTOCOMPLETED_CELLS = 0x10000;

function getLine$2 (state, line) {
  var pos = state.bMarks[line] + state.tShift[line];
  var max = state.eMarks[line];

  return state.src.slice(pos, max)
}

function escapedSplit$2 (str) {
  var result = [];
  var max = str.length;

  var pos = 0;
  var ch = str.charCodeAt(pos);
  var isEscaped = false;
  var lastPos = 0;
  var current = '';

  while (pos < max) {
    if (ch === 0x7c/* | */) {
      if (!isEscaped) {
        // pipe separating cells, '|'
        result.push(current + str.substring(lastPos, pos));
        current = '';
        lastPos = pos + 1;
      } else {
        // escaped pipe, '\|'
        current += str.substring(lastPos, pos - 1);
        lastPos = pos;
      }
    }

    isEscaped = (ch === 0x5c/* \ */);
    pos++;

    ch = str.charCodeAt(pos);
  }

  result.push(current + str.substring(lastPos));

  return result
}

function table$2 (state, startLine, endLine, silent) {
  // should have at least two lines
  if (startLine + 2 > endLine) { return false }

  var nextLine = startLine + 1;

  if (state.sCount[nextLine] < state.blkIndent) { return false }

  // if it's indented more than 3 spaces, it should be a code block
  if (state.sCount[nextLine] - state.blkIndent >= 4) { return false }

  // first character of the second line should be '|', '-', ':',
  // and no other characters are allowed but spaces;
  // basically, this is the equivalent of /^[-:|][-:|\s]*$/ regexp

  var pos = state.bMarks[nextLine] + state.tShift[nextLine];
  if (pos >= state.eMarks[nextLine]) { return false }

  var firstCh = state.src.charCodeAt(pos++);
  if (firstCh !== 0x7C/* | */ && firstCh !== 0x2D/* - */ && firstCh !== 0x3A/* : */) { return false }

  if (pos >= state.eMarks[nextLine]) { return false }

  var secondCh = state.src.charCodeAt(pos++);
  if (secondCh !== 0x7C/* | */ && secondCh !== 0x2D/* - */ && secondCh !== 0x3A/* : */ && !isSpace$e(secondCh)) {
    return false
  }

  // if first character is '-', then second character must not be a space
  // (due to parsing ambiguity with list)
  if (firstCh === 0x2D/* - */ && isSpace$e(secondCh)) { return false }

  while (pos < state.eMarks[nextLine]) {
    var ch = state.src.charCodeAt(pos);

    if (ch !== 0x7C/* | */ && ch !== 0x2D/* - */ && ch !== 0x3A/* : */ && !isSpace$e(ch)) { return false }

    pos++;
  }

  var lineText = getLine$2(state, startLine + 1);
  var columns = lineText.split('|');
  var aligns = [];
  for (var i = 0; i < columns.length; i++) {
    var t = columns[i].trim();
    if (!t) {
      // allow empty columns before and after table, but not in between columns;
      // e.g. allow ` |---| `, disallow ` ---||--- `
      if (i === 0 || i === columns.length - 1) {
        continue
      } else {
        return false
      }
    }

    if (!/^:?-+:?$/.test(t)) { return false }
    if (t.charCodeAt(t.length - 1) === 0x3A/* : */) {
      aligns.push(t.charCodeAt(0) === 0x3A/* : */ ? 'center' : 'right');
    } else if (t.charCodeAt(0) === 0x3A/* : */) {
      aligns.push('left');
    } else {
      aligns.push('');
    }
  }

  lineText = getLine$2(state, startLine).trim();
  if (lineText.indexOf('|') === -1) { return false }
  if (state.sCount[startLine] - state.blkIndent >= 4) { return false }
  columns = escapedSplit$2(lineText);
  if (columns.length && columns[0] === '') { columns.shift(); }
  if (columns.length && columns[columns.length - 1] === '') { columns.pop(); }

  // header row will define an amount of columns in the entire table,
  // and align row should be exactly the same (the rest of the rows can differ)
  var columnCount = columns.length;
  if (columnCount === 0 || columnCount !== aligns.length) { return false }

  if (silent) { return true }

  var oldParentType = state.parentType;
  state.parentType = 'table';

  // use 'blockquote' lists for termination because it's
  // the most similar to tables
  var terminatorRules = state.md.block.ruler.getRules('blockquote');

  var token_to = state.push('table_open', 'table', 1);
  var tableLines = [startLine, 0];
  token_to.map = tableLines;

  var token_tho = state.push('thead_open', 'thead', 1);
  token_tho.map = [startLine, startLine + 1];

  var token_htro = state.push('tr_open', 'tr', 1);
  token_htro.map = [startLine, startLine + 1];

  for (var i$1 = 0; i$1 < columns.length; i$1++) {
    var token_ho = state.push('th_open', 'th', 1);
    if (aligns[i$1]) {
      token_ho.attrs  = [['style', 'text-align:' + aligns[i$1]]];
    }

    var token_il = state.push('inline', '', 0);
    token_il.content  = columns[i$1].trim();
    token_il.children = [];

    state.push('th_close', 'th', -1);
  }

  state.push('tr_close', 'tr', -1);
  state.push('thead_close', 'thead', -1);

  var tbodyLines;
  var autocompletedCells = 0;

  for (nextLine = startLine + 2; nextLine < endLine; nextLine++) {
    if (state.sCount[nextLine] < state.blkIndent) { break }

    var terminate = false;
    for (var i$2 = 0, l = terminatorRules.length; i$2 < l; i$2++) {
      if (terminatorRules[i$2](state, nextLine, endLine, true)) {
        terminate = true;
        break
      }
    }

    if (terminate) { break }
    lineText = getLine$2(state, nextLine).trim();
    if (!lineText) { break }
    if (state.sCount[nextLine] - state.blkIndent >= 4) { break }
    columns = escapedSplit$2(lineText);
    if (columns.length && columns[0] === '') { columns.shift(); }
    if (columns.length && columns[columns.length - 1] === '') { columns.pop(); }

    // note: autocomplete count can be negative if user specifies more columns than header,
    // but that does not affect intended use (which is limiting expansion)
    autocompletedCells += columnCount - columns.length;
    if (autocompletedCells > MAX_AUTOCOMPLETED_CELLS) { break }

    if (nextLine === startLine + 2) {
      var token_tbo = state.push('tbody_open', 'tbody', 1);
      token_tbo.map = tbodyLines = [startLine + 2, 0];
    }

    var token_tro = state.push('tr_open', 'tr', 1);
    token_tro.map = [nextLine, nextLine + 1];

    for (var i$3 = 0; i$3 < columnCount; i$3++) {
      var token_tdo = state.push('td_open', 'td', 1);
      if (aligns[i$3]) {
        token_tdo.attrs  = [['style', 'text-align:' + aligns[i$3]]];
      }

      var token_il$1 = state.push('inline', '', 0);
      token_il$1.content  = columns[i$3] ? columns[i$3].trim() : '';
      token_il$1.children = [];

      state.push('td_close', 'td', -1);
    }
    state.push('tr_close', 'tr', -1);
  }

  if (tbodyLines) {
    state.push('tbody_close', 'tbody', -1);
    tbodyLines[1] = nextLine;
  }

  state.push('table_close', 'table', -1);
  tableLines[1] = nextLine;

  state.parentType = oldParentType;
  state.line = nextLine;
  return true
}// Code block (4 spaces padded)

function code$2 (state, startLine, endLine/*, silent */) {
  if (state.sCount[startLine] - state.blkIndent < 4) { return false }

  var nextLine = startLine + 1;
  var last = nextLine;

  while (nextLine < endLine) {
    if (state.isEmpty(nextLine)) {
      nextLine++;
      continue
    }

    if (state.sCount[nextLine] - state.blkIndent >= 4) {
      nextLine++;
      last = nextLine;
      continue
    }
    break
  }

  state.line = last;

  var token   = state.push('code_block', 'code', 0);
  token.content = state.getLines(startLine, last, 4 + state.blkIndent, false) + '\n';
  token.map     = [startLine, state.line];

  return true
}// fences (``` lang, ~~~ lang)

function fence$2 (state, startLine, endLine, silent) {
  var pos = state.bMarks[startLine] + state.tShift[startLine];
  var max = state.eMarks[startLine];

  // if it's indented more than 3 spaces, it should be a code block
  if (state.sCount[startLine] - state.blkIndent >= 4) { return false }

  if (pos + 3 > max) { return false }

  var marker = state.src.charCodeAt(pos);

  if (marker !== 0x7E/* ~ */ && marker !== 0x60 /* ` */) {
    return false
  }

  // scan marker length
  var mem = pos;
  pos = state.skipChars(pos, marker);

  var len = pos - mem;

  if (len < 3) { return false }

  var markup = state.src.slice(mem, pos);
  var params = state.src.slice(pos, max);

  if (marker === 0x60 /* ` */) {
    if (params.indexOf(String.fromCharCode(marker)) >= 0) {
      return false
    }
  }

  // Since start is found, we can report success here in validation mode
  if (silent) { return true }

  // search end of block
  var nextLine = startLine;
  var haveEndMarker = false;

  for (;;) {
    nextLine++;
    if (nextLine >= endLine) {
      // unclosed block should be autoclosed by end of document.
      // also block seems to be autoclosed by end of parent
      break
    }

    pos = mem = state.bMarks[nextLine] + state.tShift[nextLine];
    max = state.eMarks[nextLine];

    if (pos < max && state.sCount[nextLine] < state.blkIndent) {
      // non-empty line with negative indent should stop the list:
      // - ```
      //  test
      break
    }

    if (state.src.charCodeAt(pos) !== marker) { continue }

    if (state.sCount[nextLine] - state.blkIndent >= 4) {
      // closing fence should be indented less than 4 spaces
      continue
    }

    pos = state.skipChars(pos, marker);

    // closing code fence must be at least as long as the opening one
    if (pos - mem < len) { continue }

    // make sure tail has spaces only
    pos = state.skipSpaces(pos);

    if (pos < max) { continue }

    haveEndMarker = true;
    // found!
    break
  }

  // If a fence has heading spaces, they should be removed from its inner block
  len = state.sCount[startLine];

  state.line = nextLine + (haveEndMarker ? 1 : 0);

  var token   = state.push('fence', 'code', 0);
  token.info    = params;
  token.content = state.getLines(startLine + 1, nextLine, len, true);
  token.markup  = markup;
  token.map     = [startLine, state.line];

  return true
}// Block quotes


function blockquote$2 (state, startLine, endLine, silent) {
  var pos = state.bMarks[startLine] + state.tShift[startLine];
  var max = state.eMarks[startLine];

  var oldLineMax = state.lineMax;

  // if it's indented more than 3 spaces, it should be a code block
  if (state.sCount[startLine] - state.blkIndent >= 4) { return false }

  // check the block quote marker
  if (state.src.charCodeAt(pos) !== 0x3E/* > */) { return false }

  // we know that it's going to be a valid blockquote,
  // so no point trying to find the end of it in silent mode
  if (silent) { return true }

  var oldBMarks  = [];
  var oldBSCount = [];
  var oldSCount  = [];
  var oldTShift  = [];

  var terminatorRules = state.md.block.ruler.getRules('blockquote');

  var oldParentType = state.parentType;
  state.parentType = 'blockquote';
  var lastLineEmpty = false;
  var nextLine;

  // Search the end of the block
  //
  // Block ends with either:
  //  1. an empty line outside:
  //     ```
  //     > test
  //
  //     ```
  //  2. an empty line inside:
  //     ```
  //     >
  //     test
  //     ```
  //  3. another tag:
  //     ```
  //     > test
  //      - - -
  //     ```
  for (nextLine = startLine; nextLine < endLine; nextLine++) {
    // check if it's outdented, i.e. it's inside list item and indented
    // less than said list item:
    //
    // ```
    // 1. anything
    //    > current blockquote
    // 2. checking this line
    // ```
    var isOutdented = state.sCount[nextLine] < state.blkIndent;

    pos = state.bMarks[nextLine] + state.tShift[nextLine];
    max = state.eMarks[nextLine];

    if (pos >= max) {
      // Case 1: line is not inside the blockquote, and this line is empty.
      break
    }

    if (state.src.charCodeAt(pos++) === 0x3E/* > */ && !isOutdented) {
      // This line is inside the blockquote.

      // set offset past spaces and ">"
      var initial = state.sCount[nextLine] + 1;
      var spaceAfterMarker = (void 0);
      var adjustTab = (void 0);

      // skip one optional space after '>'
      if (state.src.charCodeAt(pos) === 0x20 /* space */) {
        // ' >   test '
        //     ^ -- position start of line here:
        pos++;
        initial++;
        adjustTab = false;
        spaceAfterMarker = true;
      } else if (state.src.charCodeAt(pos) === 0x09 /* tab */) {
        spaceAfterMarker = true;

        if ((state.bsCount[nextLine] + initial) % 4 === 3) {
          // '  >\t  test '
          //       ^ -- position start of line here (tab has width===1)
          pos++;
          initial++;
          adjustTab = false;
        } else {
          // ' >\t  test '
          //    ^ -- position start of line here + shift bsCount slightly
          //         to make extra space appear
          adjustTab = true;
        }
      } else {
        spaceAfterMarker = false;
      }

      var offset = initial;
      oldBMarks.push(state.bMarks[nextLine]);
      state.bMarks[nextLine] = pos;

      while (pos < max) {
        var ch = state.src.charCodeAt(pos);

        if (isSpace$e(ch)) {
          if (ch === 0x09) {
            offset += 4 - (offset + state.bsCount[nextLine] + (adjustTab ? 1 : 0)) % 4;
          } else {
            offset++;
          }
        } else {
          break
        }

        pos++;
      }

      lastLineEmpty = pos >= max;

      oldBSCount.push(state.bsCount[nextLine]);
      state.bsCount[nextLine] = state.sCount[nextLine] + 1 + (spaceAfterMarker ? 1 : 0);

      oldSCount.push(state.sCount[nextLine]);
      state.sCount[nextLine] = offset - initial;

      oldTShift.push(state.tShift[nextLine]);
      state.tShift[nextLine] = pos - state.bMarks[nextLine];
      continue
    }

    // Case 2: line is not inside the blockquote, and the last line was empty.
    if (lastLineEmpty) { break }

    // Case 3: another tag found.
    var terminate = false;
    for (var i = 0, l = terminatorRules.length; i < l; i++) {
      if (terminatorRules[i](state, nextLine, endLine, true)) {
        terminate = true;
        break
      }
    }

    if (terminate) {
      // Quirk to enforce "hard termination mode" for paragraphs;
      // normally if you call `tokenize(state, startLine, nextLine)`,
      // paragraphs will look below nextLine for paragraph continuation,
      // but if blockquote is terminated by another tag, they shouldn't
      state.lineMax = nextLine;

      if (state.blkIndent !== 0) {
        // state.blkIndent was non-zero, we now set it to zero,
        // so we need to re-calculate all offsets to appear as
        // if indent wasn't changed
        oldBMarks.push(state.bMarks[nextLine]);
        oldBSCount.push(state.bsCount[nextLine]);
        oldTShift.push(state.tShift[nextLine]);
        oldSCount.push(state.sCount[nextLine]);
        state.sCount[nextLine] -= state.blkIndent;
      }

      break
    }

    oldBMarks.push(state.bMarks[nextLine]);
    oldBSCount.push(state.bsCount[nextLine]);
    oldTShift.push(state.tShift[nextLine]);
    oldSCount.push(state.sCount[nextLine]);

    // A negative indentation means that this is a paragraph continuation
    //
    state.sCount[nextLine] = -1;
  }

  var oldIndent = state.blkIndent;
  state.blkIndent = 0;

  var token_o  = state.push('blockquote_open', 'blockquote', 1);
  token_o.markup = '>';
  var lines = [startLine, 0];
  token_o.map    = lines;

  state.md.block.tokenize(state, startLine, nextLine);

  var token_c  = state.push('blockquote_close', 'blockquote', -1);
  token_c.markup = '>';

  state.lineMax = oldLineMax;
  state.parentType = oldParentType;
  lines[1] = state.line;

  // Restore original tShift; this might not be necessary since the parser
  // has already been here, but just to make sure we can do that.
  for (var i$1 = 0; i$1 < oldTShift.length; i$1++) {
    state.bMarks[i$1 + startLine] = oldBMarks[i$1];
    state.tShift[i$1 + startLine] = oldTShift[i$1];
    state.sCount[i$1 + startLine] = oldSCount[i$1];
    state.bsCount[i$1 + startLine] = oldBSCount[i$1];
  }
  state.blkIndent = oldIndent;

  return true
}// Horizontal rule


function hr$1 (state, startLine, endLine, silent) {
  var max = state.eMarks[startLine];
  // if it's indented more than 3 spaces, it should be a code block
  if (state.sCount[startLine] - state.blkIndent >= 4) { return false }

  var pos = state.bMarks[startLine] + state.tShift[startLine];
  var marker = state.src.charCodeAt(pos++);

  // Check hr marker
  if (marker !== 0x2A/* * */ &&
      marker !== 0x2D/* - */ &&
      marker !== 0x5F/* _ */) {
    return false
  }

  // markers can be mixed with spaces, but there should be at least 3 of them

  var cnt = 1;
  while (pos < max) {
    var ch = state.src.charCodeAt(pos++);
    if (ch !== marker && !isSpace$e(ch)) { return false }
    if (ch === marker) { cnt++; }
  }

  if (cnt < 3) { return false }

  if (silent) { return true }

  state.line = startLine + 1;

  var token  = state.push('hr', 'hr', 0);
  token.map    = [startLine, state.line];
  token.markup = Array(cnt + 1).join(String.fromCharCode(marker));

  return true
}// Lists


// Search `[-+*][\n ]`, returns next pos after marker on success
// or -1 on fail.
function skipBulletListMarker$1 (state, startLine) {
  var max = state.eMarks[startLine];
  var pos = state.bMarks[startLine] + state.tShift[startLine];

  var marker = state.src.charCodeAt(pos++);
  // Check bullet
  if (marker !== 0x2A/* * */ &&
      marker !== 0x2D/* - */ &&
      marker !== 0x2B/* + */) {
    return -1
  }

  if (pos < max) {
    var ch = state.src.charCodeAt(pos);

    if (!isSpace$e(ch)) {
      // " -test " - is not a list item
      return -1
    }
  }

  return pos
}

// Search `\d+[.)][\n ]`, returns next pos after marker on success
// or -1 on fail.
function skipOrderedListMarker$1 (state, startLine) {
  var start = state.bMarks[startLine] + state.tShift[startLine];
  var max = state.eMarks[startLine];
  var pos = start;

  // List marker should have at least 2 chars (digit + dot)
  if (pos + 1 >= max) { return -1 }

  var ch = state.src.charCodeAt(pos++);

  if (ch < 0x30/* 0 */ || ch > 0x39/* 9 */) { return -1 }

  for (;;) {
    // EOL -> fail
    if (pos >= max) { return -1 }

    ch = state.src.charCodeAt(pos++);

    if (ch >= 0x30/* 0 */ && ch <= 0x39/* 9 */) {
      // List marker should have no more than 9 digits
      // (prevents integer overflow in browsers)
      if (pos - start >= 10) { return -1 }

      continue
    }

    // found valid marker
    if (ch === 0x29/* ) */ || ch === 0x2e/* . */) {
      break
    }

    return -1
  }

  if (pos < max) {
    ch = state.src.charCodeAt(pos);

    if (!isSpace$e(ch)) {
      // " 1.test " - is not a list item
      return -1
    }
  }
  return pos
}

function markTightParagraphs$1 (state, idx) {
  var level = state.level + 2;

  for (var i = idx + 2, l = state.tokens.length - 2; i < l; i++) {
    if (state.tokens[i].level === level && state.tokens[i].type === 'paragraph_open') {
      state.tokens[i + 2].hidden = true;
      state.tokens[i].hidden = true;
      i += 2;
    }
  }
}

function list$1 (state, startLine, endLine, silent) {
  var max, pos, start, token;
  var nextLine = startLine;
  var tight = true;

  // if it's indented more than 3 spaces, it should be a code block
  if (state.sCount[nextLine] - state.blkIndent >= 4) { return false }

  // Special case:
  //  - item 1
  //   - item 2
  //    - item 3
  //     - item 4
  //      - this one is a paragraph continuation
  if (state.listIndent >= 0 &&
      state.sCount[nextLine] - state.listIndent >= 4 &&
      state.sCount[nextLine] < state.blkIndent) {
    return false
  }

  var isTerminatingParagraph = false;

  // limit conditions when list can interrupt
  // a paragraph (validation mode only)
  if (silent && state.parentType === 'paragraph') {
    // Next list item should still terminate previous list item;
    //
    // This code can fail if plugins use blkIndent as well as lists,
    // but I hope the spec gets fixed long before that happens.
    //
    if (state.sCount[nextLine] >= state.blkIndent) {
      isTerminatingParagraph = true;
    }
  }

  // Detect list type and position after marker
  var isOrdered;
  var markerValue;
  var posAfterMarker;
  if ((posAfterMarker = skipOrderedListMarker$1(state, nextLine)) >= 0) {
    isOrdered = true;
    start = state.bMarks[nextLine] + state.tShift[nextLine];
    markerValue = Number(state.src.slice(start, posAfterMarker - 1));

    // If we're starting a new ordered list right after
    // a paragraph, it should start with 1.
    if (isTerminatingParagraph && markerValue !== 1) { return false }
  } else if ((posAfterMarker = skipBulletListMarker$1(state, nextLine)) >= 0) {
    isOrdered = false;
  } else {
    return false
  }

  // If we're starting a new unordered list right after
  // a paragraph, first line should not be empty.
  if (isTerminatingParagraph) {
    if (state.skipSpaces(posAfterMarker) >= state.eMarks[nextLine]) { return false }
  }

  // For validation mode we can terminate immediately
  if (silent) { return true }

  // We should terminate list on style change. Remember first one to compare.
  var markerCharCode = state.src.charCodeAt(posAfterMarker - 1);

  // Start list
  var listTokIdx = state.tokens.length;

  if (isOrdered) {
    token       = state.push('ordered_list_open', 'ol', 1);
    if (markerValue !== 1) {
      token.attrs = [['start', markerValue]];
    }
  } else {
    token       = state.push('bullet_list_open', 'ul', 1);
  }

  var listLines = [nextLine, 0];
  token.map    = listLines;
  token.markup = String.fromCharCode(markerCharCode);

  //
  // Iterate list items
  //

  var prevEmptyEnd = false;
  var terminatorRules = state.md.block.ruler.getRules('list');

  var oldParentType = state.parentType;
  state.parentType = 'list';

  while (nextLine < endLine) {
    pos = posAfterMarker;
    max = state.eMarks[nextLine];

    var initial = state.sCount[nextLine] + posAfterMarker - (state.bMarks[nextLine] + state.tShift[nextLine]);
    var offset = initial;

    while (pos < max) {
      var ch = state.src.charCodeAt(pos);

      if (ch === 0x09) {
        offset += 4 - (offset + state.bsCount[nextLine]) % 4;
      } else if (ch === 0x20) {
        offset++;
      } else {
        break
      }

      pos++;
    }

    var contentStart = pos;
    var indentAfterMarker = (void 0);

    if (contentStart >= max) {
      // trimming space in "-    \n  3" case, indent is 1 here
      indentAfterMarker = 1;
    } else {
      indentAfterMarker = offset - initial;
    }

    // If we have more than 4 spaces, the indent is 1
    // (the rest is just indented code block)
    if (indentAfterMarker > 4) { indentAfterMarker = 1; }

    // "  -  test"
    //  ^^^^^ - calculating total length of this thing
    var indent = initial + indentAfterMarker;

    // Run subparser & write tokens
    token        = state.push('list_item_open', 'li', 1);
    token.markup = String.fromCharCode(markerCharCode);
    var itemLines = [nextLine, 0];
    token.map    = itemLines;
    if (isOrdered) {
      token.info = state.src.slice(start, posAfterMarker - 1);
    }

    // change current state, then restore it after parser subcall
    var oldTight = state.tight;
    var oldTShift = state.tShift[nextLine];
    var oldSCount = state.sCount[nextLine];

    //  - example list
    // ^ listIndent position will be here
    //   ^ blkIndent position will be here
    //
    var oldListIndent = state.listIndent;
    state.listIndent = state.blkIndent;
    state.blkIndent = indent;

    state.tight = true;
    state.tShift[nextLine] = contentStart - state.bMarks[nextLine];
    state.sCount[nextLine] = offset;

    if (contentStart >= max && state.isEmpty(nextLine + 1)) {
      // workaround for this case
      // (list item is empty, list terminates before "foo"):
      // ~~~~~~~~
      //   -
      //
      //     foo
      // ~~~~~~~~
      state.line = Math.min(state.line + 2, endLine);
    } else {
      state.md.block.tokenize(state, nextLine, endLine, true);
    }

    // If any of list item is tight, mark list as tight
    if (!state.tight || prevEmptyEnd) {
      tight = false;
    }
    // Item become loose if finish with empty line,
    // but we should filter last element, because it means list finish
    prevEmptyEnd = (state.line - nextLine) > 1 && state.isEmpty(state.line - 1);

    state.blkIndent = state.listIndent;
    state.listIndent = oldListIndent;
    state.tShift[nextLine] = oldTShift;
    state.sCount[nextLine] = oldSCount;
    state.tight = oldTight;

    token        = state.push('list_item_close', 'li', -1);
    token.markup = String.fromCharCode(markerCharCode);

    nextLine = state.line;
    itemLines[1] = nextLine;

    if (nextLine >= endLine) { break }

    //
    // Try to check if list is terminated or continued.
    //
    if (state.sCount[nextLine] < state.blkIndent) { break }

    // if it's indented more than 3 spaces, it should be a code block
    if (state.sCount[nextLine] - state.blkIndent >= 4) { break }

    // fail if terminating block found
    var terminate = false;
    for (var i = 0, l = terminatorRules.length; i < l; i++) {
      if (terminatorRules[i](state, nextLine, endLine, true)) {
        terminate = true;
        break
      }
    }
    if (terminate) { break }

    // fail if list has another type
    if (isOrdered) {
      posAfterMarker = skipOrderedListMarker$1(state, nextLine);
      if (posAfterMarker < 0) { break }
      start = state.bMarks[nextLine] + state.tShift[nextLine];
    } else {
      posAfterMarker = skipBulletListMarker$1(state, nextLine);
      if (posAfterMarker < 0) { break }
    }

    if (markerCharCode !== state.src.charCodeAt(posAfterMarker - 1)) { break }
  }

  // Finalize list
  if (isOrdered) {
    token = state.push('ordered_list_close', 'ol', -1);
  } else {
    token = state.push('bullet_list_close', 'ul', -1);
  }
  token.markup = String.fromCharCode(markerCharCode);

  listLines[1] = nextLine;
  state.line = nextLine;

  state.parentType = oldParentType;

  // mark paragraphs tight if needed
  if (tight) {
    markTightParagraphs$1(state, listTokIdx);
  }

  return true
}function reference$1 (state, startLine, _endLine, silent) {
  var pos = state.bMarks[startLine] + state.tShift[startLine];
  var max = state.eMarks[startLine];
  var nextLine = startLine + 1;

  // if it's indented more than 3 spaces, it should be a code block
  if (state.sCount[startLine] - state.blkIndent >= 4) { return false }

  if (state.src.charCodeAt(pos) !== 0x5B/* [ */) { return false }

  function getNextLine (nextLine) {
    var endLine = state.lineMax;

    if (nextLine >= endLine || state.isEmpty(nextLine)) {
      // empty line or end of input
      return null
    }

    var isContinuation = false;

    // this would be a code block normally, but after paragraph
    // it's considered a lazy continuation regardless of what's there
    if (state.sCount[nextLine] - state.blkIndent > 3) { isContinuation = true; }

    // quirk for blockquotes, this line should already be checked by that rule
    if (state.sCount[nextLine] < 0) { isContinuation = true; }

    if (!isContinuation) {
      var terminatorRules = state.md.block.ruler.getRules('reference');
      var oldParentType = state.parentType;
      state.parentType = 'reference';

      // Some tags can terminate paragraph without empty line.
      var terminate = false;
      for (var i = 0, l = terminatorRules.length; i < l; i++) {
        if (terminatorRules[i](state, nextLine, endLine, true)) {
          terminate = true;
          break
        }
      }

      state.parentType = oldParentType;
      if (terminate) {
        // terminated by another block
        return null
      }
    }

    var pos = state.bMarks[nextLine] + state.tShift[nextLine];
    var max = state.eMarks[nextLine];

    // max + 1 explicitly includes the newline
    return state.src.slice(pos, max + 1)
  }

  var str = state.src.slice(pos, max + 1);

  max = str.length;
  var labelEnd = -1;

  for (pos = 1; pos < max; pos++) {
    var ch = str.charCodeAt(pos);
    if (ch === 0x5B /* [ */) {
      return false
    } else if (ch === 0x5D /* ] */) {
      labelEnd = pos;
      break
    } else if (ch === 0x0A /* \n */) {
      var lineContent = getNextLine(nextLine);
      if (lineContent !== null) {
        str += lineContent;
        max = str.length;
        nextLine++;
      }
    } else if (ch === 0x5C /* \ */) {
      pos++;
      if (pos < max && str.charCodeAt(pos) === 0x0A) {
        var lineContent$1 = getNextLine(nextLine);
        if (lineContent$1 !== null) {
          str += lineContent$1;
          max = str.length;
          nextLine++;
        }
      }
    }
  }

  if (labelEnd < 0 || str.charCodeAt(labelEnd + 1) !== 0x3A/* : */) { return false }

  // [label]:   destination   'title'
  //         ^^^ skip optional whitespace here
  for (pos = labelEnd + 2; pos < max; pos++) {
    var ch$1 = str.charCodeAt(pos);
    if (ch$1 === 0x0A) {
      var lineContent$2 = getNextLine(nextLine);
      if (lineContent$2 !== null) {
        str += lineContent$2;
        max = str.length;
        nextLine++;
      }
    } else if (isSpace$e(ch$1)) ; else {
      break
    }
  }

  // [label]:   destination   'title'
  //            ^^^^^^^^^^^ parse this
  var destRes = state.md.helpers.parseLinkDestination(str, pos, max);
  if (!destRes.ok) { return false }

  var href = state.md.normalizeLink(destRes.str);
  if (!state.md.validateLink(href)) { return false }

  pos = destRes.pos;

  // save cursor state, we could require to rollback later
  var destEndPos = pos;
  var destEndLineNo = nextLine;

  // [label]:   destination   'title'
  //                       ^^^ skipping those spaces
  var start = pos;
  for (; pos < max; pos++) {
    var ch$2 = str.charCodeAt(pos);
    if (ch$2 === 0x0A) {
      var lineContent$3 = getNextLine(nextLine);
      if (lineContent$3 !== null) {
        str += lineContent$3;
        max = str.length;
        nextLine++;
      }
    } else if (isSpace$e(ch$2)) ; else {
      break
    }
  }

  // [label]:   destination   'title'
  //                          ^^^^^^^ parse this
  var titleRes = state.md.helpers.parseLinkTitle(str, pos, max);
  while (titleRes.can_continue) {
    var lineContent$4 = getNextLine(nextLine);
    if (lineContent$4 === null) { break }
    str += lineContent$4;
    pos = max;
    max = str.length;
    nextLine++;
    titleRes = state.md.helpers.parseLinkTitle(str, pos, max, titleRes);
  }
  var title;

  if (pos < max && start !== pos && titleRes.ok) {
    title = titleRes.str;
    pos = titleRes.pos;
  } else {
    title = '';
    pos = destEndPos;
    nextLine = destEndLineNo;
  }

  // skip trailing spaces until the rest of the line
  while (pos < max) {
    var ch$3 = str.charCodeAt(pos);
    if (!isSpace$e(ch$3)) { break }
    pos++;
  }

  if (pos < max && str.charCodeAt(pos) !== 0x0A) {
    if (title) {
      // garbage at the end of the line after title,
      // but it could still be a valid reference if we roll back
      title = '';
      pos = destEndPos;
      nextLine = destEndLineNo;
      while (pos < max) {
        var ch$4 = str.charCodeAt(pos);
        if (!isSpace$e(ch$4)) { break }
        pos++;
      }
    }
  }

  if (pos < max && str.charCodeAt(pos) !== 0x0A) {
    // garbage at the end of the line
    return false
  }

  var label = normalizeReference$3(str.slice(1, labelEnd));
  if (!label) {
    // CommonMark 0.20 disallows empty labels
    return false
  }

  // Reference can not terminate anything. This check is for safety only.
  /* istanbul ignore if */
  if (silent) { return true }

  if (typeof state.env.references === 'undefined') {
    state.env.references = {};
  }
  if (typeof state.env.references[label] === 'undefined') {
    state.env.references[label] = { title: title, href: href };
  }

  state.line = nextLine;
  return true
}// List of valid html blocks names, according to commonmark spec
// https://spec.commonmark.org/0.30/#html-blocks

var block_names$1 = [
  'address',
  'article',
  'aside',
  'base',
  'basefont',
  'blockquote',
  'body',
  'caption',
  'center',
  'col',
  'colgroup',
  'dd',
  'details',
  'dialog',
  'dir',
  'div',
  'dl',
  'dt',
  'fieldset',
  'figcaption',
  'figure',
  'footer',
  'form',
  'frame',
  'frameset',
  'h1',
  'h2',
  'h3',
  'h4',
  'h5',
  'h6',
  'head',
  'header',
  'hr',
  'html',
  'iframe',
  'legend',
  'li',
  'link',
  'main',
  'menu',
  'menuitem',
  'nav',
  'noframes',
  'ol',
  'optgroup',
  'option',
  'p',
  'param',
  'search',
  'section',
  'summary',
  'table',
  'tbody',
  'td',
  'tfoot',
  'th',
  'thead',
  'title',
  'tr',
  'track',
  'ul'
];// Regexps to match html elements

var attr_name$1     = '[a-zA-Z_:][a-zA-Z0-9:._-]*';

var unquoted$1      = '[^"\'=<>`\\x00-\\x20]+';
var single_quoted$1 = "'[^']*'";
var double_quoted$1 = '"[^"]*"';

var attr_value$1  = '(?:' + unquoted$1 + '|' + single_quoted$1 + '|' + double_quoted$1 + ')';

var attribute$1   = '(?:\\s+' + attr_name$1 + '(?:\\s*=\\s*' + attr_value$1 + ')?)';

var open_tag$1    = '<[A-Za-z][A-Za-z0-9\\-]*' + attribute$1 + '*\\s*\\/?>';

var close_tag$1   = '<\\/[A-Za-z][A-Za-z0-9\\-]*\\s*>';
var comment$2     = '<!---?>|<!--(?:[^-]|-[^-]|--[^>])*-->';
var processing$1  = '<[?][\\s\\S]*?[?]>';
var declaration$1 = '<![A-Za-z][^>]*>';
var cdata$1       = '<!\\[CDATA\\[[\\s\\S]*?\\]\\]>';

var HTML_TAG_RE$2 = new RegExp('^(?:' + open_tag$1 + '|' + close_tag$1 + '|' + comment$2 +
                        '|' + processing$1 + '|' + declaration$1 + '|' + cdata$1 + ')');
var HTML_OPEN_CLOSE_TAG_RE$2 = new RegExp('^(?:' + open_tag$1 + '|' + close_tag$1 + ')');// HTML block


// An array of opening and corresponding closing sequences for html tags,
// last argument defines whether it can terminate a paragraph or not
//
var HTML_SEQUENCES$1 = [
  [/^<(script|pre|style|textarea)(?=(\s|>|$))/i, /<\/(script|pre|style|textarea)>/i, true],
  [/^<!--/,        /-->/,   true],
  [/^<\?/,         /\?>/,   true],
  [/^<![A-Z]/,     />/,     true],
  [/^<!\[CDATA\[/, /\]\]>/, true],
  [new RegExp('^</?(' + block_names$1.join('|') + ')(?=(\\s|/?>|$))', 'i'), /^$/, true],
  [new RegExp(HTML_OPEN_CLOSE_TAG_RE$2.source + '\\s*$'),  /^$/, false]
];

function html_block$1 (state, startLine, endLine, silent) {
  var pos = state.bMarks[startLine] + state.tShift[startLine];
  var max = state.eMarks[startLine];

  // if it's indented more than 3 spaces, it should be a code block
  if (state.sCount[startLine] - state.blkIndent >= 4) { return false }

  if (!state.md.options.html) { return false }

  if (state.src.charCodeAt(pos) !== 0x3C/* < */) { return false }

  var lineText = state.src.slice(pos, max);

  var i = 0;
  for (; i < HTML_SEQUENCES$1.length; i++) {
    if (HTML_SEQUENCES$1[i][0].test(lineText)) { break }
  }
  if (i === HTML_SEQUENCES$1.length) { return false }

  if (silent) {
    // true if this sequence can be a terminator, false otherwise
    return HTML_SEQUENCES$1[i][2]
  }

  var nextLine = startLine + 1;

  // If we are here - we detected HTML block.
  // Let's roll down till block end.
  if (!HTML_SEQUENCES$1[i][1].test(lineText)) {
    for (; nextLine < endLine; nextLine++) {
      if (state.sCount[nextLine] < state.blkIndent) { break }

      pos = state.bMarks[nextLine] + state.tShift[nextLine];
      max = state.eMarks[nextLine];
      lineText = state.src.slice(pos, max);

      if (HTML_SEQUENCES$1[i][1].test(lineText)) {
        if (lineText.length !== 0) { nextLine++; }
        break
      }
    }
  }

  state.line = nextLine;

  var token   = state.push('html_block', '', 0);
  token.map     = [startLine, nextLine];
  token.content = state.getLines(startLine, nextLine, state.blkIndent, true);

  return true
}// heading (#, ##, ...)


function heading$3 (state, startLine, endLine, silent) {
  var pos = state.bMarks[startLine] + state.tShift[startLine];
  var max = state.eMarks[startLine];

  // if it's indented more than 3 spaces, it should be a code block
  if (state.sCount[startLine] - state.blkIndent >= 4) { return false }

  var ch  = state.src.charCodeAt(pos);

  if (ch !== 0x23/* # */ || pos >= max) { return false }

  // count heading level
  var level = 1;
  ch = state.src.charCodeAt(++pos);
  while (ch === 0x23/* # */ && pos < max && level <= 6) {
    level++;
    ch = state.src.charCodeAt(++pos);
  }

  if (level > 6 || (pos < max && !isSpace$e(ch))) { return false }

  if (silent) { return true }

  // Let's cut tails like '    ###  ' from the end of string

  max = state.skipSpacesBack(max, pos);
  var tmp = state.skipCharsBack(max, 0x23, pos); // #
  if (tmp > pos && isSpace$e(state.src.charCodeAt(tmp - 1))) {
    max = tmp;
  }

  state.line = startLine + 1;

  var token_o  = state.push('heading_open', 'h' + String(level), 1);
  token_o.markup = '########'.slice(0, level);
  token_o.map    = [startLine, state.line];

  var token_i    = state.push('inline', '', 0);
  token_i.content  = state.src.slice(pos, max).trim();
  token_i.map      = [startLine, state.line];
  token_i.children = [];

  var token_c  = state.push('heading_close', 'h' + String(level), -1);
  token_c.markup = '########'.slice(0, level);

  return true
}// lheading (---, ===)

function lheading$1 (state, startLine, endLine/*, silent */) {
  var terminatorRules = state.md.block.ruler.getRules('paragraph');

  // if it's indented more than 3 spaces, it should be a code block
  if (state.sCount[startLine] - state.blkIndent >= 4) { return false }

  var oldParentType = state.parentType;
  state.parentType = 'paragraph'; // use paragraph to match terminatorRules

  // jump line-by-line until empty one or EOF
  var level = 0;
  var marker;
  var nextLine = startLine + 1;

  for (; nextLine < endLine && !state.isEmpty(nextLine); nextLine++) {
    // this would be a code block normally, but after paragraph
    // it's considered a lazy continuation regardless of what's there
    if (state.sCount[nextLine] - state.blkIndent > 3) { continue }

    //
    // Check for underline in setext header
    //
    if (state.sCount[nextLine] >= state.blkIndent) {
      var pos = state.bMarks[nextLine] + state.tShift[nextLine];
      var max = state.eMarks[nextLine];

      if (pos < max) {
        marker = state.src.charCodeAt(pos);

        if (marker === 0x2D/* - */ || marker === 0x3D/* = */) {
          pos = state.skipChars(pos, marker);
          pos = state.skipSpaces(pos);

          if (pos >= max) {
            level = (marker === 0x3D/* = */ ? 1 : 2);
            break
          }
        }
      }
    }

    // quirk for blockquotes, this line should already be checked by that rule
    if (state.sCount[nextLine] < 0) { continue }

    // Some tags can terminate paragraph without empty line.
    var terminate = false;
    for (var i = 0, l = terminatorRules.length; i < l; i++) {
      if (terminatorRules[i](state, nextLine, endLine, true)) {
        terminate = true;
        break
      }
    }
    if (terminate) { break }
  }

  if (!level) {
    // Didn't find valid underline
    return false
  }

  var content = state.getLines(startLine, nextLine, state.blkIndent, false).trim();

  state.line = nextLine + 1;

  var token_o    = state.push('heading_open', 'h' + String(level), 1);
  token_o.markup   = String.fromCharCode(marker);
  token_o.map      = [startLine, state.line];

  var token_i    = state.push('inline', '', 0);
  token_i.content  = content;
  token_i.map      = [startLine, state.line - 1];
  token_i.children = [];

  var token_c    = state.push('heading_close', 'h' + String(level), -1);
  token_c.markup   = String.fromCharCode(marker);

  state.parentType = oldParentType;

  return true
}// Paragraph

function paragraph$2 (state, startLine, endLine) {
  var terminatorRules = state.md.block.ruler.getRules('paragraph');
  var oldParentType = state.parentType;
  var nextLine = startLine + 1;
  state.parentType = 'paragraph';

  // jump line-by-line until empty one or EOF
  for (; nextLine < endLine && !state.isEmpty(nextLine); nextLine++) {
    // this would be a code block normally, but after paragraph
    // it's considered a lazy continuation regardless of what's there
    if (state.sCount[nextLine] - state.blkIndent > 3) { continue }

    // quirk for blockquotes, this line should already be checked by that rule
    if (state.sCount[nextLine] < 0) { continue }

    // Some tags can terminate paragraph without empty line.
    var terminate = false;
    for (var i = 0, l = terminatorRules.length; i < l; i++) {
      if (terminatorRules[i](state, nextLine, endLine, true)) {
        terminate = true;
        break
      }
    }
    if (terminate) { break }
  }

  var content = state.getLines(startLine, nextLine, state.blkIndent, false).trim();

  state.line = nextLine;

  var token_o    = state.push('paragraph_open', 'p', 1);
  token_o.map      = [startLine, state.line];

  var token_i    = state.push('inline', '', 0);
  token_i.content  = content;
  token_i.map      = [startLine, state.line];
  token_i.children = [];

  state.push('paragraph_close', 'p', -1);

  state.parentType = oldParentType;

  return true
}/** internal
 * class ParserBlock
 *
 * Block-level tokenizer.
 **/


var _rules$4 = [
  // First 2 params - rule name & source. Secondary array - list of rules,
  // which can be terminated by this one.
  ['table',      table$2,      ['paragraph', 'reference']],
  ['code',       code$2],
  ['fence',      fence$2,      ['paragraph', 'reference', 'blockquote', 'list']],
  ['blockquote', blockquote$2, ['paragraph', 'reference', 'blockquote', 'list']],
  ['hr',         hr$1,         ['paragraph', 'reference', 'blockquote', 'list']],
  ['list',       list$1,       ['paragraph', 'reference', 'blockquote']],
  ['reference',  reference$1],
  ['html_block', html_block$1, ['paragraph', 'reference', 'blockquote']],
  ['heading',    heading$3,    ['paragraph', 'reference', 'blockquote']],
  ['lheading',   lheading$1],
  ['paragraph',  paragraph$2]
];

/**
 * new ParserBlock()
 **/
function ParserBlock$2 () {
  /**
   * ParserBlock#ruler -> Ruler
   *
   * [[Ruler]] instance. Keep configuration of block rules.
   **/
  this.ruler = new Ruler$4();

  for (var i = 0; i < _rules$4.length; i++) {
    this.ruler.push(_rules$4[i][0], _rules$4[i][1], { alt: (_rules$4[i][2] || []).slice() });
  }
}

// Generate tokens for input range
//
ParserBlock$2.prototype.tokenize = function (state, startLine, endLine) {
  var rules = this.ruler.getRules('');
  var len = rules.length;
  var maxNesting = state.md.options.maxNesting;
  var line = startLine;
  var hasEmptyLines = false;

  while (line < endLine) {
    state.line = line = state.skipEmptyLines(line);
    if (line >= endLine) { break }

    // Termination condition for nested calls.
    // Nested calls currently used for blockquotes & lists
    if (state.sCount[line] < state.blkIndent) { break }

    // If nesting level exceeded - skip tail to the end. That's not ordinary
    // situation and we should not care about content.
    if (state.level >= maxNesting) {
      state.line = endLine;
      break
    }

    // Try all possible rules.
    // On success, rule should:
    //
    // - update `state.line`
    // - update `state.tokens`
    // - return true
    var prevLine = state.line;
    var ok = false;

    for (var i = 0; i < len; i++) {
      ok = rules[i](state, line, endLine, false);
      if (ok) {
        if (prevLine >= state.line) {
          throw new Error("block rule didn't increment state.line")
        }
        break
      }
    }

    // this can only happen if user disables paragraph rule
    if (!ok) { throw new Error('none of the block rules matched') }

    // set state.tight if we had an empty line before current tag
    // i.e. latest empty line should not count
    state.tight = !hasEmptyLines;

    // paragraph might "eat" one newline after it in nested lists
    if (state.isEmpty(state.line - 1)) {
      hasEmptyLines = true;
    }

    line = state.line;

    if (line < endLine && state.isEmpty(line)) {
      hasEmptyLines = true;
      line++;
      state.line = line;
    }
  }
};

/**
 * ParserBlock.parse(str, md, env, outTokens)
 *
 * Process input string and push block tokens into `outTokens`
 **/
ParserBlock$2.prototype.parse = function (src, md, env, outTokens) {
  if (!src) { return }

  var state = new this.State(src, md, env, outTokens);

  this.tokenize(state, state.line, state.lineMax);
};

ParserBlock$2.prototype.State = StateBlock$1;// Inline parser state


function StateInline$1 (src, md, env, outTokens) {
  this.src = src;
  this.env = env;
  this.md = md;
  this.tokens = outTokens;
  this.tokens_meta = Array(outTokens.length);

  this.pos = 0;
  this.posMax = this.src.length;
  this.level = 0;
  this.pending = '';
  this.pendingLevel = 0;

  // Stores { start: end } pairs. Useful for backtrack
  // optimization of pairs parse (emphasis, strikes).
  this.cache = {};

  // List of emphasis-like delimiters for current tag
  this.delimiters = [];

  // Stack of delimiter lists for upper level tags
  this._prev_delimiters = [];

  // backtick length => last seen position
  this.backticks = {};
  this.backticksScanned = false;

  // Counter used to disable inline linkify-it execution
  // inside <a> and markdown links
  this.linkLevel = 0;
}

// Flush pending text
//
StateInline$1.prototype.pushPending = function () {
  var token = new Token$4('text', '', 0);
  token.content = this.pending;
  token.level = this.pendingLevel;
  this.tokens.push(token);
  this.pending = '';
  return token
};

// Push new token to "stream".
// If pending text exists - flush it as text token
//
StateInline$1.prototype.push = function (type, tag, nesting) {
  if (this.pending) {
    this.pushPending();
  }

  var token = new Token$4(type, tag, nesting);
  var token_meta = null;

  if (nesting < 0) {
    // closing tag
    this.level--;
    this.delimiters = this._prev_delimiters.pop();
  }

  token.level = this.level;

  if (nesting > 0) {
    // opening tag
    this.level++;
    this._prev_delimiters.push(this.delimiters);
    this.delimiters = [];
    token_meta = { delimiters: this.delimiters };
  }

  this.pendingLevel = this.level;
  this.tokens.push(token);
  this.tokens_meta.push(token_meta);
  return token
};

// Scan a sequence of emphasis-like markers, and determine whether
// it can start an emphasis sequence or end an emphasis sequence.
//
//  - start - position to scan from (it should point at a valid marker);
//  - canSplitWord - determine if these markers can be found inside a word
//
StateInline$1.prototype.scanDelims = function (start, canSplitWord) {
  var max = this.posMax;
  var marker = this.src.charCodeAt(start);

  // treat beginning of the line as a whitespace
  var lastChar = start > 0 ? this.src.charCodeAt(start - 1) : 0x20;

  var pos = start;
  while (pos < max && this.src.charCodeAt(pos) === marker) { pos++; }

  var count = pos - start;

  // treat end of the line as a whitespace
  var nextChar = pos < max ? this.src.charCodeAt(pos) : 0x20;

  var isLastPunctChar = isMdAsciiPunct$2(lastChar) || isPunctChar$2(String.fromCharCode(lastChar));
  var isNextPunctChar = isMdAsciiPunct$2(nextChar) || isPunctChar$2(String.fromCharCode(nextChar));

  var isLastWhiteSpace = isWhiteSpace$2(lastChar);
  var isNextWhiteSpace = isWhiteSpace$2(nextChar);

  var left_flanking =
    !isNextWhiteSpace && (!isNextPunctChar || isLastWhiteSpace || isLastPunctChar);
  var right_flanking =
    !isLastWhiteSpace && (!isLastPunctChar || isNextWhiteSpace || isNextPunctChar);

  var can_open  = left_flanking  && (canSplitWord || !right_flanking || isLastPunctChar);
  var can_close = right_flanking && (canSplitWord || !left_flanking  || isNextPunctChar);

  return { can_open: can_open, can_close: can_close, length: count }
};

// re-export Token class to use in block rules
StateInline$1.prototype.Token = Token$4;// Skip text characters for text token, place those to pending buffer
// and increment current pos

// Rule to skip pure text
// '{}$%@~+=:' reserved for extentions

// !, ", #, $, %, &, ', (, ), *, +, ,, -, ., /, :, ;, <, =, >, ?, @, [, \, ], ^, _, `, {, |, }, or ~

// !!!! Don't confuse with "Markdown ASCII Punctuation" chars
// http://spec.commonmark.org/0.15/#ascii-punctuation-character
function isTerminatorChar$1 (ch) {
  switch (ch) {
    case 0x0A/* \n */:
    case 0x21/* ! */:
    case 0x23/* # */:
    case 0x24/* $ */:
    case 0x25/* % */:
    case 0x26/* & */:
    case 0x2A/* * */:
    case 0x2B/* + */:
    case 0x2D/* - */:
    case 0x3A/* : */:
    case 0x3C/* < */:
    case 0x3D/* = */:
    case 0x3E/* > */:
    case 0x40/* @ */:
    case 0x5B/* [ */:
    case 0x5C/* \ */:
    case 0x5D/* ] */:
    case 0x5E/* ^ */:
    case 0x5F/* _ */:
    case 0x60/* ` */:
    case 0x7B/* { */:
    case 0x7D/* } */:
    case 0x7E/* ~ */:
      return true
    default:
      return false
  }
}

function text$2 (state, silent) {
  var pos = state.pos;

  while (pos < state.posMax && !isTerminatorChar$1(state.src.charCodeAt(pos))) {
    pos++;
  }

  if (pos === state.pos) { return false }

  if (!silent) { state.pending += state.src.slice(state.pos, pos); }

  state.pos = pos;

  return true
}

// Alternative implementation, for memory.
//
// It costs 10% of performance, but allows extend terminators list, if place it
// to `ParserInline` property. Probably, will switch to it sometime, such
// flexibility required.

/*
var TERMINATOR_RE = /[\n!#$%&*+\-:<=>@[\\\]^_`{}~]/;

module.exports = function text(state, silent) {
  var pos = state.pos,
      idx = state.src.slice(pos).search(TERMINATOR_RE);

  // first char is terminator -> empty text
  if (idx === 0) { return false; }

  // no terminator -> text till end of string
  if (idx < 0) {
    if (!silent) { state.pending += state.src.slice(pos); }
    state.pos = state.src.length;
    return true;
  }

  if (!silent) { state.pending += state.src.slice(pos, pos + idx); }

  state.pos += idx;

  return true;
}; */// Process links like https://example.org/

// RFC3986: scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
var SCHEME_RE$1 = /(?:^|[^a-z0-9.+-])([a-z][a-z0-9.+-]*)$/i;

function linkify$3 (state, silent) {
  if (!state.md.options.linkify) { return false }
  if (state.linkLevel > 0) { return false }

  var pos = state.pos;
  var max = state.posMax;

  if (pos + 3 > max) { return false }
  if (state.src.charCodeAt(pos) !== 0x3A/* : */) { return false }
  if (state.src.charCodeAt(pos + 1) !== 0x2F/* / */) { return false }
  if (state.src.charCodeAt(pos + 2) !== 0x2F/* / */) { return false }

  var match = state.pending.match(SCHEME_RE$1);
  if (!match) { return false }

  var proto = match[1];

  var link = state.md.linkify.matchAtStart(state.src.slice(pos - proto.length));
  if (!link) { return false }

  var url = link.url;

  // invalid link, but still detected by linkify somehow;
  // need to check to prevent infinite loop below
  if (url.length <= proto.length) { return false }

  // disallow '*' at the end of the link (conflicts with emphasis)
  url = url.replace(/\*+$/, '');

  var fullUrl = state.md.normalizeLink(url);
  if (!state.md.validateLink(fullUrl)) { return false }

  if (!silent) {
    state.pending = state.pending.slice(0, -proto.length);

    var token_o = state.push('link_open', 'a', 1);
    token_o.attrs = [['href', fullUrl]];
    token_o.markup = 'linkify';
    token_o.info = 'auto';

    var token_t = state.push('text', '', 0);
    token_t.content = state.md.normalizeLinkText(url);

    var token_c = state.push('link_close', 'a', -1);
    token_c.markup = 'linkify';
    token_c.info = 'auto';
  }

  state.pos += url.length - proto.length;
  return true
}// Proceess '\n'


function newline$2 (state, silent) {
  var pos = state.pos;

  if (state.src.charCodeAt(pos) !== 0x0A/* \n */) { return false }

  var pmax = state.pending.length - 1;
  var max = state.posMax;

  // '  \n' -> hardbreak
  // Lookup in pending chars is bad practice! Don't copy to other rules!
  // Pending string is stored in concat mode, indexed lookups will cause
  // convertion to flat mode.
  if (!silent) {
    if (pmax >= 0 && state.pending.charCodeAt(pmax) === 0x20) {
      if (pmax >= 1 && state.pending.charCodeAt(pmax - 1) === 0x20) {
        // Find whitespaces tail of pending chars.
        var ws = pmax - 1;
        while (ws >= 1 && state.pending.charCodeAt(ws - 1) === 0x20) { ws--; }

        state.pending = state.pending.slice(0, ws);
        state.push('hardbreak', 'br', 0);
      } else {
        state.pending = state.pending.slice(0, -1);
        state.push('softbreak', 'br', 0);
      }
    } else {
      state.push('softbreak', 'br', 0);
    }
  }

  pos++;

  // skip heading spaces for next line
  while (pos < max && isSpace$e(state.src.charCodeAt(pos))) { pos++; }

  state.pos = pos;
  return true
}// Process escaped chars and hardbreaks


var ESCAPED$1 = [];

for (var i$3 = 0; i$3 < 256; i$3++) { ESCAPED$1.push(0); }

'\\!"#$%&\'()*+,./:;<=>?@[]^_`{|}~-'
  .split('').forEach(function (ch) { ESCAPED$1[ch.charCodeAt(0)] = 1; });

function escape (state, silent) {
  var pos = state.pos;
  var max = state.posMax;

  if (state.src.charCodeAt(pos) !== 0x5C/* \ */) { return false }
  pos++;

  // '\' at the end of the inline block
  if (pos >= max) { return false }

  var ch1 = state.src.charCodeAt(pos);

  if (ch1 === 0x0A) {
    if (!silent) {
      state.push('hardbreak', 'br', 0);
    }

    pos++;
    // skip leading whitespaces from next line
    while (pos < max) {
      ch1 = state.src.charCodeAt(pos);
      if (!isSpace$e(ch1)) { break }
      pos++;
    }

    state.pos = pos;
    return true
  }

  var escapedStr = state.src[pos];

  if (ch1 >= 0xD800 && ch1 <= 0xDBFF && pos + 1 < max) {
    var ch2 = state.src.charCodeAt(pos + 1);

    if (ch2 >= 0xDC00 && ch2 <= 0xDFFF) {
      escapedStr += state.src[pos + 1];
      pos++;
    }
  }

  var origStr = '\\' + escapedStr;

  if (!silent) {
    var token = state.push('text_special', '', 0);

    if (ch1 < 256 && ESCAPED$1[ch1] !== 0) {
      token.content = escapedStr;
    } else {
      token.content = origStr;
    }

    token.markup = origStr;
    token.info   = 'escape';
  }

  state.pos = pos + 1;
  return true
}// Parse backticks

function backtick (state, silent) {
  var pos = state.pos;
  var ch = state.src.charCodeAt(pos);

  if (ch !== 0x60/* ` */) { return false }

  var start = pos;
  pos++;
  var max = state.posMax;

  // scan marker length
  while (pos < max && state.src.charCodeAt(pos) === 0x60/* ` */) { pos++; }

  var marker = state.src.slice(start, pos);
  var openerLength = marker.length;

  if (state.backticksScanned && (state.backticks[openerLength] || 0) <= start) {
    if (!silent) { state.pending += marker; }
    state.pos += openerLength;
    return true
  }

  var matchEnd = pos;
  var matchStart;

  // Nothing found in the cache, scan until the end of the line (or until marker is found)
  while ((matchStart = state.src.indexOf('`', matchEnd)) !== -1) {
    matchEnd = matchStart + 1;

    // scan marker length
    while (matchEnd < max && state.src.charCodeAt(matchEnd) === 0x60/* ` */) { matchEnd++; }

    var closerLength = matchEnd - matchStart;

    if (closerLength === openerLength) {
      // Found matching closer length.
      if (!silent) {
        var token = state.push('code_inline', 'code', 0);
        token.markup = marker;
        token.content = state.src.slice(pos, matchStart)
          .replace(/\n/g, ' ')
          .replace(/^ (.+) $/, '$1');
      }
      state.pos = matchEnd;
      return true
    }

    // Some different length found, put it in cache as upper limit of where closer can be found
    state.backticks[closerLength] = matchStart;
  }

  // Scanned through the end, didn't find anything
  state.backticksScanned = true;

  if (!silent) { state.pending += marker; }
  state.pos += openerLength;
  return true
}// ~~strike through~~
//

// Insert each marker as a separate text token, and add it to delimiter list
//
function strikethrough_tokenize (state, silent) {
  var start = state.pos;
  var marker = state.src.charCodeAt(start);

  if (silent) { return false }

  if (marker !== 0x7E/* ~ */) { return false }

  var scanned = state.scanDelims(state.pos, true);
  var len = scanned.length;
  var ch = String.fromCharCode(marker);

  if (len < 2) { return false }

  var token;

  if (len % 2) {
    token         = state.push('text', '', 0);
    token.content = ch;
    len--;
  }

  for (var i = 0; i < len; i += 2) {
    token         = state.push('text', '', 0);
    token.content = ch + ch;

    state.delimiters.push({
      marker: marker,
      length: 0,     // disable "rule of 3" length checks meant for emphasis
      token: state.tokens.length - 1,
      end: -1,
      open: scanned.can_open,
      close: scanned.can_close
    });
  }

  state.pos += scanned.length;

  return true
}

function postProcess$3 (state, delimiters) {
  var token;
  var loneMarkers = [];
  var max = delimiters.length;

  for (var i = 0; i < max; i++) {
    var startDelim = delimiters[i];

    if (startDelim.marker !== 0x7E/* ~ */) {
      continue
    }

    if (startDelim.end === -1) {
      continue
    }

    var endDelim = delimiters[startDelim.end];

    token         = state.tokens[startDelim.token];
    token.type    = 's_open';
    token.tag     = 's';
    token.nesting = 1;
    token.markup  = '~~';
    token.content = '';

    token         = state.tokens[endDelim.token];
    token.type    = 's_close';
    token.tag     = 's';
    token.nesting = -1;
    token.markup  = '~~';
    token.content = '';

    if (state.tokens[endDelim.token - 1].type === 'text' &&
        state.tokens[endDelim.token - 1].content === '~') {
      loneMarkers.push(endDelim.token - 1);
    }
  }

  // If a marker sequence has an odd number of characters, it's splitted
  // like this: `~~~~~` -> `~` + `~~` + `~~`, leaving one marker at the
  // start of the sequence.
  //
  // So, we have to move all those markers after subsequent s_close tags.
  //
  while (loneMarkers.length) {
    var i$1 = loneMarkers.pop();
    var j = i$1 + 1;

    while (j < state.tokens.length && state.tokens[j].type === 's_close') {
      j++;
    }

    j--;

    if (i$1 !== j) {
      token = state.tokens[j];
      state.tokens[j] = state.tokens[i$1];
      state.tokens[i$1] = token;
    }
  }
}

// Walk through delimiter list and replace text tokens with tags
//
function strikethrough_postProcess (state) {
  var tokens_meta = state.tokens_meta;
  var max = state.tokens_meta.length;

  postProcess$3(state, state.delimiters);

  for (var curr = 0; curr < max; curr++) {
    if (tokens_meta[curr] && tokens_meta[curr].delimiters) {
      postProcess$3(state, tokens_meta[curr].delimiters);
    }
  }
}

var r_strikethrough = {
  tokenize: strikethrough_tokenize,
  postProcess: strikethrough_postProcess
};// Process *this* and _that_
//

// Insert each marker as a separate text token, and add it to delimiter list
//
function emphasis_tokenize (state, silent) {
  var start = state.pos;
  var marker = state.src.charCodeAt(start);

  if (silent) { return false }

  if (marker !== 0x5F /* _ */ && marker !== 0x2A /* * */) { return false }

  var scanned = state.scanDelims(state.pos, marker === 0x2A);

  for (var i = 0; i < scanned.length; i++) {
    var token = state.push('text', '', 0);
    token.content = String.fromCharCode(marker);

    state.delimiters.push({
      // Char code of the starting marker (number).
      //
      marker: marker,

      // Total length of these series of delimiters.
      //
      length: scanned.length,

      // A position of the token this delimiter corresponds to.
      //
      token: state.tokens.length - 1,

      // If this delimiter is matched as a valid opener, `end` will be
      // equal to its position, otherwise it's `-1`.
      //
      end: -1,

      // Boolean flags that determine if this delimiter could open or close
      // an emphasis.
      //
      open: scanned.can_open,
      close: scanned.can_close
    });
  }

  state.pos += scanned.length;

  return true
}

function postProcess$2 (state, delimiters) {
  var max = delimiters.length;

  for (var i = max - 1; i >= 0; i--) {
    var startDelim = delimiters[i];

    if (startDelim.marker !== 0x5F/* _ */ && startDelim.marker !== 0x2A/* * */) {
      continue
    }

    // Process only opening markers
    if (startDelim.end === -1) {
      continue
    }

    var endDelim = delimiters[startDelim.end];

    // If the previous delimiter has the same marker and is adjacent to this one,
    // merge those into one strong delimiter.
    //
    // `<em><em>whatever</em></em>` -> `<strong>whatever</strong>`
    //
    var isStrong = i > 0 &&
               delimiters[i - 1].end === startDelim.end + 1 &&
               // check that first two markers match and adjacent
               delimiters[i - 1].marker === startDelim.marker &&
               delimiters[i - 1].token === startDelim.token - 1 &&
               // check that last two markers are adjacent (we can safely assume they match)
               delimiters[startDelim.end + 1].token === endDelim.token + 1;

    var ch = String.fromCharCode(startDelim.marker);

    var token_o   = state.tokens[startDelim.token];
    token_o.type    = isStrong ? 'strong_open' : 'em_open';
    token_o.tag     = isStrong ? 'strong' : 'em';
    token_o.nesting = 1;
    token_o.markup  = isStrong ? ch + ch : ch;
    token_o.content = '';

    var token_c   = state.tokens[endDelim.token];
    token_c.type    = isStrong ? 'strong_close' : 'em_close';
    token_c.tag     = isStrong ? 'strong' : 'em';
    token_c.nesting = -1;
    token_c.markup  = isStrong ? ch + ch : ch;
    token_c.content = '';

    if (isStrong) {
      state.tokens[delimiters[i - 1].token].content = '';
      state.tokens[delimiters[startDelim.end + 1].token].content = '';
      i--;
    }
  }
}

// Walk through delimiter list and replace text tokens with tags
//
function emphasis_post_process (state) {
  var tokens_meta = state.tokens_meta;
  var max = state.tokens_meta.length;

  postProcess$2(state, state.delimiters);

  for (var curr = 0; curr < max; curr++) {
    if (tokens_meta[curr] && tokens_meta[curr].delimiters) {
      postProcess$2(state, tokens_meta[curr].delimiters);
    }
  }
}

var r_emphasis = {
  tokenize: emphasis_tokenize,
  postProcess: emphasis_post_process
};// Process [link](<to> "stuff")


function link$5 (state, silent) {
  var code, label, res, ref;
  var href = '';
  var title = '';
  var start = state.pos;
  var parseReference = true;

  if (state.src.charCodeAt(state.pos) !== 0x5B/* [ */) { return false }

  var oldPos = state.pos;
  var max = state.posMax;
  var labelStart = state.pos + 1;
  var labelEnd = state.md.helpers.parseLinkLabel(state, state.pos, true);

  // parser failed to find ']', so it's not a valid link
  if (labelEnd < 0) { return false }

  var pos = labelEnd + 1;
  if (pos < max && state.src.charCodeAt(pos) === 0x28/* ( */) {
    //
    // Inline link
    //

    // might have found a valid shortcut link, disable reference parsing
    parseReference = false;

    // [link](  <href>  "title"  )
    //        ^^ skipping these spaces
    pos++;
    for (; pos < max; pos++) {
      code = state.src.charCodeAt(pos);
      if (!isSpace$e(code) && code !== 0x0A) { break }
    }
    if (pos >= max) { return false }

    // [link](  <href>  "title"  )
    //          ^^^^^^ parsing link destination
    start = pos;
    res = state.md.helpers.parseLinkDestination(state.src, pos, state.posMax);
    if (res.ok) {
      href = state.md.normalizeLink(res.str);
      if (state.md.validateLink(href)) {
        pos = res.pos;
      } else {
        href = '';
      }

      // [link](  <href>  "title"  )
      //                ^^ skipping these spaces
      start = pos;
      for (; pos < max; pos++) {
        code = state.src.charCodeAt(pos);
        if (!isSpace$e(code) && code !== 0x0A) { break }
      }

      // [link](  <href>  "title"  )
      //                  ^^^^^^^ parsing link title
      res = state.md.helpers.parseLinkTitle(state.src, pos, state.posMax);
      if (pos < max && start !== pos && res.ok) {
        title = res.str;
        pos = res.pos;

        // [link](  <href>  "title"  )
        //                         ^^ skipping these spaces
        for (; pos < max; pos++) {
          code = state.src.charCodeAt(pos);
          if (!isSpace$e(code) && code !== 0x0A) { break }
        }
      }
    }

    if (pos >= max || state.src.charCodeAt(pos) !== 0x29/* ) */) {
      // parsing a valid shortcut link failed, fallback to reference
      parseReference = true;
    }
    pos++;
  }

  if (parseReference) {
    //
    // Link reference
    //
    if (typeof state.env.references === 'undefined') { return false }

    if (pos < max && state.src.charCodeAt(pos) === 0x5B/* [ */) {
      start = pos + 1;
      pos = state.md.helpers.parseLinkLabel(state, pos);
      if (pos >= 0) {
        label = state.src.slice(start, pos++);
      } else {
        pos = labelEnd + 1;
      }
    } else {
      pos = labelEnd + 1;
    }

    // covers label === '' and label === undefined
    // (collapsed reference link and shortcut reference link respectively)
    if (!label) { label = state.src.slice(labelStart, labelEnd); }

    ref = state.env.references[normalizeReference$3(label)];
    if (!ref) {
      state.pos = oldPos;
      return false
    }
    href = ref.href;
    title = ref.title;
  }

  //
  // We found the end of the link, and know for a fact it's a valid link;
  // so all that's left to do is to call tokenizer.
  //
  if (!silent) {
    state.pos = labelStart;
    state.posMax = labelEnd;

    var token_o = state.push('link_open', 'a', 1);
    var attrs = [['href', href]];
    token_o.attrs  = attrs;
    if (title) {
      attrs.push(['title', title]);
    }

    state.linkLevel++;
    state.md.inline.tokenize(state);
    state.linkLevel--;

    state.push('link_close', 'a', -1);
  }

  state.pos = pos;
  state.posMax = max;
  return true
}// Process ![image](<src> "title")


function image$3 (state, silent) {
  var code, content, label, pos, ref, res, title, start;
  var href = '';
  var oldPos = state.pos;
  var max = state.posMax;

  if (state.src.charCodeAt(state.pos) !== 0x21/* ! */) { return false }
  if (state.src.charCodeAt(state.pos + 1) !== 0x5B/* [ */) { return false }

  var labelStart = state.pos + 2;
  var labelEnd = state.md.helpers.parseLinkLabel(state, state.pos + 1, false);

  // parser failed to find ']', so it's not a valid link
  if (labelEnd < 0) { return false }

  pos = labelEnd + 1;
  if (pos < max && state.src.charCodeAt(pos) === 0x28/* ( */) {
    //
    // Inline link
    //

    // [link](  <href>  "title"  )
    //        ^^ skipping these spaces
    pos++;
    for (; pos < max; pos++) {
      code = state.src.charCodeAt(pos);
      if (!isSpace$e(code) && code !== 0x0A) { break }
    }
    if (pos >= max) { return false }

    // [link](  <href>  "title"  )
    //          ^^^^^^ parsing link destination
    start = pos;
    res = state.md.helpers.parseLinkDestination(state.src, pos, state.posMax);
    if (res.ok) {
      href = state.md.normalizeLink(res.str);
      if (state.md.validateLink(href)) {
        pos = res.pos;
      } else {
        href = '';
      }
    }

    // [link](  <href>  "title"  )
    //                ^^ skipping these spaces
    start = pos;
    for (; pos < max; pos++) {
      code = state.src.charCodeAt(pos);
      if (!isSpace$e(code) && code !== 0x0A) { break }
    }

    // [link](  <href>  "title"  )
    //                  ^^^^^^^ parsing link title
    res = state.md.helpers.parseLinkTitle(state.src, pos, state.posMax);
    if (pos < max && start !== pos && res.ok) {
      title = res.str;
      pos = res.pos;

      // [link](  <href>  "title"  )
      //                         ^^ skipping these spaces
      for (; pos < max; pos++) {
        code = state.src.charCodeAt(pos);
        if (!isSpace$e(code) && code !== 0x0A) { break }
      }
    } else {
      title = '';
    }

    if (pos >= max || state.src.charCodeAt(pos) !== 0x29/* ) */) {
      state.pos = oldPos;
      return false
    }
    pos++;
  } else {
    //
    // Link reference
    //
    if (typeof state.env.references === 'undefined') { return false }

    if (pos < max && state.src.charCodeAt(pos) === 0x5B/* [ */) {
      start = pos + 1;
      pos = state.md.helpers.parseLinkLabel(state, pos);
      if (pos >= 0) {
        label = state.src.slice(start, pos++);
      } else {
        pos = labelEnd + 1;
      }
    } else {
      pos = labelEnd + 1;
    }

    // covers label === '' and label === undefined
    // (collapsed reference link and shortcut reference link respectively)
    if (!label) { label = state.src.slice(labelStart, labelEnd); }

    ref = state.env.references[normalizeReference$3(label)];
    if (!ref) {
      state.pos = oldPos;
      return false
    }
    href = ref.href;
    title = ref.title;
  }

  //
  // We found the end of the link, and know for a fact it's a valid link;
  // so all that's left to do is to call tokenizer.
  //
  if (!silent) {
    content = state.src.slice(labelStart, labelEnd);

    var tokens = [];
    state.md.inline.parse(
      content,
      state.md,
      state.env,
      tokens
    );

    var token = state.push('image', 'img', 0);
    var attrs = [['src', href], ['alt', '']];
    token.attrs = attrs;
    token.children = tokens;
    token.content = content;

    if (title) {
      attrs.push(['title', title]);
    }
  }

  state.pos = pos;
  state.posMax = max;
  return true
}// Process autolinks '<protocol:...>'

/* eslint max-len:0 */
var EMAIL_RE$1    = /^([a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*)$/;
/* eslint-disable-next-line no-control-regex */
var AUTOLINK_RE$1 = /^([a-zA-Z][a-zA-Z0-9+.-]{1,31}):([^<>\x00-\x20]*)$/;

function autolink$1 (state, silent) {
  var pos = state.pos;

  if (state.src.charCodeAt(pos) !== 0x3C/* < */) { return false }

  var start = state.pos;
  var max = state.posMax;

  for (;;) {
    if (++pos >= max) { return false }

    var ch = state.src.charCodeAt(pos);

    if (ch === 0x3C /* < */) { return false }
    if (ch === 0x3E /* > */) { break }
  }

  var url = state.src.slice(start + 1, pos);

  if (AUTOLINK_RE$1.test(url)) {
    var fullUrl = state.md.normalizeLink(url);
    if (!state.md.validateLink(fullUrl)) { return false }

    if (!silent) {
      var token_o   = state.push('link_open', 'a', 1);
      token_o.attrs   = [['href', fullUrl]];
      token_o.markup  = 'autolink';
      token_o.info    = 'auto';

      var token_t   = state.push('text', '', 0);
      token_t.content = state.md.normalizeLinkText(url);

      var token_c   = state.push('link_close', 'a', -1);
      token_c.markup  = 'autolink';
      token_c.info    = 'auto';
    }

    state.pos += url.length + 2;
    return true
  }

  if (EMAIL_RE$1.test(url)) {
    var fullUrl$1 = state.md.normalizeLink('mailto:' + url);
    if (!state.md.validateLink(fullUrl$1)) { return false }

    if (!silent) {
      var token_o$1   = state.push('link_open', 'a', 1);
      token_o$1.attrs   = [['href', fullUrl$1]];
      token_o$1.markup  = 'autolink';
      token_o$1.info    = 'auto';

      var token_t$1   = state.push('text', '', 0);
      token_t$1.content = state.md.normalizeLinkText(url);

      var token_c$1   = state.push('link_close', 'a', -1);
      token_c$1.markup  = 'autolink';
      token_c$1.info    = 'auto';
    }

    state.pos += url.length + 2;
    return true
  }

  return false
}// Process html tags


function isLinkOpen$2 (str) {
  return /^<a[>\s]/i.test(str)
}
function isLinkClose$2 (str) {
  return /^<\/a\s*>/i.test(str)
}

function isLetter$1 (ch) {
  /* eslint no-bitwise:0 */
  var lc = ch | 0x20; // to lower case
  return (lc >= 0x61/* a */) && (lc <= 0x7a/* z */)
}

function html_inline$1 (state, silent) {
  if (!state.md.options.html) { return false }

  // Check start
  var max = state.posMax;
  var pos = state.pos;
  if (state.src.charCodeAt(pos) !== 0x3C/* < */ ||
      pos + 2 >= max) {
    return false
  }

  // Quick fail on second char
  var ch = state.src.charCodeAt(pos + 1);
  if (ch !== 0x21/* ! */ &&
      ch !== 0x3F/* ? */ &&
      ch !== 0x2F/* / */ &&
      !isLetter$1(ch)) {
    return false
  }

  var match = state.src.slice(pos).match(HTML_TAG_RE$2);
  if (!match) { return false }

  if (!silent) {
    var token = state.push('html_inline', '', 0);
    token.content = match[0];

    if (isLinkOpen$2(token.content))  { state.linkLevel++; }
    if (isLinkClose$2(token.content)) { state.linkLevel--; }
  }
  state.pos += match[0].length;
  return true
}// Process html entity - &#123;, &#xAF;, &quot;, ...


var DIGITAL_RE$1 = /^&#((?:x[a-f0-9]{1,6}|[0-9]{1,7}));/i;
var NAMED_RE$1   = /^&([a-z][a-z0-9]{1,31});/i;

function entity$1 (state, silent) {
  var pos = state.pos;
  var max = state.posMax;

  if (state.src.charCodeAt(pos) !== 0x26/* & */) { return false }

  if (pos + 1 >= max) { return false }

  var ch = state.src.charCodeAt(pos + 1);

  if (ch === 0x23 /* # */) {
    var match = state.src.slice(pos).match(DIGITAL_RE$1);
    if (match) {
      if (!silent) {
        var code = match[1][0].toLowerCase() === 'x' ? parseInt(match[1].slice(1), 16) : parseInt(match[1], 10);

        var token   = state.push('text_special', '', 0);
        token.content = isValidEntityCode$1(code) ? fromCodePoint$2(code) : fromCodePoint$2(0xFFFD);
        token.markup  = match[0];
        token.info    = 'entity';
      }
      state.pos += match[0].length;
      return true
    }
  } else {
    var match$1 = state.src.slice(pos).match(NAMED_RE$1);
    if (match$1) {
      var decoded = decodeHTML(match$1[0]);
      if (decoded !== match$1[0]) {
        if (!silent) {
          var token$1   = state.push('text_special', '', 0);
          token$1.content = decoded;
          token$1.markup  = match$1[0];
          token$1.info    = 'entity';
        }
        state.pos += match$1[0].length;
        return true
      }
    }
  }

  return false
}// For each opening emphasis-like marker find a matching closing one
//

function processDelimiters$1 (delimiters) {
  var openersBottom = {};
  var max = delimiters.length;

  if (!max) { return }

  // headerIdx is the first delimiter of the current (where closer is) delimiter run
  var headerIdx = 0;
  var lastTokenIdx = -2; // needs any value lower than -1
  var jumps = [];

  for (var closerIdx = 0; closerIdx < max; closerIdx++) {
    var closer = delimiters[closerIdx];

    jumps.push(0);

    // markers belong to same delimiter run if:
    //  - they have adjacent tokens
    //  - AND markers are the same
    //
    if (delimiters[headerIdx].marker !== closer.marker || lastTokenIdx !== closer.token - 1) {
      headerIdx = closerIdx;
    }

    lastTokenIdx = closer.token;

    // Length is only used for emphasis-specific "rule of 3",
    // if it's not defined (in strikethrough or 3rd party plugins),
    // we can default it to 0 to disable those checks.
    //
    closer.length = closer.length || 0;

    if (!closer.close) { continue }

    // Previously calculated lower bounds (previous fails)
    // for each marker, each delimiter length modulo 3,
    // and for whether this closer can be an opener;
    // https://github.com/commonmark/cmark/commit/34250e12ccebdc6372b8b49c44fab57c72443460
    /* eslint-disable-next-line no-prototype-builtins */
    if (!openersBottom.hasOwnProperty(closer.marker)) {
      openersBottom[closer.marker] = [-1, -1, -1, -1, -1, -1];
    }

    var minOpenerIdx = openersBottom[closer.marker][(closer.open ? 3 : 0) + (closer.length % 3)];

    var openerIdx = headerIdx - jumps[headerIdx] - 1;

    var newMinOpenerIdx = openerIdx;

    for (; openerIdx > minOpenerIdx; openerIdx -= jumps[openerIdx] + 1) {
      var opener = delimiters[openerIdx];

      if (opener.marker !== closer.marker) { continue }

      if (opener.open && opener.end < 0) {
        var isOddMatch = false;

        // from spec:
        //
        // If one of the delimiters can both open and close emphasis, then the
        // sum of the lengths of the delimiter runs containing the opening and
        // closing delimiters must not be a multiple of 3 unless both lengths
        // are multiples of 3.
        //
        if (opener.close || closer.open) {
          if ((opener.length + closer.length) % 3 === 0) {
            if (opener.length % 3 !== 0 || closer.length % 3 !== 0) {
              isOddMatch = true;
            }
          }
        }

        if (!isOddMatch) {
          // If previous delimiter cannot be an opener, we can safely skip
          // the entire sequence in future checks. This is required to make
          // sure algorithm has linear complexity (see *_*_*_*_*_... case).
          //
          var lastJump = openerIdx > 0 && !delimiters[openerIdx - 1].open
            ? jumps[openerIdx - 1] + 1
            : 0;

          jumps[closerIdx] = closerIdx - openerIdx + lastJump;
          jumps[openerIdx] = lastJump;

          closer.open  = false;
          opener.end   = closerIdx;
          opener.close = false;
          newMinOpenerIdx = -1;
          // treat next token as start of run,
          // it optimizes skips in **<...>**a**<...>** pathological case
          lastTokenIdx = -2;
          break
        }
      }
    }

    if (newMinOpenerIdx !== -1) {
      // If match for this delimiter run failed, we want to set lower bound for
      // future lookups. This is required to make sure algorithm has linear
      // complexity.
      //
      // See details here:
      // https://github.com/commonmark/cmark/issues/178#issuecomment-270417442
      //
      openersBottom[closer.marker][(closer.open ? 3 : 0) + ((closer.length || 0) % 3)] = newMinOpenerIdx;
    }
  }
}

function link_pairs (state) {
  var tokens_meta = state.tokens_meta;
  var max = state.tokens_meta.length;

  processDelimiters$1(state.delimiters);

  for (var curr = 0; curr < max; curr++) {
    if (tokens_meta[curr] && tokens_meta[curr].delimiters) {
      processDelimiters$1(tokens_meta[curr].delimiters);
    }
  }
}// Clean up tokens after emphasis and strikethrough postprocessing:
// merge adjacent text nodes into one and re-calculate all token levels
//
// This is necessary because initially emphasis delimiter markers (*, _, ~)
// are treated as their own separate text tokens. Then emphasis rule either
// leaves them as text (needed to merge with adjacent text) or turns them
// into opening/closing tags (which messes up levels inside).
//

function fragments_join$1 (state) {
  var curr, last;
  var level = 0;
  var tokens = state.tokens;
  var max = state.tokens.length;

  for (curr = last = 0; curr < max; curr++) {
    // re-calculate levels after emphasis/strikethrough turns some text nodes
    // into opening/closing tags
    if (tokens[curr].nesting < 0) { level--; } // closing tag
    tokens[curr].level = level;
    if (tokens[curr].nesting > 0) { level++; } // opening tag

    if (tokens[curr].type === 'text' &&
        curr + 1 < max &&
        tokens[curr + 1].type === 'text') {
      // collapse two adjacent text nodes
      tokens[curr + 1].content = tokens[curr].content + tokens[curr + 1].content;
    } else {
      if (curr !== last) { tokens[last] = tokens[curr]; }

      last++;
    }
  }

  if (curr !== last) {
    tokens.length = last;
  }
}/** internal
 * class ParserInline
 *
 * Tokenizes paragraph content.
 **/


// Parser rules

var _rules$3 = [
  ['text',            text$2],
  ['linkify',         linkify$3],
  ['newline',         newline$2],
  ['escape',          escape],
  ['backticks',       backtick],
  ['strikethrough',   r_strikethrough.tokenize],
  ['emphasis',        r_emphasis.tokenize],
  ['link',            link$5],
  ['image',           image$3],
  ['autolink',        autolink$1],
  ['html_inline',     html_inline$1],
  ['entity',          entity$1]
];

// `rule2` ruleset was created specifically for emphasis/strikethrough
// post-processing and may be changed in the future.
//
// Don't use this for anything except pairs (plugins working with `balance_pairs`).
//
var _rules2$1 = [
  ['balance_pairs',   link_pairs],
  ['strikethrough',   r_strikethrough.postProcess],
  ['emphasis',        r_emphasis.postProcess],
  // rules for pairs separate '**' into its own text tokens, which may be left unused,
  // rule below merges unused segments back with the rest of the text
  ['fragments_join',  fragments_join$1]
];

/**
 * new ParserInline()
 **/
function ParserInline$2 () {
  /**
   * ParserInline#ruler -> Ruler
   *
   * [[Ruler]] instance. Keep configuration of inline rules.
   **/
  this.ruler = new Ruler$4();

  for (var i = 0; i < _rules$3.length; i++) {
    this.ruler.push(_rules$3[i][0], _rules$3[i][1]);
  }

  /**
   * ParserInline#ruler2 -> Ruler
   *
   * [[Ruler]] instance. Second ruler used for post-processing
   * (e.g. in emphasis-like rules).
   **/
  this.ruler2 = new Ruler$4();

  for (var i$1 = 0; i$1 < _rules2$1.length; i$1++) {
    this.ruler2.push(_rules2$1[i$1][0], _rules2$1[i$1][1]);
  }
}

// Skip single token by running all rules in validation mode;
// returns `true` if any rule reported success
//
ParserInline$2.prototype.skipToken = function (state) {
  var pos = state.pos;
  var rules = this.ruler.getRules('');
  var len = rules.length;
  var maxNesting = state.md.options.maxNesting;
  var cache = state.cache;

  if (typeof cache[pos] !== 'undefined') {
    state.pos = cache[pos];
    return
  }

  var ok = false;

  if (state.level < maxNesting) {
    for (var i = 0; i < len; i++) {
      // Increment state.level and decrement it later to limit recursion.
      // It's harmless to do here, because no tokens are created. But ideally,
      // we'd need a separate private state variable for this purpose.
      //
      state.level++;
      ok = rules[i](state, true);
      state.level--;

      if (ok) {
        if (pos >= state.pos) { throw new Error("inline rule didn't increment state.pos") }
        break
      }
    }
  } else {
    // Too much nesting, just skip until the end of the paragraph.
    //
    // NOTE: this will cause links to behave incorrectly in the following case,
    //       when an amount of `[` is exactly equal to `maxNesting + 1`:
    //
    //       [[[[[[[[[[[[[[[[[[[[[foo]()
    //
    // TODO: remove this workaround when CM standard will allow nested links
    //       (we can replace it by preventing links from being parsed in
    //       validation mode)
    //
    state.pos = state.posMax;
  }

  if (!ok) { state.pos++; }
  cache[pos] = state.pos;
};

// Generate tokens for input range
//
ParserInline$2.prototype.tokenize = function (state) {
  var rules = this.ruler.getRules('');
  var len = rules.length;
  var end = state.posMax;
  var maxNesting = state.md.options.maxNesting;

  while (state.pos < end) {
    // Try all possible rules.
    // On success, rule should:
    //
    // - update `state.pos`
    // - update `state.tokens`
    // - return true
    var prevPos = state.pos;
    var ok = false;

    if (state.level < maxNesting) {
      for (var i = 0; i < len; i++) {
        ok = rules[i](state, false);
        if (ok) {
          if (prevPos >= state.pos) { throw new Error("inline rule didn't increment state.pos") }
          break
        }
      }
    }

    if (ok) {
      if (state.pos >= end) { break }
      continue
    }

    state.pending += state.src[state.pos++];
  }

  if (state.pending) {
    state.pushPending();
  }
};

/**
 * ParserInline.parse(str, md, env, outTokens)
 *
 * Process input string and push inline tokens into `outTokens`
 **/
ParserInline$2.prototype.parse = function (str, md, env, outTokens) {
  var state = new this.State(str, md, env, outTokens);

  this.tokenize(state);

  var rules = this.ruler2.getRules('');
  var len = rules.length;

  for (var i = 0; i < len; i++) {
    rules[i](state);
  }
};

ParserInline$2.prototype.State = StateInline$1;function reFactory (opts) {
  var re = {};
  opts = opts || {};

  re.src_Any = Any.source;
  re.src_Cc = Cc.source;
  re.src_Z = Z.source;
  re.src_P = P.source;

  // \p{\Z\P\Cc\CF} (white spaces + control + format + punctuation)
  re.src_ZPCc = [re.src_Z, re.src_P, re.src_Cc].join('|');

  // \p{\Z\Cc} (white spaces + control)
  re.src_ZCc = [re.src_Z, re.src_Cc].join('|');

  // Experimental. List of chars, completely prohibited in links
  // because can separate it from other part of text
  var text_separators = '[><\uff5c]';

  // All possible word characters (everything without punctuation, spaces & controls)
  // Defined via punctuation & spaces to save space
  // Should be something like \p{\L\N\S\M} (\w but without `_`)
  re.src_pseudo_letter = '(?:(?!' + text_separators + '|' + re.src_ZPCc + ')' + re.src_Any + ')';
  // The same as abothe but without [0-9]
  // var src_pseudo_letter_non_d = '(?:(?![0-9]|' + src_ZPCc + ')' + src_Any + ')';

  re.src_ip4 =

    '(?:(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)';

  // Prohibit any of "@/[]()" in user/pass to avoid wrong domain fetch.
  re.src_auth = '(?:(?:(?!' + re.src_ZCc + '|[@/\\[\\]()]).)+@)?';

  re.src_port =

    '(?::(?:6(?:[0-4]\\d{3}|5(?:[0-4]\\d{2}|5(?:[0-2]\\d|3[0-5])))|[1-5]?\\d{1,4}))?';

  re.src_host_terminator =

    '(?=$|' + text_separators + '|' + re.src_ZPCc + ')' +
    '(?!' + (opts['---'] ? '-(?!--)|' : '-|') + '_|:\\d|\\.-|\\.(?!$|' + re.src_ZPCc + '))';

  re.src_path =

    '(?:' +
      '[/?#]' +
        '(?:' +
          '(?!' + re.src_ZCc + '|' + text_separators + '|[()[\\]{}.,"\'?!\\-;]).|' +
          '\\[(?:(?!' + re.src_ZCc + '|\\]).)*\\]|' +
          '\\((?:(?!' + re.src_ZCc + '|[)]).)*\\)|' +
          '\\{(?:(?!' + re.src_ZCc + '|[}]).)*\\}|' +
          '\\"(?:(?!' + re.src_ZCc + '|["]).)+\\"|' +
          "\\'(?:(?!" + re.src_ZCc + "|[']).)+\\'|" +

          // allow `I'm_king` if no pair found
          "\\'(?=" + re.src_pseudo_letter + '|[-])|' +

          // google has many dots in "google search" links (#66, #81).
          // github has ... in commit range links,
          // Restrict to
          // - english
          // - percent-encoded
          // - parts of file path
          // - params separator
          // until more examples found.
          '\\.{2,}[a-zA-Z0-9%/&]|' +

          '\\.(?!' + re.src_ZCc + '|[.]|$)|' +
          (opts['---']
            ? '\\-(?!--(?:[^-]|$))(?:-*)|' // `---` => long dash, terminate
            : '\\-+|'
          ) +
          // allow `,,,` in paths
          ',(?!' + re.src_ZCc + '|$)|' +

          // allow `;` if not followed by space-like char
          ';(?!' + re.src_ZCc + '|$)|' +

          // allow `!!!` in paths, but not at the end
          '\\!+(?!' + re.src_ZCc + '|[!]|$)|' +

          '\\?(?!' + re.src_ZCc + '|[?]|$)' +
        ')+' +
      '|\\/' +
    ')?';

  // Allow anything in markdown spec, forbid quote (") at the first position
  // because emails enclosed in quotes are far more common
  re.src_email_name =

    '[\\-;:&=\\+\\$,\\.a-zA-Z0-9_][\\-;:&=\\+\\$,\\"\\.a-zA-Z0-9_]*';

  re.src_xn =

    'xn--[a-z0-9\\-]{1,59}';

  // More to read about domain names
  // http://serverfault.com/questions/638260/

  re.src_domain_root =

    // Allow letters & digits (http://test1)
    '(?:' +
      re.src_xn +
      '|' +
      re.src_pseudo_letter + '{1,63}' +
    ')';

  re.src_domain =

    '(?:' +
      re.src_xn +
      '|' +
      '(?:' + re.src_pseudo_letter + ')' +
      '|' +
      '(?:' + re.src_pseudo_letter + '(?:-|' + re.src_pseudo_letter + '){0,61}' + re.src_pseudo_letter + ')' +
    ')';

  re.src_host =

    '(?:' +
    // Don't need IP check, because digits are already allowed in normal domain names
    //   src_ip4 +
    // '|' +
      '(?:(?:(?:' + re.src_domain + ')\\.)*' + re.src_domain/* _root */ + ')' +
    ')';

  re.tpl_host_fuzzy =

    '(?:' +
      re.src_ip4 +
    '|' +
      '(?:(?:(?:' + re.src_domain + ')\\.)+(?:%TLDS%))' +
    ')';

  re.tpl_host_no_ip_fuzzy =

    '(?:(?:(?:' + re.src_domain + ')\\.)+(?:%TLDS%))';

  re.src_host_strict =

    re.src_host + re.src_host_terminator;

  re.tpl_host_fuzzy_strict =

    re.tpl_host_fuzzy + re.src_host_terminator;

  re.src_host_port_strict =

    re.src_host + re.src_port + re.src_host_terminator;

  re.tpl_host_port_fuzzy_strict =

    re.tpl_host_fuzzy + re.src_port + re.src_host_terminator;

  re.tpl_host_port_no_ip_fuzzy_strict =

    re.tpl_host_no_ip_fuzzy + re.src_port + re.src_host_terminator;

  //
  // Main rules
  //

  // Rude test fuzzy links by host, for quick deny
  re.tpl_host_fuzzy_test =

    'localhost|www\\.|\\.\\d{1,3}\\.|(?:\\.(?:%TLDS%)(?:' + re.src_ZPCc + '|>|$))';

  re.tpl_email_fuzzy =

      '(^|' + text_separators + '|"|\\(|' + re.src_ZCc + ')' +
      '(' + re.src_email_name + '@' + re.tpl_host_fuzzy_strict + ')';

  re.tpl_link_fuzzy =
      // Fuzzy link can't be prepended with .:/\- and non punctuation.
      // but can start with > (markdown blockquote)
      '(^|(?![.:/\\-_@])(?:[$+<=>^`|\uff5c]|' + re.src_ZPCc + '))' +
      '((?![$+<=>^`|\uff5c])' + re.tpl_host_port_fuzzy_strict + re.src_path + ')';

  re.tpl_link_no_ip_fuzzy =
      // Fuzzy link can't be prepended with .:/\- and non punctuation.
      // but can start with > (markdown blockquote)
      '(^|(?![.:/\\-_@])(?:[$+<=>^`|\uff5c]|' + re.src_ZPCc + '))' +
      '((?![$+<=>^`|\uff5c])' + re.tpl_host_port_no_ip_fuzzy_strict + re.src_path + ')';

  return re
}//
// Helpers
//

// Merge objects
//
function assign$2 (obj /* from1, from2, from3, ... */) {
  var sources = Array.prototype.slice.call(arguments, 1);

  sources.forEach(function (source) {
    if (!source) { return }

    Object.keys(source).forEach(function (key) {
      obj[key] = source[key];
    });
  });

  return obj
}

function _class$1 (obj) { return Object.prototype.toString.call(obj) }
function isString$1 (obj) { return _class$1(obj) === '[object String]' }
function isObject$1 (obj) { return _class$1(obj) === '[object Object]' }
function isRegExp$1 (obj) { return _class$1(obj) === '[object RegExp]' }
function isFunction$1 (obj) { return _class$1(obj) === '[object Function]' }

function escapeRE$1 (str) { return str.replace(/[.?*+^$[\]\\(){}|-]/g, '\\$&') }

//

var defaultOptions$1 = {
  fuzzyLink: true,
  fuzzyEmail: true,
  fuzzyIP: false
};

function isOptionsObj$1 (obj) {
  return Object.keys(obj || {}).reduce(function (acc, k) {
    /* eslint-disable-next-line no-prototype-builtins */
    return acc || defaultOptions$1.hasOwnProperty(k)
  }, false)
}

var defaultSchemas$1 = {
  'http:': {
    validate: function (text, pos, self) {
      var tail = text.slice(pos);

      if (!self.re.http) {
        // compile lazily, because "host"-containing variables can change on tlds update.
        self.re.http = new RegExp(
          '^\\/\\/' + self.re.src_auth + self.re.src_host_port_strict + self.re.src_path, 'i'
        );
      }
      if (self.re.http.test(tail)) {
        return tail.match(self.re.http)[0].length
      }
      return 0
    }
  },
  'https:': 'http:',
  'ftp:': 'http:',
  '//': {
    validate: function (text, pos, self) {
      var tail = text.slice(pos);

      if (!self.re.no_http) {
      // compile lazily, because "host"-containing variables can change on tlds update.
        self.re.no_http = new RegExp(
          '^' +
          self.re.src_auth +
          // Don't allow single-level domains, because of false positives like '//test'
          // with code comments
          '(?:localhost|(?:(?:' + self.re.src_domain + ')\\.)+' + self.re.src_domain_root + ')' +
          self.re.src_port +
          self.re.src_host_terminator +
          self.re.src_path,

          'i'
        );
      }

      if (self.re.no_http.test(tail)) {
        // should not be `://` & `///`, that protects from errors in protocol name
        if (pos >= 3 && text[pos - 3] === ':') { return 0 }
        if (pos >= 3 && text[pos - 3] === '/') { return 0 }
        return tail.match(self.re.no_http)[0].length
      }
      return 0
    }
  },
  'mailto:': {
    validate: function (text, pos, self) {
      var tail = text.slice(pos);

      if (!self.re.mailto) {
        self.re.mailto = new RegExp(
          '^' + self.re.src_email_name + '@' + self.re.src_host_strict, 'i'
        );
      }
      if (self.re.mailto.test(tail)) {
        return tail.match(self.re.mailto)[0].length
      }
      return 0
    }
  }
};

// RE pattern for 2-character tlds (autogenerated by ./support/tlds_2char_gen.js)
/* eslint-disable-next-line max-len */
var tlds_2ch_src_re$1 = 'a[cdefgilmnoqrstuwxz]|b[abdefghijmnorstvwyz]|c[acdfghiklmnoruvwxyz]|d[ejkmoz]|e[cegrstu]|f[ijkmor]|g[abdefghilmnpqrstuwy]|h[kmnrtu]|i[delmnoqrst]|j[emop]|k[eghimnprwyz]|l[abcikrstuvy]|m[acdeghklmnopqrstuvwxyz]|n[acefgilopruz]|om|p[aefghklmnrstwy]|qa|r[eosuw]|s[abcdeghijklmnortuvxyz]|t[cdfghjklmnortvwz]|u[agksyz]|v[aceginu]|w[fs]|y[et]|z[amw]';

// DON'T try to make PRs with changes. Extend TLDs with LinkifyIt.tlds() instead
var tlds_default$1 = 'biz|com|edu|gov|net|org|pro|web|xxx|aero|asia|coop|info|museum|name|shop|рф'.split('|');

function resetScanCache$1 (self) {
  self.__index__ = -1;
  self.__text_cache__ = '';
}

function createValidator$1 (re) {
  return function (text, pos) {
    var tail = text.slice(pos);

    if (re.test(tail)) {
      return tail.match(re)[0].length
    }
    return 0
  }
}

function createNormalizer$1 () {
  return function (match, self) {
    self.normalize(match);
  }
}

// Schemas compiler. Build regexps.
//
function compile$1 (self) {
  // Load & clone RE patterns.
  var re = self.re = reFactory(self.__opts__);

  // Define dynamic patterns
  var tlds = self.__tlds__.slice();

  self.onCompile();

  if (!self.__tlds_replaced__) {
    tlds.push(tlds_2ch_src_re$1);
  }
  tlds.push(re.src_xn);

  re.src_tlds = tlds.join('|');

  function untpl (tpl) { return tpl.replace('%TLDS%', re.src_tlds) }

  re.email_fuzzy = RegExp(untpl(re.tpl_email_fuzzy), 'i');
  re.link_fuzzy = RegExp(untpl(re.tpl_link_fuzzy), 'i');
  re.link_no_ip_fuzzy = RegExp(untpl(re.tpl_link_no_ip_fuzzy), 'i');
  re.host_fuzzy_test = RegExp(untpl(re.tpl_host_fuzzy_test), 'i');

  //
  // Compile each schema
  //

  var aliases = [];

  self.__compiled__ = {}; // Reset compiled data

  function schemaError (name, val) {
    throw new Error('(LinkifyIt) Invalid schema "' + name + '": ' + val)
  }

  Object.keys(self.__schemas__).forEach(function (name) {
    var val = self.__schemas__[name];

    // skip disabled methods
    if (val === null) { return }

    var compiled = { validate: null, link: null };

    self.__compiled__[name] = compiled;

    if (isObject$1(val)) {
      if (isRegExp$1(val.validate)) {
        compiled.validate = createValidator$1(val.validate);
      } else if (isFunction$1(val.validate)) {
        compiled.validate = val.validate;
      } else {
        schemaError(name, val);
      }

      if (isFunction$1(val.normalize)) {
        compiled.normalize = val.normalize;
      } else if (!val.normalize) {
        compiled.normalize = createNormalizer$1();
      } else {
        schemaError(name, val);
      }

      return
    }

    if (isString$1(val)) {
      aliases.push(name);
      return
    }

    schemaError(name, val);
  });

  //
  // Compile postponed aliases
  //

  aliases.forEach(function (alias) {
    if (!self.__compiled__[self.__schemas__[alias]]) {
      // Silently fail on missed schemas to avoid errons on disable.
      // schemaError(alias, self.__schemas__[alias]);
      return
    }

    self.__compiled__[alias].validate =
      self.__compiled__[self.__schemas__[alias]].validate;
    self.__compiled__[alias].normalize =
      self.__compiled__[self.__schemas__[alias]].normalize;
  });

  //
  // Fake record for guessed links
  //
  self.__compiled__[''] = { validate: null, normalize: createNormalizer$1() };

  //
  // Build schema condition
  //
  var slist = Object.keys(self.__compiled__)
    .filter(function (name) {
      // Filter disabled & fake schemas
      return name.length > 0 && self.__compiled__[name]
    })
    .map(escapeRE$1)
    .join('|');
  // (?!_) cause 1.5x slowdown
  self.re.schema_test = RegExp('(^|(?!_)(?:[><\uff5c]|' + re.src_ZPCc + '))(' + slist + ')', 'i');
  self.re.schema_search = RegExp('(^|(?!_)(?:[><\uff5c]|' + re.src_ZPCc + '))(' + slist + ')', 'ig');
  self.re.schema_at_start = RegExp('^' + self.re.schema_search.source, 'i');

  self.re.pretest = RegExp(
    '(' + self.re.schema_test.source + ')|(' + self.re.host_fuzzy_test.source + ')|@',
    'i'
  );

  //
  // Cleanup
  //

  resetScanCache$1(self);
}

/**
 * class Match
 *
 * Match result. Single element of array, returned by [[LinkifyIt#match]]
 **/
function Match$1 (self, shift) {
  var start = self.__index__;
  var end = self.__last_index__;
  var text = self.__text_cache__.slice(start, end);

  /**
   * Match#schema -> String
   *
   * Prefix (protocol) for matched string.
   **/
  this.schema = self.__schema__.toLowerCase();
  /**
   * Match#index -> Number
   *
   * First position of matched string.
   **/
  this.index = start + shift;
  /**
   * Match#lastIndex -> Number
   *
   * Next position after matched string.
   **/
  this.lastIndex = end + shift;
  /**
   * Match#raw -> String
   *
   * Matched string.
   **/
  this.raw = text;
  /**
   * Match#text -> String
   *
   * Notmalized text of matched string.
   **/
  this.text = text;
  /**
   * Match#url -> String
   *
   * Normalized url of matched string.
   **/
  this.url = text;
}

function createMatch$1 (self, shift) {
  var match = new Match$1(self, shift);

  self.__compiled__[match.schema].normalize(match, self);

  return match
}

/**
 * class LinkifyIt
 **/

/**
 * new LinkifyIt(schemas, options)
 * - schemas (Object): Optional. Additional schemas to validate (prefix/validator)
 * - options (Object): { fuzzyLink|fuzzyEmail|fuzzyIP: true|false }
 *
 * Creates new linkifier instance with optional additional schemas.
 * Can be called without `new` keyword for convenience.
 *
 * By default understands:
 *
 * - `http(s)://...` , `ftp://...`, `mailto:...` & `//...` links
 * - "fuzzy" links and emails (example.com, foo@bar.com).
 *
 * `schemas` is an object, where each key/value describes protocol/rule:
 *
 * - __key__ - link prefix (usually, protocol name with `:` at the end, `skype:`
 *   for example). `linkify-it` makes shure that prefix is not preceeded with
 *   alphanumeric char and symbols. Only whitespaces and punctuation allowed.
 * - __value__ - rule to check tail after link prefix
 *   - _String_ - just alias to existing rule
 *   - _Object_
 *     - _validate_ - validator function (should return matched length on success),
 *       or `RegExp`.
 *     - _normalize_ - optional function to normalize text & url of matched result
 *       (for example, for @twitter mentions).
 *
 * `options`:
 *
 * - __fuzzyLink__ - recognige URL-s without `http(s):` prefix. Default `true`.
 * - __fuzzyIP__ - allow IPs in fuzzy links above. Can conflict with some texts
 *   like version numbers. Default `false`.
 * - __fuzzyEmail__ - recognize emails without `mailto:` prefix.
 *
 **/
function LinkifyIt$2 (schemas, options) {
  if (!(this instanceof LinkifyIt$2)) {
    return new LinkifyIt$2(schemas, options)
  }

  if (!options) {
    if (isOptionsObj$1(schemas)) {
      options = schemas;
      schemas = {};
    }
  }

  this.__opts__ = assign$2({}, defaultOptions$1, options);

  // Cache last tested result. Used to skip repeating steps on next `match` call.
  this.__index__ = -1;
  this.__last_index__ = -1; // Next scan position
  this.__schema__ = '';
  this.__text_cache__ = '';

  this.__schemas__ = assign$2({}, defaultSchemas$1, schemas);
  this.__compiled__ = {};

  this.__tlds__ = tlds_default$1;
  this.__tlds_replaced__ = false;

  this.re = {};

  compile$1(this);
}

/** chainable
 * LinkifyIt#add(schema, definition)
 * - schema (String): rule name (fixed pattern prefix)
 * - definition (String|RegExp|Object): schema definition
 *
 * Add new rule definition. See constructor description for details.
 **/
LinkifyIt$2.prototype.add = function add (schema, definition) {
  this.__schemas__[schema] = definition;
  compile$1(this);
  return this
};

/** chainable
 * LinkifyIt#set(options)
 * - options (Object): { fuzzyLink|fuzzyEmail|fuzzyIP: true|false }
 *
 * Set recognition options for links without schema.
 **/
LinkifyIt$2.prototype.set = function set (options) {
  this.__opts__ = assign$2(this.__opts__, options);
  return this
};

/**
 * LinkifyIt#test(text) -> Boolean
 *
 * Searches linkifiable pattern and returns `true` on success or `false` on fail.
 **/
LinkifyIt$2.prototype.test = function test (text) {
  // Reset scan cache
  this.__text_cache__ = text;
  this.__index__ = -1;

  if (!text.length) { return false }

  var m, ml, me, len, shift, next, re, tld_pos, at_pos;

  // try to scan for link with schema - that's the most simple rule
  if (this.re.schema_test.test(text)) {
    re = this.re.schema_search;
    re.lastIndex = 0;
    while ((m = re.exec(text)) !== null) {
      len = this.testSchemaAt(text, m[2], re.lastIndex);
      if (len) {
        this.__schema__ = m[2];
        this.__index__ = m.index + m[1].length;
        this.__last_index__ = m.index + m[0].length + len;
        break
      }
    }
  }

  if (this.__opts__.fuzzyLink && this.__compiled__['http:']) {
    // guess schemaless links
    tld_pos = text.search(this.re.host_fuzzy_test);
    if (tld_pos >= 0) {
      // if tld is located after found link - no need to check fuzzy pattern
      if (this.__index__ < 0 || tld_pos < this.__index__) {
        if ((ml = text.match(this.__opts__.fuzzyIP ? this.re.link_fuzzy : this.re.link_no_ip_fuzzy)) !== null) {
          shift = ml.index + ml[1].length;

          if (this.__index__ < 0 || shift < this.__index__) {
            this.__schema__ = '';
            this.__index__ = shift;
            this.__last_index__ = ml.index + ml[0].length;
          }
        }
      }
    }
  }

  if (this.__opts__.fuzzyEmail && this.__compiled__['mailto:']) {
    // guess schemaless emails
    at_pos = text.indexOf('@');
    if (at_pos >= 0) {
      // We can't skip this check, because this cases are possible:
      // 192.168.1.1@gmail.com, my.in@example.com
      if ((me = text.match(this.re.email_fuzzy)) !== null) {
        shift = me.index + me[1].length;
        next = me.index + me[0].length;

        if (this.__index__ < 0 || shift < this.__index__ ||
            (shift === this.__index__ && next > this.__last_index__)) {
          this.__schema__ = 'mailto:';
          this.__index__ = shift;
          this.__last_index__ = next;
        }
      }
    }
  }

  return this.__index__ >= 0
};

/**
 * LinkifyIt#pretest(text) -> Boolean
 *
 * Very quick check, that can give false positives. Returns true if link MAY BE
 * can exists. Can be used for speed optimization, when you need to check that
 * link NOT exists.
 **/
LinkifyIt$2.prototype.pretest = function pretest (text) {
  return this.re.pretest.test(text)
};

/**
 * LinkifyIt#testSchemaAt(text, name, position) -> Number
 * - text (String): text to scan
 * - name (String): rule (schema) name
 * - position (Number): text offset to check from
 *
 * Similar to [[LinkifyIt#test]] but checks only specific protocol tail exactly
 * at given position. Returns length of found pattern (0 on fail).
 **/
LinkifyIt$2.prototype.testSchemaAt = function testSchemaAt (text, schema, pos) {
  // If not supported schema check requested - terminate
  if (!this.__compiled__[schema.toLowerCase()]) {
    return 0
  }
  return this.__compiled__[schema.toLowerCase()].validate(text, pos, this)
};

/**
 * LinkifyIt#match(text) -> Array|null
 *
 * Returns array of found link descriptions or `null` on fail. We strongly
 * recommend to use [[LinkifyIt#test]] first, for best speed.
 *
 * ##### Result match description
 *
 * - __schema__ - link schema, can be empty for fuzzy links, or `//` for
 *   protocol-neutral  links.
 * - __index__ - offset of matched text
 * - __lastIndex__ - index of next char after mathch end
 * - __raw__ - matched text
 * - __text__ - normalized text
 * - __url__ - link, generated from matched text
 **/
LinkifyIt$2.prototype.match = function match (text) {
  var result = [];
  var shift = 0;

  // Try to take previous element from cache, if .test() called before
  if (this.__index__ >= 0 && this.__text_cache__ === text) {
    result.push(createMatch$1(this, shift));
    shift = this.__last_index__;
  }

  // Cut head if cache was used
  var tail = shift ? text.slice(shift) : text;

  // Scan string until end reached
  while (this.test(tail)) {
    result.push(createMatch$1(this, shift));

    tail = tail.slice(this.__last_index__);
    shift += this.__last_index__;
  }

  if (result.length) {
    return result
  }

  return null
};

/**
 * LinkifyIt#matchAtStart(text) -> Match|null
 *
 * Returns fully-formed (not fuzzy) link if it starts at the beginning
 * of the string, and null otherwise.
 **/
LinkifyIt$2.prototype.matchAtStart = function matchAtStart (text) {
  // Reset scan cache
  this.__text_cache__ = text;
  this.__index__ = -1;

  if (!text.length) { return null }

  var m = this.re.schema_at_start.exec(text);
  if (!m) { return null }

  var len = this.testSchemaAt(text, m[2], m[0].length);
  if (!len) { return null }

  this.__schema__ = m[2];
  this.__index__ = m.index + m[1].length;
  this.__last_index__ = m.index + m[0].length + len;

  return createMatch$1(this, 0)
};

/** chainable
 * LinkifyIt#tlds(list [, keepOld]) -> this
 * - list (Array): list of tlds
 * - keepOld (Boolean): merge with current list if `true` (`false` by default)
 *
 * Load (or merge) new tlds list. Those are user for fuzzy links (without prefix)
 * to avoid false positives. By default this algorythm used:
 *
 * - hostname with any 2-letter root zones are ok.
 * - biz|com|edu|gov|net|org|pro|web|xxx|aero|asia|coop|info|museum|name|shop|рф
 *   are ok.
 * - encoded (`xn--...`) root zones are ok.
 *
 * If list is replaced, then exact match for 2-chars root zones will be checked.
 **/
LinkifyIt$2.prototype.tlds = function tlds (list, keepOld) {
  list = Array.isArray(list) ? list : [list];

  if (!keepOld) {
    this.__tlds__ = list.slice();
    this.__tlds_replaced__ = true;
    compile$1(this);
    return this
  }

  this.__tlds__ = this.__tlds__.concat(list)
    .sort()
    .filter(function (el, idx, arr) {
      return el !== arr[idx - 1]
    })
    .reverse();

  compile$1(this);
  return this
};

/**
 * LinkifyIt#normalize(match)
 *
 * Default normalizer (if schema does not define it's own).
 **/
LinkifyIt$2.prototype.normalize = function normalize (match) {
  // Do minimal possible changes by default. Need to collect feedback prior
  // to move forward https://github.com/markdown-it/linkify-it/issues/1

  if (!match.schema) { match.url = 'http://' + match.url; }

  if (match.schema === 'mailto:' && !/^mailto:/i.test(match.url)) {
    match.url = 'mailto:' + match.url;
  }
};

/**
 * LinkifyIt#onCompile()
 *
 * Override to modify basic RegExp-s.
 **/
LinkifyIt$2.prototype.onCompile = function onCompile () {
};/** Highest positive signed 32-bit float value */
var maxInt$1 = 2147483647; // aka. 0x7FFFFFFF or 2^31-1

/** Bootstring parameters */
var base$1 = 36;
var tMin$1 = 1;
var tMax$1 = 26;
var skew$1 = 38;
var damp$1 = 700;
var initialBias$1 = 72;
var initialN$1 = 128; // 0x80
var delimiter$1 = '-'; // '\x2D'

/** Regular expressions */
var regexPunycode$1 = /^xn--/;
var regexNonASCII$1 = /[^\0-\x7F]/; // Note: U+007F DEL is excluded too.
var regexSeparators$1 = /[\x2E\u3002\uFF0E\uFF61]/g; // RFC 3490 separators

/** Error messages */
var errors$1 = {
	'overflow': 'Overflow: input needs wider integers to process',
	'not-basic': 'Illegal input >= 0x80 (not a basic code point)',
	'invalid-input': 'Invalid input'
};

/** Convenience shortcuts */
var baseMinusTMin$1 = base$1 - tMin$1;
var floor$1 = Math.floor;
var stringFromCharCode$1 = String.fromCharCode;

/*--------------------------------------------------------------------------*/

/**
 * A generic error utility function.
 * @private
 * @param {String} type The error type.
 * @returns {Error} Throws a `RangeError` with the applicable error message.
 */
function error$1(type) {
	throw new RangeError(errors$1[type]);
}

/**
 * A generic `Array#map` utility function.
 * @private
 * @param {Array} array The array to iterate over.
 * @param {Function} callback The function that gets called for every array
 * item.
 * @returns {Array} A new array of values returned by the callback function.
 */
function map$2(array, callback) {
	var result = [];
	var length = array.length;
	while (length--) {
		result[length] = callback(array[length]);
	}
	return result;
}

/**
 * A simple `Array#map`-like wrapper to work with domain name strings or email
 * addresses.
 * @private
 * @param {String} domain The domain name or email address.
 * @param {Function} callback The function that gets called for every
 * character.
 * @returns {String} A new string of characters returned by the callback
 * function.
 */
function mapDomain$1(domain, callback) {
	var parts = domain.split('@');
	var result = '';
	if (parts.length > 1) {
		// In email addresses, only the domain name should be punycoded. Leave
		// the local part (i.e. everything up to `@`) intact.
		result = parts[0] + '@';
		domain = parts[1];
	}
	// Avoid `split(regex)` for IE8 compatibility. See #17.
	domain = domain.replace(regexSeparators$1, '\x2E');
	var labels = domain.split('.');
	var encoded = map$2(labels, callback).join('.');
	return result + encoded;
}

/**
 * Creates an array containing the numeric code points of each Unicode
 * character in the string. While JavaScript uses UCS-2 internally,
 * this function will convert a pair of surrogate halves (each of which
 * UCS-2 exposes as separate characters) into a single code point,
 * matching UTF-16.
 * @see `punycode.ucs2.encode`
 * @see <https://mathiasbynens.be/notes/javascript-encoding>
 * @memberOf punycode.ucs2
 * @name decode
 * @param {String} string The Unicode input string (UCS-2).
 * @returns {Array} The new array of code points.
 */
function ucs2decode$1(string) {
	var output = [];
	var counter = 0;
	var length = string.length;
	while (counter < length) {
		var value = string.charCodeAt(counter++);
		if (value >= 0xD800 && value <= 0xDBFF && counter < length) {
			// It's a high surrogate, and there is a next character.
			var extra = string.charCodeAt(counter++);
			if ((extra & 0xFC00) == 0xDC00) { // Low surrogate.
				output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000);
			} else {
				// It's an unmatched surrogate; only append this code unit, in case the
				// next code unit is the high surrogate of a surrogate pair.
				output.push(value);
				counter--;
			}
		} else {
			output.push(value);
		}
	}
	return output;
}

/**
 * Creates a string based on an array of numeric code points.
 * @see `punycode.ucs2.decode`
 * @memberOf punycode.ucs2
 * @name encode
 * @param {Array} codePoints The array of numeric code points.
 * @returns {String} The new Unicode string (UCS-2).
 */
var ucs2encode$1 = function (codePoints) { return String.fromCodePoint.apply(String, codePoints); };

/**
 * Converts a basic code point into a digit/integer.
 * @see `digitToBasic()`
 * @private
 * @param {Number} codePoint The basic numeric code point value.
 * @returns {Number} The numeric value of a basic code point (for use in
 * representing integers) in the range `0` to `base - 1`, or `base` if
 * the code point does not represent a value.
 */
var basicToDigit$1 = function(codePoint) {
	if (codePoint >= 0x30 && codePoint < 0x3A) {
		return 26 + (codePoint - 0x30);
	}
	if (codePoint >= 0x41 && codePoint < 0x5B) {
		return codePoint - 0x41;
	}
	if (codePoint >= 0x61 && codePoint < 0x7B) {
		return codePoint - 0x61;
	}
	return base$1;
};

/**
 * Converts a digit/integer into a basic code point.
 * @see `basicToDigit()`
 * @private
 * @param {Number} digit The numeric value of a basic code point.
 * @returns {Number} The basic code point whose value (when used for
 * representing integers) is `digit`, which needs to be in the range
 * `0` to `base - 1`. If `flag` is non-zero, the uppercase form is
 * used; else, the lowercase form is used. The behavior is undefined
 * if `flag` is non-zero and `digit` has no uppercase form.
 */
var digitToBasic$1 = function(digit, flag) {
	//  0..25 map to ASCII a..z or A..Z
	// 26..35 map to ASCII 0..9
	return digit + 22 + 75 * (digit < 26) - ((flag != 0) << 5);
};

/**
 * Bias adaptation function as per section 3.4 of RFC 3492.
 * https://tools.ietf.org/html/rfc3492#section-3.4
 * @private
 */
var adapt$1 = function(delta, numPoints, firstTime) {
	var k = 0;
	delta = firstTime ? floor$1(delta / damp$1) : delta >> 1;
	delta += floor$1(delta / numPoints);
	for (/* no initialization */; delta > baseMinusTMin$1 * tMax$1 >> 1; k += base$1) {
		delta = floor$1(delta / baseMinusTMin$1);
	}
	return floor$1(k + (baseMinusTMin$1 + 1) * delta / (delta + skew$1));
};

/**
 * Converts a Punycode string of ASCII-only symbols to a string of Unicode
 * symbols.
 * @memberOf punycode
 * @param {String} input The Punycode string of ASCII-only symbols.
 * @returns {String} The resulting string of Unicode symbols.
 */
var decode$2 = function(input) {
	// Don't use UCS-2.
	var output = [];
	var inputLength = input.length;
	var i = 0;
	var n = initialN$1;
	var bias = initialBias$1;

	// Handle the basic code points: let `basic` be the number of input code
	// points before the last delimiter, or `0` if there is none, then copy
	// the first basic code points to the output.

	var basic = input.lastIndexOf(delimiter$1);
	if (basic < 0) {
		basic = 0;
	}

	for (var j = 0; j < basic; ++j) {
		// if it's not a basic code point
		if (input.charCodeAt(j) >= 0x80) {
			error$1('not-basic');
		}
		output.push(input.charCodeAt(j));
	}

	// Main decoding loop: start just after the last delimiter if any basic code
	// points were copied; start at the beginning otherwise.

	for (var index = basic > 0 ? basic + 1 : 0; index < inputLength; /* no final expression */) {

		// `index` is the index of the next character to be consumed.
		// Decode a generalized variable-length integer into `delta`,
		// which gets added to `i`. The overflow checking is easier
		// if we increase `i` as we go, then subtract off its starting
		// value at the end to obtain `delta`.
		var oldi = i;
		for (var w = 1, k = base$1; /* no condition */; k += base$1) {

			if (index >= inputLength) {
				error$1('invalid-input');
			}

			var digit = basicToDigit$1(input.charCodeAt(index++));

			if (digit >= base$1) {
				error$1('invalid-input');
			}
			if (digit > floor$1((maxInt$1 - i) / w)) {
				error$1('overflow');
			}

			i += digit * w;
			var t = k <= bias ? tMin$1 : (k >= bias + tMax$1 ? tMax$1 : k - bias);

			if (digit < t) {
				break;
			}

			var baseMinusT = base$1 - t;
			if (w > floor$1(maxInt$1 / baseMinusT)) {
				error$1('overflow');
			}

			w *= baseMinusT;

		}

		var out = output.length + 1;
		bias = adapt$1(i - oldi, out, oldi == 0);

		// `i` was supposed to wrap around from `out` to `0`,
		// incrementing `n` each time, so we'll fix that now:
		if (floor$1(i / out) > maxInt$1 - n) {
			error$1('overflow');
		}

		n += floor$1(i / out);
		i %= out;

		// Insert `n` at position `i` of the output.
		output.splice(i++, 0, n);

	}

	return String.fromCodePoint.apply(String, output);
};

/**
 * Converts a string of Unicode symbols (e.g. a domain name label) to a
 * Punycode string of ASCII-only symbols.
 * @memberOf punycode
 * @param {String} input The string of Unicode symbols.
 * @returns {String} The resulting Punycode string of ASCII-only symbols.
 */
var encode$2 = function(input) {
	var output = [];

	// Convert the input in UCS-2 to an array of Unicode code points.
	input = ucs2decode$1(input);

	// Cache the length.
	var inputLength = input.length;

	// Initialize the state.
	var n = initialN$1;
	var delta = 0;
	var bias = initialBias$1;

	// Handle the basic code points.
	for (var currentValue of input) {
		if (currentValue < 0x80) {
			output.push(stringFromCharCode$1(currentValue));
		}
	}

	var basicLength = output.length;
	var handledCPCount = basicLength;

	// `handledCPCount` is the number of code points that have been handled;
	// `basicLength` is the number of basic code points.

	// Finish the basic string with a delimiter unless it's empty.
	if (basicLength) {
		output.push(delimiter$1);
	}

	// Main encoding loop:
	while (handledCPCount < inputLength) {

		// All non-basic code points < n have been handled already. Find the next
		// larger one:
		var m = maxInt$1;
		for (var currentValue$1 of input) {
			if (currentValue$1 >= n && currentValue$1 < m) {
				m = currentValue$1;
			}
		}

		// Increase `delta` enough to advance the decoder's <n,i> state to <m,0>,
		// but guard against overflow.
		var handledCPCountPlusOne = handledCPCount + 1;
		if (m - n > floor$1((maxInt$1 - delta) / handledCPCountPlusOne)) {
			error$1('overflow');
		}

		delta += (m - n) * handledCPCountPlusOne;
		n = m;

		for (var currentValue$2 of input) {
			if (currentValue$2 < n && ++delta > maxInt$1) {
				error$1('overflow');
			}
			if (currentValue$2 === n) {
				// Represent delta as a generalized variable-length integer.
				var q = delta;
				for (var k = base$1; /* no condition */; k += base$1) {
					var t = k <= bias ? tMin$1 : (k >= bias + tMax$1 ? tMax$1 : k - bias);
					if (q < t) {
						break;
					}
					var qMinusT = q - t;
					var baseMinusT = base$1 - t;
					output.push(
						stringFromCharCode$1(digitToBasic$1(t + qMinusT % baseMinusT, 0))
					);
					q = floor$1(qMinusT / baseMinusT);
				}

				output.push(stringFromCharCode$1(digitToBasic$1(q, 0)));
				bias = adapt$1(delta, handledCPCountPlusOne, handledCPCount === basicLength);
				delta = 0;
				++handledCPCount;
			}
		}

		++delta;
		++n;

	}
	return output.join('');
};

/**
 * Converts a Punycode string representing a domain name or an email address
 * to Unicode. Only the Punycoded parts of the input will be converted, i.e.
 * it doesn't matter if you call it on a string that has already been
 * converted to Unicode.
 * @memberOf punycode
 * @param {String} input The Punycoded domain name or email address to
 * convert to Unicode.
 * @returns {String} The Unicode representation of the given Punycode
 * string.
 */
var toUnicode$1 = function(input) {
	return mapDomain$1(input, function(string) {
		return regexPunycode$1.test(string)
			? decode$2(string.slice(4).toLowerCase())
			: string;
	});
};

/**
 * Converts a Unicode string representing a domain name or an email address to
 * Punycode. Only the non-ASCII parts of the domain name will be converted,
 * i.e. it doesn't matter if you call it with a domain that's already in
 * ASCII.
 * @memberOf punycode
 * @param {String} input The domain name or email address to convert, as a
 * Unicode string.
 * @returns {String} The Punycode representation of the given domain name or
 * email address.
 */
var toASCII$1 = function(input) {
	return mapDomain$1(input, function(string) {
		return regexNonASCII$1.test(string)
			? 'xn--' + encode$2(string)
			: string;
	});
};

/*--------------------------------------------------------------------------*/

/** Define the public API */
var punycode$2 = {
	/**
	 * A string representing the current Punycode.js version number.
	 * @memberOf punycode
	 * @type String
	 */
	'version': '2.3.1',
	/**
	 * An object of methods to convert from JavaScript's internal character
	 * representation (UCS-2) to Unicode code points, and back.
	 * @see <https://mathiasbynens.be/notes/javascript-encoding>
	 * @memberOf punycode
	 * @type Object
	 */
	'ucs2': {
		'decode': ucs2decode$1,
		'encode': ucs2encode$1
	},
	'decode': decode$2,
	'encode': encode$2,
	'toASCII': toASCII$1,
	'toUnicode': toUnicode$1
};// markdown-it default options

var cfg_default = {
  options: {
    // Enable HTML tags in source
    html: false,

    // Use '/' to close single tags (<br />)
    xhtmlOut: false,

    // Convert '\n' in paragraphs into <br>
    breaks: false,

    // CSS language prefix for fenced blocks
    langPrefix: 'language-',

    // autoconvert URL-like texts to links
    linkify: false,

    // Enable some language-neutral replacements + quotes beautification
    typographer: false,

    // Double + single quotes replacement pairs, when typographer enabled,
    // and smartquotes on. Could be either a String or an Array.
    //
    // For example, you can use '«»„“' for Russian, '„“‚‘' for German,
    // and ['«\xA0', '\xA0»', '‹\xA0', '\xA0›'] for French (including nbsp).
    quotes: '\u201c\u201d\u2018\u2019', /* “”‘’ */

    // Highlighter function. Should return escaped HTML,
    // or '' if the source string is not changed and should be escaped externaly.
    // If result starts with <pre... internal wrapper is skipped.
    //
    // function (/*str, lang*/) { return ''; }
    //
    highlight: null,

    // Internal protection, recursion limit
    maxNesting: 100
  },

  components: {
    core: {},
    block: {},
    inline: {}
  }
};// "Zero" preset, with nothing enabled. Useful for manual configuring of simple
// modes. For example, to parse bold/italic only.

var cfg_zero = {
  options: {
    // Enable HTML tags in source
    html: false,

    // Use '/' to close single tags (<br />)
    xhtmlOut: false,

    // Convert '\n' in paragraphs into <br>
    breaks: false,

    // CSS language prefix for fenced blocks
    langPrefix: 'language-',

    // autoconvert URL-like texts to links
    linkify: false,

    // Enable some language-neutral replacements + quotes beautification
    typographer: false,

    // Double + single quotes replacement pairs, when typographer enabled,
    // and smartquotes on. Could be either a String or an Array.
    //
    // For example, you can use '«»„“' for Russian, '„“‚‘' for German,
    // and ['«\xA0', '\xA0»', '‹\xA0', '\xA0›'] for French (including nbsp).
    quotes: '\u201c\u201d\u2018\u2019', /* “”‘’ */

    // Highlighter function. Should return escaped HTML,
    // or '' if the source string is not changed and should be escaped externaly.
    // If result starts with <pre... internal wrapper is skipped.
    //
    // function (/*str, lang*/) { return ''; }
    //
    highlight: null,

    // Internal protection, recursion limit
    maxNesting: 20
  },

  components: {

    core: {
      rules: [
        'normalize',
        'block',
        'inline',
        'text_join'
      ]
    },

    block: {
      rules: [
        'paragraph'
      ]
    },

    inline: {
      rules: [
        'text'
      ],
      rules2: [
        'balance_pairs',
        'fragments_join'
      ]
    }
  }
};// Commonmark default options

var cfg_commonmark = {
  options: {
    // Enable HTML tags in source
    html: true,

    // Use '/' to close single tags (<br />)
    xhtmlOut: true,

    // Convert '\n' in paragraphs into <br>
    breaks: false,

    // CSS language prefix for fenced blocks
    langPrefix: 'language-',

    // autoconvert URL-like texts to links
    linkify: false,

    // Enable some language-neutral replacements + quotes beautification
    typographer: false,

    // Double + single quotes replacement pairs, when typographer enabled,
    // and smartquotes on. Could be either a String or an Array.
    //
    // For example, you can use '«»„“' for Russian, '„“‚‘' for German,
    // and ['«\xA0', '\xA0»', '‹\xA0', '\xA0›'] for French (including nbsp).
    quotes: '\u201c\u201d\u2018\u2019', /* “”‘’ */

    // Highlighter function. Should return escaped HTML,
    // or '' if the source string is not changed and should be escaped externaly.
    // If result starts with <pre... internal wrapper is skipped.
    //
    // function (/*str, lang*/) { return ''; }
    //
    highlight: null,

    // Internal protection, recursion limit
    maxNesting: 20
  },

  components: {

    core: {
      rules: [
        'normalize',
        'block',
        'inline',
        'text_join'
      ]
    },

    block: {
      rules: [
        'blockquote',
        'code',
        'fence',
        'heading',
        'hr',
        'html_block',
        'lheading',
        'list',
        'reference',
        'paragraph'
      ]
    },

    inline: {
      rules: [
        'autolink',
        'backticks',
        'emphasis',
        'entity',
        'escape',
        'html_inline',
        'image',
        'link',
        'newline',
        'text'
      ],
      rules2: [
        'balance_pairs',
        'emphasis',
        'fragments_join'
      ]
    }
  }
};// Main parser class


var config$1 = {
  default: cfg_default,
  zero: cfg_zero,
  commonmark: cfg_commonmark
};

//
// This validator can prohibit more than really needed to prevent XSS. It's a
// tradeoff to keep code simple and to be secure by default.
//
// If you need different setup - override validator method as you wish. Or
// replace it with dummy function and use external sanitizer.
//

var BAD_PROTO_RE$1 = /^(vbscript|javascript|file|data):/;
var GOOD_DATA_RE$1 = /^data:image\/(gif|png|jpeg|webp);/;

function validateLink$1 (url) {
  // url should be normalized at this point, and existing entities are decoded
  var str = url.trim().toLowerCase();

  return BAD_PROTO_RE$1.test(str) ? GOOD_DATA_RE$1.test(str) : true
}

var RECODE_HOSTNAME_FOR$1 = ['http:', 'https:', 'mailto:'];

function normalizeLink$1 (url) {
  var parsed = urlParse$1(url, true);

  if (parsed.hostname) {
    // Encode hostnames in urls like:
    // `http://host/`, `https://host/`, `mailto:user@host`, `//host/`
    //
    // We don't encode unknown schemas, because it's likely that we encode
    // something we shouldn't (e.g. `skype:name` treated as `skype:host`)
    //
    if (!parsed.protocol || RECODE_HOSTNAME_FOR$1.indexOf(parsed.protocol) >= 0) {
      try {
        parsed.hostname = punycode$2.toASCII(parsed.hostname);
      } catch (er) { /**/ }
    }
  }

  return encode$3(format$1(parsed))
}

function normalizeLinkText$1 (url) {
  var parsed = urlParse$1(url, true);

  if (parsed.hostname) {
    // Encode hostnames in urls like:
    // `http://host/`, `https://host/`, `mailto:user@host`, `//host/`
    //
    // We don't encode unknown schemas, because it's likely that we encode
    // something we shouldn't (e.g. `skype:name` treated as `skype:host`)
    //
    if (!parsed.protocol || RECODE_HOSTNAME_FOR$1.indexOf(parsed.protocol) >= 0) {
      try {
        parsed.hostname = punycode$2.toUnicode(parsed.hostname);
      } catch (er) { /**/ }
    }
  }

  // add '%' to exclude list because of https://github.com/markdown-it/markdown-it/issues/720
  return decode$3(format$1(parsed), decode$3.defaultChars + '%')
}

/**
 * class MarkdownIt
 *
 * Main parser/renderer class.
 *
 * ##### Usage
 *
 * ```javascript
 * // node.js, "classic" way:
 * var MarkdownIt = require('markdown-it'),
 *     md = new MarkdownIt();
 * var result = md.render('# markdown-it rulezz!');
 *
 * // node.js, the same, but with sugar:
 * var md = require('markdown-it')();
 * var result = md.render('# markdown-it rulezz!');
 *
 * // browser without AMD, added to "window" on script load
 * // Note, there are no dash.
 * var md = window.markdownit();
 * var result = md.render('# markdown-it rulezz!');
 * ```
 *
 * Single line rendering, without paragraph wrap:
 *
 * ```javascript
 * var md = require('markdown-it')();
 * var result = md.renderInline('__markdown-it__ rulezz!');
 * ```
 **/

/**
 * new MarkdownIt([presetName, options])
 * - presetName (String): optional, `commonmark` / `zero`
 * - options (Object)
 *
 * Creates parser instanse with given config. Can be called without `new`.
 *
 * ##### presetName
 *
 * MarkdownIt provides named presets as a convenience to quickly
 * enable/disable active syntax rules and options for common use cases.
 *
 * - ["commonmark"](https://github.com/markdown-it/markdown-it/blob/master/lib/presets/commonmark.mjs) -
 *   configures parser to strict [CommonMark](http://commonmark.org/) mode.
 * - [default](https://github.com/markdown-it/markdown-it/blob/master/lib/presets/default.mjs) -
 *   similar to GFM, used when no preset name given. Enables all available rules,
 *   but still without html, typographer & autolinker.
 * - ["zero"](https://github.com/markdown-it/markdown-it/blob/master/lib/presets/zero.mjs) -
 *   all rules disabled. Useful to quickly setup your config via `.enable()`.
 *   For example, when you need only `bold` and `italic` markup and nothing else.
 *
 * ##### options:
 *
 * - __html__ - `false`. Set `true` to enable HTML tags in source. Be careful!
 *   That's not safe! You may need external sanitizer to protect output from XSS.
 *   It's better to extend features via plugins, instead of enabling HTML.
 * - __xhtmlOut__ - `false`. Set `true` to add '/' when closing single tags
 *   (`<br />`). This is needed only for full CommonMark compatibility. In real
 *   world you will need HTML output.
 * - __breaks__ - `false`. Set `true` to convert `\n` in paragraphs into `<br>`.
 * - __langPrefix__ - `language-`. CSS language class prefix for fenced blocks.
 *   Can be useful for external highlighters.
 * - __linkify__ - `false`. Set `true` to autoconvert URL-like text to links.
 * - __typographer__  - `false`. Set `true` to enable [some language-neutral
 *   replacement](https://github.com/markdown-it/markdown-it/blob/master/lib/rules_core/replacements.mjs) +
 *   quotes beautification (smartquotes).
 * - __quotes__ - `“”‘’`, String or Array. Double + single quotes replacement
 *   pairs, when typographer enabled and smartquotes on. For example, you can
 *   use `'«»„“'` for Russian, `'„“‚‘'` for German, and
 *   `['«\xA0', '\xA0»', '‹\xA0', '\xA0›']` for French (including nbsp).
 * - __highlight__ - `null`. Highlighter function for fenced code blocks.
 *   Highlighter `function (str, lang)` should return escaped HTML. It can also
 *   return empty string if the source was not changed and should be escaped
 *   externaly. If result starts with <pre... internal wrapper is skipped.
 *
 * ##### Example
 *
 * ```javascript
 * // commonmark mode
 * var md = require('markdown-it')('commonmark');
 *
 * // default mode
 * var md = require('markdown-it')();
 *
 * // enable everything
 * var md = require('markdown-it')({
 *   html: true,
 *   linkify: true,
 *   typographer: true
 * });
 * ```
 *
 * ##### Syntax highlighting
 *
 * ```js
 * var hljs = require('highlight.js') // https://highlightjs.org/
 *
 * var md = require('markdown-it')({
 *   highlight: function (str, lang) {
 *     if (lang && hljs.getLanguage(lang)) {
 *       try {
 *         return hljs.highlight(str, { language: lang, ignoreIllegals: true }).value;
 *       } catch (__) {}
 *     }
 *
 *     return ''; // use external default escaping
 *   }
 * });
 * ```
 *
 * Or with full wrapper override (if you need assign class to `<pre>` or `<code>`):
 *
 * ```javascript
 * var hljs = require('highlight.js') // https://highlightjs.org/
 *
 * // Actual default values
 * var md = require('markdown-it')({
 *   highlight: function (str, lang) {
 *     if (lang && hljs.getLanguage(lang)) {
 *       try {
 *         return '<pre><code class="hljs">' +
 *                hljs.highlight(str, { language: lang, ignoreIllegals: true }).value +
 *                '</code></pre>';
 *       } catch (__) {}
 *     }
 *
 *     return '<pre><code class="hljs">' + md.utils.escapeHtml(str) + '</code></pre>';
 *   }
 * });
 * ```
 *
 **/
function MarkdownIt$1 (presetName, options) {
  if (!(this instanceof MarkdownIt$1)) {
    return new MarkdownIt$1(presetName, options)
  }

  if (!options) {
    if (!isString$2(presetName)) {
      options = presetName || {};
      presetName = 'default';
    }
  }

  /**
   * MarkdownIt#inline -> ParserInline
   *
   * Instance of [[ParserInline]]. You may need it to add new rules when
   * writing plugins. For simple rules control use [[MarkdownIt.disable]] and
   * [[MarkdownIt.enable]].
   **/
  this.inline = new ParserInline$2();

  /**
   * MarkdownIt#block -> ParserBlock
   *
   * Instance of [[ParserBlock]]. You may need it to add new rules when
   * writing plugins. For simple rules control use [[MarkdownIt.disable]] and
   * [[MarkdownIt.enable]].
   **/
  this.block = new ParserBlock$2();

  /**
   * MarkdownIt#core -> Core
   *
   * Instance of [[Core]] chain executor. You may need it to add new rules when
   * writing plugins. For simple rules control use [[MarkdownIt.disable]] and
   * [[MarkdownIt.enable]].
   **/
  this.core = new Core$1();

  /**
   * MarkdownIt#renderer -> Renderer
   *
   * Instance of [[Renderer]]. Use it to modify output look. Or to add rendering
   * rules for new token types, generated by plugins.
   *
   * ##### Example
   *
   * ```javascript
   * var md = require('markdown-it')();
   *
   * function myToken(tokens, idx, options, env, self) {
   *   //...
   *   return result;
   * };
   *
   * md.renderer.rules['my_token'] = myToken
   * ```
   *
   * See [[Renderer]] docs and [source code](https://github.com/markdown-it/markdown-it/blob/master/lib/renderer.mjs).
   **/
  this.renderer = new Renderer$2();

  /**
   * MarkdownIt#linkify -> LinkifyIt
   *
   * [linkify-it](https://github.com/markdown-it/linkify-it) instance.
   * Used by [linkify](https://github.com/markdown-it/markdown-it/blob/master/lib/rules_core/linkify.mjs)
   * rule.
   **/
  this.linkify = new LinkifyIt$2();

  /**
   * MarkdownIt#validateLink(url) -> Boolean
   *
   * Link validation function. CommonMark allows too much in links. By default
   * we disable `javascript:`, `vbscript:`, `file:` schemas, and almost all `data:...` schemas
   * except some embedded image types.
   *
   * You can change this behaviour:
   *
   * ```javascript
   * var md = require('markdown-it')();
   * // enable everything
   * md.validateLink = function () { return true; }
   * ```
   **/
  this.validateLink = validateLink$1;

  /**
   * MarkdownIt#normalizeLink(url) -> String
   *
   * Function used to encode link url to a machine-readable format,
   * which includes url-encoding, punycode, etc.
   **/
  this.normalizeLink = normalizeLink$1;

  /**
   * MarkdownIt#normalizeLinkText(url) -> String
   *
   * Function used to decode link url to a human-readable format`
   **/
  this.normalizeLinkText = normalizeLinkText$1;

  // Expose utils & helpers for easy acces from plugins

  /**
   * MarkdownIt#utils -> utils
   *
   * Assorted utility functions, useful to write plugins. See details
   * [here](https://github.com/markdown-it/markdown-it/blob/master/lib/common/utils.mjs).
   **/
  this.utils = utils$2;

  /**
   * MarkdownIt#helpers -> helpers
   *
   * Link components parser functions, useful to write plugins. See details
   * [here](https://github.com/markdown-it/markdown-it/blob/master/lib/helpers).
   **/
  this.helpers = assign$3({}, helpers$2);

  this.options = {};
  this.configure(presetName);

  if (options) { this.set(options); }
}

/** chainable
 * MarkdownIt.set(options)
 *
 * Set parser options (in the same format as in constructor). Probably, you
 * will never need it, but you can change options after constructor call.
 *
 * ##### Example
 *
 * ```javascript
 * var md = require('markdown-it')()
 *             .set({ html: true, breaks: true })
 *             .set({ typographer, true });
 * ```
 *
 * __Note:__ To achieve the best possible performance, don't modify a
 * `markdown-it` instance options on the fly. If you need multiple configurations
 * it's best to create multiple instances and initialize each with separate
 * config.
 **/
MarkdownIt$1.prototype.set = function (options) {
  assign$3(this.options, options);
  return this
};

/** chainable, internal
 * MarkdownIt.configure(presets)
 *
 * Batch load of all options and compenent settings. This is internal method,
 * and you probably will not need it. But if you will - see available presets
 * and data structure [here](https://github.com/markdown-it/markdown-it/tree/master/lib/presets)
 *
 * We strongly recommend to use presets instead of direct config loads. That
 * will give better compatibility with next versions.
 **/
MarkdownIt$1.prototype.configure = function (presets) {
  var self = this;

  if (isString$2(presets)) {
    var presetName = presets;
    presets = config$1[presetName];
    if (!presets) { throw new Error('Wrong `markdown-it` preset "' + presetName + '", check name') }
  }

  if (!presets) { throw new Error('Wrong `markdown-it` preset, can\'t be empty') }

  if (presets.options) { self.set(presets.options); }

  if (presets.components) {
    Object.keys(presets.components).forEach(function (name) {
      if (presets.components[name].rules) {
        self[name].ruler.enableOnly(presets.components[name].rules);
      }
      if (presets.components[name].rules2) {
        self[name].ruler2.enableOnly(presets.components[name].rules2);
      }
    });
  }
  return this
};

/** chainable
 * MarkdownIt.enable(list, ignoreInvalid)
 * - list (String|Array): rule name or list of rule names to enable
 * - ignoreInvalid (Boolean): set `true` to ignore errors when rule not found.
 *
 * Enable list or rules. It will automatically find appropriate components,
 * containing rules with given names. If rule not found, and `ignoreInvalid`
 * not set - throws exception.
 *
 * ##### Example
 *
 * ```javascript
 * var md = require('markdown-it')()
 *             .enable(['sub', 'sup'])
 *             .disable('smartquotes');
 * ```
 **/
MarkdownIt$1.prototype.enable = function (list, ignoreInvalid) {
  var result = [];

  if (!Array.isArray(list)) { list = [list]; }

  ['core', 'block', 'inline'].forEach(function (chain) {
    result = result.concat(this[chain].ruler.enable(list, true));
  }, this);

  result = result.concat(this.inline.ruler2.enable(list, true));

  var missed = list.filter(function (name) { return result.indexOf(name) < 0 });

  if (missed.length && !ignoreInvalid) {
    throw new Error('MarkdownIt. Failed to enable unknown rule(s): ' + missed)
  }

  return this
};

/** chainable
 * MarkdownIt.disable(list, ignoreInvalid)
 * - list (String|Array): rule name or list of rule names to disable.
 * - ignoreInvalid (Boolean): set `true` to ignore errors when rule not found.
 *
 * The same as [[MarkdownIt.enable]], but turn specified rules off.
 **/
MarkdownIt$1.prototype.disable = function (list, ignoreInvalid) {
  var result = [];

  if (!Array.isArray(list)) { list = [list]; }

  ['core', 'block', 'inline'].forEach(function (chain) {
    result = result.concat(this[chain].ruler.disable(list, true));
  }, this);

  result = result.concat(this.inline.ruler2.disable(list, true));

  var missed = list.filter(function (name) { return result.indexOf(name) < 0 });

  if (missed.length && !ignoreInvalid) {
    throw new Error('MarkdownIt. Failed to disable unknown rule(s): ' + missed)
  }
  return this
};

/** chainable
 * MarkdownIt.use(plugin, params)
 *
 * Load specified plugin with given params into current parser instance.
 * It's just a sugar to call `plugin(md, params)` with curring.
 *
 * ##### Example
 *
 * ```javascript
 * var iterator = require('markdown-it-for-inline');
 * var md = require('markdown-it')()
 *             .use(iterator, 'foo_replace', 'text', function (tokens, idx) {
 *               tokens[idx].content = tokens[idx].content.replace(/foo/g, 'bar');
 *             });
 * ```
 **/
MarkdownIt$1.prototype.use = function (plugin /*, params, ... */) {
  var args = [this].concat(Array.prototype.slice.call(arguments, 1));
  plugin.apply(plugin, args);
  return this
};

/** internal
 * MarkdownIt.parse(src, env) -> Array
 * - src (String): source string
 * - env (Object): environment sandbox
 *
 * Parse input string and return list of block tokens (special token type
 * "inline" will contain list of inline tokens). You should not call this
 * method directly, until you write custom renderer (for example, to produce
 * AST).
 *
 * `env` is used to pass data between "distributed" rules and return additional
 * metadata like reference info, needed for the renderer. It also can be used to
 * inject data in specific cases. Usually, you will be ok to pass `{}`,
 * and then pass updated object to renderer.
 **/
MarkdownIt$1.prototype.parse = function (src, env) {
  if (typeof src !== 'string') {
    throw new Error('Input data should be a String')
  }

  var state = new this.core.State(src, this, env);

  this.core.process(state);

  return state.tokens
};

/**
 * MarkdownIt.render(src [, env]) -> String
 * - src (String): source string
 * - env (Object): environment sandbox
 *
 * Render markdown string into html. It does all magic for you :).
 *
 * `env` can be used to inject additional metadata (`{}` by default).
 * But you will not need it with high probability. See also comment
 * in [[MarkdownIt.parse]].
 **/
MarkdownIt$1.prototype.render = function (src, env) {
  env = env || {};

  return this.renderer.render(this.parse(src, env), this.options, env)
};

/** internal
 * MarkdownIt.parseInline(src, env) -> Array
 * - src (String): source string
 * - env (Object): environment sandbox
 *
 * The same as [[MarkdownIt.parse]] but skip all block rules. It returns the
 * block tokens list with the single `inline` element, containing parsed inline
 * tokens in `children` property. Also updates `env` object.
 **/
MarkdownIt$1.prototype.parseInline = function (src, env) {
  var state = new this.core.State(src, this, env);

  state.inlineMode = true;
  this.core.process(state);

  return state.tokens
};

/**
 * MarkdownIt.renderInline(src [, env]) -> String
 * - src (String): source string
 * - env (Object): environment sandbox
 *
 * Similar to [[MarkdownIt.render]] but for single paragraph content. Result
 * will NOT be wrapped into `<p>` tags.
 **/
MarkdownIt$1.prototype.renderInline = function (src, env) {
  env = env || {};

  return this.renderer.render(this.parseInline(src, env), this.options, env)
};/**
Document schema for the data model used by CommonMark.
*/
var schema$o = new Schema({
    nodes: {
        doc: {
            content: "block+"
        },
        paragraph: {
            content: "inline*",
            group: "block",
            parseDOM: [{ tag: "p" }],
            toDOM: function toDOM() { return ["p", 0]; }
        },
        blockquote: {
            content: "block+",
            group: "block",
            parseDOM: [{ tag: "blockquote" }],
            toDOM: function toDOM() { return ["blockquote", 0]; }
        },
        horizontal_rule: {
            group: "block",
            parseDOM: [{ tag: "hr" }],
            toDOM: function toDOM() { return ["div", ["hr"]]; }
        },
        heading: {
            attrs: { level: { default: 1 } },
            content: "(text | image)*",
            group: "block",
            defining: true,
            parseDOM: [{ tag: "h1", attrs: { level: 1 } },
                { tag: "h2", attrs: { level: 2 } },
                { tag: "h3", attrs: { level: 3 } },
                { tag: "h4", attrs: { level: 4 } },
                { tag: "h5", attrs: { level: 5 } },
                { tag: "h6", attrs: { level: 6 } }],
            toDOM: function toDOM(node) { return ["h" + node.attrs.level, 0]; }
        },
        code_block: {
            content: "text*",
            group: "block",
            code: true,
            defining: true,
            marks: "",
            attrs: { params: { default: "" } },
            parseDOM: [{ tag: "pre", preserveWhitespace: "full", getAttrs: function (node) { return ({ params: node.getAttribute("data-params") || "" }); } }],
            toDOM: function toDOM(node) { return ["pre", node.attrs.params ? { "data-params": node.attrs.params } : {}, ["code", 0]]; }
        },
        ordered_list: {
            content: "list_item+",
            group: "block",
            attrs: { order: { default: 1 }, tight: { default: false } },
            parseDOM: [{ tag: "ol", getAttrs: function getAttrs(dom) {
                        return { order: dom.hasAttribute("start") ? +dom.getAttribute("start") : 1,
                            tight: dom.hasAttribute("data-tight") };
                    } }],
            toDOM: function toDOM(node) {
                return ["ol", { start: node.attrs.order == 1 ? null : node.attrs.order,
                        "data-tight": node.attrs.tight ? "true" : null }, 0];
            }
        },
        bullet_list: {
            content: "list_item+",
            group: "block",
            attrs: { tight: { default: false } },
            parseDOM: [{ tag: "ul", getAttrs: function (dom) { return ({ tight: dom.hasAttribute("data-tight") }); } }],
            toDOM: function toDOM(node) { return ["ul", { "data-tight": node.attrs.tight ? "true" : null }, 0]; }
        },
        list_item: {
            content: "block+",
            defining: true,
            parseDOM: [{ tag: "li" }],
            toDOM: function toDOM() { return ["li", 0]; }
        },
        text: {
            group: "inline"
        },
        image: {
            inline: true,
            attrs: {
                src: {},
                alt: { default: null },
                title: { default: null }
            },
            group: "inline",
            draggable: true,
            parseDOM: [{ tag: "img[src]", getAttrs: function getAttrs(dom) {
                        return {
                            src: dom.getAttribute("src"),
                            title: dom.getAttribute("title"),
                            alt: dom.getAttribute("alt")
                        };
                    } }],
            toDOM: function toDOM(node) { return ["img", node.attrs]; }
        },
        hard_break: {
            inline: true,
            group: "inline",
            selectable: false,
            parseDOM: [{ tag: "br" }],
            toDOM: function toDOM() { return ["br"]; }
        }
    },
    marks: {
        em: {
            parseDOM: [
                { tag: "i" }, { tag: "em" },
                { style: "font-style=italic" },
                { style: "font-style=normal", clearMark: function (m) { return m.type.name == "em"; } }
            ],
            toDOM: function toDOM() { return ["em"]; }
        },
        strong: {
            parseDOM: [
                { tag: "strong" },
                { tag: "b", getAttrs: function (node) { return node.style.fontWeight != "normal" && null; } },
                { style: "font-weight=400", clearMark: function (m) { return m.type.name == "strong"; } },
                { style: "font-weight", getAttrs: function (value) { return /^(bold(er)?|[5-9]\d{2,})$/.test(value) && null; } }
            ],
            toDOM: function toDOM() { return ["strong"]; }
        },
        link: {
            attrs: {
                href: {},
                title: { default: null }
            },
            inclusive: false,
            parseDOM: [{ tag: "a[href]", getAttrs: function getAttrs(dom) {
                        return { href: dom.getAttribute("href"), title: dom.getAttribute("title") };
                    } }],
            toDOM: function toDOM(node) { return ["a", node.attrs]; }
        },
        code: {
            parseDOM: [{ tag: "code" }],
            toDOM: function toDOM() { return ["code"]; }
        }
    }
});

// @ts-ignore
function maybeMerge(a, b) {
    if (a.isText && b.isText && Mark.sameSet(a.marks, b.marks))
        { return a.withText(a.text + b.text); }
}
// Object used to track the context of a running parse.
var MarkdownParseState = function MarkdownParseState(schema, tokenHandlers) {
    this.schema = schema;
    this.tokenHandlers = tokenHandlers;
    this.stack = [{ type: schema.topNodeType, attrs: null, content: [], marks: Mark.none }];
};
MarkdownParseState.prototype.top = function top () {
    return this.stack[this.stack.length - 1];
};
MarkdownParseState.prototype.push = function push (elt) {
    if (this.stack.length)
        { this.top().content.push(elt); }
};
// Adds the given text to the current position in the document,
// using the current marks as styling.
MarkdownParseState.prototype.addText = function addText (text) {
    if (!text)
        { return; }
    var top = this.top(), nodes = top.content, last = nodes[nodes.length - 1];
    var node = this.schema.text(text, top.marks), merged;
    if (last && (merged = maybeMerge(last, node)))
        { nodes[nodes.length - 1] = merged; }
    else
        { nodes.push(node); }
};
// Adds the given mark to the set of active marks.
MarkdownParseState.prototype.openMark = function openMark (mark) {
    var top = this.top();
    top.marks = mark.addToSet(top.marks);
};
// Removes the given mark from the set of active marks.
MarkdownParseState.prototype.closeMark = function closeMark (mark) {
    var top = this.top();
    top.marks = mark.removeFromSet(top.marks);
};
MarkdownParseState.prototype.parseTokens = function parseTokens (toks) {
    for (var i = 0; i < toks.length; i++) {
        var tok = toks[i];
        var handler = this.tokenHandlers[tok.type];
        if (!handler)
            { throw new Error("Token type `" + tok.type + "` not supported by Markdown parser"); }
        handler(this, tok, toks, i);
    }
};
// Add a node at the current position.
MarkdownParseState.prototype.addNode = function addNode (type, attrs, content) {
    var top = this.top();
    var node = type.createAndFill(attrs, content, top ? top.marks : []);
    if (!node)
        { return null; }
    this.push(node);
    return node;
};
// Wrap subsequent content in a node of the given type.
MarkdownParseState.prototype.openNode = function openNode (type, attrs) {
    this.stack.push({ type: type, attrs: attrs, content: [], marks: Mark.none });
};
// Close and return the node that is currently on top of the stack.
MarkdownParseState.prototype.closeNode = function closeNode () {
    var info = this.stack.pop();
    return this.addNode(info.type, info.attrs, info.content);
};
function attrs(spec, token, tokens, i) {
    if (spec.getAttrs)
        { return spec.getAttrs(token, tokens, i); }
    // For backwards compatibility when `attrs` is a Function
    else if (spec.attrs instanceof Function)
        { return spec.attrs(token); }
    else
        { return spec.attrs; }
}
// Code content is represented as a single token with a `content`
// property in Markdown-it.
function noCloseToken(spec, type) {
    return spec.noCloseToken || type == "code_inline" || type == "code_block" || type == "fence";
}
function withoutTrailingNewline(str) {
    return str[str.length - 1] == "\n" ? str.slice(0, str.length - 1) : str;
}
function noOp() { }
function tokenHandlers(schema, tokens) {
    var handlers = Object.create(null);
    var loop = function ( type ) {
        var spec = tokens[type];
        if (spec.block) {
            var nodeType = schema.nodeType(spec.block);
            if (noCloseToken(spec, type)) {
                handlers[type] = function (state, tok, tokens, i) {
                    state.openNode(nodeType, attrs(spec, tok, tokens, i));
                    state.addText(withoutTrailingNewline(tok.content));
                    state.closeNode();
                };
            }
            else {
                handlers[type + "_open"] = function (state, tok, tokens, i) { return state.openNode(nodeType, attrs(spec, tok, tokens, i)); };
                handlers[type + "_close"] = function (state) { return state.closeNode(); };
            }
        }
        else if (spec.node) {
            var nodeType$1 = schema.nodeType(spec.node);
            handlers[type] = function (state, tok, tokens, i) { return state.addNode(nodeType$1, attrs(spec, tok, tokens, i)); };
        }
        else if (spec.mark) {
            var markType = schema.marks[spec.mark];
            if (noCloseToken(spec, type)) {
                handlers[type] = function (state, tok, tokens, i) {
                    state.openMark(markType.create(attrs(spec, tok, tokens, i)));
                    state.addText(withoutTrailingNewline(tok.content));
                    state.closeMark(markType);
                };
            }
            else {
                handlers[type + "_open"] = function (state, tok, tokens, i) { return state.openMark(markType.create(attrs(spec, tok, tokens, i))); };
                handlers[type + "_close"] = function (state) { return state.closeMark(markType); };
            }
        }
        else if (spec.ignore) {
            if (noCloseToken(spec, type)) {
                handlers[type] = noOp;
            }
            else {
                handlers[type + "_open"] = noOp;
                handlers[type + "_close"] = noOp;
            }
        }
        else {
            throw new RangeError("Unrecognized parsing spec " + JSON.stringify(spec));
        }
    };

    for (var type in tokens) loop( type );
    handlers.text = function (state, tok) { return state.addText(tok.content); };
    handlers.inline = function (state, tok) { return state.parseTokens(tok.children); };
    handlers.softbreak = handlers.softbreak || (function (state) { return state.addText(" "); });
    return handlers;
}
/**
A configuration of a Markdown parser. Such a parser uses
[markdown-it](https://github.com/markdown-it/markdown-it) to
tokenize a file, and then runs the custom rules it is given over
the tokens to create a ProseMirror document tree.
*/
var MarkdownParser = function MarkdownParser(
/**
The parser's document schema.
*/
schema, 
/**
This parser's markdown-it tokenizer.
*/
tokenizer, 
/**
The value of the `tokens` object used to construct this
parser. Can be useful to copy and modify to base other parsers
on.
*/
tokens) {
    this.schema = schema;
    this.tokenizer = tokenizer;
    this.tokens = tokens;
    this.tokenHandlers = tokenHandlers(schema, tokens);
};
/**
Parse a string as [CommonMark](http://commonmark.org/) markup,
and create a ProseMirror document as prescribed by this parser's
rules.
    
The second argument, when given, is passed through to the
[Markdown
parser](https://markdown-it.github.io/markdown-it/#MarkdownIt.parse).
*/
MarkdownParser.prototype.parse = function parse (text, markdownEnv) {
        if ( markdownEnv === void 0 ) markdownEnv = {};

    var state = new MarkdownParseState(this.schema, this.tokenHandlers), doc;
    state.parseTokens(this.tokenizer.parse(text, markdownEnv));
    do {
        doc = state.closeNode();
    } while (state.stack.length);
    return doc || this.schema.topNodeType.createAndFill();
};
function listIsTight(tokens, i) {
    while (++i < tokens.length)
        { if (tokens[i].type != "list_item_open")
            { return tokens[i].hidden; } }
    return false;
}
/**
A parser parsing unextended [CommonMark](http://commonmark.org/),
without inline HTML, and producing a document in the basic schema.
*/
var defaultMarkdownParser = new MarkdownParser(schema$o, MarkdownIt$1("commonmark", { html: false }), {
    blockquote: { block: "blockquote" },
    paragraph: { block: "paragraph" },
    list_item: { block: "list_item" },
    bullet_list: { block: "bullet_list", getAttrs: function (_, tokens, i) { return ({ tight: listIsTight(tokens, i) }); } },
    ordered_list: { block: "ordered_list", getAttrs: function (tok, tokens, i) { return ({
            order: +tok.attrGet("start") || 1,
            tight: listIsTight(tokens, i)
        }); } },
    heading: { block: "heading", getAttrs: function (tok) { return ({ level: +tok.tag.slice(1) }); } },
    code_block: { block: "code_block", noCloseToken: true },
    fence: { block: "code_block", getAttrs: function (tok) { return ({ params: tok.info || "" }); }, noCloseToken: true },
    hr: { node: "horizontal_rule" },
    image: { node: "image", getAttrs: function (tok) { return ({
            src: tok.attrGet("src"),
            title: tok.attrGet("title") || null,
            alt: tok.children[0] && tok.children[0].content || null
        }); } },
    hardbreak: { node: "hard_break" },
    em: { mark: "em" },
    strong: { mark: "strong" },
    link: { mark: "link", getAttrs: function (tok) { return ({
            href: tok.attrGet("href"),
            title: tok.attrGet("title") || null
        }); } },
    code_inline: { mark: "code", noCloseToken: true }
});

var blankMark = { open: "", close: "", mixable: true };
/**
A specification for serializing a ProseMirror document as
Markdown/CommonMark text.
*/
var MarkdownSerializer = function MarkdownSerializer(
/**
The node serializer functions for this serializer.
*/
nodes, 
/**
The mark serializer info.
*/
marks, options) {
    if ( options === void 0 ) options = {};

    this.nodes = nodes;
    this.marks = marks;
    this.options = options;
};
/**
Serialize the content of the given node to
[CommonMark](http://commonmark.org/).
*/
MarkdownSerializer.prototype.serialize = function serialize (content, options) {
        if ( options === void 0 ) options = {};

    options = Object.assign({}, this.options, options);
    var state = new MarkdownSerializerState(this.nodes, this.marks, options);
    state.renderContent(content);
    return state.out;
};
/**
A serializer for the [basic schema](https://prosemirror.net/docs/ref/#schema).
*/
var defaultMarkdownSerializer = new MarkdownSerializer({
    blockquote: function blockquote(state, node) {
        state.wrapBlock("> ", null, node, function () { return state.renderContent(node); });
    },
    code_block: function code_block(state, node) {
        // Make sure the front matter fences are longer than any dash sequence within it
        var backticks = node.textContent.match(/`{3,}/gm);
        var fence = backticks ? (backticks.sort().slice(-1)[0] + "`") : "```";
        state.write(fence + (node.attrs.params || "") + "\n");
        state.text(node.textContent, false);
        // Add a newline to the current content before adding closing marker
        state.write("\n");
        state.write(fence);
        state.closeBlock(node);
    },
    heading: function heading(state, node) {
        state.write(state.repeat("#", node.attrs.level) + " ");
        state.renderInline(node, false);
        state.closeBlock(node);
    },
    horizontal_rule: function horizontal_rule(state, node) {
        state.write(node.attrs.markup || "---");
        state.closeBlock(node);
    },
    bullet_list: function bullet_list(state, node) {
        state.renderList(node, "  ", function () { return (node.attrs.bullet || "*") + " "; });
    },
    ordered_list: function ordered_list(state, node) {
        var start = node.attrs.order || 1;
        var maxW = String(start + node.childCount - 1).length;
        var space = state.repeat(" ", maxW + 2);
        state.renderList(node, space, function (i) {
            var nStr = String(start + i);
            return state.repeat(" ", maxW - nStr.length) + nStr + ". ";
        });
    },
    list_item: function list_item(state, node) {
        state.renderContent(node);
    },
    paragraph: function paragraph(state, node) {
        state.renderInline(node);
        state.closeBlock(node);
    },
    image: function image(state, node) {
        state.write("![" + state.esc(node.attrs.alt || "") + "](" + node.attrs.src.replace(/[\(\)]/g, "\\$&") +
            (node.attrs.title ? ' "' + node.attrs.title.replace(/"/g, '\\"') + '"' : "") + ")");
    },
    hard_break: function hard_break(state, node, parent, index) {
        for (var i = index + 1; i < parent.childCount; i++)
            { if (parent.child(i).type != node.type) {
                state.write("\\\n");
                return;
            } }
    },
    text: function text(state, node) {
        state.text(node.text, !state.inAutolink);
    }
}, {
    em: { open: "*", close: "*", mixable: true, expelEnclosingWhitespace: true },
    strong: { open: "**", close: "**", mixable: true, expelEnclosingWhitespace: true },
    link: {
        open: function open(state, mark, parent, index) {
            state.inAutolink = isPlainURL(mark, parent, index);
            return state.inAutolink ? "<" : "[";
        },
        close: function close(state, mark, parent, index) {
            var inAutolink = state.inAutolink;
            state.inAutolink = undefined;
            return inAutolink ? ">"
                : "](" + mark.attrs.href.replace(/[\(\)"]/g, "\\$&") + (mark.attrs.title ? (" \"" + (mark.attrs.title.replace(/"/g, '\\"')) + "\"") : "") + ")";
        },
        mixable: true
    },
    code: { open: function open(_state, _mark, parent, index) { return backticksFor(parent.child(index), -1); },
        close: function close(_state, _mark, parent, index) { return backticksFor(parent.child(index - 1), 1); },
        escape: false }
});
function backticksFor(node, side) {
    var ticks = /`+/g, m, len = 0;
    if (node.isText)
        { while (m = ticks.exec(node.text))
            { len = Math.max(len, m[0].length); } }
    var result = len > 0 && side > 0 ? " `" : "`";
    for (var i = 0; i < len; i++)
        { result += "`"; }
    if (len > 0 && side < 0)
        { result += " "; }
    return result;
}
function isPlainURL(link, parent, index) {
    if (link.attrs.title || !/^\w+:/.test(link.attrs.href))
        { return false; }
    var content = parent.child(index);
    if (!content.isText || content.text != link.attrs.href || content.marks[content.marks.length - 1] != link)
        { return false; }
    return index == parent.childCount - 1 || !link.isInSet(parent.child(index + 1).marks);
}
/**
This is an object used to track state and expose
methods related to markdown serialization. Instances are passed to
node and mark serialization methods (see `toMarkdown`).
*/
var MarkdownSerializerState = function MarkdownSerializerState(
/**
@internal
*/
nodes, 
/**
@internal
*/
marks, 
/**
The options passed to the serializer.
*/
options) {
    this.nodes = nodes;
    this.marks = marks;
    this.options = options;
    /**
    @internal
    */
    this.delim = "";
    /**
    @internal
    */
    this.out = "";
    /**
    @internal
    */
    this.closed = null;
    /**
    @internal
    */
    this.inAutolink = undefined;
    /**
    @internal
    */
    this.atBlockStart = false;
    /**
    @internal
    */
    this.inTightList = false;
    if (typeof this.options.tightLists == "undefined")
        { this.options.tightLists = false; }
    if (typeof this.options.hardBreakNodeName == "undefined")
        { this.options.hardBreakNodeName = "hard_break"; }
};
/**
@internal
*/
MarkdownSerializerState.prototype.flushClose = function flushClose (size) {
        if ( size === void 0 ) size = 2;

    if (this.closed) {
        if (!this.atBlank())
            { this.out += "\n"; }
        if (size > 1) {
            var delimMin = this.delim;
            var trim = /\s+$/.exec(delimMin);
            if (trim)
                { delimMin = delimMin.slice(0, delimMin.length - trim[0].length); }
            for (var i = 1; i < size; i++)
                { this.out += delimMin + "\n"; }
        }
        this.closed = null;
    }
};
/**
@internal
*/
MarkdownSerializerState.prototype.getMark = function getMark (name) {
    var info = this.marks[name];
    if (!info) {
        if (this.options.strict !== false)
            { throw new Error(("Mark type `" + name + "` not supported by Markdown renderer")); }
        info = blankMark;
    }
    return info;
};
/**
Render a block, prefixing each line with `delim`, and the first
line in `firstDelim`. `node` should be the node that is closed at
the end of the block, and `f` is a function that renders the
content of the block.
*/
MarkdownSerializerState.prototype.wrapBlock = function wrapBlock (delim, firstDelim, node, f) {
    var old = this.delim;
    this.write(firstDelim != null ? firstDelim : delim);
    this.delim += delim;
    f();
    this.delim = old;
    this.closeBlock(node);
};
/**
@internal
*/
MarkdownSerializerState.prototype.atBlank = function atBlank () {
    return /(^|\n)$/.test(this.out);
};
/**
Ensure the current content ends with a newline.
*/
MarkdownSerializerState.prototype.ensureNewLine = function ensureNewLine () {
    if (!this.atBlank())
        { this.out += "\n"; }
};
/**
Prepare the state for writing output (closing closed paragraphs,
adding delimiters, and so on), and then optionally add content
(unescaped) to the output.
*/
MarkdownSerializerState.prototype.write = function write (content) {
    this.flushClose();
    if (this.delim && this.atBlank())
        { this.out += this.delim; }
    if (content)
        { this.out += content; }
};
/**
Close the block for the given node.
*/
MarkdownSerializerState.prototype.closeBlock = function closeBlock (node) {
    this.closed = node;
};
/**
Add the given text to the document. When escape is not `false`,
it will be escaped.
*/
MarkdownSerializerState.prototype.text = function text (text$1, escape) {
        if ( escape === void 0 ) escape = true;

    var lines = text$1.split("\n");
    for (var i = 0; i < lines.length; i++) {
        this.write();
        // Escape exclamation marks in front of links
        if (!escape && lines[i][0] == "[" && /(^|[^\\])\!$/.test(this.out))
            { this.out = this.out.slice(0, this.out.length - 1) + "\\!"; }
        this.out += escape ? this.esc(lines[i], this.atBlockStart) : lines[i];
        if (i != lines.length - 1)
            { this.out += "\n"; }
    }
};
/**
Render the given node as a block.
*/
MarkdownSerializerState.prototype.render = function render (node, parent, index) {
    if (this.nodes[node.type.name]) {
        this.nodes[node.type.name](this, node, parent, index);
    }
    else {
        if (this.options.strict !== false) {
            throw new Error("Token type `" + node.type.name + "` not supported by Markdown renderer");
        }
        else if (!node.type.isLeaf) {
            if (node.type.inlineContent)
                { this.renderInline(node); }
            else
                { this.renderContent(node); }
            if (node.isBlock)
                { this.closeBlock(node); }
        }
    }
};
/**
Render the contents of `parent` as block nodes.
*/
MarkdownSerializerState.prototype.renderContent = function renderContent (parent) {
        var this$1$1 = this;

    parent.forEach(function (node, _, i) { return this$1$1.render(node, parent, i); });
};
/**
Render the contents of `parent` as inline content.
*/
MarkdownSerializerState.prototype.renderInline = function renderInline (parent, fromBlockStart) {
        var this$1$1 = this;
        if ( fromBlockStart === void 0 ) fromBlockStart = true;

    this.atBlockStart = fromBlockStart;
    var active = [], trailing = "";
    var progress = function (node, offset, index) {
        var marks = node ? node.marks : [];
        // Remove marks from `hard_break` that are the last node inside
        // that mark to prevent parser edge cases with new lines just
        // before closing marks.
        if (node && node.type.name === this$1$1.options.hardBreakNodeName)
            { marks = marks.filter(function (m) {
                if (index + 1 == parent.childCount)
                    { return false; }
                var next = parent.child(index + 1);
                return m.isInSet(next.marks) && (!next.isText || /\S/.test(next.text));
            }); }
        var leading = trailing;
        trailing = "";
        // If whitespace has to be expelled from the node, adjust
        // leading and trailing accordingly.
        if (node && node.isText && marks.some(function (mark) {
            var info = this$1$1.getMark(mark.type.name);
            return info && info.expelEnclosingWhitespace && !mark.isInSet(active);
        })) {
            var ref = /^(\s*)(.*)$/m.exec(node.text);
                ref[0];
                var lead = ref[1];
                var rest = ref[2];
            if (lead) {
                leading += lead;
                node = rest ? node.withText(rest) : null;
                if (!node)
                    { marks = active; }
            }
        }
        if (node && node.isText && marks.some(function (mark) {
            var info = this$1$1.getMark(mark.type.name);
            return info && info.expelEnclosingWhitespace &&
                (index == parent.childCount - 1 || !mark.isInSet(parent.child(index + 1).marks));
        })) {
            var ref$1 = /^(.*?)(\s*)$/m.exec(node.text);
                ref$1[0];
                var rest$1 = ref$1[1];
                var trail = ref$1[2];
            if (trail) {
                trailing = trail;
                node = rest$1 ? node.withText(rest$1) : null;
                if (!node)
                    { marks = active; }
            }
        }
        var inner = marks.length ? marks[marks.length - 1] : null;
        var noEsc = inner && this$1$1.getMark(inner.type.name).escape === false;
        var len = marks.length - (noEsc ? 1 : 0);
        // Try to reorder 'mixable' marks, such as em and strong, which
        // in Markdown may be opened and closed in different order, so
        // that order of the marks for the token matches the order in
        // active.
        outer: for (var i = 0; i < len; i++) {
            var mark = marks[i];
            if (!this$1$1.getMark(mark.type.name).mixable)
                { break; }
            for (var j = 0; j < active.length; j++) {
                var other = active[j];
                if (!this$1$1.getMark(other.type.name).mixable)
                    { break; }
                if (mark.eq(other)) {
                    if (i > j)
                        { marks = marks.slice(0, j).concat(mark).concat(marks.slice(j, i)).concat(marks.slice(i + 1, len)); }
                    else if (j > i)
                        { marks = marks.slice(0, i).concat(marks.slice(i + 1, j)).concat(mark).concat(marks.slice(j, len)); }
                    continue outer;
                }
            }
        }
        // Find the prefix of the mark set that didn't change
        var keep = 0;
        while (keep < Math.min(active.length, len) && marks[keep].eq(active[keep]))
            { ++keep; }
        // Close the marks that need to be closed
        while (keep < active.length)
            { this$1$1.text(this$1$1.markString(active.pop(), false, parent, index), false); }
        // Output any previously expelled trailing whitespace outside the marks
        if (leading)
            { this$1$1.text(leading); }
        // Open the marks that need to be opened
        if (node) {
            while (active.length < len) {
                var add = marks[active.length];
                active.push(add);
                this$1$1.text(this$1$1.markString(add, true, parent, index), false);
                this$1$1.atBlockStart = false;
            }
            // Render the node. Special case code marks, since their content
            // may not be escaped.
            if (noEsc && node.isText)
                { this$1$1.text(this$1$1.markString(inner, true, parent, index) + node.text +
                    this$1$1.markString(inner, false, parent, index + 1), false); }
            else
                { this$1$1.render(node, parent, index); }
            this$1$1.atBlockStart = false;
        }
        // After the first non-empty text node is rendered, the end of output
        // is no longer at block start.
        //
        // FIXME: If a non-text node writes something to the output for this
        // block, the end of output is also no longer at block start. But how
        // can we detect that?
        if ((node === null || node === void 0 ? void 0 : node.isText) && node.nodeSize > 0) {
            this$1$1.atBlockStart = false;
        }
    };
    parent.forEach(progress);
    progress(null, 0, parent.childCount);
    this.atBlockStart = false;
};
/**
Render a node's content as a list. `delim` should be the extra
indentation added to all lines except the first in an item,
`firstDelim` is a function going from an item index to a
delimiter for the first line of the item.
*/
MarkdownSerializerState.prototype.renderList = function renderList (node, delim, firstDelim) {
        var this$1$1 = this;

    if (this.closed && this.closed.type == node.type)
        { this.flushClose(3); }
    else if (this.inTightList)
        { this.flushClose(1); }
    var isTight = typeof node.attrs.tight != "undefined" ? node.attrs.tight : this.options.tightLists;
    var prevTight = this.inTightList;
    this.inTightList = isTight;
    node.forEach(function (child, _, i) {
        if (i && isTight)
            { this$1$1.flushClose(1); }
        this$1$1.wrapBlock(delim, firstDelim(i), node, function () { return this$1$1.render(child, node, i); });
    });
    this.inTightList = prevTight;
};
/**
Escape the given string so that it can safely appear in Markdown
content. If `startOfLine` is true, also escape characters that
have special meaning only at the start of the line.
*/
MarkdownSerializerState.prototype.esc = function esc (str, startOfLine) {
        if ( startOfLine === void 0 ) startOfLine = false;

    str = str.replace(/[`*\\~\[\]_]/g, function (m, i) { return m == "_" && i > 0 && i + 1 < str.length && str[i - 1].match(/\w/) && str[i + 1].match(/\w/) ? m : "\\" + m; });
    if (startOfLine)
        { str = str.replace(/^(\+[ ]|[\-*>])/, "\\$&").replace(/^(\s*)(#{1,6})(\s|$)/, '$1\\$2$3').replace(/^(\s*\d+)\.\s/, "$1\\. "); }
    if (this.options.escapeExtraCharacters)
        { str = str.replace(this.options.escapeExtraCharacters, "\\$&"); }
    return str;
};
/**
@internal
*/
MarkdownSerializerState.prototype.quote = function quote (str) {
    var wrap = str.indexOf('"') == -1 ? '""' : str.indexOf("'") == -1 ? "''" : "()";
    return wrap[0] + str + wrap[1];
};
/**
Repeat the given string `n` times.
*/
MarkdownSerializerState.prototype.repeat = function repeat (str, n) {
    var out = "";
    for (var i = 0; i < n; i++)
        { out += str; }
    return out;
};
/**
Get the markdown string for a given opening or closing mark.
*/
MarkdownSerializerState.prototype.markString = function markString (mark, open, parent, index) {
    var info = this.getMark(mark.type.name);
    var value = open ? info.open : info.close;
    return typeof value == "string" ? value : value(this, mark, parent, index);
};
/**
Get leading and trailing whitespace from a string. Values of
leading or trailing property of the return object will be undefined
if there is no match.
*/
MarkdownSerializerState.prototype.getEnclosingWhitespace = function getEnclosingWhitespace (text) {
    return {
        leading: (text.match(/^(\s+)/) || [undefined])[0],
        trailing: (text.match(/(\s+)$/) || [undefined])[0]
    };
};/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 *
 */

var schema$n = {
    nodes: {
        doc: {
            sortOrder: 0,
            content: "block+"
        }
    }
};/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 *
 */

var doc$1 = {
    id: 'doc',
    schema: schema$n
};var schema$m = {
    nodes: {
        blockquote: {
            sortOrder: 200,
            content: "block+",
            group: "block",
            marks: "",
            parseDOM: [{tag: "blockquote"}],
            toDOM: function () {
                return ["blockquote", 0]
            },
            parseMarkdown: {block: "blockquote"},
            toMarkdown: function (state, node) {
                if (state.table) { return state.renderContent(node); }
                state.wrapBlock("> ", null, node, function () { return state.renderContent(node); });
            }
        }
    }
};// : (NodeType) → InputRule
// Given a blockquote node type, returns an input rule that turns `"> "`
// at the start of a textblock into a blockquote.
var blockquoteRule = function (schema) { return wrappingInputRule(/^\s*>\s$/, schema.nodes.blockquote); };/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 */


function wrapBlockQuote(context) {
    return wrapItem(context.schema.nodes.blockquote, {
        title: context.translate("Wrap in block quote"),
        icon: icons.blockquote,
        hideOnCollapse: true,
        sortOrder: 300
    });
}

function menu$j(context) {
    return [{
        id: 'wrapBlockQuote',
        node: 'blockquote',
        group: 'format',
        item: wrapBlockQuote(context)
    }];
}/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 */


var blockquote$1 = {
    id: 'blockquote',
    schema: schema$m,
    menu: function (context) { return menu$j(context); },
    inputRules: function (schema) {
        return [blockquoteRule(schema)]
    }
};/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 *
 */
var schema$l = {
    nodes: {
        bullet_list: {
            sortOrder: 700,
            content: "list_item+",
            group: "block",
            attrs: {level: {default: 1}, tight: {default: true}},
            parseDOM: [{
                tag: "ul", getAttrs: function (dom) {
                    return ({level: 1, tight: dom.hasAttribute("data-tight")});
                }
            }],
            toDOM: function (node) {
                return ["ul", {"data-tight": node.attrs.tight ? "true" : null}, 0]
            },
            parseMarkdown: {block: "bullet_list"},
            toMarkdown: function (state, node) {
                state.renderList(node, "  ", function () { return (node.attrs.bullet || "-") + " "; });
            }
        }
    }
};/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 *
 */


// : (NodeType) → InputRule
// Given a blockquote node type, returns an input rule that turns `"> "`
// at the start of a textblock into a blockquote.
var bulletListRule = function (schema) {
    return wrappingInputRule(/^\s*([-+*])\s$/, schema.nodes.bullet_list)
};/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 *
 */


function wrapBulletList(context) {
    return cmdItem(wrapInList(context.schema.nodes.bullet_list), {
        title: context.translate("Wrap in bullet list"),
        icon: icons.bulletList,
        hideOnCollapse: true,
        sortOrder: 100
    });
}

function menu$i(context) {
    return [
        {
            id: 'wrapBulletList',
            node: 'bullet_list',
            group: 'format',
            item: wrapBulletList(context)
        }
    ]
}/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 */


var bullet_list = {
    id: 'bullet_list',
    schema: schema$l,
    menu: function (context) { return menu$i(context); },
    inputRules: function (schema) {return [bulletListRule(schema)]}
};/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 *
 */

var schema$k = {
    marks: {
        code:{
            isCode: true,
            sortOrder: 400,
            preventMarks: ['link'],
            parseDOM: [{tag: "code"}],
            toDOM: function () {
                return ["code"]
            },
            parseMarkdown:  {code_inline: {mark: "code"}},
            toMarkdown: {open: "`", close: "`"}
        }
    }
};/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 *
 */



function markCode(context) {
    return markItem(context.schema.marks.code, {
        title: context.translate("Toggle code font"),
        icon: icons.code,
        sortOrder: 400
    }, context);
}

function menu$h(context) {
    return [
        {
            id: 'markCode',
            mark: 'code',
            group: 'marks',
            item: markCode(context)
        }
    ]
}var codeRules = function (schema) {
    return [
        markInputRuleOpen(/(?:`)([^`]+)$/, schema.marks.code),
        markInputRuleClosed(/(?:`)([^`]+)(?:`)$/, schema.marks.code)
    ]
};

function markInputRuleOpen(regexp, markType, getAttrs) {
    return new InputRule(regexp, function (state, match, start, end) {
        var attrs = getAttrs instanceof Function ? getAttrs(match) : getAttrs;
        var tr = state.tr;

        var nodeAfter = state.selection.$to.nodeAfter;
        if (nodeAfter && nodeAfter.isText && nodeAfter.text.indexOf('`') === 0) {
            tr.delete(start, end + 1);
            tr.addStoredMark(markType.create(attrs));
            tr.insertText(match[1], start);
            return tr;
        }

        return null;
    })
}

function markInputRuleClosed(regexp, markType, getAttrs) {
    return new InputRule(regexp, function (state, match, start, end) {
        var attrs = getAttrs instanceof Function ? getAttrs(match) : getAttrs;
        var tr = state.tr;

        if (match[1]) {
            var textStart = start + match[0].indexOf(match[1]);
            var textEnd = textStart + match[1].length;
            if (textEnd < end) { tr.delete(textEnd, end); }
            if (textStart > start) { tr.delete(start, textStart); }
            end = start + match[1].length;
            tr.addMark(start, end, markType.create(attrs));
            tr.removeStoredMark(markType); // Do not continue with mark.
            return tr;
        }

        return null;
    })
}/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 *
 */

var code$1 = {
    id: 'code',
    schema: schema$k,
    menu: function (context) { return menu$h(context); },
    inputRules: function (schema) { return codeRules(schema); },
};/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 */

var code_block$1 = {
    content: "text*",
    group: "block",
    code: true,
    defining: true,
    isolating: true,
    marks: "",
    parseDOM: [{
        tag: "pre"
    }],
    toDOM: function () {
        return ["pre", 0];
    },
    parseMarkdown: {block: "code_block"},
    toMarkdown: function (state, node) {
        if (state.table) {
            state.wrapBlock("`", "`", node, function () {
                return state.text(node.textContent, false);
            });
        } else if (!node.attrs.params) {
            state.write("```\n");
            state.text(node.textContent, false);
            state.ensureNewLine();
            state.write("```");
            state.closeBlock(node);
        } else {
            state.write("```" + node.attrs.params + "\n");
            state.text(node.textContent, false);
            state.ensureNewLine();
            state.write("```");
            state.closeBlock(node);
        }
    }
};

var fence$1 = {
    parseMarkdown: {
        block: "code_block",
        getAttrs: function (tok) { return ({params: tok.info || ""}); }
    }
};

var schema$j = {
    nodes: { code_block: code_block$1, fence: fence$1 }
};/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 */


function makeCodeBlock(context) {
    return blockTypeItem(context.schema.nodes.code_block, {
        label: context.translate("Code"),
        title: context.translate("Change to code block")
    });
}

function menu$g(context) {
    return [{
        id: 'makeCodeBlock',
        node: 'code_block',
        group: 'types',
        sortOrder: 800,
        item: makeCodeBlock(context)
    }];
}function arrowHandler(dir) {
    return function (state, dispatch, view) {
        if (state.selection.empty && view.endOfTextblock(dir)) {
            var side = dir === "left" || dir === "up" ? -1 : 1, $head = state.selection.$head;
            var pos = side > 0 ? $head.after() : $head.before();
            var nextPos = Selection.near(state.doc.resolve(pos), side);
            if (nextPos.$head && nextPos.$head.parent.type.name === "code_block") {
                dispatch(state.tr.setSelection(nextPos));
                return true;
            }
        }
        return false;
    };
}

var keymap$4 = function () {
    return {
        ArrowLeft: arrowHandler("left"),
        ArrowRight: arrowHandler("right"),
        ArrowUp: arrowHandler("up"),
        ArrowDown: arrowHandler("down")
    };
};/**
The data structure for documents. @nonabstract
*/
var Text = function Text() { };
 /**
 Create a `Text` instance for the given array of lines.
 */
 Text.prototype.lineAt = function 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.
 */
 Text.prototype.line = function 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.
 */
 Text.prototype.replace = function replace (from, to, text) {
        var assign;

     (assign = clip(this, from, to), from = assign[0], to = assign[1]);
     var 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.
 */
 Text.prototype.append = function append (other) {
     return this.replace(this.length, this.length, other);
 };
 /**
 Retrieve the text between the given points.
 */
 Text.prototype.slice = function slice (from, to) {
        var assign;

        if ( to === void 0 ) to = this.length;
     (assign = clip(this, from, to), from = assign[0], to = assign[1]);
     var parts = [];
     this.decompose(from, to, parts, 0);
     return TextNode.from(parts, to - from);
 };
 /**
 Test whether this text is equal to another instance.
 */
 Text.prototype.eq = function eq (other) {
     if (other == this)
         { return true; }
     if (other.length != this.length || other.lines != this.lines)
         { return false; }
     var start = this.scanIdentical(other, 1), end = this.length - this.scanIdentical(other, -1);
     var a = new RawTextCursor(this), b = new RawTextCursor(other);
     for (var 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.
 */
 Text.prototype.iter = function iter (dir) {
    if ( dir === void 0 ) dir = 1;
 return new RawTextCursor(this, dir); };
 /**
 Iterate over a range of the text. When `from` > `to`, the
 iterator will run in reverse.
 */
 Text.prototype.iterRange = function iterRange (from, to) {
    if ( to === void 0 ) 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.
 */
 Text.prototype.iterLines = function iterLines (from, to) {
     var inner;
     if (from == null) {
         inner = this.iter();
     }
     else {
         if (to == null)
             { to = this.lines + 1; }
         var 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.
 */
 Text.prototype.toString = function 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)).
 */
 Text.prototype.toJSON = function toJSON () {
     var lines = [];
     this.flatten(lines);
     return lines;
 };

Text.of = function 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.
var TextLeaf = /*@__PURE__*/(function (Text) {
   function TextLeaf(text, length) {
        if ( length === void 0 ) length = textLength(text);

        Text.call(this);
        this.text = text;
        this.length = length;
    }

   if ( Text ) TextLeaf.__proto__ = Text;
   TextLeaf.prototype = Object.create( Text && Text.prototype );
   TextLeaf.prototype.constructor = TextLeaf;

   var prototypeAccessors = { lines: { configurable: true },children: { configurable: true } };
    prototypeAccessors.lines.get = function () { return this.text.length; };
    prototypeAccessors.children.get = function () { return null; };
    TextLeaf.prototype.lineInner = function lineInner (target, isLine, line, offset) {
        for (var i = 0;; i++) {
            var string = this.text[i], end = offset + string.length;
            if ((isLine ? line : end) >= target)
                { return new Line(offset, end, line, string); }
            offset = end + 1;
            line++;
        }
    };
    TextLeaf.prototype.decompose = function decompose (from, to, target, open) {
        var 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 */) {
            var prev = target.pop();
            var 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 {
                var mid = joined.length >> 1;
                target.push(new TextLeaf(joined.slice(0, mid)), new TextLeaf(joined.slice(mid)));
            }
        }
        else {
            target.push(text);
        }
    };
    TextLeaf.prototype.replace = function replace (from, to, text) {
        var assign;

        if (!(text instanceof TextLeaf))
            { return Text.prototype.replace.call(this, from, to, text); }
        (assign = clip(this, from, to), from = assign[0], to = assign[1]);
        var lines = appendText(this.text, appendText(text.text, sliceText(this.text, 0, from)), to);
        var 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);
    };
    TextLeaf.prototype.sliceString = function sliceString (from, to, lineSep) {
        var assign;

        if ( to === void 0 ) to = this.length;
        if ( lineSep === void 0 ) lineSep = "\n";
        (assign = clip(this, from, to), from = assign[0], to = assign[1]);
        var result = "";
        for (var pos = 0, i = 0; pos <= to && i < this.text.length; i++) {
            var 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;
    };
    TextLeaf.prototype.flatten = function flatten (target) {
        for (var line of this.text)
            target.push(line);
    };
    TextLeaf.prototype.scanIdentical = function scanIdentical () { return 0; };
    TextLeaf.split = function split (text, target) {
        var part = [], len = -1;
        for (var 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;
    };

   Object.defineProperties( TextLeaf.prototype, prototypeAccessors );

   return TextLeaf;
}(Text));
// 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).
var TextNode = /*@__PURE__*/(function (Text) {
   function TextNode(children, length) {
        Text.call(this);
        this.children = children;
        this.length = length;
        this.lines = 0;
        for (var child of children)
            this.lines += child.lines;
    }

   if ( Text ) TextNode.__proto__ = Text;
   TextNode.prototype = Object.create( Text && Text.prototype );
   TextNode.prototype.constructor = TextNode;
    TextNode.prototype.lineInner = function lineInner (target, isLine, line, offset) {
        for (var i = 0;; i++) {
            var 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;
        }
    };
    TextNode.prototype.decompose = function decompose (from, to, target, open) {
        for (var i = 0, pos = 0; pos <= to && i < this.children.length; i++) {
            var child = this.children[i], end = pos + child.length;
            if (from <= end && to >= pos) {
                var 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;
        }
    };
    TextNode.prototype.replace = function replace (from, to, text) {
        var this$1$1 = this;
        var assign;

        (assign = clip(this, from, to), from = assign[0], to = assign[1]);
        if (text.lines < this.lines)
            { for (var i = 0, pos = 0; i < this.children.length; i++) {
                var 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) {
                    var updated = child.replace(from - pos, to - pos, text);
                    var totalLines = this.lines - child.lines + updated.lines;
                    if (updated.lines < (totalLines >> (5 /* Tree.BranchShift */ - 1)) &&
                        updated.lines > (totalLines >> (5 /* Tree.BranchShift */ + 1))) {
                        var copy = this.children.slice();
                        copy[i] = updated;
                        return new TextNode(copy, this.length - (to - from) + text.length);
                    }
                    return Text.prototype.replace.call(this$1$1, pos, end, updated);
                }
                pos = end + 1;
            } }
        return Text.prototype.replace.call(this, from, to, text);
    };
    TextNode.prototype.sliceString = function sliceString (from, to, lineSep) {
        var assign;

        if ( to === void 0 ) to = this.length;
        if ( lineSep === void 0 ) lineSep = "\n";
        (assign = clip(this, from, to), from = assign[0], to = assign[1]);
        var result = "";
        for (var i = 0, pos = 0; i < this.children.length && pos <= to; i++) {
            var 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;
    };
    TextNode.prototype.flatten = function flatten (target) {
        for (var child of this.children)
            child.flatten(target);
    };
    TextNode.prototype.scanIdentical = function scanIdentical (other, dir) {
        if (!(other instanceof TextNode))
            { return 0; }
        var length = 0;
        var ref = dir > 0 ? [0, 0, this.children.length, other.children.length]
            : [this.children.length - 1, other.children.length - 1, -1, -1];
        var iA = ref[0];
        var iB = ref[1];
        var eA = ref[2];
        var eB = ref[3];
        for (;; iA += dir, iB += dir) {
            if (iA == eA || iB == eB)
                { return length; }
            var chA = this.children[iA], chB = other.children[iB];
            if (chA != chB)
                { return length + chA.scanIdentical(chB, dir); }
            length += chA.length + 1;
        }
    };
    TextNode.from = function from (children, length) {
        if ( length === void 0 ) length = children.reduce(function (l, ch) { return l + ch.length + 1; }, -1);

        var lines = 0;
        for (var ch of children)
            lines += ch.lines;
        if (lines < 32 /* Tree.Branch */) {
            var flat = [];
            for (var ch$1 of children)
                ch$1.flatten(flat);
            return new TextLeaf(flat, length);
        }
        var chunk = Math.max(32 /* Tree.Branch */, lines >> 5 /* Tree.BranchShift */), maxChunk = chunk << 1, minChunk = chunk >> 1;
        var chunked = [], currentLines = 0, currentLen = -1, currentChunk = [];
        function add(child) {
            var last;
            if (child.lines > maxChunk && child instanceof TextNode) {
                for (var 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 (var child of children)
            add(child);
        flush();
        return chunked.length == 1 ? chunked[0] : new TextNode(chunked, length);
    };

   return TextNode;
}(Text));
Text.empty = /*@__PURE__*/new TextLeaf([""], 0);
function textLength(text) {
    var length = -1;
    for (var line of text)
        length += line.length + 1;
    return length;
}
function appendText(text, target, from, to) {
    if ( from === void 0 ) from = 0;
    if ( to === void 0 ) to = 1e9;

    for (var pos = 0, i = 0, first = true; i < text.length && pos <= to; i++) {
        var 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);
}
var RawTextCursor = function RawTextCursor(text, dir) {
     if ( dir === void 0 ) 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];
 };
 RawTextCursor.prototype.nextInner = function nextInner (skip, dir) {
     this.done = this.lineBreak = false;
     for (;;) {
         var last = this.nodes.length - 1;
         var top = this.nodes[last], offsetValue = this.offsets[last], offset = offsetValue >> 1;
         var 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
             var 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 {
             var next$1 = top.children[offset + (dir < 0 ? -1 : 0)];
             if (skip > next$1.length) {
                 skip -= next$1.length;
                 this.offsets[last] += dir;
             }
             else {
                 if (dir < 0)
                     { this.offsets[last]--; }
                 this.nodes.push(next$1);
                 this.offsets.push(dir > 0 ? 1 : (next$1 instanceof TextLeaf ? next$1.text.length : next$1.children.length) << 1);
             }
         }
     }
 };
 RawTextCursor.prototype.next = function next (skip) {
        if ( skip === void 0 ) skip = 0;

     if (skip < 0) {
         this.nextInner(-skip, (-this.dir));
         skip = this.value.length;
     }
     return this.nextInner(skip, this.dir);
 };
var PartialTextCursor = function PartialTextCursor(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);
 };

var prototypeAccessors$1$1 = { lineBreak: { configurable: true } };
 PartialTextCursor.prototype.nextInner = function 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);
     var limit = dir < 0 ? this.pos - this.from : this.to - this.pos;
     if (skip > limit)
         { skip = limit; }
     limit -= skip;
     var ref = this.cursor.next(skip);
        var value = ref.value;
     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;
 };
 PartialTextCursor.prototype.next = function next (skip) {
        if ( skip === void 0 ) 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);
 };
 prototypeAccessors$1$1.lineBreak.get = function () { return this.cursor.lineBreak && this.value != ""; };

Object.defineProperties( PartialTextCursor.prototype, prototypeAccessors$1$1 );
var LineCursor = function LineCursor(inner) {
     this.inner = inner;
     this.afterBreak = true;
     this.value = "";
     this.done = false;
 };

var prototypeAccessors$2$2 = { lineBreak: { configurable: true } };
 LineCursor.prototype.next = function next (skip) {
        if ( skip === void 0 ) skip = 0;

     var ref = this.inner.next(skip);
        var done = ref.done;
        var lineBreak = ref.lineBreak;
        var value = ref.value;
     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;
 };
 prototypeAccessors$2$2.lineBreak.get = function () { return false; };

Object.defineProperties( LineCursor.prototype, prototypeAccessors$2$2 );
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).
*/
var Line = function Line(
 /**
 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;
 };

var prototypeAccessors$3$1 = { length: { configurable: true } };
 /**
 The length of the line (not including any line break after it).
 */
 prototypeAccessors$3$1.length.get = function () { return this.to - this.from; };

Object.defineProperties( Line.prototype, prototypeAccessors$3$1 );
function clip(text, from, to) {
    from = Math.max(0, Math.min(text.length, from));
    return [from, Math.max(from, Math.min(text.length, to))];
}

// Compressed representation of the Grapheme_Cluster_Break=Extend
// information from
// http://www.unicode.org/Public/13.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.
var extend = /*@__PURE__*/"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(function (s) { return s ? parseInt(s, 36) : 1; });
// Convert offsets into absolute values
for (var i$2 = 1; i$2 < extend.length; i$2++)
    { extend[i$2] += extend[i$2 - 1]; }
function isExtendingChar(code) {
    for (var i = 1; i < extend.length; i += 2)
        { if (extend[i] > code)
            { return extend[i - 1] <= code; } }
    return false;
}
function isRegionalIndicator(code) {
    return code >= 0x1F1E6 && code <= 0x1F1FF;
}
var ZWJ = 0x200d;
/**
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, includeExtending) {
    if ( forward === void 0 ) forward = true;
    if ( includeExtending === void 0 ) 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--; }
    var prev = codePointAt(str, pos);
    pos += codePointSize(prev);
    while (pos < str.length) {
        var next = codePointAt(str, pos);
        if (prev == ZWJ || next == ZWJ || includeExtending && isExtendingChar(next)) {
            pos += codePointSize(next);
            prev = next;
        }
        else if (isRegionalIndicator(next)) {
            var 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) {
        var found = nextClusterBreak(str, pos - 2, includeExtending);
        if (found < pos)
            { return found; }
        pos--;
    }
    return 0;
}
function surrogateLow(ch) { return ch >= 0xDC00 && ch < 0xE000; }
function surrogateHigh(ch) { return ch >= 0xD800 && ch < 0xDC00; }
/**
Find the code point at the given position in a string (like the
[`codePointAt`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/codePointAt)
string method).
*/
function codePointAt(str, pos) {
    var code0 = str.charCodeAt(pos);
    if (!surrogateHigh(code0) || pos + 1 == str.length)
        { return code0; }
    var code1 = str.charCodeAt(pos + 1);
    if (!surrogateLow(code1))
        { return code0; }
    return ((code0 - 0xd800) << 10) + (code1 - 0xdc00) + 0x10000;
}
/**
Given a Unicode codepoint, return the JavaScript string that
respresents it (like
[`String.fromCodePoint`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/fromCodePoint)).
*/
function fromCodePoint$1(code) {
    if (code <= 0xffff)
        { return String.fromCharCode(code); }
    code -= 0x10000;
    return String.fromCharCode((code >> 10) + 0xd800, (code & 1023) + 0xdc00);
}
/**
The amount of positions a character takes up a JavaScript string.
*/
function codePointSize(code) { return code < 0x10000 ? 1 : 2; }

var 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.
*/
var ChangeDesc = function ChangeDesc(
 /**
 @internal
 */
 sections) {
     this.sections = sections;
 };

var prototypeAccessors$4$2 = { length: { configurable: true },newLength: { configurable: true },empty: { configurable: true },invertedDesc: { configurable: true } };
 /**
 The length of the document before the change.
 */
 prototypeAccessors$4$2.length.get = function () {
     var result = 0;
     for (var i = 0; i < this.sections.length; i += 2)
         { result += this.sections[i]; }
     return result;
 };
 /**
 The length of the document after the change.
 */
 prototypeAccessors$4$2.newLength.get = function () {
     var result = 0;
     for (var i = 0; i < this.sections.length; i += 2) {
         var ins = this.sections[i + 1];
         result += ins < 0 ? this.sections[i] : ins;
     }
     return result;
 };
 /**
 False when there are actual changes in this set.
 */
 prototypeAccessors$4$2.empty.get = function () { 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.
 */
 ChangeDesc.prototype.iterGaps = function iterGaps (f) {
     for (var i = 0, posA = 0, posB = 0; i < this.sections.length;) {
         var 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.
 */
 ChangeDesc.prototype.iterChangedRanges = function iterChangedRanges (f, individual) {
        if ( individual === void 0 ) individual = false;

     iterChanges(this, f, individual);
 };
 /**
 Get a description of the inverted form of these changes.
 */
 prototypeAccessors$4$2.invertedDesc.get = function () {
     var sections = [];
     for (var i = 0; i < this.sections.length;) {
         var 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`.
 */
 ChangeDesc.prototype.composeDesc = function 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 `other` happened before the ones in `this`.
 */
 ChangeDesc.prototype.mapDesc = function mapDesc (other, before) {
    if ( before === void 0 ) before = false;
 return other.empty ? this : mapSet(this, other, before); };
 ChangeDesc.prototype.mapPos = function mapPos (pos, assoc, mode) {
        if ( assoc === void 0 ) assoc = -1;
        if ( mode === void 0 ) mode = MapMode.Simple;

     var posA = 0, posB = 0;
     for (var i = 0; i < this.sections.length;) {
         var 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.
 */
 ChangeDesc.prototype.touchesRange = function touchesRange (from, to) {
        if ( to === void 0 ) to = from;

     for (var i = 0, pos = 0; i < this.sections.length && pos <= to;) {
         var 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
 */
 ChangeDesc.prototype.toString = function toString () {
     var result = "";
     for (var i = 0; i < this.sections.length;) {
         var 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.
 */
 ChangeDesc.prototype.toJSON = function 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).
 */
 ChangeDesc.fromJSON = function fromJSON (json) {
     if (!Array.isArray(json) || json.length % 2 || json.some(function (a) { return typeof a != "number"; }))
         { throw new RangeError("Invalid JSON representation of ChangeDesc"); }
     return new ChangeDesc(json);
 };
 /**
 @internal
 */
 ChangeDesc.create = function create (sections) { return new ChangeDesc(sections); };

Object.defineProperties( ChangeDesc.prototype, prototypeAccessors$4$2 );
/**
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.
*/
var ChangeSet = /*@__PURE__*/(function (ChangeDesc) {
   function ChangeSet(sections, 
    /**
    @internal
    */
    inserted) {
        ChangeDesc.call(this, sections);
        this.inserted = inserted;
    }

   if ( ChangeDesc ) ChangeSet.__proto__ = ChangeDesc;
   ChangeSet.prototype = Object.create( ChangeDesc && ChangeDesc.prototype );
   ChangeSet.prototype.constructor = ChangeSet;

   var prototypeAccessors$5 = { desc: { configurable: true } };
    /**
    Apply the changes to a document, returning the modified
    document.
    */
    ChangeSet.prototype.apply = function apply (doc) {
        if (this.length != doc.length)
            { throw new RangeError("Applying change set to a document with the wrong length"); }
        iterChanges(this, function (fromA, toA, fromB, _toB, text) { return doc = doc.replace(fromB, fromB + (toA - fromA), text); }, false);
        return doc;
    };
    ChangeSet.prototype.mapDesc = function mapDesc (other, before) {
    if ( before === void 0 ) 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.
    */
    ChangeSet.prototype.invert = function invert (doc) {
        var sections = this.sections.slice(), inserted = [];
        for (var i = 0, pos = 0; i < sections.length; i += 2) {
            var len = sections[i], ins = sections[i + 1];
            if (ins >= 0) {
                sections[i] = ins;
                sections[i + 1] = len;
                var 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`.
    */
    ChangeSet.prototype.compose = function 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.
    */
    ChangeSet.prototype.map = function map (other, before) {
    if ( before === void 0 ) 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.
    */
    ChangeSet.prototype.iterChanges = function iterChanges$1 (f, individual) {
        if ( individual === void 0 ) individual = false;

        iterChanges(this, f, individual);
    };
    /**
    Get a [change description](https://codemirror.net/6/docs/ref/#state.ChangeDesc) for this change
    set.
    */
    prototypeAccessors$5.desc.get = function () { return ChangeDesc.create(this.sections); };
    /**
    @internal
    */
    ChangeSet.prototype.filter = function filter (ranges) {
        var resultSections = [], resultInserted = [], filteredSections = [];
        var iter = new SectionIter(this);
        done: for (var i = 0, pos = 0;;) {
            var next = i == ranges.length ? 1e9 : ranges[i++];
            while (pos < next || pos == next && iter.len == 0) {
                if (iter.done)
                    { break done; }
                var len = Math.min(iter.len, next - pos);
                addSection(filteredSections, len, -1);
                var 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;
            }
            var end = ranges[i++];
            while (pos < end) {
                if (iter.done)
                    { break done; }
                var len$1 = Math.min(iter.len, end - pos);
                addSection(resultSections, len$1, -1);
                addSection(filteredSections, len$1, iter.ins == -1 ? -1 : iter.off == 0 ? iter.ins : 0);
                iter.forward(len$1);
                pos += len$1;
            }
        }
        return { changes: new ChangeSet(resultSections, resultInserted),
            filtered: ChangeDesc.create(filteredSections) };
    };
    /**
    Serialize this change set to a JSON-representable value.
    */
    ChangeSet.prototype.toJSON = function toJSON () {
        var parts = [];
        for (var i = 0; i < this.sections.length; i += 2) {
            var 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.
    */
    ChangeSet.of = function of (changes, length, lineSep) {
        var sections = [], inserted = [], pos = 0;
        var total = null;
        function flush(force) {
            if ( force === void 0 ) force = false;

            if (!force && !sections.length)
                { return; }
            if (pos < length)
                { addSection(sections, length - pos, -1); }
            var 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 (var 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 {
                var from = spec.from;
                var to = spec.to; if ( to === void 0 ) to = from;
                var insert = spec.insert;
                if (from > to || from < 0 || to > length)
                    { throw new RangeError(("Invalid change range " + from + " to " + to + " (in doc of length " + length + ")")); }
                var insText = !insert ? Text.empty : typeof insert == "string" ? Text.of(insert.split(lineSep || DefaultSplit)) : insert;
                var 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.
    */
    ChangeSet.empty = function 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).
    */
    ChangeSet.fromJSON = function fromJSON (json) {
        if (!Array.isArray(json))
            { throw new RangeError("Invalid JSON representation of ChangeSet"); }
        var sections = [], inserted = [];
        for (var i = 0; i < json.length; i++) {
            var part = json[i];
            if (typeof part == "number") {
                sections.push(part, -1);
            }
            else if (!Array.isArray(part) || typeof part[0] != "number" || part.some(function (e, i) { return 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
    */
    ChangeSet.createSet = function createSet (sections, inserted) {
        return new ChangeSet(sections, inserted);
    };

   Object.defineProperties( ChangeSet.prototype, prototypeAccessors$5 );

   return ChangeSet;
}(ChangeDesc));
function addSection(sections, len, ins, forceJoin) {
    if ( forceJoin === void 0 ) forceJoin = false;

    if (len == 0 && ins <= 0)
        { return; }
    var last = sections.length - 2;
    if (last >= 0 && ins <= 0 && ins == sections[last + 1])
        { sections[last] += len; }
    else if (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; }
    var 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) {
    var inserted = desc.inserted;
    for (var posA = 0, posB = 0, i = 0; i < desc.sections.length;) {
        var len = desc.sections[i++], ins = desc.sections[i++];
        if (ins < 0) {
            posA += len;
            posB += len;
        }
        else {
            var 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) {
    if ( mkSet === void 0 ) mkSet = false;

    // Produce a copy of setA that applies to the document after setB
    // has been applied (assuming both start at the same document).
    var sections = [], insert = mkSet ? [] : null;
    var 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 (var inserted = -1;;) {
        if (a.ins == -1 && b.ins == -1) {
            // Move across ranges skipped by both sets.
            var 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).
            var len$1 = b.len;
            addSection(sections, b.ins, -1);
            while (len$1) {
                var piece = Math.min(a.len, len$1);
                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$1 -= 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).
            var len$2 = 0, left = a.len;
            while (left) {
                if (b.ins == -1) {
                    var piece$1 = Math.min(left, b.len);
                    len$2 += piece$1;
                    left -= piece$1;
                    b.forward(piece$1);
                }
                else if (b.ins == 0 && b.len < left) {
                    left -= b.len;
                    b.next();
                }
                else {
                    break;
                }
            }
            addSection(sections, len$2, 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) {
    if ( mkSet === void 0 ) mkSet = false;

    var sections = [];
    var insert = mkSet ? [] : null;
    var a = new SectionIter(setA), b = new SectionIter(setB);
    for (var 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 {
            var len = Math.min(a.len2, b.len), sectionLen = sections.length;
            if (a.ins == -1) {
                var 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);
        }
    }
}
var SectionIter = function SectionIter(set) {
     this.set = set;
     this.i = 0;
     this.next();
 };

var prototypeAccessors$6 = { done: { configurable: true },len2: { configurable: true },text: { configurable: true } };
 SectionIter.prototype.next = function next () {
     var ref = this.set;
        var sections = ref.sections;
     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;
 };
 prototypeAccessors$6.done.get = function () { return this.ins == -2; };
 prototypeAccessors$6.len2.get = function () { return this.ins < 0 ? this.len : this.ins; };
 prototypeAccessors$6.text.get = function () {
     var ref = this.set;
        var inserted = ref.inserted;
        var index = (this.i - 2) >> 1;
     return index >= inserted.length ? Text.empty : inserted[index];
 };
 SectionIter.prototype.textBit = function textBit (len) {
     var ref = this.set;
        var inserted = ref.inserted;
        var index = (this.i - 2) >> 1;
     return index >= inserted.length && !len ? Text.empty
         : inserted[index].slice(this.off, len == null ? undefined : this.off + len);
 };
 SectionIter.prototype.forward = function forward (len) {
     if (len == this.len)
         { this.next(); }
     else {
         this.len -= len;
         this.off += len;
     }
 };
 SectionIter.prototype.forward2 = function forward2 (len) {
     if (this.ins == -1)
         { this.forward(len); }
     else if (len == this.ins)
         { this.next(); }
     else {
         this.ins -= len;
         this.off += len;
     }
 };

Object.defineProperties( SectionIter.prototype, prototypeAccessors$6 );

/**
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.
*/
var SelectionRange = function SelectionRange(
 /**
 The lower boundary of the range.
 */
 from, 
 /**
 The upper boundary of the range.
 */
 to, flags) {
     this.from = from;
     this.to = to;
     this.flags = flags;
 };

var prototypeAccessors$7 = { anchor: { configurable: true },head: { configurable: true },empty: { configurable: true },assoc: { configurable: true },bidiLevel: { configurable: true },goalColumn: { configurable: true } };
 /**
 The anchor of the range—the side that doesn't move when you
 extend it.
 */
 prototypeAccessors$7.anchor.get = function () { 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).
 */
 prototypeAccessors$7.head.get = function () { return this.flags & 32 /* RangeFlag.Inverted */ ? this.from : this.to; };
 /**
 True when `anchor` and `head` are at the same position.
 */
 prototypeAccessors$7.empty.get = function () { 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.
 */
 prototypeAccessors$7.assoc.get = function () { return this.flags & 8 /* RangeFlag.AssocBefore */ ? -1 : this.flags & 16 /* RangeFlag.AssocAfter */ ? 1 : 0; };
 /**
 The bidirectional text level associated with this cursor, if
 any.
 */
 prototypeAccessors$7.bidiLevel.get = function () {
     var 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.
 */
 prototypeAccessors$7.goalColumn.get = function () {
     var 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.
 */
 SelectionRange.prototype.map = function map (change, assoc) {
        if ( assoc === void 0 ) assoc = -1;

     var 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`.
 */
 SelectionRange.prototype.extend = function extend (from, to) {
        if ( to === void 0 ) to = from;

     if (from <= this.anchor && to >= this.anchor)
         { return EditorSelection.range(from, to); }
     var head = Math.abs(from - this.anchor) > Math.abs(to - this.anchor) ? from : to;
     return EditorSelection.range(this.anchor, head);
 };
 /**
 Compare this range to another range.
 */
 SelectionRange.prototype.eq = function eq (other, includeAssoc) {
        if ( includeAssoc === void 0 ) includeAssoc = false;

     return this.anchor == other.anchor && this.head == other.head &&
         (!includeAssoc || !this.empty || this.assoc == other.assoc);
 };
 /**
 Return a JSON-serializable object representing the range.
 */
 SelectionRange.prototype.toJSON = function toJSON () { return { anchor: this.anchor, head: this.head }; };
 /**
 Convert a JSON representation of a range to a `SelectionRange`
 instance.
 */
 SelectionRange.fromJSON = function 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
 */
 SelectionRange.create = function create (from, to, flags) {
     return new SelectionRange(from, to, flags);
 };

Object.defineProperties( SelectionRange.prototype, prototypeAccessors$7 );
/**
An editor selection holds one or more selection ranges.
*/
var EditorSelection = function EditorSelection(
 /**
 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;
 };

var prototypeAccessors$8 = { main: { configurable: true } };
 /**
 Map a selection through a change. Used to adjust the selection
 position for changes.
 */
 EditorSelection.prototype.map = function map (change, assoc) {
        if ( assoc === void 0 ) assoc = -1;

     if (change.empty)
         { return this; }
     return EditorSelection.create(this.ranges.map(function (r) { return 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.
 */
 EditorSelection.prototype.eq = function eq (other, includeAssoc) {
        if ( includeAssoc === void 0 ) includeAssoc = false;

     if (this.ranges.length != other.ranges.length ||
         this.mainIndex != other.mainIndex)
         { return false; }
     for (var 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).
 */
 prototypeAccessors$8.main.get = function () { return this.ranges[this.mainIndex]; };
 /**
 Make sure the selection only has one range. Returns a selection
 holding only the main range from this selection.
 */
 EditorSelection.prototype.asSingle = function asSingle () {
     return this.ranges.length == 1 ? this : new EditorSelection([this.main], 0);
 };
 /**
 Extend this selection with an extra range.
 */
 EditorSelection.prototype.addRange = function addRange (range, main) {
        if ( main === void 0 ) 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.
 */
 EditorSelection.prototype.replaceRange = function replaceRange (range, which) {
        if ( which === void 0 ) which = this.mainIndex;

     var 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.
 */
 EditorSelection.prototype.toJSON = function toJSON () {
     return { ranges: this.ranges.map(function (r) { return r.toJSON(); }), main: this.mainIndex };
 };
 /**
 Create a selection from a JSON representation.
 */
 EditorSelection.fromJSON = function 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(function (r) { return SelectionRange.fromJSON(r); }), json.main);
 };
 /**
 Create a selection holding a single range.
 */
 EditorSelection.single = function single (anchor, head) {
        if ( head === void 0 ) head = anchor;

     return new EditorSelection([EditorSelection.range(anchor, head)], 0);
 };
 /**
 Sort and merge the given set of ranges, creating a valid
 selection.
 */
 EditorSelection.create = function create (ranges, mainIndex) {
        if ( mainIndex === void 0 ) mainIndex = 0;

     if (ranges.length == 0)
         { throw new RangeError("A selection needs at least one range"); }
     for (var pos = 0, i = 0; i < ranges.length; i++) {
         var 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.
 */
 EditorSelection.cursor = function cursor (pos, assoc, bidiLevel, goalColumn) {
        if ( assoc === void 0 ) assoc = 0;

     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.
 */
 EditorSelection.range = function range (anchor, head, goalColumn, bidiLevel) {
     var flags = ((goalColumn !== null && goalColumn !== void 0 ? goalColumn : 16777215 /* RangeFlag.NoGoalColumn */) << 6 /* RangeFlag.GoalColumnOffset */) |
         (bidiLevel == null ? 7 : Math.min(6, bidiLevel));
     return head < anchor ? SelectionRange.create(head, anchor, 32 /* RangeFlag.Inverted */ | 16 /* RangeFlag.AssocAfter */ | flags)
         : SelectionRange.create(anchor, head, (head > anchor ? 8 /* RangeFlag.AssocBefore */ : 0) | flags);
 };
 /**
 @internal
 */
 EditorSelection.normalized = function normalized (ranges, mainIndex) {
        if ( mainIndex === void 0 ) mainIndex = 0;

     var main = ranges[mainIndex];
     ranges.sort(function (a, b) { return a.from - b.from; });
     mainIndex = ranges.indexOf(main);
     for (var i = 1; i < ranges.length; i++) {
         var range = ranges[i], prev = ranges[i - 1];
         if (range.empty ? range.from <= prev.to : range.from < prev.to) {
             var 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);
 };

Object.defineProperties( EditorSelection.prototype, prototypeAccessors$8 );
function checkSelection(selection, docLength) {
    for (var range of selection.ranges)
        if (range.to > docLength)
            { throw new RangeError("Selection points outside of document"); }
}

var 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.
*/
var Facet = function Facet(
 /**
 @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;
 };

var prototypeAccessors$9 = { reader: { configurable: true } };
 /**
 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.
 */
 prototypeAccessors$9.reader.get = function () { return this; };
 /**
 Define a new facet.
 */
 Facet.define = function define (config) {
        if ( config === void 0 ) config = {};

     return new Facet(config.combine || (function (a) { return a; }), config.compareInput || (function (a, b) { return a === b; }), config.compare || (!config.combine ? sameArray$1 : function (a, b) { return a === b; }), !!config.static, config.enables);
 };
 /**
 Returns an extension that adds the given value to this facet.
 */
 Facet.prototype.of = function 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.
 */
 Facet.prototype.compute = function 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.
 */
 Facet.prototype.computeN = function computeN (deps, get) {
     if (this.isStatic)
         { throw new Error("Can't compute a static facet"); }
     return new FacetProvider(deps, this, 2 /* Provider.Multi */, get);
 };
 Facet.prototype.from = function from (field, get) {
     if (!get)
         { get = function (x) { return x; }; }
     return this.compute([field], function (state) { return get(state.field(field)); });
 };

Object.defineProperties( Facet.prototype, prototypeAccessors$9 );
function sameArray$1(a, b) {
    return a == b || a.length == b.length && a.every(function (e, i) { return e === b[i]; });
}
var FacetProvider = function FacetProvider(dependencies, facet, type, value) {
     this.dependencies = dependencies;
     this.facet = facet;
     this.type = type;
     this.value = value;
     this.id = nextID++;
 };
 FacetProvider.prototype.dynamicSlot = function dynamicSlot (addresses) {
        var this$1$1 = this;

     var _a;
     var getter = this.value;
     var compare = this.facet.compareInput;
     var id = this.id, idx = addresses[id] >> 1, multi = this.type == 2 /* Provider.Multi */;
     var depDoc = false, depSel = false, depAddrs = [];
     for (var 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: function create(state) {
             state.values[idx] = getter(state);
             return 1 /* SlotStatus.Changed */;
         },
         update: function update(state, tr) {
             if ((depDoc && tr.docChanged) || (depSel && (tr.docChanged || tr.selection)) || ensureAll(state, depAddrs)) {
                 var 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: function (state, oldState) {
             var newVal, oldAddr = oldState.config.address[id];
             if (oldAddr != null) {
                 var oldVal = getAddr(oldState, oldAddr);
                 if (this$1$1.dependencies.every(function (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 (var i = 0; i < a.length; i++)
        { if (!compare(a[i], b[i]))
            { return false; } }
    return true;
}
function ensureAll(state, addrs) {
    var changed = false;
    for (var addr of addrs)
        if (ensureAddr(state, addr) & 1 /* SlotStatus.Changed */)
            { changed = true; }
    return changed;
}
function dynamicFacetSlot(addresses, facet, providers) {
    var providerAddrs = providers.map(function (p) { return addresses[p.id]; });
    var providerTypes = providers.map(function (p) { return p.type; });
    var dynamic = providerAddrs.filter(function (p) { return !(p & 1); });
    var idx = addresses[facet.id] >> 1;
    function get(state) {
        var values = [];
        for (var i = 0; i < providerAddrs.length; i++) {
            var value = getAddr(state, providerAddrs[i]);
            if (providerTypes[i] == 2 /* Provider.Multi */)
                { for (var val of value)
                    values.push(val); }
            else
                { values.push(value); }
        }
        return facet.combine(values);
    }
    return {
        create: function create(state) {
            for (var addr of providerAddrs)
                ensureAddr(state, addr);
            state.values[idx] = get(state);
            return 1 /* SlotStatus.Changed */;
        },
        update: function update(state, tr) {
            if (!ensureAll(state, dynamic))
                { return 0; }
            var value = get(state);
            if (facet.compare(value, state.values[idx]))
                { return 0; }
            state.values[idx] = value;
            return 1 /* SlotStatus.Changed */;
        },
        reconfigure: function reconfigure(state, oldState) {
            var depChanged = ensureAll(state, providerAddrs);
            var oldProviders = oldState.config.facets[facet.id], oldValue = oldState.facet(facet);
            if (oldProviders && !depChanged && sameArray$1(providers, oldProviders)) {
                state.values[idx] = oldValue;
                return 0;
            }
            var value = get(state);
            if (facet.compare(value, oldValue)) {
                state.values[idx] = oldValue;
                return 0;
            }
            state.values[idx] = value;
            return 1 /* SlotStatus.Changed */;
        }
    };
}
var 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.
*/
var StateField = function StateField(
 /**
 @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;
 };

var prototypeAccessors$10$1 = { extension: { configurable: true } };
 /**
 Define a state field.
 */
 StateField.define = function define (config) {
     var field = new StateField(nextID++, config.create, config.update, config.compare || (function (a, b) { return a === b; }), config);
     if (config.provide)
         { field.provides = config.provide(field); }
     return field;
 };
 StateField.prototype.create = function create (state) {
        var this$1$1 = this;

     var init = state.facet(initField).find(function (i) { return i.field == this$1$1; });
     return ((init === null || init === void 0 ? void 0 : init.create) || this.createF)(state);
 };
 /**
 @internal
 */
 StateField.prototype.slot = function slot (addresses) {
        var this$1$1 = this;

     var idx = addresses[this.id] >> 1;
     return {
         create: function (state) {
             state.values[idx] = this$1$1.create(state);
             return 1 /* SlotStatus.Changed */;
         },
         update: function (state, tr) {
             var oldVal = state.values[idx];
             var value = this$1$1.updateF(oldVal, tr);
             if (this$1$1.compareF(oldVal, value))
                 { return 0; }
             state.values[idx] = value;
             return 1 /* SlotStatus.Changed */;
         },
         reconfigure: function (state, oldState) {
             if (oldState.config.address[this$1$1.id] != null) {
                 state.values[idx] = oldState.field(this$1$1);
                 return 0;
             }
             state.values[idx] = this$1$1.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.
 */
 StateField.prototype.init = function init (create) {
     return [this, initField.of({ field: this, create: 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.
 */
 prototypeAccessors$10$1.extension.get = function () { return this; };

Object.defineProperties( StateField.prototype, prototypeAccessors$10$1 );
var Prec_ = { lowest: 4, low: 3, default: 2, high: 1, highest: 0 };
function prec$1(value) {
    return function (ext) { return 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.
*/
var Prec = {
    /**
    The highest precedence level, for extensions that should end up
    near the start of the precedence ordering.
    */
    highest: /*@__PURE__*/prec$1(Prec_.highest),
    /**
    A higher-than-default precedence, for extensions that should
    come before those with default precedence.
    */
    high: /*@__PURE__*/prec$1(Prec_.high),
    /**
    The default precedence, which is also used for extensions
    without an explicit precedence.
    */
    default: /*@__PURE__*/prec$1(Prec_.default),
    /**
    A lower-than-default precedence.
    */
    low: /*@__PURE__*/prec$1(Prec_.low),
    /**
    The lowest precedence level. Meant for things that should end up
    near the end of the extension order.
    */
    lowest: /*@__PURE__*/prec$1(Prec_.lowest)
};
var PrecExtension = function PrecExtension(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.
*/
var Compartment = function Compartment () {};

Compartment.prototype.of = function of (ext) { return new CompartmentInstance(this, ext); };
 /**
 Create an [effect](https://codemirror.net/6/docs/ref/#state.TransactionSpec.effects) that
 reconfigures this compartment.
 */
 Compartment.prototype.reconfigure = function 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.
 */
 Compartment.prototype.get = function get (state) {
     return state.config.compartments.get(this);
 };
var CompartmentInstance = function CompartmentInstance(compartment, inner) {
     this.compartment = compartment;
     this.inner = inner;
 };
var Configuration = function Configuration(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 */); }
 };
 Configuration.prototype.staticFacet = function staticFacet (facet) {
     var addr = this.address[facet.id];
     return addr == null ? facet.default : this.staticValues[addr >> 1];
 };
 Configuration.resolve = function resolve (base, compartments, oldState) {
     var fields = [];
     var facets = Object.create(null);
     var newCompartments = new Map();
     for (var ext of flatten(base, compartments, newCompartments)) {
         if (ext instanceof StateField)
             { fields.push(ext); }
         else
             { (facets[ext.facet.id] || (facets[ext.facet.id] = [])).push(ext); }
     }
     var address = Object.create(null);
     var staticValues = [];
     var dynamicSlots = [];
     var loop = function () {
         address[field.id] = dynamicSlots.length << 1;
         dynamicSlots.push(function (a) { return field.slot(a); });
     };

        for (var field of fields) loop();
     var oldFacets = oldState === null || oldState === void 0 ? void 0 : oldState.config.facets;
     var loop$1 = function ( id ) {
         var providers = facets[id], facet = providers[0].facet;
         var oldProviders = oldFacets && oldFacets[id] || [];
         if (providers.every(function (p) { return p.type == 0; } /* Provider.Static */)) {
             address[facet.id] = (staticValues.length << 1) | 1;
             if (sameArray$1(oldProviders, providers)) {
                 staticValues.push(oldState.facet(facet));
             }
             else {
                 var value = facet.combine(providers.map(function (p) { return p.value; }));
                 staticValues.push(oldState && facet.compare(value, oldState.facet(facet)) ? oldState.facet(facet) : value);
             }
         }
         else {
             var loop$2 = function () {
                 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(function (a) { return p.dynamicSlot(a); });
                 }
             };

                for (var p of providers) loop$2();
             address[facet.id] = dynamicSlots.length << 1;
             dynamicSlots.push(function (a) { return dynamicFacetSlot(a, facet, providers); });
         }
     };

        for (var id in facets) loop$1( id );
     var dynamic = dynamicSlots.map(function (f) { return f(address); });
     return new Configuration(base, newCompartments, dynamic, address, staticValues, facets);
 };
function flatten(extension, compartments, newCompartments) {
    var result = [[], [], [], [], []];
    var seen = new Map();
    function inner(ext, prec) {
        var known = seen.get(ext);
        if (known != null) {
            if (known <= prec)
                { return; }
            var 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 (var 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"); }
            var 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 {
            var content$1 = ext.extension;
            if (!content$1)
                { 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$1, prec);
        }
    }
    inner(extension, Prec_.default);
    return result.reduce(function (a, b) { return a.concat(b); });
}
function ensureAddr(state, addr) {
    if (addr & 1)
        { return 2 /* SlotStatus.Computed */; }
    var idx = addr >> 1;
    var 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 */;
    var 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];
}

var languageData = /*@__PURE__*/Facet.define();
var allowMultipleSelections = /*@__PURE__*/Facet.define({
    combine: function (values) { return values.some(function (v) { return v; }); },
    static: true
});
var lineSeparator = /*@__PURE__*/Facet.define({
    combine: function (values) { return values.length ? values[0] : undefined; },
    static: true
});
var changeFilter = /*@__PURE__*/Facet.define();
var transactionFilter = /*@__PURE__*/Facet.define();
var transactionExtender = /*@__PURE__*/Facet.define();
var readOnly = /*@__PURE__*/Facet.define({
    combine: function (values) { return 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.
*/
var Annotation = function Annotation(
 /**
 The annotation type.
 */
 type, 
 /**
 The value of this annotation.
 */
 value) {
     this.type = type;
     this.value = value;
 };
 /**
 Define a new type of annotation.
 */
 Annotation.define = function define () { return new AnnotationType(); };
/**
Marker that identifies a type of [annotation](https://codemirror.net/6/docs/ref/#state.Annotation).
*/
var AnnotationType = function AnnotationType () {};

AnnotationType.prototype.of = function 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).
*/
var StateEffectType = function StateEffectType(
 // 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.
 */
 StateEffectType.prototype.of = function 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.
*/
var StateEffect = function StateEffect(
 /**
 @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.
 */
 StateEffect.prototype.map = function map (mapping) {
     var 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).
 */
 StateEffect.prototype.is = function 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.
 */
 StateEffect.define = function define (spec) {
        if ( spec === void 0 ) spec = {};

     return new StateEffectType(spec.map || (function (v) { return v; }));
 };
 /**
 Map an array of effects through a change set.
 */
 StateEffect.mapEffects = function mapEffects (effects, mapping) {
     if (!effects.length)
         { return effects; }
     var result = [];
     for (var effect of effects) {
         var 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).
*/
var Transaction = function Transaction(
 /**
 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(function (a) { return a.type == Transaction.time; }))
         { this.annotations = annotations.concat(Transaction.time.of(Date.now())); }
 };

var prototypeAccessors$11$1 = { newDoc: { configurable: true },newSelection: { configurable: true },state: { configurable: true },docChanged: { configurable: true },reconfigured: { configurable: true } };
 /**
 @internal
 */
 Transaction.create = function 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.
 */
 prototypeAccessors$11$1.newDoc.get = function () {
     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.
 */
 prototypeAccessors$11$1.newSelection.get = function () {
     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.
 */
 prototypeAccessors$11$1.state.get = function () {
     if (!this._state)
         { this.startState.applyTransaction(this); }
     return this._state;
 };
 /**
 Get the value of the given annotation type, if any.
 */
 Transaction.prototype.annotation = function annotation (type) {
     for (var ann of this.annotations)
         if (ann.type == type)
             { return ann.value; }
     return undefined;
 };
 /**
 Indicates whether the transaction changed the document.
 */
 prototypeAccessors$11$1.docChanged.get = function () { 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).
 */
 prototypeAccessors$11$1.reconfigured.get = function () { 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.
 */
 Transaction.prototype.isUserEvent = function isUserEvent (event) {
     var e = this.annotation(Transaction.userEvent);
     return !!(e && (e == event || e.length > event.length && e.slice(0, event.length) == event && e[event.length] == "."));
 };

Object.defineProperties( Transaction.prototype, prototypeAccessors$11$1 );
/**
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) {
    var result = [];
    for (var iA = 0, iB = 0;;) {
        var from = (void 0), to = (void 0);
        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;
    var 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: 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) {
    var sel = spec.selection, annotations = asArray$1(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$1(spec.effects),
        annotations: annotations,
        scrollIntoView: !!spec.scrollIntoView
    };
}
function resolveTransaction(state, specs, filter) {
    var s = resolveTransactionInner(state, specs.length ? specs[0] : {}, state.doc.length);
    if (specs.length && specs[0].filter === false)
        { filter = false; }
    for (var i = 1; i < specs.length; i++) {
        if (specs[i].filter === false)
            { filter = false; }
        var seq = !!specs[i].sequential;
        s = mergeTransaction(s, resolveTransactionInner(state, specs[i], seq ? s.changes.newLength : state.doc.length), seq);
    }
    var 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) {
    var state = tr.startState;
    // Change filters
    var result = true;
    for (var filter of state.facet(changeFilter)) {
        var value = filter(tr);
        if (value === false) {
            result = false;
            break;
        }
        if (Array.isArray(value))
            { result = result === true ? value : joinRanges(result, value); }
    }
    if (result !== true) {
        var changes, back;
        if (result === false) {
            back = tr.changes.invertedDesc;
            changes = ChangeSet.empty(state.doc.length);
        }
        else {
            var 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
    var filters = state.facet(transactionFilter);
    for (var i = filters.length - 1; i >= 0; i--) {
        var filtered$1 = filters[i](tr);
        if (filtered$1 instanceof Transaction)
            { tr = filtered$1; }
        else if (Array.isArray(filtered$1) && filtered$1.length == 1 && filtered$1[0] instanceof Transaction)
            { tr = filtered$1[0]; }
        else
            { tr = resolveTransaction(state, asArray$1(filtered$1), false); }
    }
    return tr;
}
function extendTransaction(tr) {
    var state = tr.startState, extenders = state.facet(transactionExtender), spec = tr;
    for (var i = extenders.length - 1; i >= 0; i--) {
        var 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);
}
var none$1 = [];
function asArray$1(value) {
    return value == null ? none$1 : 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 = {}));
var nonASCIISingleCaseWordChar = /[\u00df\u0587\u0590-\u05f4\u0600-\u06ff\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc\uac00-\ud7af]/;
var wordChar;
try {
    wordChar = /*@__PURE__*/new RegExp("[\\p{Alphabetic}\\p{Number}_]", "u");
}
catch (_) { }
function hasWordChar(str) {
    if (wordChar)
        { return wordChar.test(str); }
    for (var i = 0; i < str.length; i++) {
        var ch = str[i];
        if (/\w/.test(ch) || ch > "\x80" && (ch.toUpperCase() != ch.toLowerCase() || nonASCIISingleCaseWordChar.test(ch)))
            { return true; }
    }
    return false;
}
function makeCategorizer(wordChars) {
    return function (char) {
        if (!/\S/.test(char))
            { return CharCategory.Space; }
        if (hasWordChar(char))
            { return CharCategory.Word; }
        for (var 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.
*/
var EditorState = function EditorState(
 /**
 @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 (var i = 0; i < this.config.dynamicSlots.length; i++)
         { ensureAddr(this, i << 1); }
     this.computeSlot = null;
 };

var prototypeAccessors$12 = { tabSize: { configurable: true },lineBreak: { configurable: true },readOnly: { configurable: true } };
 EditorState.prototype.field = function field (field$1, require) {
        if ( require === void 0 ) require = true;

     var addr = this.config.address[field$1.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.
 */
 EditorState.prototype.update = function update () {
        var specs = [], len = arguments.length;
        while ( len-- ) specs[ len ] = arguments[ len ];

     return resolveTransaction(this, specs, true);
 };
 /**
 @internal
 */
 EditorState.prototype.applyTransaction = function applyTransaction (tr) {
        var this$1$1 = this;

     var conf = this.config;
        var base = conf.base;
        var compartments = conf.compartments;
     for (var effect of tr.effects) {
         if (effect.is(Compartment.reconfigure)) {
             if (conf) {
                 compartments = new Map;
                 conf.compartments.forEach(function (val, key) { return 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$1(base).concat(effect.value);
         }
     }
     var startValues;
     if (!conf) {
         conf = Configuration.resolve(base, compartments, this);
         var intermediateState = new EditorState(conf, this.doc, this.selection, conf.dynamicSlots.map(function () { return null; }), function (state, slot) { return slot.reconfigure(state, this$1$1); }, null);
         startValues = intermediateState.values;
     }
     else {
         startValues = tr.startState.values.slice();
     }
     var selection = tr.startState.facet(allowMultipleSelections) ? tr.newSelection : tr.newSelection.asSingle();
     new EditorState(conf, tr.newDoc, selection, startValues, function (state, slot) { return 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.
 */
 EditorState.prototype.replaceSelection = function replaceSelection (text) {
     if (typeof text == "string")
         { text = this.toText(text); }
     return this.changeByRange(function (range) { return ({ 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).
 */
 EditorState.prototype.changeByRange = function changeByRange (f) {
     var sel = this.selection;
     var result1 = f(sel.ranges[0]);
     var changes = this.changes(result1.changes), ranges = [result1.range];
     var effects = asArray$1(result1.effects);
     for (var i = 1; i < sel.ranges.length; i++) {
         var result = f(sel.ranges[i]);
         var newChanges = this.changes(result.changes), newMapped = newChanges.map(changes);
         for (var j = 0; j < i; j++)
             { ranges[j] = ranges[j].map(newMapped); }
         var mapBy = changes.mapDesc(newChanges, true);
         ranges.push(result.range.map(mapBy));
         changes = changes.compose(newMapped);
         effects = StateEffect.mapEffects(effects, newMapped).concat(StateEffect.mapEffects(asArray$1(result.effects), mapBy));
     }
     return {
         changes: changes,
         selection: EditorSelection.create(ranges, sel.mainIndex),
         effects: 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.
 */
 EditorState.prototype.changes = function changes (spec) {
        if ( spec === void 0 ) 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.
 */
 EditorState.prototype.toText = function toText (string) {
     return Text.of(string.split(this.facet(EditorState.lineSeparator) || DefaultSplit));
 };
 /**
 Return the given range of the document as a string.
 */
 EditorState.prototype.sliceDoc = function sliceDoc (from, to) {
        if ( from === void 0 ) from = 0;
        if ( to === void 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).
 */
 EditorState.prototype.facet = function facet (facet$1) {
     var addr = this.config.address[facet$1.id];
     if (addr == null)
         { return facet$1.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.
 */
 EditorState.prototype.toJSON = function toJSON (fields) {
     var result = {
         doc: this.sliceDoc(),
         selection: this.selection.toJSON()
     };
     if (fields)
         { for (var prop in fields) {
             var 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.
 */
 EditorState.fromJSON = function fromJSON (json, config, fields) {
        if ( config === void 0 ) config = {};

     if (!json || typeof json.doc != "string")
         { throw new RangeError("Invalid JSON representation for EditorState"); }
     var fieldInit = [];
     if (fields)
         { for (var prop in fields) {
             if (Object.prototype.hasOwnProperty.call(json, prop)) {
                 var field = fields[prop], value = json[prop];
                 fieldInit.push(field.init(function (state) { return 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.
 */
 EditorState.create = function create (config) {
        if ( config === void 0 ) config = {};

     var configuration = Configuration.resolve(config.extensions || [], new Map);
     var doc = config.doc instanceof Text ? config.doc
         : Text.of((config.doc || "").split(configuration.staticFacet(EditorState.lineSeparator) || DefaultSplit));
     var 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(function () { return null; }), function (state, slot) { return 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.
 */
 prototypeAccessors$12.tabSize.get = function () { return this.facet(EditorState.tabSize); };
 /**
 Get the proper [line-break](https://codemirror.net/6/docs/ref/#state.EditorState^lineSeparator)
 string for this state.
 */
 prototypeAccessors$12.lineBreak.get = function () { 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.
 */
 prototypeAccessors$12.readOnly.get = function () { 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.
 */
 EditorState.prototype.phrase = function phrase (phrase$1) {
        var insert = [], len = arguments.length - 1;
        while ( len-- > 0 ) insert[ len ] = arguments[ len + 1 ];

     for (var map of this.facet(EditorState.phrases))
         if (Object.prototype.hasOwnProperty.call(map, phrase$1)) {
             phrase$1 = map[phrase$1];
             break;
         }
     if (insert.length)
         { phrase$1 = phrase$1.replace(/\$(\$|\d*)/g, function (m, i) {
             if (i == "$")
                 { return "$"; }
             var n = +(i || 1);
             return !n || n > insert.length ? m : insert[n - 1];
         }); }
     return phrase$1;
 };
 /**
 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.
 */
 EditorState.prototype.languageDataAt = function languageDataAt (name, pos, side) {
        if ( side === void 0 ) side = -1;

     var values = [];
     for (var provider of this.facet(languageData)) {
         for (var 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)
 */
 EditorState.prototype.charCategorizer = function charCategorizer (at) {
     return makeCategorizer(this.languageDataAt("wordChars", at).join(""));
 };
 /**
 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.
 */
 EditorState.prototype.wordAt = function wordAt (pos) {
     var ref = this.doc.lineAt(pos);
        var text = ref.text;
        var from = ref.from;
        var length = ref.length;
     var cat = this.charCategorizer(pos);
     var start = pos - from, end = pos - from;
     while (start > 0) {
         var prev = findClusterBreak(text, start, false);
         if (cat(text.slice(prev, start)) != CharCategory.Word)
             { break; }
         start = prev;
     }
     while (end < length) {
         var 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);
 };

Object.defineProperties( EditorState.prototype, prototypeAccessors$12 );
/**
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: function (values) { return 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: function compare(a, b) {
        var kA = Object.keys(a), kB = Object.keys(b);
        return kA.length == kB.length && kA.every(function (k) { return 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) {
    if ( combine === void 0 ) combine = {};

    var result = {};
    for (var config of configs)
        for (var key of Object.keys(config)) {
            var 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 (var key$1 in defaults)
        { if (result[key$1] === undefined)
            { result[key$1] = defaults[key$1]; } }
    return result;
}

/**
Each range is associated with a value, which must inherit from
this class.
*/
var RangeValue = function RangeValue () {};

RangeValue.prototype.eq = function eq (other) { return this == other; };
 /**
 Create a [range](https://codemirror.net/6/docs/ref/#state.Range) with this value.
 */
 RangeValue.prototype.range = function range (from, to) {
    if ( to === void 0 ) 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;
/**
A range associates a value with a range of positions.
*/
var Range$1 = function Range(
 /**
 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
 */
 Range$1.create = function create (from, to, value) {
     return new Range$1(from, to, value);
 };
function cmpRange(a, b) {
    return a.from - b.from || a.value.startSide - b.value.startSide;
}
var Chunk = function Chunk(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;
 };

var prototypeAccessors$13$1 = { length: { configurable: true } };
 prototypeAccessors$13$1.length.get = function () { 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`.
 Chunk.prototype.findIndex = function findIndex (pos, side, end, startAt) {
        if ( startAt === void 0 ) startAt = 0;

     var arr = end ? this.to : this.from;
     for (var lo = startAt, hi = arr.length;;) {
         if (lo == hi)
             { return lo; }
         var mid = (lo + hi) >> 1;
         var 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; }
     }
 };
 Chunk.prototype.between = function between (offset, from, to, f) {
     for (var i = this.findIndex(from, -1000000000 /* 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; } }
 };
 Chunk.prototype.map = function map (offset, changes) {
     var value = [], from = [], to = [], newPos = -1, maxPoint = -1;
     for (var i = 0; i < this.value.length; i++) {
         var val = this.value[i], curFrom = this.from[i] + offset, curTo = this.to[i] + offset, newFrom = (void 0), newTo = (void 0);
         if (curFrom == curTo) {
             var 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 };
 };

Object.defineProperties( Chunk.prototype, prototypeAccessors$13$1 );
/**
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.
*/
var RangeSet = function RangeSet(
 /**
 @internal
 */
 chunkPos, 
 /**
 @internal
 */
 chunk, 
 /**
 @internal
 */
 nextLayer, 
 /**
 @internal
 */
 maxPoint) {
     this.chunkPos = chunkPos;
     this.chunk = chunk;
     this.nextLayer = nextLayer;
     this.maxPoint = maxPoint;
 };

var prototypeAccessors$14$1 = { length: { configurable: true },size: { configurable: true },isEmpty: { configurable: true } };
 /**
 @internal
 */
 RangeSet.create = function create (chunkPos, chunk, nextLayer, maxPoint) {
     return new RangeSet(chunkPos, chunk, nextLayer, maxPoint);
 };
 /**
 @internal
 */
 prototypeAccessors$14$1.length.get = function () {
     var last = this.chunk.length - 1;
     return last < 0 ? 0 : Math.max(this.chunkEnd(last), this.nextLayer.length);
 };
 /**
 The number of ranges in the set.
 */
 prototypeAccessors$14$1.size.get = function () {
     if (this.isEmpty)
         { return 0; }
     var size = this.nextLayer.size;
     for (var chunk of this.chunk)
         size += chunk.value.length;
     return size;
 };
 /**
 @internal
 */
 RangeSet.prototype.chunkEnd = function 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`.)
 */
 RangeSet.prototype.update = function update (updateSpec) {
     var add = updateSpec.add; if ( add === void 0 ) add = [];
        var sort = updateSpec.sort; if ( sort === void 0 ) sort = false;
        var filterFrom = updateSpec.filterFrom; if ( filterFrom === void 0 ) filterFrom = 0;
        var filterTo = updateSpec.filterTo; if ( filterTo === void 0 ) filterTo = this.length;
     var 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; }
     var cur = new LayerCursor(this, null, -1).goto(0), i = 0, spill = [];
     var 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) {
             var 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: filter, filterFrom: filterFrom, filterTo: filterTo }));
 };
 /**
 Map this range set through a set of changes, return the new set.
 */
 RangeSet.prototype.map = function map (changes) {
     if (changes.empty || this.isEmpty)
         { return this; }
     var chunks = [], chunkPos = [], maxPoint = -1;
     for (var i = 0; i < this.chunk.length; i++) {
         var start = this.chunkPos[i], chunk = this.chunk[i];
         var 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) {
             var ref = chunk.map(start, changes);
                var mapped = ref.mapped;
                var pos = ref.pos;
             if (mapped) {
                 maxPoint = Math.max(maxPoint, mapped.maxPoint);
                 chunks.push(mapped);
                 chunkPos.push(pos);
             }
         }
     }
     var 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.
 */
 RangeSet.prototype.between = function between (from, to, f) {
     if (this.isEmpty)
         { return; }
     for (var i = 0; i < this.chunk.length; i++) {
         var 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`.
 */
 RangeSet.prototype.iter = function iter (from) {
        if ( from === void 0 ) from = 0;

     return HeapCursor.from([this]).goto(from);
 };
 /**
 @internal
 */
 prototypeAccessors$14$1.isEmpty.get = function () { return this.nextLayer == this; };
 /**
 Iterate over the ranges in a collection of sets, in order,
 starting from `from`.
 */
 RangeSet.iter = function iter (sets, from) {
        if ( from === void 0 ) from = 0;

     return HeapCursor.from(sets).goto(from);
 };
 /**
 Iterate over two groups of sets, calling methods on `comparator`
 to notify it of possible differences.
 */
 RangeSet.compare = function compare$1 (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) {
        if ( minPointSize === void 0 ) minPointSize = -1;

     var a = oldSets.filter(function (set) { return set.maxPoint > 0 || !set.isEmpty && set.maxPoint >= minPointSize; });
     var b = newSets.filter(function (set) { return set.maxPoint > 0 || !set.isEmpty && set.maxPoint >= minPointSize; });
     var sharedChunks = findSharedChunks(a, b, textDiff);
     var sideA = new SpanCursor(a, sharedChunks, minPointSize);
     var sideB = new SpanCursor(b, sharedChunks, minPointSize);
     textDiff.iterGaps(function (fromA, fromB, length) { return 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.
 */
 RangeSet.eq = function eq (oldSets, newSets, from, to) {
        if ( from === void 0 ) from = 0;

     if (to == null)
         { to = 1000000000 /* C.Far */ - 1; }
     var a = oldSets.filter(function (set) { return !set.isEmpty && newSets.indexOf(set) < 0; });
     var b = newSets.filter(function (set) { return !set.isEmpty && oldSets.indexOf(set) < 0; });
     if (a.length != b.length)
         { return false; }
     if (!a.length)
         { return true; }
     var sharedChunks = findSharedChunks(a, b);
     var 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 || !sideA.point.eq(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.
 */
 RangeSet.spans = function spans (sets, from, to, iterator, 
 /**
 When given and greater than -1, only points of at least this
 size are taken into account.
 */
 minPointSize) {
        if ( minPointSize === void 0 ) minPointSize = -1;

     var cursor = new SpanCursor(sets, null, minPointSize).goto(from), pos = from;
     var openRanges = cursor.openStart;
     for (;;) {
         var curTo = Math.min(cursor.to, to);
         if (cursor.point) {
             var active = cursor.activeForPoint(cursor.to);
             var 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.
 */
 RangeSet.of = function of (ranges, sort) {
        if ( sort === void 0 ) sort = false;

     var build = new RangeSetBuilder();
     for (var 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.
 */
 RangeSet.join = function join (sets) {
     if (!sets.length)
         { return RangeSet.empty; }
     var result = sets[sets.length - 1];
     for (var i = sets.length - 2; i >= 0; i--) {
         for (var 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;
 };

Object.defineProperties( RangeSet.prototype, prototypeAccessors$14$1 );
/**
The empty set of ranges.
*/
RangeSet.empty = /*@__PURE__*/new RangeSet([], [], null, -1);
function lazySort(ranges) {
    if (ranges.length > 1)
        { for (var prev = ranges[0], i = 1; i < ranges.length; i++) {
            var 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.
*/
var RangeSetBuilder = function RangeSetBuilder() {
     this.chunks = [];
     this.chunkPos = [];
     this.chunkStart = -1;
     this.last = null;
     this.lastFrom = -1000000000 /* C.Far */;
     this.lastTo = -1000000000 /* 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.
 */
 RangeSetBuilder.prototype.finishChunk = function 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 = [];
     }
 };

RangeSetBuilder.prototype.add = function add (from, to, value) {
     if (!this.addInner(from, to, value))
         { (this.nextLayer || (this.nextLayer = new RangeSetBuilder)).add(from, to, value); }
 };
 /**
 @internal
 */
 RangeSetBuilder.prototype.addInner = function addInner (from, to, value) {
     var 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
 */
 RangeSetBuilder.prototype.addChunk = function 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);
     var 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.
 */
 RangeSetBuilder.prototype.finish = function finish () { return this.finishInner(RangeSet.empty); };
 /**
 @internal
 */
 RangeSetBuilder.prototype.finishInner = function finishInner (next) {
     if (this.from.length)
         { this.finishChunk(false); }
     if (this.chunks.length == 0)
         { return next; }
     var 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) {
    var inA = new Map();
    for (var set of a)
        for (var i = 0; i < set.chunk.length; i++)
            { if (set.chunk[i].maxPoint <= 0)
                { inA.set(set.chunk[i], set.chunkPos[i]); } }
    var shared = new Set();
    for (var set$1 of b)
        for (var i$1 = 0; i$1 < set$1.chunk.length; i$1++) {
            var known = inA.get(set$1.chunk[i$1]);
            if (known != null && (textDiff ? textDiff.mapPos(known) : known) == set$1.chunkPos[i$1] &&
                !(textDiff === null || textDiff === void 0 ? void 0 : textDiff.touchesRange(known, known + set$1.chunk[i$1].length)))
                { shared.add(set$1.chunk[i$1]); }
        }
    return shared;
}
var LayerCursor = function LayerCursor(layer, skip, minPoint, rank) {
     if ( rank === void 0 ) rank = 0;

     this.layer = layer;
     this.skip = skip;
     this.minPoint = minPoint;
     this.rank = rank;
 };

var prototypeAccessors$15$1 = { startSide: { configurable: true },endSide: { configurable: true } };
 prototypeAccessors$15$1.startSide.get = function () { return this.value ? this.value.startSide : 0; };
 prototypeAccessors$15$1.endSide.get = function () { return this.value ? this.value.endSide : 0; };
 LayerCursor.prototype.goto = function goto (pos, side /* C.Far */) {
        if ( side === void 0 ) side = -1000000000;

     this.chunkIndex = this.rangeIndex = 0;
     this.gotoInner(pos, side, false);
     return this;
 };
 LayerCursor.prototype.gotoInner = function gotoInner (pos, side, forward) {
     while (this.chunkIndex < this.layer.chunk.length) {
         var 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) {
         var 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();
 };
 LayerCursor.prototype.forward = function forward (pos, side) {
     if ((this.to - pos || this.endSide - side) < 0)
         { this.gotoInner(pos, side, true); }
 };
 LayerCursor.prototype.next = function next () {
     for (;;) {
         if (this.chunkIndex == this.layer.chunk.length) {
             this.from = this.to = 1000000000 /* C.Far */;
             this.value = null;
             break;
         }
         else {
             var chunkPos = this.layer.chunkPos[this.chunkIndex], chunk = this.layer.chunk[this.chunkIndex];
             var 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; }
         }
     }
 };
 LayerCursor.prototype.setRangeIndex = function 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;
     }
 };
 LayerCursor.prototype.nextChunk = function nextChunk () {
     this.chunkIndex++;
     this.rangeIndex = 0;
     this.next();
 };
 LayerCursor.prototype.compare = function compare (other) {
     return this.from - other.from || this.startSide - other.startSide || this.rank - other.rank ||
         this.to - other.to || this.endSide - other.endSide;
 };

Object.defineProperties( LayerCursor.prototype, prototypeAccessors$15$1 );
var HeapCursor = function HeapCursor(heap) {
     this.heap = heap;
 };

var prototypeAccessors$16 = { startSide: { configurable: true } };
 HeapCursor.from = function from (sets, skip, minPoint) {
        if ( skip === void 0 ) skip = null;
        if ( minPoint === void 0 ) minPoint = -1;

     var heap = [];
     for (var i = 0; i < sets.length; i++) {
         for (var 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);
 };
 prototypeAccessors$16.startSide.get = function () { return this.value ? this.value.startSide : 0; };
 HeapCursor.prototype.goto = function goto (pos, side /* C.Far */) {
        if ( side === void 0 ) side = -1000000000;

     for (var cur of this.heap)
         cur.goto(pos, side);
     for (var i = this.heap.length >> 1; i >= 0; i--)
         { heapBubble(this.heap, i); }
     this.next();
     return this;
 };
 HeapCursor.prototype.forward = function forward (pos, side) {
     for (var cur of this.heap)
         cur.forward(pos, side);
     for (var i = this.heap.length >> 1; i >= 0; i--)
         { heapBubble(this.heap, i); }
     if ((this.to - pos || this.value.endSide - side) < 0)
         { this.next(); }
 };
 HeapCursor.prototype.next = function next () {
     if (this.heap.length == 0) {
         this.from = this.to = 1000000000 /* C.Far */;
         this.value = null;
         this.rank = -1;
     }
     else {
         var 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);
     }
 };

Object.defineProperties( HeapCursor.prototype, prototypeAccessors$16 );
function heapBubble(heap, index) {
    for (var cur = heap[index];;) {
        var childIndex = (index << 1) + 1;
        if (childIndex >= heap.length)
            { break; }
        var 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;
    }
}
var SpanCursor = function SpanCursor(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 = -1000000000 /* 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);
 };
 SpanCursor.prototype.goto = function goto (pos, side /* C.Far */) {
        if ( side === void 0 ) side = -1000000000;

     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;
 };
 SpanCursor.prototype.forward = function 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);
 };
 SpanCursor.prototype.removeActive = function removeActive (index) {
     remove(this.active, index);
     remove(this.activeTo, index);
     remove(this.activeRank, index);
     this.minActive = findMinIndex(this.active, this.activeTo);
 };
 SpanCursor.prototype.addActive = function addActive (trackOpen) {
     var i = 0;
        var ref = this.cursor;
        var value = ref.value;
        var to = ref.to;
        var rank = ref.rank;
     // 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`.
 SpanCursor.prototype.next = function next () {
     var from = this.to, wasPoint = this.point;
     this.point = null;
     var trackOpen = this.openStart < 0 ? [] : null;
     for (;;) {
         var 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 {
             var 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 (var i = trackOpen.length - 1; i >= 0 && trackOpen[i] < from; i--)
             { this.openStart++; }
     }
 };
 SpanCursor.prototype.activeForPoint = function activeForPoint (to) {
     if (!this.active.length)
         { return this.active; }
     var active = [];
     for (var 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();
 };
 SpanCursor.prototype.openEnd = function openEnd (to) {
     var open = 0;
     for (var 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);
    var endB = startB + length;
    var pos = startB, dPos = startB - startA;
    for (;;) {
        var diff = (a.to + dPos) - b.to || a.endSide - b.endSide;
        var end = diff < 0 ? a.to + dPos : b.to, clipEnd = Math.min(end, endB);
        if (a.point || b.point) {
            if (!(a.point && b.point && (a.point == b.point || a.point.eq(b.point)) &&
                sameValues(a.activeForPoint(a.to), b.activeForPoint(b.to))))
                { comparator.comparePoint(pos, clipEnd, a.point, b.point); }
        }
        else {
            if (clipEnd > pos && !sameValues(a.active, b.active))
                { comparator.compareRange(pos, clipEnd, a.active, b.active); }
        }
        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 (var i = 0; i < a.length; i++)
        { if (a[i] != b[i] && !a[i].eq(b[i]))
            { return false; } }
    return true;
}
function remove(array, index) {
    for (var i = index, e = array.length - 1; i < e; i++)
        { array[i] = array[i + 1]; }
    array.pop();
}
function insert(array, index, value) {
    for (var i = array.length - 1; i >= index; i--)
        { array[i + 1] = array[i]; }
    array[index] = value;
}
function findMinIndex(value, array) {
    var found = -1, foundPos = 1000000000 /* C.Far */;
    for (var i = 0; i < array.length; i++)
        { if ((array[i] - foundPos || value[i].endSide - value[found].endSide) < 0) {
            found = i;
            foundPos = array[i];
        } }
    return found;
}

/**
Count the column position at the given offset into the string,
taking extending characters and tab size into account.
*/
function countColumn(string, tabSize, to) {
    if ( to === void 0 ) to = string.length;

    var n = 0;
    for (var i = 0; i < to;) {
        if (string.charCodeAt(i) == 9) {
            n += tabSize - (n % tabSize);
            i++;
        }
        else {
            n++;
            i = findClusterBreak(string, i);
        }
    }
    return n;
}
/**
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 (var 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 strict === true ? -1 : string.length;
}var C = "\u037c";
var COUNT = typeof Symbol == "undefined" ? "__" + C : Symbol.for(C);
var SET = typeof Symbol == "undefined" ? "__styleSet" + Math.floor(Math.random() * 1e8) : Symbol("styleSet");
var top$4 = 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.
var StyleModule = function StyleModule(spec, options) {
  this.rules = [];
  var ref = options || {};
  var finish = ref.finish;

  function splitSelector(selector) {
    return /^@/.test(selector) ? [selector] : selector.split(/,\s*/)
  }

  function render(selectors, spec, target, isKeyframes) {
    var local = [], isAt = /^@(\w+)\b/.exec(selectors[0]), keyframes = isAt && isAt[1] == "keyframes";
    if (isAt && spec == null) { return target.push(selectors[0] + ";") }
    for (var prop in spec) {
      var value = spec[prop];
      if (/&/.test(prop)) {
        render(prop.split(/,\s*/).map(function (part) { return selectors.map(function (sel) { return part.replace(/&/, sel); }); }).reduce(function (a, b) { return 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, function (l) { return "-" + l.toLowerCase(); }) + ": " + value + ";");
      }
    }
    if (local.length || keyframes) {
      target.push((finish && !isAt && !isKeyframes ? selectors.map(finish) : selectors).join(", ") +
                  " {" + local.join(" ") + "}");
    }
  }

  for (var prop in spec) { render(splitSelector(prop), spec[prop], this.rules); }
};

// :: () → string
// Returns a string containing the module's CSS rules.
StyleModule.prototype.getRules = function getRules () { return this.rules.join("\n") };

// :: () → string
// Generate a new unique CSS class name.
StyleModule.newName = function newName () {
  var id = top$4[COUNT] || 1;
  top$4[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.
StyleModule.mount = function mount (root, modules, options) {
  var 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);
};

var adoptedSet = new Map; //<Document, StyleSet>

var StyleSet = function StyleSet(root, nonce) {
  var doc = root.ownerDocument || root, win = doc.defaultView;
  if (!root.head && root.adoptedStyleSheets && win.CSSStyleSheet) {
    var 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;
};

StyleSet.prototype.mount = function mount (modules, root) {
  var sheet = this.sheet;
  var pos = 0 /* Current rule offset */, j = 0; /* Index into this.modules */
  for (var i = 0; i < modules.length; i++) {
    var 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 (var 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 ].concat( root.adoptedStyleSheets); }
  } else {
    var text = "";
    for (var i$1 = 0; i$1 < this.modules.length; i$1++)
      { text += this.modules[i$1].getRules() + "\n"; }
    this.styleTag.textContent = text;
    var target = root.head || root;
    if (this.styleTag.parentNode != target)
      { target.insertBefore(this.styleTag, target.firstChild); }
  }
};

StyleSet.prototype.setNonce = function 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)": {...}}`.
function getSelection$1(root) {
    var 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; }
            var 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) {
    var x = left ? rect.left : rect.right;
    return { left: x, right: x, top: rect.top, bottom: rect.bottom };
}
function windowRect(win) {
    var 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) {
    var scaleX = rect.width / elt.offsetWidth;
    var 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: scaleX, scaleY: scaleY };
}
function scrollRectIntoView(dom, rect, side, x, y, xMargin, yMargin, ltr) {
    var assign;

    var doc = dom.ownerDocument, win = doc.defaultView || window;
    for (var cur = dom, stop = false; cur && !stop;) {
        if (cur.nodeType == 1) { // Element
            var bounding = (void 0), top = cur == doc.body;
            var 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;
                }
                var rect$1 = cur.getBoundingClientRect();
                ((assign = getScale(cur, rect$1), scaleX = assign.scaleX, scaleY = assign.scaleY));
                // Make sure scrollbar width isn't included in the rectangle
                bounding = { left: rect$1.left, right: rect$1.left + cur.clientWidth * scaleX,
                    top: rect$1.top, bottom: rect$1.top + cur.clientHeight * scaleY };
            }
            var moveX = 0, moveY = 0;
            if (y == "nearest") {
                if (rect.top < bounding.top) {
                    moveY = -(bounding.top - rect.top + yMargin);
                    if (side > 0 && rect.bottom > bounding.bottom + moveY)
                        { moveY = rect.bottom - bounding.bottom + moveY + yMargin; }
                }
                else if (rect.bottom > bounding.bottom) {
                    moveY = rect.bottom - bounding.bottom + yMargin;
                    if (side < 0 && (rect.top - moveY) < bounding.top)
                        { moveY = -(bounding.top + moveY - rect.top + yMargin); }
                }
            }
            else {
                var rectHeight = rect.bottom - rect.top, boundingHeight = bounding.bottom - bounding.top;
                var 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) {
                    moveX = -(bounding.left - rect.left + xMargin);
                    if (side > 0 && rect.right > bounding.right + moveX)
                        { moveX = rect.right - bounding.right + moveX + xMargin; }
                }
                else if (rect.right > bounding.right) {
                    moveX = rect.right - bounding.right + xMargin;
                    if (side < 0 && rect.left < bounding.left + moveX)
                        { moveX = -(bounding.left + moveX - rect.left + xMargin); }
                }
            }
            else {
                var 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 {
                    var movedX = 0, movedY = 0;
                    if (moveY) {
                        var start = cur.scrollTop;
                        cur.scrollTop += moveY / scaleY;
                        movedY = (cur.scrollTop - start) * scaleY;
                    }
                    if (moveX) {
                        var start$1 = cur.scrollLeft;
                        cur.scrollLeft += moveX / scaleX;
                        movedX = (cur.scrollLeft - start$1) * 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; }
            cur = cur.assignedSlot || cur.parentNode;
        }
        else if (cur.nodeType == 11) { // A shadow root
            cur = cur.host;
        }
        else {
            break;
        }
    }
}
function scrollableParents(dom) {
    var doc = dom.ownerDocument, x, y;
    for (var cur = dom.parentNode; cur;) {
        if (cur == doc.body || (x && y)) {
            break;
        }
        else if (cur.nodeType == 1) {
            if (!y && cur.scrollHeight > cur.clientHeight)
                { y = cur; }
            if (!x && cur.scrollWidth > cur.clientWidth)
                { x = cur; }
            cur = cur.assignedSlot || cur.parentNode;
        }
        else if (cur.nodeType == 11) {
            cur = cur.host;
        }
        else {
            break;
        }
    }
    return { x: x, y: y };
}
var DOMSelectionState = function DOMSelectionState() {
    this.anchorNode = null;
    this.anchorOffset = 0;
    this.focusNode = null;
    this.focusOffset = 0;
};
DOMSelectionState.prototype.eq = function eq (domSel) {
    return this.anchorNode == domSel.anchorNode && this.anchorOffset == domSel.anchorOffset &&
        this.focusNode == domSel.focusNode && this.focusOffset == domSel.focusOffset;
};
DOMSelectionState.prototype.setRange = function setRange (range) {
    var anchorNode = range.anchorNode;
        var focusNode = range.focusNode;
    // 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));
};
DOMSelectionState.prototype.set = function set (anchorNode, anchorOffset, focusNode, focusOffset) {
    this.anchorNode = anchorNode;
    this.anchorOffset = anchorOffset;
    this.focusNode = focusNode;
    this.focusOffset = focusOffset;
};
var preventScrollSupported = null;
// 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); }
    var stack = [];
    for (var 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 (var i = 0; i < stack.length;) {
            var elt = stack[i++], top = stack[i++], left = stack[i++];
            if (elt.scrollTop != top)
                { elt.scrollTop = top; }
            if (elt.scrollLeft != left)
                { elt.scrollLeft = left; }
        }
    }
}
var scratchRange;
function textRange(node, from, to) {
    if ( to === void 0 ) to = from;

    var range = scratchRange || (scratchRange = document.createRange());
    range.setEnd(node, to);
    range.setStart(node, from);
    return range;
}
function dispatchKey(elt, name, code, mods) {
    var assign;

    var options = { key: name, code: name, keyCode: code, which: code, cancelable: true };
    if (mods)
        { ((assign = mods, options.altKey = assign.altKey, options.ctrlKey = assign.ctrlKey, options.shiftKey = assign.shiftKey, options.metaKey = assign.metaKey)); }
    var down = new KeyboardEvent("keydown", options);
    down.synthetic = true;
    elt.dispatchEvent(down);
    var 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 clearAttributes(node) {
    while (node.attributes.length)
        { node.removeAttributeNode(node.attributes[0]); }
}
function atElementStart(doc, selection) {
    var 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; }
            var 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) {
    return elt.scrollTop > Math.max(1, elt.scrollHeight - elt.clientHeight - 4);
}
function textNodeBefore(startNode, startOffset) {
    for (var 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 (var 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;
        }
    }
}

var DOMPos = function DOMPos(node, offset, precise) {
    if ( precise === void 0 ) precise = true;

    this.node = node;
    this.offset = offset;
    this.precise = precise;
};
DOMPos.before = function before (dom, precise) { return new DOMPos(dom.parentNode, domIndex(dom), precise); };
DOMPos.after = function after (dom, precise) { return new DOMPos(dom.parentNode, domIndex(dom) + 1, precise); };
var noChildren = [];
var ContentView = function ContentView() {
    this.parent = null;
    this.dom = null;
    this.flags = 2 /* ViewFlag.NodeDirty */;
};

var prototypeAccessors$4 = { overrideDOMText: { configurable: true },posAtStart: { configurable: true },posAtEnd: { configurable: true },rootView: { configurable: true },isEditable: { configurable: true },isWidget: { configurable: true },isHidden: { configurable: true } };
prototypeAccessors$4.overrideDOMText.get = function () { return null; };
prototypeAccessors$4.posAtStart.get = function () {
    return this.parent ? this.parent.posBefore(this) : 0;
};
prototypeAccessors$4.posAtEnd.get = function () {
    return this.posAtStart + this.length;
};
ContentView.prototype.posBefore = function posBefore (view) {
    var pos = this.posAtStart;
    for (var child of this.children) {
        if (child == view)
            { return pos; }
        pos += child.length + child.breakAfter;
    }
    throw new RangeError("Invalid child in posBefore");
};
ContentView.prototype.posAfter = function posAfter (view) {
    return this.posBefore(view) + view.length;
};
ContentView.prototype.sync = function sync (view, track) {
    if (this.flags & 2 /* ViewFlag.NodeDirty */) {
        var parent = this.dom;
        var prev = null, next;
        for (var child of this.children) {
            if (child.flags & 7 /* ViewFlag.Dirty */) {
                if (!child.dom && (next = prev ? prev.nextSibling : parent.firstChild)) {
                    var contentView = ContentView.get(next);
                    if (!contentView || !contentView.parent && contentView.canReuseDOM(child))
                        { child.reuseDOM(next); }
                }
                child.sync(view, track);
                child.flags &= ~7 /* ViewFlag.Dirty */;
            }
            next = prev ? prev.nextSibling : parent.firstChild;
            if (track && !track.written && track.node == parent && next != child.dom)
                { track.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 (next && track && track.node == parent)
            { track.written = true; }
        while (next)
            { next = rm$1(next); }
    }
    else if (this.flags & 1 /* ViewFlag.ChildDirty */) {
        for (var child$1 of this.children)
            if (child$1.flags & 7 /* ViewFlag.Dirty */) {
                child$1.sync(view, track);
                child$1.flags &= ~7 /* ViewFlag.Dirty */;
            }
    }
};
ContentView.prototype.reuseDOM = function reuseDOM (_dom) { };
ContentView.prototype.localPosFromDOM = function localPosFromDOM (node, offset) {
    var after;
    if (node == this.dom) {
        after = this.dom.childNodes[offset];
    }
    else {
        var bias = maxOffset(node) == 0 ? 0 : offset == 0 ? -1 : 1;
        for (;;) {
            var parent = node.parentNode;
            if (parent == this.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 == this.dom.firstChild)
        { return 0; }
    while (after && !ContentView.get(after))
        { after = after.nextSibling; }
    if (!after)
        { return this.length; }
    for (var i = 0, pos = 0;; i++) {
        var child = this.children[i];
        if (child.dom == after)
            { return pos; }
        pos += child.length + child.breakAfter;
    }
};
ContentView.prototype.domBoundsAround = function domBoundsAround (from, to, offset) {
        if ( offset === void 0 ) offset = 0;

    var fromI = -1, fromStart = -1, toI = -1, toEnd = -1;
    for (var i = 0, pos = offset, prevEnd = offset; i < this.children.length; i++) {
        var child = this.children[i], end = pos + child.length;
        if (pos < from && end > to)
            { return child.domBoundsAround(from, to, pos); }
        if (end >= from && fromI == -1) {
            fromI = i;
            fromStart = pos;
        }
        if (pos > to && child.dom.parentNode == this.dom) {
            toI = i;
            toEnd = prevEnd;
            break;
        }
        prevEnd = end;
        pos = end + child.breakAfter;
    }
    return { from: fromStart, to: toEnd < 0 ? offset + this.length : toEnd,
        startDOM: (fromI ? this.children[fromI - 1].dom.nextSibling : null) || this.dom.firstChild,
        endDOM: toI < this.children.length && toI >= 0 ? this.children[toI].dom : null };
};
ContentView.prototype.markDirty = function markDirty (andParent) {
        if ( andParent === void 0 ) andParent = false;

    this.flags |= 2 /* ViewFlag.NodeDirty */;
    this.markParentsDirty(andParent);
};
ContentView.prototype.markParentsDirty = function markParentsDirty (childList) {
    for (var parent = this.parent; parent; parent = parent.parent) {
        if (childList)
            { parent.flags |= 2 /* ViewFlag.NodeDirty */; }
        if (parent.flags & 1 /* ViewFlag.ChildDirty */)
            { return; }
        parent.flags |= 1 /* ViewFlag.ChildDirty */;
        childList = false;
    }
};
ContentView.prototype.setParent = function setParent (parent) {
    if (this.parent != parent) {
        this.parent = parent;
        if (this.flags & 7 /* ViewFlag.Dirty */)
            { this.markParentsDirty(true); }
    }
};
ContentView.prototype.setDOM = function setDOM (dom) {
    if (this.dom == dom)
        { return; }
    if (this.dom)
        { this.dom.cmView = null; }
    this.dom = dom;
    dom.cmView = this;
};
prototypeAccessors$4.rootView.get = function () {
    for (var v = this;;) {
        var parent = v.parent;
        if (!parent)
            { return v; }
        v = parent;
    }
};
ContentView.prototype.replaceChildren = function replaceChildren (from, to, children) {
        var ref;

        if ( children === void 0 ) children = noChildren;
    this.markDirty();
    for (var i = from; i < to; i++) {
        var child = this.children[i];
        if (child.parent == this && children.indexOf(child) < 0)
            { child.destroy(); }
    }
    if (children.length < 250)
        { (ref = this.children).splice.apply(ref, [ from, to - from ].concat( children )); }
    else
        { this.children = [].concat(this.children.slice(0, from), children, this.children.slice(to)); }
    for (var i$1 = 0; i$1 < children.length; i$1++)
        { children[i$1].setParent(this); }
};
ContentView.prototype.ignoreMutation = function ignoreMutation (_rec) { return false; };
ContentView.prototype.ignoreEvent = function ignoreEvent (_event) { return false; };
ContentView.prototype.childCursor = function childCursor (pos) {
        if ( pos === void 0 ) pos = this.length;

    return new ChildCursor(this.children, pos, this.children.length);
};
ContentView.prototype.childPos = function childPos (pos, bias) {
        if ( bias === void 0 ) bias = 1;

    return this.childCursor().findPos(pos, bias);
};
ContentView.prototype.toString = function toString () {
    var name = this.constructor.name.replace("View", "");
    return name + (this.children.length ? "(" + this.children.join() + ")" :
        this.length ? "[" + (name == "Text" ? this.text : this.length) + "]" : "") +
        (this.breakAfter ? "#" : "");
};
ContentView.get = function get (node) { return node.cmView; };
prototypeAccessors$4.isEditable.get = function () { return true; };
prototypeAccessors$4.isWidget.get = function () { return false; };
prototypeAccessors$4.isHidden.get = function () { return false; };
ContentView.prototype.merge = function merge (from, to, source, hasStart, openStart, openEnd) {
    return false;
};
ContentView.prototype.become = function become (other) { return false; };
ContentView.prototype.canReuseDOM = function canReuseDOM (other) {
    return other.constructor == this.constructor && !((this.flags | other.flags) & 8 /* ViewFlag.Composition */);
};
// When this is a zero-length view with a side, this should return a
// number <= 0 to indicate it is before its position, or a
// number > 0 when after its position.
ContentView.prototype.getSide = function getSide () { return 0; };
ContentView.prototype.destroy = function destroy () {
    for (var child of this.children)
        if (child.parent == this)
            { child.destroy(); }
    this.parent = null;
};

Object.defineProperties( ContentView.prototype, prototypeAccessors$4 );
ContentView.prototype.breakAfter = 0;
// Remove a DOM node and return its next sibling.
function rm$1(dom) {
    var next = dom.nextSibling;
    dom.parentNode.removeChild(dom);
    return next;
}
var ChildCursor = function ChildCursor(children, pos, i) {
    this.children = children;
    this.pos = pos;
    this.i = i;
    this.off = 0;
};
ChildCursor.prototype.findPos = function findPos (pos, bias) {
        if ( bias === void 0 ) bias = 1;

    for (;;) {
        if (pos > this.pos || pos == this.pos &&
            (bias > 0 || this.i == 0 || this.children[this.i - 1].breakAfter)) {
            this.off = pos - this.pos;
            return this;
        }
        var next = this.children[--this.i];
        this.pos -= next.length + next.breakAfter;
    }
};
function replaceRange(parent, fromI, fromOff, toI, toOff, insert, breakAtStart, openStart, openEnd) {
    var children = parent.children;
    var before = children.length ? children[fromI] : null;
    var last = insert.length ? insert[insert.length - 1] : null;
    var breakAtEnd = last ? last.breakAfter : breakAtStart;
    // Change within a single child
    if (fromI == toI && before && !breakAtStart && !breakAtEnd && insert.length < 2 &&
        before.merge(fromOff, toOff, insert.length ? last : null, fromOff == 0, openStart, openEnd))
        { return; }
    if (toI < children.length) {
        var after = children[toI];
        // Make sure the end of the child after the update is preserved in `after`
        if (after && (toOff < after.length || after.breakAfter && (last === null || last === void 0 ? void 0 : last.breakAfter))) {
            // If we're splitting a child, separate part of it to avoid that
            // being mangled when updating the child before the update.
            if (fromI == toI) {
                after = after.split(toOff);
                toOff = 0;
            }
            // If the element after the replacement should be merged with
            // the last replacing element, update `content`
            if (!breakAtEnd && last && after.merge(0, toOff, last, true, 0, openEnd)) {
                insert[insert.length - 1] = after;
            }
            else {
                // Remove the start of the after element, if necessary, and
                // add it to `content`.
                if (toOff || after.children.length && !after.children[0].length)
                    { after.merge(0, toOff, null, false, 0, openEnd); }
                insert.push(after);
            }
        }
        else if (after === null || after === void 0 ? void 0 : after.breakAfter) {
            // The element at `toI` is entirely covered by this range.
            // Preserve its line break, if any.
            if (last)
                { last.breakAfter = 1; }
            else
                { breakAtStart = 1; }
        }
        // Since we've handled the next element from the current elements
        // now, make sure `toI` points after that.
        toI++;
    }
    if (before) {
        before.breakAfter = breakAtStart;
        if (fromOff > 0) {
            if (!breakAtStart && insert.length && before.merge(fromOff, before.length, insert[0], false, openStart, 0)) {
                before.breakAfter = insert.shift().breakAfter;
            }
            else if (fromOff < before.length || before.children.length && before.children[before.children.length - 1].length == 0) {
                before.merge(fromOff, before.length, null, false, openStart, 0);
            }
            fromI++;
        }
    }
    // Try to merge widgets on the boundaries of the replacement
    while (fromI < toI && insert.length) {
        if (children[toI - 1].become(insert[insert.length - 1])) {
            toI--;
            insert.pop();
            openEnd = insert.length ? 0 : openStart;
        }
        else if (children[fromI].become(insert[0])) {
            fromI++;
            insert.shift();
            openStart = insert.length ? 0 : openEnd;
        }
        else {
            break;
        }
    }
    if (!insert.length && fromI && toI < children.length && !children[fromI - 1].breakAfter &&
        children[toI].merge(0, 0, children[fromI - 1], false, openStart, openEnd))
        { fromI--; }
    if (fromI < toI || insert.length)
        { parent.replaceChildren(fromI, toI, insert); }
}
function mergeChildrenInto(parent, from, to, insert, openStart, openEnd) {
    var cur = parent.childCursor();
    var ref = cur.findPos(to, 1);
    var toI = ref.i;
    var toOff = ref.off;
    var ref$1 = cur.findPos(from, -1);
    var fromI = ref$1.i;
    var fromOff = ref$1.off;
    var dLen = from - to;
    for (var view of insert)
        dLen += view.length;
    parent.length += dLen;
    replaceRange(parent, fromI, fromOff, toI, toOff, insert, 0, openStart, openEnd);
}

var nav = typeof navigator != "undefined" ? navigator : { userAgent: "", vendor: "", platform: "" };
var doc = typeof document != "undefined" ? document : { documentElement: { style: {} } };
var ie_edge = /*@__PURE__*//Edge\/(\d+)/.exec(nav.userAgent);
var ie_upto10 = /*@__PURE__*//MSIE \d/.test(nav.userAgent);
var ie_11up = /*@__PURE__*//Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(nav.userAgent);
var ie = !!(ie_upto10 || ie_11up || ie_edge);
var gecko = !ie && /*@__PURE__*//gecko\/(\d+)/i.test(nav.userAgent);
var chrome = !ie && /*@__PURE__*//Chrome\/(\d+)/.exec(nav.userAgent);
var webkit = "webkitFontSmoothing" in doc.documentElement.style;
var safari = !ie && /*@__PURE__*//Apple Computer/.test(nav.vendor);
var ios = safari && (/*@__PURE__*//Mobile\/\w+/.test(nav.userAgent) || nav.maxTouchPoints > 2);
var browser = {
    mac: ios || /*@__PURE__*//Mac/.test(nav.platform),
    windows: /*@__PURE__*//Win/.test(nav.platform),
    linux: /*@__PURE__*//Linux|X11/.test(nav.platform),
    ie: ie,
    ie_version: ie_upto10 ? doc.documentMode || 6 : ie_11up ? +ie_11up[1] : ie_edge ? +ie_edge[1] : 0,
    gecko: gecko,
    gecko_version: gecko ? +(/*@__PURE__*//Firefox\/(\d+)/.exec(nav.userAgent) || [0, 0])[1] : 0,
    chrome: !!chrome,
    chrome_version: chrome ? +chrome[1] : 0,
    ios: ios,
    android: /*@__PURE__*//Android\b/.test(nav.userAgent),
    webkit: webkit,
    safari: safari,
    webkit_version: webkit ? +(/*@__PURE__*//\bAppleWebKit\/(\d+)/.exec(nav.userAgent) || [0, 0])[1] : 0,
    tabSize: doc.documentElement.style.tabSize != null ? "tab-size" : "-moz-tab-size"
};

var MaxJoinLen = 256;
var TextView = /*@__PURE__*/(function (ContentView) {
    function TextView(text) {
        ContentView.call(this);
        this.text = text;
    }

    if ( ContentView ) TextView.__proto__ = ContentView;
    TextView.prototype = Object.create( ContentView && ContentView.prototype );
    TextView.prototype.constructor = TextView;

    var prototypeAccessors$1 = { length: { configurable: true } };
    prototypeAccessors$1.length.get = function () { return this.text.length; };
    TextView.prototype.createDOM = function createDOM (textDOM) {
        this.setDOM(textDOM || document.createTextNode(this.text));
    };
    TextView.prototype.sync = function sync (view, track) {
        if (!this.dom)
            { this.createDOM(); }
        if (this.dom.nodeValue != this.text) {
            if (track && track.node == this.dom)
                { track.written = true; }
            this.dom.nodeValue = this.text;
        }
    };
    TextView.prototype.reuseDOM = function reuseDOM (dom) {
        if (dom.nodeType == 3)
            { this.createDOM(dom); }
    };
    TextView.prototype.merge = function merge (from, to, source) {
        if ((this.flags & 8 /* ViewFlag.Composition */) ||
            source && (!(source instanceof TextView) ||
                this.length - (to - from) + source.length > MaxJoinLen ||
                (source.flags & 8 /* ViewFlag.Composition */)))
            { return false; }
        this.text = this.text.slice(0, from) + (source ? source.text : "") + this.text.slice(to);
        this.markDirty();
        return true;
    };
    TextView.prototype.split = function split (from) {
        var result = new TextView(this.text.slice(from));
        this.text = this.text.slice(0, from);
        this.markDirty();
        result.flags |= this.flags & 8 /* ViewFlag.Composition */;
        return result;
    };
    TextView.prototype.localPosFromDOM = function localPosFromDOM (node, offset) {
        return node == this.dom ? offset : offset ? this.text.length : 0;
    };
    TextView.prototype.domAtPos = function domAtPos (pos) { return new DOMPos(this.dom, pos); };
    TextView.prototype.domBoundsAround = function domBoundsAround (_from, _to, offset) {
        return { from: offset, to: offset + this.length, startDOM: this.dom, endDOM: this.dom.nextSibling };
    };
    TextView.prototype.coordsAt = function coordsAt (pos, side) {
        return textCoords(this.dom, pos, side);
    };

    Object.defineProperties( TextView.prototype, prototypeAccessors$1 );

    return TextView;
}(ContentView));
var MarkView = /*@__PURE__*/(function (ContentView) {
    function MarkView(mark, children, length) {
        if ( children === void 0 ) children = [];
        if ( length === void 0 ) length = 0;

        ContentView.call(this);
        this.mark = mark;
        this.children = children;
        this.length = length;
        for (var ch of children)
            ch.setParent(this);
    }

    if ( ContentView ) MarkView.__proto__ = ContentView;
    MarkView.prototype = Object.create( ContentView && ContentView.prototype );
    MarkView.prototype.constructor = MarkView;
    MarkView.prototype.setAttrs = function setAttrs (dom) {
        clearAttributes(dom);
        if (this.mark.class)
            { dom.className = this.mark.class; }
        if (this.mark.attrs)
            { for (var name in this.mark.attrs)
                { dom.setAttribute(name, this.mark.attrs[name]); } }
        return dom;
    };
    MarkView.prototype.canReuseDOM = function canReuseDOM (other) {
        return ContentView.prototype.canReuseDOM.call(this, other) && !((this.flags | other.flags) & 8 /* ViewFlag.Composition */);
    };
    MarkView.prototype.reuseDOM = function reuseDOM (node) {
        if (node.nodeName == this.mark.tagName.toUpperCase()) {
            this.setDOM(node);
            this.flags |= 4 /* ViewFlag.AttrsDirty */ | 2 /* ViewFlag.NodeDirty */;
        }
    };
    MarkView.prototype.sync = function sync (view, track) {
        if (!this.dom)
            { this.setDOM(this.setAttrs(document.createElement(this.mark.tagName))); }
        else if (this.flags & 4 /* ViewFlag.AttrsDirty */)
            { this.setAttrs(this.dom); }
        ContentView.prototype.sync.call(this, view, track);
    };
    MarkView.prototype.merge = function merge (from, to, source, _hasStart, openStart, openEnd) {
        if (source && (!(source instanceof MarkView && source.mark.eq(this.mark)) ||
            (from && openStart <= 0) || (to < this.length && openEnd <= 0)))
            { return false; }
        mergeChildrenInto(this, from, to, source ? source.children.slice() : [], openStart - 1, openEnd - 1);
        this.markDirty();
        return true;
    };
    MarkView.prototype.split = function split (from) {
        var result = [], off = 0, detachFrom = -1, i = 0;
        for (var elt of this.children) {
            var end = off + elt.length;
            if (end > from)
                { result.push(off < from ? elt.split(from - off) : elt); }
            if (detachFrom < 0 && off >= from)
                { detachFrom = i; }
            off = end;
            i++;
        }
        var length = this.length - from;
        this.length = from;
        if (detachFrom > -1) {
            this.children.length = detachFrom;
            this.markDirty();
        }
        return new MarkView(this.mark, result, length);
    };
    MarkView.prototype.domAtPos = function domAtPos (pos) {
        return inlineDOMAtPos(this, pos);
    };
    MarkView.prototype.coordsAt = function coordsAt (pos, side) {
        return coordsInChildren(this, pos, side);
    };

    return MarkView;
}(ContentView));
function textCoords(text, pos, side) {
    var length = text.nodeValue.length;
    if (pos > length)
        { pos = length; }
    var 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++; }
    }
    var rects = textRange(text, from, to).getClientRects();
    if (!rects.length)
        { return null; }
    var rect = rects[(flatten ? flatten < 0 : side >= 0) ? 0 : rects.length - 1];
    if (browser.safari && !flatten && rect.width == 0)
        { rect = Array.prototype.find.call(rects, function (r) { return r.width; }) || rect; }
    return flatten ? flattenRect(rect, flatten < 0) : rect || null;
}
// Also used for collapsed ranges that don't have a placeholder widget!
var WidgetView = /*@__PURE__*/(function (ContentView) {
    function WidgetView(widget, length, side) {
        ContentView.call(this);
        this.widget = widget;
        this.length = length;
        this.side = side;
        this.prevWidget = null;
    }

    if ( ContentView ) WidgetView.__proto__ = ContentView;
    WidgetView.prototype = Object.create( ContentView && ContentView.prototype );
    WidgetView.prototype.constructor = WidgetView;

    var prototypeAccessors$2 = { overrideDOMText: { configurable: true },isEditable: { configurable: true },isWidget: { configurable: true },isHidden: { configurable: true } };
    WidgetView.create = function create (widget, length, side) {
        return new WidgetView(widget, length, side);
    };

    WidgetView.prototype.split = function split (from) {
        var result = WidgetView.create(this.widget, this.length - from, this.side);
        this.length -= from;
        return result;
    };
    WidgetView.prototype.sync = function sync (view) {
        if (!this.dom || !this.widget.updateDOM(this.dom, view)) {
            if (this.dom && this.prevWidget)
                { this.prevWidget.destroy(this.dom); }
            this.prevWidget = null;
            this.setDOM(this.widget.toDOM(view));
            if (!this.widget.editable)
                { this.dom.contentEditable = "false"; }
        }
    };
    WidgetView.prototype.getSide = function getSide () { return this.side; };
    WidgetView.prototype.merge = function merge (from, to, source, hasStart, openStart, openEnd) {
        if (source && (!(source instanceof WidgetView) || !this.widget.compare(source.widget) ||
            from > 0 && openStart <= 0 || to < this.length && openEnd <= 0))
            { return false; }
        this.length = from + (source ? source.length : 0) + (this.length - to);
        return true;
    };
    WidgetView.prototype.become = function become (other) {
        if (other instanceof WidgetView && other.side == this.side &&
            this.widget.constructor == other.widget.constructor) {
            if (!this.widget.compare(other.widget))
                { this.markDirty(true); }
            if (this.dom && !this.prevWidget)
                { this.prevWidget = this.widget; }
            this.widget = other.widget;
            this.length = other.length;
            return true;
        }
        return false;
    };
    WidgetView.prototype.ignoreMutation = function ignoreMutation () { return true; };
    WidgetView.prototype.ignoreEvent = function ignoreEvent (event) { return this.widget.ignoreEvent(event); };
    prototypeAccessors$2.overrideDOMText.get = function () {
        if (this.length == 0)
            { return Text.empty; }
        var top = this;
        while (top.parent)
            { top = top.parent; }
        var view = top.view;
        var text = view && view.state.doc, start = this.posAtStart;
        return text ? text.slice(start, start + this.length) : Text.empty;
    };
    WidgetView.prototype.domAtPos = function domAtPos (pos) {
        return (this.length ? pos == 0 : this.side > 0)
            ? DOMPos.before(this.dom)
            : DOMPos.after(this.dom, pos == this.length);
    };
    WidgetView.prototype.domBoundsAround = function domBoundsAround () { return null; };
    WidgetView.prototype.coordsAt = function coordsAt (pos, side) {
        var custom = this.widget.coordsAt(this.dom, pos, side);
        if (custom)
            { return custom; }
        var rects = this.dom.getClientRects(), rect = null;
        if (!rects.length)
            { return null; }
        var fromBack = this.side ? this.side < 0 : pos > 0;
        for (var 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);
    };
    prototypeAccessors$2.isEditable.get = function () { return false; };
    prototypeAccessors$2.isWidget.get = function () { return true; };
    prototypeAccessors$2.isHidden.get = function () { return this.widget.isHidden; };
    WidgetView.prototype.destroy = function destroy () {
        ContentView.prototype.destroy.call(this);
        if (this.dom)
            { this.widget.destroy(this.dom); }
    };

    Object.defineProperties( WidgetView.prototype, prototypeAccessors$2 );

    return WidgetView;
}(ContentView));
// 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.
var WidgetBufferView = /*@__PURE__*/(function (ContentView) {
    function WidgetBufferView(side) {
        ContentView.call(this);
        this.side = side;
    }

    if ( ContentView ) WidgetBufferView.__proto__ = ContentView;
    WidgetBufferView.prototype = Object.create( ContentView && ContentView.prototype );
    WidgetBufferView.prototype.constructor = WidgetBufferView;

    var prototypeAccessors$3 = { length: { configurable: true },overrideDOMText: { configurable: true },isHidden: { configurable: true } };
    prototypeAccessors$3.length.get = function () { return 0; };
    WidgetBufferView.prototype.merge = function merge () { return false; };
    WidgetBufferView.prototype.become = function become (other) {
        return other instanceof WidgetBufferView && other.side == this.side;
    };
    WidgetBufferView.prototype.split = function split () { return new WidgetBufferView(this.side); };
    WidgetBufferView.prototype.sync = function sync () {
        if (!this.dom) {
            var dom = document.createElement("img");
            dom.className = "cm-widgetBuffer";
            dom.setAttribute("aria-hidden", "true");
            this.setDOM(dom);
        }
    };
    WidgetBufferView.prototype.getSide = function getSide () { return this.side; };
    WidgetBufferView.prototype.domAtPos = function domAtPos (pos) { return this.side > 0 ? DOMPos.before(this.dom) : DOMPos.after(this.dom); };
    WidgetBufferView.prototype.localPosFromDOM = function localPosFromDOM () { return 0; };
    WidgetBufferView.prototype.domBoundsAround = function domBoundsAround () { return null; };
    WidgetBufferView.prototype.coordsAt = function coordsAt (pos) {
        return this.dom.getBoundingClientRect();
    };
    prototypeAccessors$3.overrideDOMText.get = function () {
        return Text.empty;
    };
    prototypeAccessors$3.isHidden.get = function () { return true; };

    Object.defineProperties( WidgetBufferView.prototype, prototypeAccessors$3 );

    return WidgetBufferView;
}(ContentView));
TextView.prototype.children = WidgetView.prototype.children = WidgetBufferView.prototype.children = noChildren;
function inlineDOMAtPos(parent, pos) {
    var dom = parent.dom;
    var children = parent.children;
    var i = 0;
    for (var off = 0; i < children.length; i++) {
        var child = children[i], end = off + child.length;
        if (end == off && child.getSide() <= 0)
            { continue; }
        if (pos > off && pos < end && child.dom.parentNode == dom)
            { return child.domAtPos(pos - off); }
        if (pos <= off)
            { break; }
        off = end;
    }
    for (var j = i; j > 0; j--) {
        var prev = children[j - 1];
        if (prev.dom.parentNode == dom)
            { return prev.domAtPos(prev.length); }
    }
    for (var j$1 = i; j$1 < children.length; j$1++) {
        var next = children[j$1];
        if (next.dom.parentNode == dom)
            { return next.domAtPos(0); }
    }
    return new DOMPos(dom, 0);
}
// Assumes `view`, if a mark view, has precisely 1 child.
function joinInlineInto(parent, view, open) {
    var last;
    var children = parent.children;
    if (open > 0 && view instanceof MarkView && children.length &&
        (last = children[children.length - 1]) instanceof MarkView && last.mark.eq(view.mark)) {
        joinInlineInto(last, view.children[0], open - 1);
    }
    else {
        children.push(view);
        view.setParent(parent);
    }
    parent.length += view.length;
}
function coordsInChildren(view, pos, side) {
    var before = null, beforePos = -1, after = null, afterPos = -1;
    function scan(view, pos) {
        for (var i = 0, off = 0; i < view.children.length && off <= pos; i++) {
            var child = view.children[i], end = off + child.length;
            if (end >= pos) {
                if (child.children.length) {
                    scan(child, pos - off);
                }
                else if ((!after || after.isHidden && side > 0) &&
                    (end > pos || off == end && child.getSide() > 0)) {
                    after = child;
                    afterPos = pos - off;
                }
                else if (off < pos || (off == end && child.getSide() < 0) && !child.isHidden) {
                    before = child;
                    beforePos = pos - off;
                }
            }
            off = end;
        }
    }
    scan(view, pos);
    var target = (side < 0 ? before : after) || before || after;
    if (target)
        { return target.coordsAt(Math.max(0, target == before ? beforePos : afterPos), side); }
    return fallbackRect(view);
}
function fallbackRect(view) {
    var last = view.dom.lastChild;
    if (!last)
        { return view.dom.getBoundingClientRect(); }
    var rects = clientRectsFor(last);
    return rects[rects.length - 1] || null;
}

function combineAttrs(source, target) {
    for (var 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;
}
var noAttrs$1 = /*@__PURE__*/Object.create(null);
function attrsEq(a, b, ignore) {
    if (a == b)
        { return true; }
    if (!a)
        { a = noAttrs$1; }
    if (!b)
        { b = noAttrs$1; }
    var keysA = Object.keys(a), keysB = Object.keys(b);
    if (keysA.length - (ignore && keysA.indexOf(ignore) > -1 ? 1 : 0) !=
        keysB.length - (ignore && keysB.indexOf(ignore) > -1 ? 1 : 0))
        { return false; }
    for (var key of keysA) {
        if (key != ignore && (keysB.indexOf(key) == -1 || a[key] !== b[key]))
            { return false; }
    }
    return true;
}
function updateAttrs(dom, prev, attrs) {
    var changed = false;
    if (prev)
        { for (var name in prev)
            { if (!(attrs && name in attrs)) {
                changed = true;
                if (name == "style")
                    { dom.style.cssText = ""; }
                else
                    { dom.removeAttribute(name); }
            } } }
    if (attrs)
        { for (var name$1 in attrs)
            { if (!(prev && prev[name$1] == attrs[name$1])) {
                changed = true;
                if (name$1 == "style")
                    { dom.style.cssText = attrs[name$1]; }
                else
                    { dom.setAttribute(name$1, attrs[name$1]); }
            } } }
    return changed;
}
function getAttrs(dom) {
    var attrs = Object.create(null);
    for (var i = 0; i < dom.attributes.length; i++) {
        var 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.
*/
var WidgetType = function WidgetType () {};

var prototypeAccessors$4$1 = { estimatedHeight: { configurable: true },lineBreaks: { configurable: true },isHidden: { configurable: true },editable: { configurable: true } };

WidgetType.prototype.eq = function 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.
*/
WidgetType.prototype.updateDOM = function updateDOM (dom, view) { return false; };
/**
@internal
*/
WidgetType.prototype.compare = function 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.
*/
prototypeAccessors$4$1.estimatedHeight.get = function () { 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.
*/
prototypeAccessors$4$1.lineBreaks.get = function () { 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.
*/
WidgetType.prototype.ignoreEvent = function 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.
*/
WidgetType.prototype.coordsAt = function coordsAt (dom, pos, side) { return null; };
/**
@internal
*/
prototypeAccessors$4$1.isHidden.get = function () { return false; };
/**
@internal
*/
prototypeAccessors$4$1.editable.get = function () { return false; };
/**
This is called when the an instance of the widget is removed
from the editor view.
*/
WidgetType.prototype.destroy = function destroy (dom) { };

Object.defineProperties( WidgetType.prototype, prototypeAccessors$4$1 );
/**
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
*/
var Decoration = /*@__PURE__*/(function (RangeValue) {
    function Decoration(
    /**
    @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) {
        RangeValue.call(this);
        this.startSide = startSide;
        this.endSide = endSide;
        this.widget = widget;
        this.spec = spec;
    }

    if ( RangeValue ) Decoration.__proto__ = RangeValue;
    Decoration.prototype = Object.create( RangeValue && RangeValue.prototype );
    Decoration.prototype.constructor = Decoration;

    var prototypeAccessors$5 = { heightRelevant: { configurable: true } };
    /**
    @internal
    */
    prototypeAccessors$5.heightRelevant.get = function () { 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.
    */
    Decoration.mark = function mark (spec) {
        return new MarkDecoration(spec);
    };
    /**
    Create a widget decoration, which displays a DOM element at the
    given position.
    */
    Decoration.widget = function widget (spec) {
        var side = Math.max(-10000, Math.min(10000, spec.side || 0)), block = !!spec.block;
        side += (block && !spec.inlineOrder)
            ? (side > 0 ? 300000000 /* Side.BlockAfter */ : -400000000 /* Side.BlockBefore */)
            : (side > 0 ? 100000000 /* Side.InlineAfter */ : -100000000 /* 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.
    */
    Decoration.replace = function replace (spec) {
        var block = !!spec.block, startSide, endSide;
        if (spec.isBlockGap) {
            startSide = -500000000 /* Side.GapStart */;
            endSide = 400000000 /* Side.GapEnd */;
        }
        else {
            var ref = getInclusive(spec, block);
            var start = ref.start;
            var end = ref.end;
            startSide = (start ? (block ? -300000000 /* Side.BlockIncStart */ : -1 /* Side.InlineIncStart */) : 500000000 /* Side.NonIncStart */) - 1;
            endSide = (end ? (block ? 200000000 /* Side.BlockIncEnd */ : 1 /* Side.InlineIncEnd */) : -600000000 /* 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.
    */
    Decoration.line = function 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.
    */
    Decoration.set = function set (of, sort) {
        if ( sort === void 0 ) sort = false;

        return RangeSet.of(of, sort);
    };
    /**
    @internal
    */
    Decoration.prototype.hasHeight = function hasHeight () { return this.widget ? this.widget.estimatedHeight > -1 : false; };

    Object.defineProperties( Decoration.prototype, prototypeAccessors$5 );

    return Decoration;
}(RangeValue));
/**
The empty set of decorations.
*/
Decoration.none = RangeSet.empty;
var MarkDecoration = /*@__PURE__*/(function (Decoration) {
    function MarkDecoration(spec) {
        var ref = getInclusive(spec);
        var start = ref.start;
        var end = ref.end;
        Decoration.call(this, start ? -1 /* Side.InlineIncStart */ : 500000000 /* Side.NonIncStart */, end ? 1 /* Side.InlineIncEnd */ : -600000000 /* Side.NonIncEnd */, null, spec);
        this.tagName = spec.tagName || "span";
        this.class = spec.class || "";
        this.attrs = spec.attributes || null;
    }

    if ( Decoration ) MarkDecoration.__proto__ = Decoration;
    MarkDecoration.prototype = Object.create( Decoration && Decoration.prototype );
    MarkDecoration.prototype.constructor = MarkDecoration;
    MarkDecoration.prototype.eq = function eq (other) {
        var _a, _b;
        return this == other ||
            other instanceof MarkDecoration &&
                this.tagName == other.tagName &&
                (this.class || ((_a = this.attrs) === null || _a === void 0 ? void 0 : _a.class)) == (other.class || ((_b = other.attrs) === null || _b === void 0 ? void 0 : _b.class)) &&
                attrsEq(this.attrs, other.attrs, "class");
    };
    MarkDecoration.prototype.range = function range (from, to) {
        if ( to === void 0 ) to = from;

        if (from >= to)
            { throw new RangeError("Mark decorations may not be empty"); }
        return Decoration.prototype.range.call(this, from, to);
    };

    return MarkDecoration;
}(Decoration));
MarkDecoration.prototype.point = false;
var LineDecoration = /*@__PURE__*/(function (Decoration) {
    function LineDecoration(spec) {
        Decoration.call(this, -200000000 /* Side.Line */, -200000000 /* Side.Line */, null, spec);
    }

    if ( Decoration ) LineDecoration.__proto__ = Decoration;
    LineDecoration.prototype = Object.create( Decoration && Decoration.prototype );
    LineDecoration.prototype.constructor = LineDecoration;
    LineDecoration.prototype.eq = function eq (other) {
        return other instanceof LineDecoration &&
            this.spec.class == other.spec.class &&
            attrsEq(this.spec.attributes, other.spec.attributes);
    };
    LineDecoration.prototype.range = function range (from, to) {
        if ( to === void 0 ) to = from;

        if (to != from)
            { throw new RangeError("Line decoration ranges must be zero-length"); }
        return Decoration.prototype.range.call(this, from, to);
    };

    return LineDecoration;
}(Decoration));
LineDecoration.prototype.mapMode = MapMode.TrackBefore;
LineDecoration.prototype.point = true;
var PointDecoration = /*@__PURE__*/(function (Decoration) {
    function PointDecoration(spec, startSide, endSide, block, widget, isReplace) {
        Decoration.call(this, startSide, endSide, widget, spec);
        this.block = block;
        this.isReplace = isReplace;
        this.mapMode = !block ? MapMode.TrackDel : startSide <= 0 ? MapMode.TrackBefore : MapMode.TrackAfter;
    }

    if ( Decoration ) PointDecoration.__proto__ = Decoration;
    PointDecoration.prototype = Object.create( Decoration && Decoration.prototype );
    PointDecoration.prototype.constructor = PointDecoration;

    var prototypeAccessors$6 = { type: { configurable: true },heightRelevant: { configurable: true } };
    // Only relevant when this.block == true
    prototypeAccessors$6.type.get = function () {
        return this.startSide != this.endSide ? BlockType.WidgetRange
            : this.startSide <= 0 ? BlockType.WidgetBefore : BlockType.WidgetAfter;
    };
    prototypeAccessors$6.heightRelevant.get = function () {
        return this.block || !!this.widget && (this.widget.estimatedHeight >= 5 || this.widget.lineBreaks > 0);
    };
    PointDecoration.prototype.eq = function eq (other) {
        return other instanceof PointDecoration &&
            widgetsEq(this.widget, other.widget) &&
            this.block == other.block &&
            this.startSide == other.startSide && this.endSide == other.endSide;
    };
    PointDecoration.prototype.range = function range (from, to) {
        if ( to === void 0 ) 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 Decoration.prototype.range.call(this, from, to);
    };

    Object.defineProperties( PointDecoration.prototype, prototypeAccessors$6 );

    return PointDecoration;
}(Decoration));
PointDecoration.prototype.point = true;
function getInclusive(spec, block) {
    if ( block === void 0 ) block = false;

    var start = spec.inclusiveStart;
    var end = spec.inclusiveEnd;
    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) {
    if ( margin === void 0 ) margin = 0;

    var last = ranges.length - 1;
    if (last >= 0 && ranges[last] + margin >= from)
        { ranges[last] = Math.max(ranges[last], to); }
    else
        { ranges.push(from, to); }
}

var LineView = /*@__PURE__*/(function (ContentView) {
    function LineView() {
        ContentView.apply(this, arguments);
        this.children = [];
        this.length = 0;
        this.prevAttrs = undefined;
        this.attrs = null;
        this.breakAfter = 0;
    }

    if ( ContentView ) LineView.__proto__ = ContentView;
    LineView.prototype = Object.create( ContentView && ContentView.prototype );
    LineView.prototype.constructor = LineView;
    // Consumes source
    LineView.prototype.merge = function merge (from, to, source, hasStart, openStart, openEnd) {
        if (source) {
            if (!(source instanceof LineView))
                { return false; }
            if (!this.dom)
                { source.transferDOM(this); } // Reuse source.dom when appropriate
        }
        if (hasStart)
            { this.setDeco(source ? source.attrs : null); }
        mergeChildrenInto(this, from, to, source ? source.children.slice() : [], openStart, openEnd);
        return true;
    };
    LineView.prototype.split = function split (at) {
        var end = new LineView;
        end.breakAfter = this.breakAfter;
        if (this.length == 0)
            { return end; }
        var ref = this.childPos(at);
        var i = ref.i;
        var off = ref.off;
        if (off) {
            end.append(this.children[i].split(off), 0);
            this.children[i].merge(off, this.children[i].length, null, false, 0, 0);
            i++;
        }
        for (var j = i; j < this.children.length; j++)
            { end.append(this.children[j], 0); }
        while (i > 0 && this.children[i - 1].length == 0)
            { this.children[--i].destroy(); }
        this.children.length = i;
        this.markDirty();
        this.length = at;
        return end;
    };
    LineView.prototype.transferDOM = function transferDOM (other) {
        if (!this.dom)
            { return; }
        this.markDirty();
        other.setDOM(this.dom);
        other.prevAttrs = this.prevAttrs === undefined ? this.attrs : this.prevAttrs;
        this.prevAttrs = undefined;
        this.dom = null;
    };
    LineView.prototype.setDeco = function setDeco (attrs) {
        if (!attrsEq(this.attrs, attrs)) {
            if (this.dom) {
                this.prevAttrs = this.attrs;
                this.markDirty();
            }
            this.attrs = attrs;
        }
    };
    LineView.prototype.append = function append (child, openStart) {
        joinInlineInto(this, child, openStart);
    };
    // Only called when building a line view in ContentBuilder
    LineView.prototype.addLineDeco = function addLineDeco (deco) {
        var attrs = deco.spec.attributes, cls = deco.spec.class;
        if (attrs)
            { this.attrs = combineAttrs(attrs, this.attrs || {}); }
        if (cls)
            { this.attrs = combineAttrs({ class: cls }, this.attrs || {}); }
    };
    LineView.prototype.domAtPos = function domAtPos (pos) {
        return inlineDOMAtPos(this, pos);
    };
    LineView.prototype.reuseDOM = function reuseDOM (node) {
        if (node.nodeName == "DIV") {
            this.setDOM(node);
            this.flags |= 4 /* ViewFlag.AttrsDirty */ | 2 /* ViewFlag.NodeDirty */;
        }
    };
    LineView.prototype.sync = function sync (view, track) {
        var _a;
        if (!this.dom) {
            this.setDOM(document.createElement("div"));
            this.dom.className = "cm-line";
            this.prevAttrs = this.attrs ? null : undefined;
        }
        else if (this.flags & 4 /* ViewFlag.AttrsDirty */) {
            clearAttributes(this.dom);
            this.dom.className = "cm-line";
            this.prevAttrs = this.attrs ? null : undefined;
        }
        if (this.prevAttrs !== undefined) {
            updateAttrs(this.dom, this.prevAttrs, this.attrs);
            this.dom.classList.add("cm-line");
            this.prevAttrs = undefined;
        }
        ContentView.prototype.sync.call(this, view, track);
        var last = this.dom.lastChild;
        while (last && ContentView.get(last) instanceof MarkView)
            { last = last.lastChild; }
        if (!last || !this.length ||
            last.nodeName != "BR" && ((_a = ContentView.get(last)) === null || _a === void 0 ? void 0 : _a.isEditable) == false &&
                (!browser.ios || !this.children.some(function (ch) { return ch instanceof TextView; }))) {
            var hack = document.createElement("BR");
            hack.cmIgnore = true;
            this.dom.appendChild(hack);
        }
    };
    LineView.prototype.measureTextSize = function measureTextSize () {
        if (this.children.length == 0 || this.length > 20)
            { return null; }
        var totalWidth = 0, textHeight;
        for (var child of this.children) {
            if (!(child instanceof TextView) || /[^ -~]/.test(child.text))
                { return null; }
            var rects = clientRectsFor(child.dom);
            if (rects.length != 1)
                { return null; }
            totalWidth += rects[0].width;
            textHeight = rects[0].height;
        }
        return !totalWidth ? null : {
            lineHeight: this.dom.getBoundingClientRect().height,
            charWidth: totalWidth / this.length,
            textHeight: textHeight
        };
    };
    LineView.prototype.coordsAt = function coordsAt (pos, side) {
        var rect = coordsInChildren(this, pos, side);
        // Correct rectangle height for empty lines when the returned
        // height is larger than the text height.
        if (!this.children.length && rect && this.parent) {
            var ref = this.parent.view.viewState;
            var heightOracle = ref.heightOracle;
            var height = rect.bottom - rect.top;
            if (Math.abs(height - heightOracle.lineHeight) < 2 && heightOracle.textHeight < height) {
                var dist = (height - heightOracle.textHeight) / 2;
                return { top: rect.top + dist, bottom: rect.bottom - dist, left: rect.left, right: rect.left };
            }
        }
        return rect;
    };
    LineView.prototype.become = function become (other) {
        return other instanceof LineView && this.children.length == 0 && other.children.length == 0 &&
            attrsEq(this.attrs, other.attrs) && this.breakAfter == other.breakAfter;
    };
    LineView.prototype.covers = function covers () { return true; };
    LineView.find = function find (docView, pos) {
        for (var i = 0, off = 0; i < docView.children.length; i++) {
            var block = docView.children[i], end = off + block.length;
            if (end >= pos) {
                if (block instanceof LineView)
                    { return block; }
                if (end > pos)
                    { break; }
            }
            off = end + block.breakAfter;
        }
        return null;
    };

    return LineView;
}(ContentView));
var BlockWidgetView = /*@__PURE__*/(function (ContentView) {
    function BlockWidgetView(widget, length, deco) {
        ContentView.call(this);
        this.widget = widget;
        this.length = length;
        this.deco = deco;
        this.breakAfter = 0;
        this.prevWidget = null;
    }

    if ( ContentView ) BlockWidgetView.__proto__ = ContentView;
    BlockWidgetView.prototype = Object.create( ContentView && ContentView.prototype );
    BlockWidgetView.prototype.constructor = BlockWidgetView;

    var prototypeAccessors$7 = { children: { configurable: true },overrideDOMText: { configurable: true },isEditable: { configurable: true },isWidget: { configurable: true } };
    BlockWidgetView.prototype.merge = function merge (from, to, source, _takeDeco, openStart, openEnd) {
        if (source && (!(source instanceof BlockWidgetView) || !this.widget.compare(source.widget) ||
            from > 0 && openStart <= 0 || to < this.length && openEnd <= 0))
            { return false; }
        this.length = from + (source ? source.length : 0) + (this.length - to);
        return true;
    };
    BlockWidgetView.prototype.domAtPos = function domAtPos (pos) {
        return pos == 0 ? DOMPos.before(this.dom) : DOMPos.after(this.dom, pos == this.length);
    };
    BlockWidgetView.prototype.split = function split (at) {
        var len = this.length - at;
        this.length = at;
        var end = new BlockWidgetView(this.widget, len, this.deco);
        end.breakAfter = this.breakAfter;
        return end;
    };
    prototypeAccessors$7.children.get = function () { return noChildren; };
    BlockWidgetView.prototype.sync = function sync (view) {
        if (!this.dom || !this.widget.updateDOM(this.dom, view)) {
            if (this.dom && this.prevWidget)
                { this.prevWidget.destroy(this.dom); }
            this.prevWidget = null;
            this.setDOM(this.widget.toDOM(view));
            if (!this.widget.editable)
                { this.dom.contentEditable = "false"; }
        }
    };
    prototypeAccessors$7.overrideDOMText.get = function () {
        return this.parent ? this.parent.view.state.doc.slice(this.posAtStart, this.posAtEnd) : Text.empty;
    };
    BlockWidgetView.prototype.domBoundsAround = function domBoundsAround () { return null; };
    BlockWidgetView.prototype.become = function become (other) {
        if (other instanceof BlockWidgetView &&
            other.widget.constructor == this.widget.constructor) {
            if (!other.widget.compare(this.widget))
                { this.markDirty(true); }
            if (this.dom && !this.prevWidget)
                { this.prevWidget = this.widget; }
            this.widget = other.widget;
            this.length = other.length;
            this.deco = other.deco;
            this.breakAfter = other.breakAfter;
            return true;
        }
        return false;
    };
    BlockWidgetView.prototype.ignoreMutation = function ignoreMutation () { return true; };
    BlockWidgetView.prototype.ignoreEvent = function ignoreEvent (event) { return this.widget.ignoreEvent(event); };
    prototypeAccessors$7.isEditable.get = function () { return false; };
    prototypeAccessors$7.isWidget.get = function () { return true; };
    BlockWidgetView.prototype.coordsAt = function coordsAt (pos, side) {
        var custom = this.widget.coordsAt(this.dom, pos, side);
        if (custom)
            { return custom; }
        if (this.widget instanceof BlockGapWidget)
            { return null; }
        return flattenRect(this.dom.getBoundingClientRect(), this.length ? pos == 0 : side <= 0);
    };
    BlockWidgetView.prototype.destroy = function destroy () {
        ContentView.prototype.destroy.call(this);
        if (this.dom)
            { this.widget.destroy(this.dom); }
    };
    BlockWidgetView.prototype.covers = function covers (side) {
        var ref = this.deco;
        var startSide = ref.startSide;
        var endSide = ref.endSide;
        return startSide == endSide ? false : side < 0 ? startSide < 0 : endSide > 0;
    };

    Object.defineProperties( BlockWidgetView.prototype, prototypeAccessors$7 );

    return BlockWidgetView;
}(ContentView));
var BlockGapWidget = /*@__PURE__*/(function (WidgetType) {
    function BlockGapWidget(height) {
        WidgetType.call(this);
        this.height = height;
    }

    if ( WidgetType ) BlockGapWidget.__proto__ = WidgetType;
    BlockGapWidget.prototype = Object.create( WidgetType && WidgetType.prototype );
    BlockGapWidget.prototype.constructor = BlockGapWidget;

    var prototypeAccessors$8 = { editable: { configurable: true },estimatedHeight: { configurable: true } };
    BlockGapWidget.prototype.toDOM = function toDOM () {
        var elt = document.createElement("div");
        elt.className = "cm-gap";
        this.updateDOM(elt);
        return elt;
    };
    BlockGapWidget.prototype.eq = function eq (other) { return other.height == this.height; };
    BlockGapWidget.prototype.updateDOM = function updateDOM (elt) {
        elt.style.height = this.height + "px";
        return true;
    };
    prototypeAccessors$8.editable.get = function () { return true; };
    prototypeAccessors$8.estimatedHeight.get = function () { return this.height; };
    BlockGapWidget.prototype.ignoreEvent = function ignoreEvent () { return false; };

    Object.defineProperties( BlockGapWidget.prototype, prototypeAccessors$8 );

    return BlockGapWidget;
}(WidgetType));

var ContentBuilder = function ContentBuilder(doc, pos, end, disallowBlockEffectsFor) {
    this.doc = doc;
    this.pos = pos;
    this.end = end;
    this.disallowBlockEffectsFor = disallowBlockEffectsFor;
    this.content = [];
    this.curLine = null;
    this.breakAtStart = 0;
    this.pendingBuffer = 0 /* Buf.No */;
    this.bufferMarks = [];
    // Set to false directly after a widget that covers the position after it
    this.atCursorPos = true;
    this.openStart = -1;
    this.openEnd = -1;
    this.text = "";
    this.textOff = 0;
    this.cursor = doc.iter();
    this.skip = pos;
};
ContentBuilder.prototype.posCovered = function posCovered () {
    if (this.content.length == 0)
        { return !this.breakAtStart && this.doc.lineAt(this.pos).from != this.pos; }
    var last = this.content[this.content.length - 1];
    return !(last.breakAfter || last instanceof BlockWidgetView && last.deco.endSide < 0);
};
ContentBuilder.prototype.getLine = function getLine () {
    if (!this.curLine) {
        this.content.push(this.curLine = new LineView);
        this.atCursorPos = true;
    }
    return this.curLine;
};
ContentBuilder.prototype.flushBuffer = function flushBuffer (active) {
        if ( active === void 0 ) active = this.bufferMarks;

    if (this.pendingBuffer) {
        this.curLine.append(wrapMarks(new WidgetBufferView(-1), active), active.length);
        this.pendingBuffer = 0 /* Buf.No */;
    }
};
ContentBuilder.prototype.addBlockWidget = function addBlockWidget (view) {
    this.flushBuffer();
    this.curLine = null;
    this.content.push(view);
};
ContentBuilder.prototype.finish = function finish (openEnd) {
    if (this.pendingBuffer && openEnd <= this.bufferMarks.length)
        { this.flushBuffer(); }
    else
        { this.pendingBuffer = 0 /* Buf.No */; }
    if (!this.posCovered() &&
        !(openEnd && this.content.length && this.content[this.content.length - 1] instanceof BlockWidgetView))
        { this.getLine(); }
};
ContentBuilder.prototype.buildText = function buildText (length, active, openStart) {
    while (length > 0) {
        if (this.textOff == this.text.length) {
            var ref = this.cursor.next(this.skip);
                var value = ref.value;
                var lineBreak = ref.lineBreak;
                var done = ref.done;
            this.skip = 0;
            if (done)
                { throw new Error("Ran out of text content when drawing inline views"); }
            if (lineBreak) {
                if (!this.posCovered())
                    { this.getLine(); }
                if (this.content.length)
                    { this.content[this.content.length - 1].breakAfter = 1; }
                else
                    { this.breakAtStart = 1; }
                this.flushBuffer();
                this.curLine = null;
                this.atCursorPos = true;
                length--;
                continue;
            }
            else {
                this.text = value;
                this.textOff = 0;
            }
        }
        var take = Math.min(this.text.length - this.textOff, length, 512 /* T.Chunk */);
        this.flushBuffer(active.slice(active.length - openStart));
        this.getLine().append(wrapMarks(new TextView(this.text.slice(this.textOff, this.textOff + take)), active), openStart);
        this.atCursorPos = true;
        this.textOff += take;
        length -= take;
        openStart = 0;
    }
};
ContentBuilder.prototype.span = function span (from, to, active, openStart) {
    this.buildText(to - from, active, openStart);
    this.pos = to;
    if (this.openStart < 0)
        { this.openStart = openStart; }
};
ContentBuilder.prototype.point = function point (from, to, deco, active, openStart, index) {
    if (this.disallowBlockEffectsFor[index] && deco instanceof PointDecoration) {
        if (deco.block)
            { throw new RangeError("Block decorations may not be specified via plugins"); }
        if (to > this.doc.lineAt(this.pos).to)
            { throw new RangeError("Decorations that replace line breaks may not be specified via plugins"); }
    }
    var len = to - from;
    if (deco instanceof PointDecoration) {
        if (deco.block) {
            if (deco.startSide > 0 && !this.posCovered())
                { this.getLine(); }
            this.addBlockWidget(new BlockWidgetView(deco.widget || NullWidget.block, len, deco));
        }
        else {
            var view = WidgetView.create(deco.widget || NullWidget.inline, len, len ? 0 : deco.startSide);
            var cursorBefore = this.atCursorPos && !view.isEditable && openStart <= active.length &&
                (from < to || deco.startSide > 0);
            var cursorAfter = !view.isEditable && (from < to || openStart > active.length || deco.startSide <= 0);
            var line = this.getLine();
            if (this.pendingBuffer == 2 /* Buf.IfCursor */ && !cursorBefore && !view.isEditable)
                { this.pendingBuffer = 0 /* Buf.No */; }
            this.flushBuffer(active);
            if (cursorBefore) {
                line.append(wrapMarks(new WidgetBufferView(1), active), openStart);
                openStart = active.length + Math.max(0, openStart - active.length);
            }
            line.append(wrapMarks(view, active), openStart);
            this.atCursorPos = cursorAfter;
            this.pendingBuffer = !cursorAfter ? 0 /* Buf.No */ : from < to || openStart > active.length ? 1 /* Buf.Yes */ : 2 /* Buf.IfCursor */;
            if (this.pendingBuffer)
                { this.bufferMarks = active.slice(); }
        }
    }
    else if (this.doc.lineAt(this.pos).from == this.pos) { // Line decoration
        this.getLine().addLineDeco(deco);
    }
    if (len) {
        // Advance the iterator past the replaced content
        if (this.textOff + len <= this.text.length) {
            this.textOff += len;
        }
        else {
            this.skip += len - (this.text.length - this.textOff);
            this.text = "";
            this.textOff = 0;
        }
        this.pos = to;
    }
    if (this.openStart < 0)
        { this.openStart = openStart; }
};
ContentBuilder.build = function build (text, from, to, decorations, dynamicDecorationMap) {
    var builder = new ContentBuilder(text, from, to, dynamicDecorationMap);
    builder.openEnd = RangeSet.spans(decorations, from, to, builder);
    if (builder.openStart < 0)
        { builder.openStart = builder.openEnd; }
    builder.finish(builder.openEnd);
    return builder;
};
function wrapMarks(view, active) {
    for (var mark of active)
        view = new MarkView(mark, [view], view.length);
    return view;
}
var NullWidget = /*@__PURE__*/(function (WidgetType) {
    function NullWidget(tag) {
        WidgetType.call(this);
        this.tag = tag;
    }

    if ( WidgetType ) NullWidget.__proto__ = WidgetType;
    NullWidget.prototype = Object.create( WidgetType && WidgetType.prototype );
    NullWidget.prototype.constructor = NullWidget;

    var prototypeAccessors$9 = { isHidden: { configurable: true } };
    NullWidget.prototype.eq = function eq (other) { return other.tag == this.tag; };
    NullWidget.prototype.toDOM = function toDOM () { return document.createElement(this.tag); };
    NullWidget.prototype.updateDOM = function updateDOM (elt) { return elt.nodeName.toLowerCase() == this.tag; };
    prototypeAccessors$9.isHidden.get = function () { return true; };

    Object.defineProperties( NullWidget.prototype, prototypeAccessors$9 );

    return NullWidget;
}(WidgetType));
NullWidget.inline = /*@__PURE__*/new NullWidget("span");
NullWidget.block = /*@__PURE__*/new NullWidget("div");

/**
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 = {}));
var LTR = Direction.LTR, RTL = Direction.RTL;
// Decode a string with each type encoded as log2(type)
function dec(str) {
    var result = [];
    for (var i = 0; i < str.length; i++)
        { result.push(1 << +str[i]); }
    return result;
}
// Character types for codepoints 0 to 0xf8
var LowTypes = /*@__PURE__*/dec("88888888888888888888888888888888888666888888787833333333337888888000000000000000000000000008888880000000000000000000000000088888888888888888888888888888888888887866668888088888663380888308888800000000000000000000000800000000000000000000000000000008");
// Character types for codepoints 0x600 to 0x6f9
var ArabicTypes = /*@__PURE__*/dec("4444448826627288999999999992222222222222222222222222222222222222222222222229999999999999999999994444444444644222822222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222999999949999999229989999223333333333");
var 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 (var p$1 of ["()", "[]", "{}"]) {
    var l$1 = /*@__PURE__*/p$1.charCodeAt(0), r$1 = /*@__PURE__*/p$1.charCodeAt(1);
    Brackets[l$1] = r$1;
    Brackets[r$1] = -l$1;
}
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 */;
}
var 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).
*/
var BidiSpan = function BidiSpan(
/**
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;
};

var prototypeAccessors$10 = { dir: { configurable: true } };
/**
@internal
*/
prototypeAccessors$10.dir.get = function () { return this.level % 2 ? RTL : LTR; };

BidiSpan.prototype.side = function side (end, dir) { return (this.dir == dir) == end ? this.to : this.from; };
/**
@internal
*/
BidiSpan.prototype.forward = function forward (forward$1, dir) { return forward$1 == (this.dir == dir); };
/**
@internal
*/
BidiSpan.find = function find (order, index, level, assoc) {
    var maybe = -1;
    for (var i = 0; i < order.length; i++) {
        var 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;
};

Object.defineProperties( BidiSpan.prototype, prototypeAccessors$10 );
function isolatesEq(a, b) {
    if (a.length != b.length)
        { return false; }
    for (var i = 0; i < a.length; i++) {
        var 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
var 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 (var iI = 0; iI <= isolates.length; iI++) {
        var from = iI ? isolates[iI - 1].to : rFrom, to = iI < isolates.length ? isolates[iI].from : rTo;
        var 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 (var i = from, prev = prevType, prevStrong = prevType; i < to; i++) {
            var 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 (var i$1 = from, prev$1 = prevType, prevStrong$1 = prevType; i$1 < to; i$1++) {
            var type$1 = types[i$1];
            if (type$1 == 128 /* T.CS */) {
                if (i$1 < to - 1 && prev$1 == types[i$1 + 1] && (prev$1 & 24 /* T.Num */))
                    { type$1 = types[i$1] = prev$1; }
                else
                    { types[i$1] = 256 /* T.NI */; }
            }
            else if (type$1 == 64 /* T.ET */) {
                var end = i$1 + 1;
                while (end < to && types[end] == 64 /* T.ET */)
                    { end++; }
                var replace = (i$1 && prev$1 == 8 /* T.EN */) || (end < rTo && types[end] == 8 /* T.EN */) ? (prevStrong$1 == 1 /* T.L */ ? 1 /* T.L */ : 8 /* T.EN */) : 256 /* T.NI */;
                for (var j = i$1; j < end; j++)
                    { types[j] = replace; }
                i$1 = end - 1;
            }
            else if (type$1 == 8 /* T.EN */ && prevStrong$1 == 1 /* T.L */) {
                types[i$1] = 1 /* T.L */;
            }
            prev$1 = type$1;
            if (type$1 & 7 /* T.Strong */)
                { prevStrong$1 = type$1; }
        }
    }
}
// Process brackets throughout a run sequence.
function processBracketPairs(line, rFrom, rTo, isolates, outerType) {
    var oppositeType = outerType == 1 /* T.L */ ? 2 /* T.R */ : 1 /* T.L */;
    for (var iI = 0, sI = 0, context = 0; iI <= isolates.length; iI++) {
        var 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 (var i = from, ch = (void 0), br = (void 0), type = (void 0); 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 (var sJ = sI - 3; sJ >= 0; sJ -= 3) {
                        if (BracketStack[sJ + 1] == -br) {
                            var flags = BracketStack[sJ + 2];
                            var type$1 = (flags & 2 /* Bracketed.EmbedInside */) ? outerType :
                                !(flags & 4 /* Bracketed.OppositeInside */) ? 0 :
                                    (flags & 1 /* Bracketed.OppositeBefore */) ? oppositeType : outerType;
                            if (type$1)
                                { types[i] = types[BracketStack[sJ]] = type$1; }
                            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 */) {
                var embed = type == outerType;
                context = embed ? 0 : 1 /* Bracketed.OppositeBefore */;
                for (var sJ$1 = sI - 3; sJ$1 >= 0; sJ$1 -= 3) {
                    var cur = BracketStack[sJ$1 + 2];
                    if (cur & 2 /* Bracketed.EmbedInside */)
                        { break; }
                    if (embed) {
                        BracketStack[sJ$1 + 2] |= 2 /* Bracketed.EmbedInside */;
                    }
                    else {
                        if (cur & 4 /* Bracketed.OppositeInside */)
                            { break; }
                        BracketStack[sJ$1 + 2] |= 4 /* Bracketed.OppositeInside */;
                    }
                }
            }
        }
    }
}
function processNeutrals(rFrom, rTo, isolates, outerType) {
    for (var iI = 0, prev = outerType; iI <= isolates.length; iI++) {
        var 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 (var i = from; i < to;) {
            var type = types[i];
            if (type == 256 /* T.NI */) {
                var 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;
                    }
                }
                var beforeL = prev == 1 /* T.L */;
                var afterL = (end < rTo ? types[end] : outerType) == 1 /* T.L */;
                var replace = beforeL == afterL ? (beforeL ? 1 /* T.L */ : 2 /* T.R */) : outerType;
                for (var 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) {
    var ourType = level % 2 ? 2 /* T.R */ : 1 /* T.L */;
    if ((level % 2) == (baseLevel % 2)) { // Same dir as base direction, don't flip
        for (var 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).
            var sameDir = true, isNum = false;
            if (iI == isolates.length || iCh < isolates[iI].from) {
                var 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
            var recurse = !sameDir && ourType == 1 /* T.L */ ? [] : null;
            var localLevel = sameDir ? level : level + 1;
            var iScan = iCh;
            run: for (;;) {
                if (iI < isolates.length && iScan == isolates[iI].from) {
                    if (isNum)
                        { break run; }
                    var iso = isolates[iI];
                    // Scan ahead to verify that there is another char in this dir after the isolate(s)
                    if (!sameDir)
                        { for (var 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)); }
                        var 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 (var iCh$1 = to, iI$1 = isolates.length; iCh$1 > from;) {
            var sameDir$1 = true, isNum$1 = false;
            if (!iI$1 || iCh$1 > isolates[iI$1 - 1].to) {
                var next$1 = types[iCh$1 - 1];
                if (next$1 != ourType) {
                    sameDir$1 = false;
                    isNum$1 = next$1 == 16 /* T.AN */;
                }
            }
            var recurse$1 = !sameDir$1 && ourType == 1 /* T.L */ ? [] : null;
            var localLevel$1 = sameDir$1 ? level : level + 1;
            var iScan$1 = iCh$1;
            run: for (;;) {
                if (iI$1 && iScan$1 == isolates[iI$1 - 1].to) {
                    if (isNum$1)
                        { break run; }
                    var iso$1 = isolates[--iI$1];
                    // Scan ahead to verify that there is another char in this dir after the isolate(s)
                    if (!sameDir$1)
                        { for (var upto$1 = iso$1.from, jI$1 = iI$1;;) {
                            if (upto$1 == from)
                                { break run; }
                            if (jI$1 && isolates[jI$1 - 1].to == upto$1)
                                { upto$1 = isolates[--jI$1].from; }
                            else if (types[upto$1 - 1] == ourType)
                                { break run; }
                            else
                                { break; }
                        } }
                    if (recurse$1) {
                        recurse$1.push(iso$1);
                    }
                    else {
                        if (iso$1.to < iCh$1)
                            { order.push(new BidiSpan(iso$1.to, iCh$1, localLevel$1)); }
                        var dirSwap$1 = (iso$1.direction == LTR) != !(localLevel$1 % 2);
                        computeSectionOrder(line, dirSwap$1 ? level + 1 : level, baseLevel, iso$1.inner, iso$1.from, iso$1.to, order);
                        iCh$1 = iso$1.from;
                    }
                    iScan$1 = iso$1.from;
                }
                else if (iScan$1 == from || (sameDir$1 ? types[iScan$1 - 1] != ourType : types[iScan$1 - 1] == ourType)) {
                    break;
                }
                else {
                    iScan$1--;
                }
            }
            if (recurse$1)
                { emitSpans(line, iScan$1, iCh$1, level + 1, baseLevel, recurse$1, order); }
            else if (iScan$1 < iCh$1)
                { order.push(new BidiSpan(iScan$1, iCh$1, localLevel$1)); }
            iCh$1 = iScan$1;
        }
    }
}
function computeSectionOrder(line, level, baseLevel, isolates, from, to, order) {
    var 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
    var 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)];
}
var 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;
    var startIndex = start.head - line.from;
    var spanI = BidiSpan.find(order, startIndex, (_a = start.bidiLevel) !== null && _a !== void 0 ? _a : -1, start.assoc);
    var span = order[spanI], spanEnd = span.side(forward, dir);
    // End of span
    if (startIndex == spanEnd) {
        var 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);
    }
    var 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));
    var 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 (var i = from; i < to; i++) {
        var 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;
}

var clickAddsSelectionRange = /*@__PURE__*/Facet.define();
var dragMovesSelection$1 = /*@__PURE__*/Facet.define();
var mouseSelectionStyle = /*@__PURE__*/Facet.define();
var exceptionSink = /*@__PURE__*/Facet.define();
var updateListener = /*@__PURE__*/Facet.define();
var inputHandler = /*@__PURE__*/Facet.define();
var focusChangeEffect = /*@__PURE__*/Facet.define();
var clipboardInputFilter = /*@__PURE__*/Facet.define();
var clipboardOutputFilter = /*@__PURE__*/Facet.define();
var perLineTextDirection = /*@__PURE__*/Facet.define({
    combine: function (values) { return values.some(function (x) { return x; }); }
});
var nativeSelectionHidden = /*@__PURE__*/Facet.define({
    combine: function (values) { return values.some(function (x) { return x; }); }
});
var scrollHandler = /*@__PURE__*/Facet.define();
var ScrollTarget = function ScrollTarget(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) {
    if ( y === void 0 ) y = "nearest";
    if ( x === void 0 ) x = "nearest";
    if ( yMargin === void 0 ) yMargin = 5;
    if ( xMargin === void 0 ) xMargin = 5;
    if ( isSnapshot === void 0 ) isSnapshot = false;

    this.range = range;
    this.y = y;
    this.x = x;
    this.yMargin = yMargin;
    this.xMargin = xMargin;
    this.isSnapshot = isSnapshot;
};
ScrollTarget.prototype.map = function map (changes) {
    return changes.empty ? this :
        new ScrollTarget(this.range.map(changes), this.y, this.x, this.yMargin, this.xMargin, this.isSnapshot);
};
ScrollTarget.prototype.clip = function 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);
};
var scrollIntoView$1 = /*@__PURE__*/StateEffect.define({ map: function (t, ch) { return t.map(ch); } });
var 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) {
    var 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); }
}
var editable = /*@__PURE__*/Facet.define({ combine: function (values) { return values.length ? values[0] : true; } });
var nextPluginID = 0;
var viewPlugin = /*@__PURE__*/Facet.define();
/**
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.
*/
var ViewPlugin = function ViewPlugin(
/**
@internal
*/
id, 
/**
@internal
*/
create, 
/**
@internal
*/
domEventHandlers, 
/**
@internal
*/
domEventObservers, buildExtensions) {
    this.id = id;
    this.create = create;
    this.domEventHandlers = domEventHandlers;
    this.domEventObservers = domEventObservers;
    this.extension = buildExtensions(this);
};
/**
Define a plugin from a constructor function that creates the
plugin's value, given an editor view.
*/
ViewPlugin.define = function define (create, spec) {
    var ref = spec || {};
        var eventHandlers = ref.eventHandlers;
        var eventObservers = ref.eventObservers;
        var provide = ref.provide;
        var deco = ref.decorations;
    return new ViewPlugin(nextPluginID++, create, eventHandlers, eventObservers, function (plugin) {
        var ext = [viewPlugin.of(plugin)];
        if (deco)
            { ext.push(decorations.of(function (view) {
                var 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.
*/
ViewPlugin.fromClass = function fromClass (cls, spec) {
    return ViewPlugin.define(function (view) { return new cls(view); }, spec);
};
var PluginInstance = function PluginInstance(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 `false`. 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;
};
PluginInstance.prototype.update = function update (view) {
    if (!this.value) {
        if (this.spec) {
            try {
                this.value = this.spec.create(view);
            }
            catch (e) {
                logException(view.state, e, "CodeMirror plugin crashed");
                this.deactivate();
            }
        }
    }
    else if (this.mustUpdate) {
        var update = this.mustUpdate;
        this.mustUpdate = null;
        if (this.value.update) {
            try {
                this.value.update(update);
            }
            catch (e$1) {
                logException(update.state, e$1, "CodeMirror plugin crashed");
                if (this.value.destroy)
                    { try {
                        this.value.destroy();
                    }
                    catch (_) { } }
                this.deactivate();
            }
        }
    }
    return this;
};
PluginInstance.prototype.destroy = function 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");
        }
    }
};
PluginInstance.prototype.deactivate = function deactivate () {
    this.spec = this.value = null;
};
var editorAttributes = /*@__PURE__*/Facet.define();
var contentAttributes = /*@__PURE__*/Facet.define();
// Provide decorations
var decorations = /*@__PURE__*/Facet.define();
var outerDecorations = /*@__PURE__*/Facet.define();
var atomicRanges = /*@__PURE__*/Facet.define();
var bidiIsolatedRanges = /*@__PURE__*/Facet.define();
function getIsolatedRanges(view, line) {
    var isolates = view.state.facet(bidiIsolatedRanges);
    if (!isolates.length)
        { return isolates; }
    var sets = isolates.map(function (i) { return i instanceof Function ? i(view) : i; });
    var result = [];
    RangeSet.spans(sets, line.from, line.to, {
        point: function point() { },
        span: function span(fromDoc, toDoc, active, open) {
            var from = fromDoc - line.from, to = toDoc - line.from;
            var level = result;
            for (var i = active.length - 1; i >= 0; i--, open--) {
                var direction = active[i].spec.bidiIsolate, update = (void 0);
                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 {
                    var add = { from: from, to: to, direction: direction, inner: [] };
                    level.push(add);
                    level = add.inner;
                }
            }
        }
    });
    return result;
}
var scrollMargins = /*@__PURE__*/Facet.define();
function getScrollMargins(view) {
    var left = 0, right = 0, top = 0, bottom = 0;
    for (var source of view.state.facet(scrollMargins)) {
        var 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: left, right: right, top: top, bottom: bottom };
}
var styleModule = /*@__PURE__*/Facet.define();
var ChangedRange = function ChangedRange(fromA, toA, fromB, toB) {
    this.fromA = fromA;
    this.toA = toA;
    this.fromB = fromB;
    this.toB = toB;
};
ChangedRange.prototype.join = function 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));
};
ChangedRange.prototype.addToSet = function addToSet (set) {
    var i = set.length, me = this;
    for (; i > 0; i--) {
        var 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;
};
ChangedRange.extendWithRanges = function extendWithRanges (diff, ranges) {
    if (ranges.length == 0)
        { return diff; }
    var result = [];
    for (var dI = 0, rI = 0, posA = 0, posB = 0;; dI++) {
        var next = dI == diff.length ? null : diff[dI], off = posA - posB;
        var end = next ? next.fromB : 1e9;
        while (rI < ranges.length && ranges[rI] < end) {
            var from = ranges[rI], to = ranges[rI + 1];
            var fromB = Math.max(posB, from), toB = Math.min(end, to);
            if (fromB <= toB)
                { new ChangedRange(fromB + off, toB + off, fromB, toB).addToSet(result); }
            if (to > end)
                { break; }
            else
                { rI += 2; }
        }
        if (!next)
            { return result; }
        new ChangedRange(next.fromA, next.toA, next.fromB, next.toB).addToSet(result);
        posA = next.toA;
        posB = next.toB;
    }
};
/**
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.
*/
var ViewUpdate = function ViewUpdate(
/**
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 (var tr of transactions)
        this.changes = this.changes.compose(tr.changes);
    var changedRanges = [];
    this.changes.iterChangedRanges(function (fromA, toA, fromB, toB) { return changedRanges.push(new ChangedRange(fromA, toA, fromB, toB)); });
    this.changedRanges = changedRanges;
};

var prototypeAccessors$11 = { viewportChanged: { configurable: true },heightChanged: { configurable: true },geometryChanged: { configurable: true },focusChanged: { configurable: true },docChanged: { configurable: true },selectionSet: { configurable: true },empty: { configurable: true } };
/**
@internal
*/
ViewUpdate.create = function 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.
*/
prototypeAccessors$11.viewportChanged.get = function () {
    return (this.flags & 4 /* UpdateFlag.Viewport */) > 0;
};
/**
Indicates whether the height of a block element in the editor
changed in this update.
*/
prototypeAccessors$11.heightChanged.get = function () {
    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.
*/
prototypeAccessors$11.geometryChanged.get = function () {
    return this.docChanged || (this.flags & (8 /* UpdateFlag.Geometry */ | 2 /* UpdateFlag.Height */)) > 0;
};
/**
True when this update indicates a focus change.
*/
prototypeAccessors$11.focusChanged.get = function () {
    return (this.flags & 1 /* UpdateFlag.Focus */) > 0;
};
/**
Whether the document changed in this update.
*/
prototypeAccessors$11.docChanged.get = function () {
    return !this.changes.empty;
};
/**
Whether the selection was explicitly set in this update.
*/
prototypeAccessors$11.selectionSet.get = function () {
    return this.transactions.some(function (tr) { return tr.selection; });
};
/**
@internal
*/
prototypeAccessors$11.empty.get = function () { return this.flags == 0 && this.transactions.length == 0; };

Object.defineProperties( ViewUpdate.prototype, prototypeAccessors$11 );

var DocView = /*@__PURE__*/(function (ContentView) {
    function DocView(view) {
        ContentView.call(this);
        this.view = view;
        this.decorations = [];
        this.dynamicDecorationMap = [false];
        this.domChanged = null;
        this.hasComposition = null;
        this.markedForComposition = new Set;
        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.setDOM(view.contentDOM);
        this.children = [new LineView];
        this.children[0].setParent(this);
        this.updateDeco();
        this.updateInner([new ChangedRange(0, 0, 0, view.state.doc.length)], 0, null);
    }

    if ( ContentView ) DocView.__proto__ = ContentView;
    DocView.prototype = Object.create( ContentView && ContentView.prototype );
    DocView.prototype.constructor = DocView;

    var prototypeAccessors$12 = { length: { configurable: true } };
    // Update the document view to a given state.
    prototypeAccessors$12.length.get = function () { return this.view.state.doc.length; };

    DocView.prototype.update = function update (update$1) {
        var this$1$1 = this;

        var _a;
        var changedRanges = update$1.changedRanges;
        if (this.minWidth > 0 && changedRanges.length) {
            if (!changedRanges.every(function (ref) {
                var fromA = ref.fromA;
                var toA = ref.toA;

                return toA < this$1$1.minWidthFrom || fromA > this$1$1.minWidthTo;
            })) {
                this.minWidth = this.minWidthFrom = this.minWidthTo = 0;
            }
            else {
                this.minWidthFrom = update$1.changes.mapPos(this.minWidthFrom, 1);
                this.minWidthTo = update$1.changes.mapPos(this.minWidthTo, 1);
            }
        }
        this.updateEditContextFormatting(update$1);
        var 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$1.changes, this.hasComposition) && !update$1.selectionSet)
                { readCompositionAt = update$1.state.selection.main.head; }
        }
        var composition = readCompositionAt > -1 ? findCompositionRange(this.view, update$1.changes, readCompositionAt) : null;
        this.domChanged = null;
        if (this.hasComposition) {
            this.markedForComposition.clear();
            var ref = this.hasComposition;
            var from = ref.from;
            var to = ref.to;
            changedRanges = new ChangedRange(from, to, update$1.changes.mapPos(from, -1), update$1.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$1 &&
            update$1.state.doc.lines != update$1.startState.doc.lines)
            { this.forceSelection = true; }
        var prevDeco = this.decorations, deco = this.updateDeco();
        var decoDiff = findChangedDeco(prevDeco, deco, update$1.changes);
        changedRanges = ChangedRange.extendWithRanges(changedRanges, decoDiff);
        if (!(this.flags & 7 /* ViewFlag.Dirty */) && changedRanges.length == 0) {
            return false;
        }
        else {
            this.updateInner(changedRanges, update$1.startState.doc.length, composition);
            if (update$1.transactions.length)
                { this.lastUpdate = Date.now(); }
            return true;
        }
    };
    // Used by update and the constructor do perform the actual DOM
    // update
    DocView.prototype.updateInner = function updateInner (changes, oldLength, composition) {
        var this$1$1 = this;

        this.view.viewState.mustMeasureContent = true;
        this.updateChildren(changes, oldLength, composition);
        var ref = this.view;
        var observer = ref.observer;
        observer.ignore(function () {
            // 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$1$1.dom.style.height = this$1$1.view.viewState.contentHeight / this$1$1.view.scaleY + "px";
            this$1$1.dom.style.flexBasis = this$1$1.minWidth ? this$1$1.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.
            var track = browser.chrome || browser.ios ? { node: observer.selectionRange.focusNode, written: false } : undefined;
            this$1$1.sync(this$1$1.view, track);
            this$1$1.flags &= ~7 /* ViewFlag.Dirty */;
            if (track && (track.written || observer.selectionRange.focusNode != track.node))
                { this$1$1.forceSelection = true; }
            this$1$1.dom.style.height = "";
        });
        this.markedForComposition.forEach(function (cView) { return cView.flags &= ~8; } /* ViewFlag.Composition */);
        var gaps = [];
        if (this.view.viewport.from || this.view.viewport.to < this.view.state.doc.length)
            { for (var child of this.children)
                if (child instanceof BlockWidgetView && child.widget instanceof BlockGapWidget)
                    { gaps.push(child.dom); } }
        observer.updateGaps(gaps);
    };
    DocView.prototype.updateChildren = function updateChildren (changes, oldLength, composition) {
        var assign;

        var ranges = composition ? composition.range.addToSet(changes.slice()) : changes;
        var cursor = this.childCursor(oldLength);
        for (var i = ranges.length - 1;; i--) {
            var next = i >= 0 ? ranges[i] : null;
            if (!next)
                { break; }
            var fromA = next.fromA;
            var toA = next.toA;
            var fromB = next.fromB;
            var toB = next.toB;
            var content = (void 0), breakAtStart = (void 0), openStart = (void 0), openEnd = (void 0);
            if (composition && composition.range.fromB < toB && composition.range.toB > fromB) {
                var before = ContentBuilder.build(this.view.state.doc, fromB, composition.range.fromB, this.decorations, this.dynamicDecorationMap);
                var after = ContentBuilder.build(this.view.state.doc, composition.range.toB, toB, this.decorations, this.dynamicDecorationMap);
                breakAtStart = before.breakAtStart;
                openStart = before.openStart;
                openEnd = after.openEnd;
                var compLine = this.compositionView(composition);
                if (after.breakAtStart) {
                    compLine.breakAfter = 1;
                }
                else if (after.content.length &&
                    compLine.merge(compLine.length, compLine.length, after.content[0], false, after.openStart, 0)) {
                    compLine.breakAfter = after.content[0].breakAfter;
                    after.content.shift();
                }
                if (before.content.length &&
                    compLine.merge(0, 0, before.content[before.content.length - 1], true, 0, before.openEnd)) {
                    before.content.pop();
                }
                content = before.content.concat(compLine).concat(after.content);
            }
            else {
                ((assign =
                    ContentBuilder.build(this.view.state.doc, fromB, toB, this.decorations, this.dynamicDecorationMap), content = assign.content, breakAtStart = assign.breakAtStart, openStart = assign.openStart, openEnd = assign.openEnd));
            }
            var ref = cursor.findPos(toA, 1);
            var toI = ref.i;
            var toOff = ref.off;
            var ref$1 = cursor.findPos(fromA, -1);
            var fromI = ref$1.i;
            var fromOff = ref$1.off;
            replaceRange(this, fromI, fromOff, toI, toOff, content, breakAtStart, openStart, openEnd);
        }
        if (composition)
            { this.fixCompositionDOM(composition); }
    };
    DocView.prototype.updateEditContextFormatting = function updateEditContextFormatting (update) {
        this.editContextFormatting = this.editContextFormatting.map(update.changes);
        for (var tr of update.transactions)
            for (var effect of tr.effects)
                if (effect.is(setEditContextFormatting)) {
                    this.editContextFormatting = effect.value;
                }
    };
    DocView.prototype.compositionView = function compositionView (composition) {
        var cur = new TextView(composition.text.nodeValue);
        cur.flags |= 8 /* ViewFlag.Composition */;
        for (var { deco } of composition.marks)
            cur = new MarkView(deco, [cur], cur.length);
        var line = new LineView;
        line.append(cur, 0);
        return line;
    };
    DocView.prototype.fixCompositionDOM = function fixCompositionDOM (composition) {
        var this$1$1 = this;

        var fix = function (dom, cView) {
            cView.flags |= 8 /* ViewFlag.Composition */ | (cView.children.some(function (c) { return c.flags & 7; } /* ViewFlag.Dirty */) ? 1 /* ViewFlag.ChildDirty */ : 0);
            this$1$1.markedForComposition.add(cView);
            var prev = ContentView.get(dom);
            if (prev && prev != cView)
                { prev.dom = null; }
            cView.setDOM(dom);
        };
        var pos = this.childPos(composition.range.fromB, 1);
        var cView = this.children[pos.i];
        fix(composition.line, cView);
        for (var i = composition.marks.length - 1; i >= -1; i--) {
            pos = cView.childPos(pos.off, 1);
            cView = cView.children[pos.i];
            fix(i >= 0 ? composition.marks[i].node : composition.text, cView);
        }
    };
    // Sync the DOM selection to this.state.selection
    DocView.prototype.updateSelection = function updateSelection (mustRead, fromPointer) {
        var this$1$1 = this;
        if ( mustRead === void 0 ) mustRead = false;
        if ( fromPointer === void 0 ) fromPointer = false;

        if (mustRead || !this.view.observer.selectionRange.focusNode)
            { this.view.observer.readSelectionRange(); }
        var activeElt = this.view.root.activeElement, focused = activeElt == this.dom;
        var selectionNotFocus = !focused &&
            hasSelection(this.dom, this.view.observer.selectionRange) && !(activeElt && this.dom.contains(activeElt));
        if (!(focused || fromPointer || selectionNotFocus))
            { return; }
        var force = this.forceSelection;
        this.forceSelection = false;
        var main = this.view.state.selection.main;
        var anchor = this.moveToLine(this.domAtPos(main.anchor));
        var head = main.empty ? anchor : this.moveToLine(this.domAtPos(main.head));
        // 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)) {
            var dummy = document.createTextNode("");
            this.view.observer.ignore(function () { return anchor.node.insertBefore(dummy, anchor.node.childNodes[anchor.offset] || null); });
            anchor = head = new DOMPos(dummy, 0);
            force = true;
        }
        var 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(function () {
                var assign;

                // 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 && this$1$1.dom.contains(domSel.focusNode) &&
                    inUneditable(domSel.focusNode, this$1$1.dom)) {
                    this$1$1.dom.blur();
                    this$1$1.dom.focus({ preventScroll: true });
                }
                var rawSel = getSelection$1(this$1$1.view.root);
                if (!rawSel) ;
                else if (main.empty) {
                    // Work around https://bugzilla.mozilla.org/show_bug.cgi?id=1612076
                    if (browser.gecko) {
                        var nextTo = nextToUneditable(anchor.node, anchor.offset);
                        if (nextTo && nextTo != (1 /* NextTo.Before */ | 2 /* NextTo.After */)) {
                            var 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
                    var range = document.createRange();
                    if (main.anchor > main.head)
                        { (assign = [head, anchor], anchor = assign[0], head = assign[1]); }
                    range.setEnd(head.node, head.offset);
                    range.setStart(anchor.node, anchor.offset);
                    rawSel.removeAllRanges();
                    rawSel.addRange(range);
                }
                if (selectionNotFocus && this$1$1.view.root.activeElement == this$1$1.dom) {
                    this$1$1.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.
    DocView.prototype.suppressWidgetCursorChange = function 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;
    };
    DocView.prototype.enforceCursorAssoc = function enforceCursorAssoc () {
        if (this.hasComposition)
            { return; }
        var ref = this;
        var view = ref.view;
        var cursor = view.state.selection.main;
        var sel = getSelection$1(view.root);
        var ref$1 = view.observer.selectionRange;
        var anchorNode = ref$1.anchorNode;
        var anchorOffset = ref$1.anchorOffset;
        if (!sel || !cursor.empty || !cursor.assoc || !sel.modify)
            { return; }
        var line = LineView.find(this, cursor.head);
        if (!line)
            { return; }
        var lineStart = line.posAtStart;
        if (cursor.head == lineStart || cursor.head == lineStart + line.length)
            { return; }
        var before = this.coordsAt(cursor.head, -1), after = this.coordsAt(cursor.head, 1);
        if (!before || !after || before.bottom > after.top)
            { return; }
        var dom = this.domAtPos(cursor.head + 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();
        var newRange = view.observer.selectionRange;
        if (view.docView.posFromDOM(newRange.anchorNode, newRange.anchorOffset) != cursor.from)
            { sel.collapse(anchorNode, anchorOffset); }
    };
    // If a position is in/near a block widget, move it to a nearby text
    // line, since we don't want the cursor inside a block widget.
    DocView.prototype.moveToLine = function moveToLine (pos) {
        // Block widgets will return positions before/after them, which
        // are thus directly in the document DOM element.
        var dom = this.dom, newPos;
        if (pos.node != dom)
            { return pos; }
        for (var i = pos.offset; !newPos && i < dom.childNodes.length; i++) {
            var view = ContentView.get(dom.childNodes[i]);
            if (view instanceof LineView)
                { newPos = view.domAtPos(0); }
        }
        for (var i$1 = pos.offset - 1; !newPos && i$1 >= 0; i$1--) {
            var view$1 = ContentView.get(dom.childNodes[i$1]);
            if (view$1 instanceof LineView)
                { newPos = view$1.domAtPos(view$1.length); }
        }
        return newPos ? new DOMPos(newPos.node, newPos.offset, true) : pos;
    };
    DocView.prototype.nearest = function nearest (dom) {
        for (var cur = dom; cur;) {
            var domView = ContentView.get(cur);
            if (domView && domView.rootView == this)
                { return domView; }
            cur = cur.parentNode;
        }
        return null;
    };
    DocView.prototype.posFromDOM = function posFromDOM (node, offset) {
        var view = this.nearest(node);
        if (!view)
            { throw new RangeError("Trying to find position for a DOM position outside of the document"); }
        return view.localPosFromDOM(node, offset) + view.posAtStart;
    };
    DocView.prototype.domAtPos = function domAtPos (pos) {
        var ref = this.childCursor().findPos(pos, -1);
        var i = ref.i;
        var off = ref.off;
        for (; i < this.children.length - 1;) {
            var child = this.children[i];
            if (off < child.length || child instanceof LineView)
                { break; }
            i++;
            off = 0;
        }
        return this.children[i].domAtPos(off);
    };
    DocView.prototype.coordsAt = function coordsAt (pos, side) {
        var best = null, bestPos = 0;
        for (var off = this.length, i = this.children.length - 1; i >= 0; i--) {
            var child = this.children[i], end = off - child.breakAfter, start = end - child.length;
            if (end < pos)
                { break; }
            if (start <= pos && (start < pos || child.covers(-1)) && (end > pos || child.covers(1)) &&
                (!best || child instanceof LineView && !(best instanceof LineView && side >= 0))) {
                best = child;
                bestPos = start;
            }
            else if (best && start == pos && end == pos && child instanceof BlockWidgetView && Math.abs(side) < 2) {
                if (child.deco.startSide < 0)
                    { break; }
                else if (i)
                    { best = null; }
            }
            off = start;
        }
        return best ? best.coordsAt(pos - bestPos, side) : null;
    };
    DocView.prototype.coordsForChar = function coordsForChar (pos) {
        var ref = this.childPos(pos, 1);
        var i = ref.i;
        var off = ref.off;
        var child = this.children[i];
        if (!(child instanceof LineView))
            { return null; }
        while (child.children.length) {
            var ref$1 = child.childPos(off, 1);
            var i$1 = ref$1.i;
            var childOff = ref$1.off;
            for (;; i$1++) {
                if (i$1 == child.children.length)
                    { return null; }
                if ((child = child.children[i$1]).length)
                    { break; }
            }
            off = childOff;
        }
        if (!(child instanceof TextView))
            { return null; }
        var end = findClusterBreak(child.text, off);
        if (end == off)
            { return null; }
        var rects = textRange(child.dom, off, end).getClientRects();
        for (var i$2 = 0; i$2 < rects.length; i$2++) {
            var rect = rects[i$2];
            if (i$2 == rects.length - 1 || rect.top < rect.bottom && rect.left < rect.right)
                { return rect; }
        }
        return null;
    };
    DocView.prototype.measureVisibleLineHeights = function measureVisibleLineHeights (viewport) {
        var result = [];
        var from = viewport.from;
        var to = viewport.to;
        var contentWidth = this.view.contentDOM.clientWidth;
        var isWider = contentWidth > Math.max(this.view.scrollDOM.clientWidth, this.minWidth) + 1;
        var widest = -1, ltr = this.view.textDirection == Direction.LTR;
        for (var pos = 0, i = 0; i < this.children.length; i++) {
            var child = this.children[i], end = pos + child.length;
            if (end > to)
                { break; }
            if (pos >= from) {
                var childRect = child.dom.getBoundingClientRect();
                result.push(childRect.height);
                if (isWider) {
                    var last = child.dom.lastChild;
                    var rects = last ? clientRectsFor(last) : [];
                    if (rects.length) {
                        var rect = rects[rects.length - 1];
                        var width = ltr ? rect.right - childRect.left : childRect.right - rect.left;
                        if (width > widest) {
                            widest = width;
                            this.minWidth = contentWidth;
                            this.minWidthFrom = pos;
                            this.minWidthTo = end;
                        }
                    }
                }
            }
            pos = end + child.breakAfter;
        }
        return result;
    };
    DocView.prototype.textDirectionAt = function textDirectionAt (pos) {
        var ref = this.childPos(pos, 1);
        var i = ref.i;
        return getComputedStyle(this.children[i].dom).direction == "rtl" ? Direction.RTL : Direction.LTR;
    };
    DocView.prototype.measureTextSize = function measureTextSize () {
        var this$1$1 = this;

        for (var child of this.children) {
            if (child instanceof LineView) {
                var measure = child.measureTextSize();
                if (measure)
                    { return measure; }
            }
        }
        // If no workable line exists, force a layout of a measurable element
        var 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(function () {
            this$1$1.dom.appendChild(dummy);
            var rect = clientRectsFor(dummy.firstChild)[0];
            lineHeight = dummy.getBoundingClientRect().height;
            charWidth = rect ? rect.width / 27 : 7;
            textHeight = rect ? rect.height : lineHeight;
            dummy.remove();
        });
        return { lineHeight: lineHeight, charWidth: charWidth, textHeight: textHeight };
    };
    DocView.prototype.childCursor = function childCursor (pos) {
        if ( pos === void 0 ) pos = this.length;

        // Move back to start of last element when possible, so that
        // `ChildCursor.findPos` doesn't have to deal with the edge case
        // of being after the last element.
        var i = this.children.length;
        if (i)
            { pos -= this.children[--i].length; }
        return new ChildCursor(this.children, pos, i);
    };
    DocView.prototype.computeBlockGapDeco = function computeBlockGapDeco () {
        var deco = [], vs = this.view.viewState;
        for (var pos = 0, i = 0;; i++) {
            var next = i == vs.viewports.length ? null : vs.viewports[i];
            var end = next ? next.from - 1 : this.length;
            if (end > pos) {
                var 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);
    };
    DocView.prototype.updateDeco = function updateDeco () {
        var this$1$1 = this;

        var i = 1;
        var allDeco = this.view.state.facet(decorations).map(function (d) {
            var dynamic = this$1$1.dynamicDecorationMap[i++] = typeof d == "function";
            return dynamic ? d(this$1$1.view) : d;
        });
        var dynamicOuter = false, outerDeco = this.view.state.facet(outerDecorations).map(function (d, i) {
            var dynamic = typeof d == "function";
            if (dynamic)
                { dynamicOuter = true; }
            return dynamic ? d(this$1$1.view) : d;
        });
        if (outerDeco.length) {
            this.dynamicDecorationMap[i++] = dynamicOuter;
            allDeco.push(RangeSet.join(outerDeco));
        }
        this.decorations = [
            this.editContextFormatting ].concat( allDeco,
            [this.computeBlockGapDeco()],
            [this.view.viewState.lineGapDeco]
        );
        while (i < this.decorations.length)
            { this.dynamicDecorationMap[i++] = false; }
        return this.decorations;
    };
    DocView.prototype.scrollIntoView = function scrollIntoView (target) {
        if (target.isSnapshot) {
            var ref = this.view.viewState.lineBlockAt(target.range.head);
            this.view.scrollDOM.scrollTop = ref.top - target.yMargin;
            this.view.scrollDOM.scrollLeft = target.xMargin;
            return;
        }
        for (var 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");
            }
        }
        var range = target.range;
        var rect = this.coordsAt(range.head, range.empty ? range.assoc : 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) }; }
        var margins = getScrollMargins(this.view);
        var targetRect = {
            left: rect.left - margins.left, top: rect.top - margins.top,
            right: rect.right + margins.right, bottom: rect.bottom + margins.bottom
        };
        var ref$1 = this.view.scrollDOM;
        var offsetWidth = ref$1.offsetWidth;
        var offsetHeight = ref$1.offsetHeight;
        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);
    };

    Object.defineProperties( DocView.prototype, prototypeAccessors$12 );

    return DocView;
}(ContentView));
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) {
    var sel = view.observer.selectionRange;
    if (!sel.focusNode)
        { return null; }
    var textBefore = textNodeBefore(sel.focusNode, sel.focusOffset);
    var textAfter = textNodeAfter(sel.focusNode, sel.focusOffset);
    var textNode = textBefore || textAfter;
    if (textAfter && textBefore && textAfter.node != textBefore.node) {
        var descAfter = ContentView.get(textAfter.node);
        if (!descAfter || descAfter instanceof TextView && descAfter.text != textAfter.node.nodeValue) {
            textNode = textAfter;
        }
        else if (view.docView.lastCompositionAfterCursor) {
            var descBefore = ContentView.get(textBefore.node);
            if (!(!descBefore || descBefore instanceof TextView && descBefore.text != textBefore.node.nodeValue))
                { textNode = textAfter; }
        }
    }
    view.docView.lastCompositionAfterCursor = textNode != textBefore;
    if (!textNode)
        { return null; }
    var from = headPos - textNode.offset;
    return { from: from, to: from + textNode.node.nodeValue.length, node: textNode.node };
}
function findCompositionRange(view, changes, headPos) {
    var found = findCompositionNode(view, headPos);
    if (!found)
        { return null; }
    var textNode = found.node;
    var from = found.from;
    var to = found.to;
    var 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; }
    var inv = changes.invertedDesc;
    var range = new ChangedRange(inv.mapPos(from), inv.mapPos(to), from, to);
    var marks = [];
    for (var parent = textNode.parentNode;; parent = parent.parentNode) {
        var parentView = ContentView.get(parent);
        if (parentView instanceof MarkView)
            { marks.push({ node: parent, deco: parentView.mark }); }
        else if (parentView instanceof LineView || parent.nodeName == "DIV" && parent.parentNode == view.contentDOM)
            { return { range: range, text: textNode, marks: marks, line: parent }; }
        else if (parent != view.contentDOM)
            { marks.push({ node: parent, deco: new MarkDecoration({
                    inclusive: true,
                    attributes: getAttrs(parent),
                    tagName: parent.tagName.toLowerCase()
                }) }); }
        else
            { return null; }
    }
}
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);
}
var DecorationComparator$1 = /*@__PURE__*/(function () {
    function DecorationComparator() {
        this.changes = [];
    }
    DecorationComparator.prototype.compareRange = function compareRange (from, to) { addRange(from, to, this.changes); };
    DecorationComparator.prototype.comparePoint = function comparePoint (from, to) { addRange(from, to, this.changes); };

    return DecorationComparator;
}());
function findChangedDeco(a, b, diff) {
    var comp = new DecorationComparator$1;
    RangeSet.compare(a, b, diff, comp);
    return comp.changes;
}
function inUneditable(node, inside) {
    for (var 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) {
    var touched = false;
    if (composition)
        { changes.iterChangedRanges(function (from, to) {
            if (from < composition.to && to > composition.from)
                { touched = true; }
        }); }
    return touched;
}

function groupAt(state, pos, bias) {
    if ( bias === void 0 ) bias = 1;

    var categorize = state.charCategorizer(pos);
    var 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; }
    var from = linePos, to = linePos;
    if (bias < 0)
        { from = findClusterBreak(line.text, linePos, false); }
    else
        { to = findClusterBreak(line.text, linePos); }
    var cat = categorize(line.text.slice(from, to));
    while (from > 0) {
        var prev = findClusterBreak(line.text, from, false);
        if (categorize(line.text.slice(prev, from)) != cat)
            { break; }
        from = prev;
    }
    while (to < line.length) {
        var 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);
}
// Search the DOM for the {node, offset} position closest to the given
// coordinates. Very inefficient and crude, but can usually be avoided
// by calling caret(Position|Range)FromPoint instead.
function getdx(x, rect) {
    return rect.left > x ? rect.left - x : Math.max(0, x - rect.right);
}
function getdy(y, rect) {
    return rect.top > y ? rect.top - y : Math.max(0, y - rect.bottom);
}
function yOverlap(a, b) {
    return a.top < b.bottom - 1 && a.bottom > b.top + 1;
}
function upTop(rect, top) {
    return top < rect.top ? { top: top, left: rect.left, right: rect.right, bottom: rect.bottom } : rect;
}
function upBot(rect, bottom) {
    return bottom > rect.bottom ? { top: rect.top, left: rect.left, right: rect.right, bottom: bottom } : rect;
}
function domPosAtCoords(parent, x, y) {
    var closest, closestRect, closestX, closestY, closestOverlap = false;
    var above, below, aboveRect, belowRect;
    for (var child = parent.firstChild; child; child = child.nextSibling) {
        var rects = clientRectsFor(child);
        for (var i = 0; i < rects.length; i++) {
            var rect = rects[i];
            if (closestRect && yOverlap(closestRect, rect))
                { rect = upTop(upBot(rect, closestRect.bottom), closestRect.top); }
            var dx = getdx(x, rect), dy = getdy(y, rect);
            if (dx == 0 && dy == 0)
                { return child.nodeType == 3 ? domPosInText(child, x, y) : domPosAtCoords(child, x, y); }
            if (!closest || closestY > dy || closestY == dy && closestX > dx) {
                closest = child;
                closestRect = rect;
                closestX = dx;
                closestY = dy;
                var side = dy ? (y < rect.top ? -1 : 1) : dx ? (x < rect.left ? -1 : 1) : 0;
                closestOverlap = !side || (side > 0 ? i < rects.length - 1 : i > 0);
            }
            if (dx == 0) {
                if (y > rect.bottom && (!aboveRect || aboveRect.bottom < rect.bottom)) {
                    above = child;
                    aboveRect = rect;
                }
                else if (y < rect.top && (!belowRect || belowRect.top > rect.top)) {
                    below = child;
                    belowRect = rect;
                }
            }
            else if (aboveRect && yOverlap(aboveRect, rect)) {
                aboveRect = upBot(aboveRect, rect.bottom);
            }
            else if (belowRect && yOverlap(belowRect, rect)) {
                belowRect = upTop(belowRect, rect.top);
            }
        }
    }
    if (aboveRect && aboveRect.bottom >= y) {
        closest = above;
        closestRect = aboveRect;
    }
    else if (belowRect && belowRect.top <= y) {
        closest = below;
        closestRect = belowRect;
    }
    if (!closest)
        { return { node: parent, offset: 0 }; }
    var clipX = Math.max(closestRect.left, Math.min(closestRect.right, x));
    if (closest.nodeType == 3)
        { return domPosInText(closest, clipX, y); }
    if (closestOverlap && closest.contentEditable != "false")
        { return domPosAtCoords(closest, clipX, y); }
    var offset = Array.prototype.indexOf.call(parent.childNodes, closest) +
        (x >= (closestRect.left + closestRect.right) / 2 ? 1 : 0);
    return { node: parent, offset: offset };
}
function domPosInText(node, x, y) {
    var len = node.nodeValue.length;
    var closestOffset = -1, closestDY = 1e9, generalSide = 0;
    for (var i = 0; i < len; i++) {
        var rects = textRange(node, i, i + 1).getClientRects();
        for (var j = 0; j < rects.length; j++) {
            var rect = rects[j];
            if (rect.top == rect.bottom)
                { continue; }
            if (!generalSide)
                { generalSide = x - rect.left; }
            var dy = (rect.top > y ? rect.top - y : y - rect.bottom) - 1;
            if (rect.left - 1 <= x && rect.right + 1 >= x && dy < closestDY) {
                var right = x >= (rect.left + rect.right) / 2, after = right;
                if (browser.chrome || browser.gecko) {
                    // Check for RTL on browsers that support getting client
                    // rects for empty ranges.
                    var rectBefore = textRange(node, i).getBoundingClientRect();
                    if (rectBefore.left == rect.right)
                        { after = !right; }
                }
                if (dy <= 0)
                    { return { node: node, offset: i + (after ? 1 : 0) }; }
                closestOffset = i + (after ? 1 : 0);
                closestDY = dy;
            }
        }
    }
    return { node: node, offset: closestOffset > -1 ? closestOffset : generalSide > 0 ? node.nodeValue.length : 0 };
}
function posAtCoords(view, coords, precise, bias) {
    var assign, assign$1, assign$2;

    if ( bias === void 0 ) bias = -1;
    var _a, _b;
    var content = view.contentDOM.getBoundingClientRect(), docTop = content.top + view.viewState.paddingTop;
    var block;
    var ref = view.viewState;
    var docHeight = ref.docHeight;
    var x = coords.x;
    var y = coords.y;
    var yOffset = y - docTop;
    if (yOffset < 0)
        { return 0; }
    if (yOffset > docHeight)
        { return view.state.doc.length; }
    // Scan for a text block near the queried y position
    for (var halfLine = view.viewState.heightOracle.textHeight / 2, bounced = false;;) {
        block = view.elementAtHeight(yOffset);
        if (block.type == BlockType.Text)
            { break; }
        for (;;) {
            // Move the y position out of this block
            yOffset = bias > 0 ? block.bottom + halfLine : block.top - halfLine;
            if (yOffset >= 0 && yOffset <= docHeight)
                { break; }
            // If the document consists entirely of replaced widgets, we
            // won't find a text block, so return 0
            if (bounced)
                { return precise ? null : 0; }
            bounced = true;
            bias = -bias;
        }
    }
    y = docTop + yOffset;
    var lineStart = block.from;
    // If this is outside of the rendered viewport, we can't determine a position
    if (lineStart < view.viewport.from)
        { return view.viewport.from == 0 ? 0 : precise ? null : posAtCoordsImprecise(view, content, block, x, y); }
    if (lineStart > view.viewport.to)
        { return view.viewport.to == view.state.doc.length ? view.state.doc.length :
            precise ? null : posAtCoordsImprecise(view, content, block, x, y); }
    // Prefer ShadowRootOrDocument.elementFromPoint if present, fall back to document if not
    var doc = view.dom.ownerDocument;
    var root = view.root.elementFromPoint ? view.root : doc;
    var element = root.elementFromPoint(x, y);
    if (element && !view.contentDOM.contains(element))
        { element = null; }
    // If the element is unexpected, clip x at the sides of the content area and try again
    if (!element) {
        x = Math.max(content.left + 1, Math.min(content.right - 1, x));
        element = root.elementFromPoint(x, y);
        if (element && !view.contentDOM.contains(element))
            { element = null; }
    }
    // There's visible editor content under the point, so we can try
    // using caret(Position|Range)FromPoint as a shortcut
    var node, offset = -1;
    if (element && ((_a = view.docView.nearest(element)) === null || _a === void 0 ? void 0 : _a.isEditable) != false) {
        if (doc.caretPositionFromPoint) {
            var pos = doc.caretPositionFromPoint(x, y);
            if (pos)
                { ((assign = pos, node = assign.offsetNode, offset = assign.offset)); }
        }
        else if (doc.caretRangeFromPoint) {
            var range = doc.caretRangeFromPoint(x, y);
            if (range) {
                ((assign$1 = range, node = assign$1.startContainer, offset = assign$1.startOffset));
                if (!view.contentDOM.contains(node) ||
                    browser.safari && isSuspiciousSafariCaretResult(node, offset, x) ||
                    browser.chrome && isSuspiciousChromeCaretResult(node, offset, x))
                    { node = undefined; }
            }
        }
        // Chrome will return offsets into <input> elements without child
        // nodes, which will lead to a null deref below, so clip the
        // offset to the node size.
        if (node)
            { offset = Math.min(maxOffset(node), offset); }
    }
    // No luck, do our own (potentially expensive) search
    if (!node || !view.docView.dom.contains(node)) {
        var line = LineView.find(view.docView, lineStart);
        if (!line)
            { return yOffset > block.top + block.height / 2 ? block.to : block.from; }
        ((assign$2 = domPosAtCoords(line.dom, x, y), node = assign$2.node, offset = assign$2.offset));
    }
    var nearest = view.docView.nearest(node);
    if (!nearest)
        { return null; }
    if (nearest.isWidget && ((_b = nearest.dom) === null || _b === void 0 ? void 0 : _b.nodeType) == 1) {
        var rect = nearest.dom.getBoundingClientRect();
        return coords.y < rect.top || coords.y <= rect.bottom && coords.x <= (rect.left + rect.right) / 2
            ? nearest.posAtStart : nearest.posAtEnd;
    }
    else {
        return nearest.localPosFromDOM(node, offset) + nearest.posAtStart;
    }
}
function posAtCoordsImprecise(view, contentRect, block, x, y) {
    var into = Math.round((x - contentRect.left) * view.defaultCharacterWidth);
    if (view.lineWrapping && block.height > view.defaultLineHeight * 1.5) {
        var textHeight = view.viewState.heightOracle.textHeight;
        var line = Math.floor((y - block.top - (view.defaultLineHeight - textHeight) * 0.5) / textHeight);
        into += line * view.viewState.heightOracle.lineLength;
    }
    var content = view.state.sliceDoc(block.from, block.to);
    return block.from + findColumn(content, into, view.state.tabSize);
}
// In case of a high line height, Safari's caretRangeFromPoint treats
// the space between lines as belonging to the last character of the
// line before. This is used to detect such a result so that it can be
// ignored (issue #401).
function isSuspiciousSafariCaretResult(node, offset, x) {
    var len;
    if (node.nodeType != 3 || offset != (len = node.nodeValue.length))
        { return false; }
    for (var next = node.nextSibling; next; next = next.nextSibling)
        { if (next.nodeType != 1 || next.nodeName != "BR")
            { return false; } }
    return textRange(node, len - 1, len).getBoundingClientRect().left > x;
}
// Chrome will move positions between lines to the start of the next line
function isSuspiciousChromeCaretResult(node, offset, x) {
    if (offset != 0)
        { return false; }
    for (var cur = node;;) {
        var parent = cur.parentNode;
        if (!parent || parent.nodeType != 1 || parent.firstChild != cur)
            { return false; }
        if (parent.classList.contains("cm-line"))
            { break; }
        cur = parent;
    }
    var rect = node.nodeType == 1 ? node.getBoundingClientRect()
        : textRange(node, 0, Math.max(node.nodeValue.length, 1)).getBoundingClientRect();
    return x - rect.left > 5;
}
function blockAt(view, pos) {
    var line = view.lineBlockAt(pos);
    if (Array.isArray(line.type))
        { for (var l of line.type) {
            if (l.to > pos || l.to == pos && (l.to == line.to || l.type == BlockType.Text))
                { return l; }
        } }
    return line;
}
function moveToLineBoundary(view, start, forward, includeWrap) {
    var line = blockAt(view, start.head);
    var 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) {
        var editorRect = view.dom.getBoundingClientRect();
        var direction = view.textDirectionAt(line.from);
        var 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) {
    var line = view.state.doc.lineAt(start.head), spans = view.bidiSpans(line);
    var direction = view.textDirectionAt(line.from);
    for (var cur = start, check = null;;) {
        var 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) {
    var categorize = view.state.charCategorizer(pos);
    var cat = categorize(start);
    return function (next) {
        var nextCat = categorize(next);
        if (cat == CharCategory.Space)
            { cat = nextCat; }
        return cat == nextCat;
    };
}
function moveVertically(view, start, forward, distance) {
    var startPos = start.head, dir = forward ? 1 : -1;
    if (startPos == (forward ? view.state.doc.length : 0))
        { return EditorSelection.cursor(startPos, start.assoc); }
    var goal = start.goalColumn, startY;
    var rect = view.contentDOM.getBoundingClientRect();
    var startCoords = view.coordsAtPos(startPos, start.assoc || -1), docTop = view.documentTop;
    if (startCoords) {
        if (goal == null)
            { goal = startCoords.left - rect.left; }
        startY = dir < 0 ? startCoords.top : startCoords.bottom;
    }
    else {
        var 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;
    }
    var resolvedGoal = rect.left + goal;
    var dist = distance !== null && distance !== void 0 ? distance : (view.viewState.heightOracle.textHeight >> 1);
    for (var extra = 0;; extra += 10) {
        var curY = startY + (dist + extra) * dir;
        var pos = posAtCoords(view, { x: resolvedGoal, y: curY }, false, dir);
        if (curY < rect.top || curY > rect.bottom || (dir < 0 ? pos < startPos : pos > startPos)) {
            var charRect = view.docView.coordsForChar(pos);
            var assoc = !charRect || curY < charRect.top ? -1 : 1;
            return EditorSelection.cursor(pos, assoc, undefined, goal);
        }
    }
}
function skipAtomicRanges(atoms, pos, bias) {
    var loop = function (  ) {
        var moved = 0;
        for (var set of atoms) {
            set.between(pos - 1, pos + 1, function (from, to, value) {
                if (pos > from && pos < to) {
                    var side = moved || bias || (pos - from < to - pos ? -1 : 1);
                    pos = side < 0 ? from : to;
                    moved = side;
                }
            });
        }
        if (!moved)
            { return { v: pos }; }
    };

    for (;;) {
        var returned = loop(  );

        if ( returned ) return returned.v;
    }
}
function skipAtoms(view, oldPos, pos) {
    var newPos = skipAtomicRanges(view.state.facet(atomicRanges).map(function (f) { return f(view); }), pos.from, oldPos.head > pos.from ? -1 : 1);
    return newPos == pos.from ? pos : EditorSelection.cursor(newPos, newPos < pos.from ? 1 : -1);
}

var LineBreakPlaceholder = "\uffff";
var DOMReader = function DOMReader(points, state) {
    this.points = points;
    this.text = "";
    this.lineSeparator = state.facet(EditorState.lineSeparator);
};
DOMReader.prototype.append = function append (text) {
    this.text += text;
};
DOMReader.prototype.lineBreak = function lineBreak () {
    this.text += LineBreakPlaceholder;
};
DOMReader.prototype.readRange = function readRange (start, end) {
    if (!start)
        { return this; }
    var parent = start.parentNode;
    for (var cur = start;;) {
        this.findPointBefore(parent, cur);
        var oldLen = this.text.length;
        this.readNode(cur);
        var next = cur.nextSibling;
        if (next == end)
            { break; }
        var view = ContentView.get(cur), nextView = ContentView.get(next);
        if (view && nextView ? view.breakAfter :
            (view ? view.breakAfter : isBlockElement(cur)) ||
                (isBlockElement(next) && (cur.nodeName != "BR" || cur.cmIgnore) && this.text.length > oldLen))
            { this.lineBreak(); }
        cur = next;
    }
    this.findPointBefore(parent, end);
    return this;
};
DOMReader.prototype.readTextNode = function readTextNode (node) {
    var text = node.nodeValue;
    for (var point of this.points)
        if (point.node == node)
            { point.pos = this.text.length + Math.min(point.offset, text.length); }
    for (var off = 0, re = this.lineSeparator ? null : /\r\n?|\n/g;;) {
        var nextBreak = -1, breakSize = 1, m = (void 0);
        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 (var point$1 of this.points)
                if (point$1.node == node && point$1.pos > this.text.length)
                    { point$1.pos -= breakSize - 1; } }
        off = nextBreak + breakSize;
    }
};
DOMReader.prototype.readNode = function readNode (node) {
    if (node.cmIgnore)
        { return; }
    var view = ContentView.get(node);
    var fromView = view && view.overrideDOMText;
    if (fromView != null) {
        this.findPointInside(node, fromView.length);
        for (var 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);
    }
};
DOMReader.prototype.findPointBefore = function findPointBefore (node, next) {
    for (var point of this.points)
        if (point.node == node && node.childNodes[point.offset] == next)
            { point.pos = this.text.length; }
};
DOMReader.prototype.findPointInside = function findPointInside (node, length) {
    for (var 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;
    }
}
var DOMPoint = function DOMPoint(node, offset) {
    this.node = node;
    this.offset = offset;
    this.pos = -1;
};

var DOMChange = function DOMChange(view, start, end, typeOver) {
    this.typeOver = typeOver;
    this.bounds = null;
    this.text = "";
    this.domChanged = start > -1;
    var ref = view.docView;
    var iHead = ref.impreciseHead;
    var iAnchor = ref.impreciseAnchor;
    if (view.state.readOnly && start > -1) {
        // Ignore changes when the editor is read-only
        this.newSel = null;
    }
    else if (start > -1 && (this.bounds = view.docView.domBoundsAround(start, end, 0))) {
        var selPoints = iHead || iAnchor ? [] : selectionPoints(view);
        var reader = new DOMReader(selPoints, view.state);
        reader.readRange(this.bounds.startDOM, this.bounds.endDOM);
        this.text = reader.text;
        this.newSel = selectionFromPoints(selPoints, this.bounds.from);
    }
    else {
        var domSel = view.observer.selectionRange;
        var head = iHead && iHead.node == domSel.focusNode && iHead.offset == domSel.focusOffset ||
            !contains(view.contentDOM, domSel.focusNode)
            ? view.state.selection.main.head
            : view.docView.posFromDOM(domSel.focusNode, domSel.focusOffset);
        var anchor = iAnchor && iAnchor.node == domSel.anchorNode && iAnchor.offset == domSel.anchorOffset ||
            !contains(view.contentDOM, domSel.anchorNode)
            ? view.state.selection.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
        var vp = view.viewport;
        if ((browser.ios || browser.chrome) && view.state.selection.main.empty && head != anchor &&
            (vp.from > 0 || vp.to < view.state.doc.length)) {
            var from = Math.min(head, anchor), to = Math.max(head, anchor);
            var 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;
            }
        }
        this.newSel = EditorSelection.single(anchor, head);
    }
};
function applyDOMChange(view, domChange) {
    var change;
    var newSel = domChange.newSel;
    var sel = view.state.selection.main;
    var lastKey = view.inputState.lastKeyTime > Date.now() - 100 ? view.inputState.lastKeyCode : -1;
    if (domChange.bounds) {
        var ref = domChange.bounds;
        var from = ref.from;
        var to = ref.to;
        var 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";
        }
        var diff = findDiff(view.state.doc.sliceString(from, to, LineBreakPlaceholder), domChange.text, preferredPos - from, preferredSide);
        if (diff) {
            // 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 && view.state.facet(editable) || newSel.main.eq(sel))) {
        newSel = null;
    }
    if (!change && !newSel)
        { return false; }
    if (!change && domChange.typeOver && !sel.empty && newSel && newSel.main.empty) {
        // Heuristic to notice typing over a selected character
        change = { from: sel.from, to: sel.to, insert: view.state.doc.slice(sel.from, sel.to) };
    }
    else if (change && change.from >= sel.from && change.to <= sel.to &&
        (change.from != sel.from || change.to != sel.to) &&
        (sel.to - sel.from) - (change.to - change.from) <= 4) {
        // If the change is inside the selection and covers most of it,
        // assume it is a selection replace (with identical characters at
        // the start/end not included in the diff)
        change = {
            from: sel.from, to: sel.to,
            insert: view.state.doc.slice(sel.from, change.from).append(change.insert).append(view.state.doc.slice(change.to, sel.to))
        };
    }
    else 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: sel.from, to: sel.to, insert: Text.of([" "]) };
    }
    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 && !newSel.main.eq(sel)) {
        var scrollIntoView = false, userEvent = "select";
        if (view.inputState.lastSelectionTime > Date.now() - 50) {
            if (view.inputState.lastSelectionOrigin == "select")
                { scrollIntoView = true; }
            userEvent = view.inputState.lastSelectionOrigin;
        }
        view.dispatch({ selection: newSel, scrollIntoView: scrollIntoView, userEvent: userEvent });
        return true;
    }
    else {
        return false;
    }
}
function applyDOMChangeInner(view, change, newSel, lastKey) {
    if ( lastKey === void 0 ) lastKey = -1;

    if (browser.ios && view.inputState.flushIOSKey(change))
        { return true; }
    var 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; }
    var text = change.insert.toString();
    if (view.inputState.composing >= 0)
        { view.inputState.composing++; }
    var defaultTr;
    var defaultInsert = function () { return defaultTr || (defaultTr = applyDefaultInsert(view, change, newSel)); };
    if (!view.state.facet(inputHandler).some(function (h) { return h(view, change.from, change.to, text, defaultInsert); }))
        { view.dispatch(defaultInsert()); }
    return true;
}
function applyDefaultInsert(view, change, newSel) {
    var tr, startState = view.state, sel = startState.selection.main;
    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) {
        var before = sel.from < change.from ? startState.sliceDoc(sel.from, change.from) : "";
        var 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 {
        var changes = startState.changes(change);
        var 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 &&
            change.to <= sel.to && change.to >= sel.to - 10) {
            var replaced = view.state.sliceDoc(change.from, change.to);
            var compositionRange, composition = newSel && findCompositionNode(view, newSel.main.head);
            if (composition) {
                var dLen = change.insert.length - (change.to - change.from);
                compositionRange = { from: composition.from, to: composition.to - dLen };
            }
            else {
                compositionRange = view.state.doc.lineAt(sel.head);
            }
            var offset = sel.to - change.to, size = sel.to - sel.from;
            tr = startState.changeByRange(function (range) {
                if (range.from == sel.from && range.to == sel.to)
                    { return { changes: changes, range: mainSel || range.map(changes) }; }
                var to = range.to - offset, from = to - replaced.length;
                if (range.to - range.from != size || 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.
                    range.to >= compositionRange.from && range.from <= compositionRange.to)
                    { return { range: range }; }
                var rangeChanges = startState.changes({ from: from, to: 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: changes,
                selection: mainSel && startState.selection.replaceRange(mainSel)
            };
        }
    }
    var 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: userEvent, scrollIntoView: true });
}
function findDiff(a, b, preferredPos, preferredSide) {
    var minLen = Math.min(a.length, b.length);
    var from = 0;
    while (from < minLen && a.charCodeAt(from) == b.charCodeAt(from))
        { from++; }
    if (from == minLen && a.length == b.length)
        { return null; }
    var toA = a.length, toB = b.length;
    while (toA > 0 && toB > 0 && a.charCodeAt(toA - 1) == b.charCodeAt(toB - 1)) {
        toA--;
        toB--;
    }
    if (preferredSide == "end") {
        var adjust = Math.max(0, from - Math.min(toA, toB));
        preferredPos -= toA + adjust - from;
    }
    if (toA < from && a.length < b.length) {
        var move = preferredPos <= from && preferredPos >= toA ? from - preferredPos : 0;
        from -= move;
        toB = from + (toB - toA);
        toA = from;
    }
    else if (toB < from) {
        var move$1 = preferredPos <= from && preferredPos >= toB ? from - preferredPos : 0;
        from -= move$1;
        toA = from + (toA - toB);
        toB = from;
    }
    return { from: from, toA: toA, toB: toB };
}
function selectionPoints(view) {
    var result = [];
    if (view.root.activeElement != view.contentDOM)
        { return result; }
    var ref = view.observer.selectionRange;
    var anchorNode = ref.anchorNode;
    var anchorOffset = ref.anchorOffset;
    var focusNode = ref.focusNode;
    var focusOffset = ref.focusOffset;
    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; }
    var anchor = points[0].pos, head = points.length == 2 ? points[1].pos : anchor;
    return anchor > -1 && head > -1 ? EditorSelection.single(anchor + base, head + base) : null;
}

var InputState = function InputState(view) {
    this.view = view;
    this.lastKeyCode = 0;
    this.lastKeyTime = 0;
    this.lastTouchTime = 0;
    this.lastFocusTime = 0;
    this.lastScrollTop = 0;
    this.lastScrollLeft = 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;
    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", function () { return null; }); }
    if (browser.gecko)
        { firefoxCopyCutHack(view.contentDOM.ownerDocument); }
};
InputState.prototype.setSelectionOrigin = function setSelectionOrigin (origin) {
    this.lastSelectionOrigin = origin;
    this.lastSelectionTime = Date.now();
};

InputState.prototype.handleEvent = function handleEvent (event) {
    if (!eventBelongsToEditor(this.view, event) || this.ignoreDuringComposition(event))
        { return; }
    if (event.type == "keydown" && this.keydown(event))
        { return; }
    this.runHandlers(event.type, event);
};
InputState.prototype.runHandlers = function runHandlers (type, event) {
    var handlers = this.handlers[type];
    if (handlers) {
        for (var observer of handlers.observers)
            observer(this.view, event);
        for (var handler of handlers.handlers) {
            if (event.defaultPrevented)
                { break; }
            if (handler(this.view, event)) {
                event.preventDefault();
                break;
            }
        }
    }
};
InputState.prototype.ensureHandlers = function ensureHandlers (plugins) {
    var handlers = computeHandlers(plugins), prev = this.handlers, dom = this.view.contentDOM;
    for (var type in handlers)
        { if (type != "scroll") {
            var passive = !handlers[type].handlers.length;
            var exists = prev[type];
            if (exists && passive != !exists.handlers.length) {
                dom.removeEventListener(type, this.handleEvent);
                exists = null;
            }
            if (!exists)
                { dom.addEventListener(type, this.handleEvent, { passive: passive }); }
        } }
    for (var type$1 in prev)
        { if (type$1 != "scroll" && !handlers[type$1])
            { dom.removeEventListener(type$1, this.handleEvent); } }
    this.handlers = handlers;
};
InputState.prototype.keydown = function keydown (event) {
        var this$1$1 = this;

    // 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.
    var pending;
    if (browser.ios && !event.synthetic && !event.altKey && !event.metaKey &&
        ((pending = PendingKeys.find(function (key) { return key.keyCode == event.keyCode; })) && !event.ctrlKey ||
            EmacsyPendingKeys.indexOf(event.key) > -1 && event.ctrlKey && !event.shiftKey)) {
        this.pendingIOSKey = pending || event;
        setTimeout(function () { return this$1$1.flushIOSKey(); }, 250);
        return true;
    }
    if (event.keyCode != 229)
        { this.view.observer.forceFlush(); }
    return false;
};
InputState.prototype.flushIOSKey = function flushIOSKey (change) {
    var 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);
};
InputState.prototype.ignoreDuringComposition = function ignoreDuringComposition (event) {
    if (!/^key/.test(event.type))
        { 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;
};
InputState.prototype.startMouseSelection = function startMouseSelection (mouseSelection) {
    if (this.mouseSelection)
        { this.mouseSelection.destroy(); }
    this.mouseSelection = mouseSelection;
};
InputState.prototype.update = function update (update$1) {
    this.view.observer.update(update$1);
    if (this.mouseSelection)
        { this.mouseSelection.update(update$1); }
    if (this.draggedContent && update$1.docChanged)
        { this.draggedContent = this.draggedContent.map(update$1.changes); }
    if (update$1.transactions.length)
        { this.lastKeyCode = this.lastSelectionTime = 0; }
};
InputState.prototype.destroy = function destroy () {
    if (this.mouseSelection)
        { this.mouseSelection.destroy(); }
};
function bindHandler(plugin, handler) {
    return function (view, event) {
        try {
            return handler.call(plugin, event, view);
        }
        catch (e) {
            logException(view.state, e);
        }
    };
}
function computeHandlers(plugins) {
    var result = Object.create(null);
    function record(type) {
        return result[type] || (result[type] = { observers: [], handlers: [] });
    }
    for (var plugin of plugins) {
        var spec = plugin.spec;
        if (spec && spec.domEventHandlers)
            { for (var type in spec.domEventHandlers) {
                var f = spec.domEventHandlers[type];
                if (f)
                    { record(type).handlers.push(bindHandler(plugin.value, f)); }
            } }
        if (spec && spec.domEventObservers)
            { for (var type$1 in spec.domEventObservers) {
                var f$1 = spec.domEventObservers[type$1];
                if (f$1)
                    { record(type$1).observers.push(bindHandler(plugin.value, f$1)); }
            } }
    }
    for (var type$2 in handlers)
        { record(type$2).handlers.push(handlers[type$2]); }
    for (var type$3 in observers)
        { record(type$3).observers.push(observers[type$3]); }
    return result;
}
var 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" }
];
var EmacsyPendingKeys = "dthko";
// Key codes for modifier keys
var modifierCodes = [16, 17, 18, 20, 91, 92, 224, 225];
var 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));
}
var MouseSelection = function MouseSelection(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(function (f) { return f(view); });
    var 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;
};
MouseSelection.prototype.start = function start (event) {
    // When clicking outside of the selection, immediately apply the
    // effect of starting the selection
    if (this.dragging === false)
        { this.select(event); }
};
MouseSelection.prototype.move = function move (event) {
        var assign, assign$1;

    if (event.buttons == 0)
        { return this.destroy(); }
    if (this.dragging || this.dragging == null && dist(this.startEvent, event) < 10)
        { return; }
    this.select(this.lastEvent = event);
    var sx = 0, sy = 0;
    var left = 0, top = 0, right = this.view.win.innerWidth, bottom = this.view.win.innerHeight;
    if (this.scrollParents.x)
        { ((assign = this.scrollParents.x.getBoundingClientRect(), left = assign.left, right = assign.right)); }
    if (this.scrollParents.y)
        { ((assign$1 = this.scrollParents.y.getBoundingClientRect(), top = assign$1.top, bottom = assign$1.bottom)); }
    var 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);
};
MouseSelection.prototype.up = function up (event) {
    if (this.dragging == null)
        { this.select(this.lastEvent); }
    if (!this.dragging)
        { event.preventDefault(); }
    this.destroy();
};
MouseSelection.prototype.destroy = function destroy () {
    this.setScrollSpeed(0, 0);
    var doc = this.view.contentDOM.ownerDocument;
    doc.removeEventListener("mousemove", this.move);
    doc.removeEventListener("mouseup", this.up);
    this.view.inputState.mouseSelection = this.view.inputState.draggedContent = null;
};
MouseSelection.prototype.setScrollSpeed = function setScrollSpeed (sx, sy) {
        var this$1$1 = this;

    this.scrollSpeed = { x: sx, y: sy };
    if (sx || sy) {
        if (this.scrolling < 0)
            { this.scrolling = setInterval(function () { return this$1$1.scroll(); }, 50); }
    }
    else if (this.scrolling > -1) {
        clearInterval(this.scrolling);
        this.scrolling = -1;
    }
};
MouseSelection.prototype.scroll = function scroll () {
    var ref = this.scrollSpeed;
        var x = ref.x;
        var y = ref.y;
    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); }
};
MouseSelection.prototype.skipAtoms = function skipAtoms (sel) {
    var ranges = null;
    for (var i = 0; i < sel.ranges.length; i++) {
        var range = sel.ranges[i], updated = null;
        if (range.empty) {
            var pos = skipAtomicRanges(this.atoms, range.from, 0);
            if (pos != range.from)
                { updated = EditorSelection.cursor(pos, -1); }
        }
        else {
            var from = skipAtomicRanges(this.atoms, range.from, -1);
            var to = skipAtomicRanges(this.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;
};
MouseSelection.prototype.select = function select (event) {
    var ref = this;
        var view = ref.view;
        var selection = this.skipAtoms(this.style.get(event, this.extend, this.multiple));
    if (this.mustSelect || !selection.eq(view.state.selection, this.dragging === false))
        { this.view.dispatch({
            selection: selection,
            userEvent: "select.pointer"
        }); }
    this.mustSelect = false;
};
MouseSelection.prototype.update = function update (update$1) {
        var this$1$1 = this;

    if (update$1.transactions.some(function (tr) { return tr.isUserEvent("input.type"); }))
        { this.destroy(); }
    else if (this.style.update(update$1))
        { setTimeout(function () { return this$1$1.select(this$1$1.lastEvent); }, 20); }
};
function addsSelectionRange(view, event) {
    var facet = view.state.facet(clickAddsSelectionRange);
    return facet.length ? facet[0](event) : browser.mac ? event.metaKey : event.ctrlKey;
}
function dragMovesSelection(view, event) {
    var facet = view.state.facet(dragMovesSelection$1);
    return facet.length ? facet[0](event) : browser.mac ? !event.altKey : !event.ctrlKey;
}
function isInPrimarySelection(view, event) {
    var ref = view.state.selection;
    var main = ref.main;
    if (main.empty)
        { return false; }
    // On boundary clicks, check whether the coordinates are inside the
    // selection's client rectangles
    var sel = getSelection$1(view.root);
    if (!sel || sel.rangeCount == 0)
        { return true; }
    var rects = sel.getRangeAt(0).getClientRects();
    for (var i = 0; i < rects.length; i++) {
        var 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 (var node = event.target, cView = (void 0); node != view.contentDOM; node = node.parentNode)
        { if (!node || node.nodeType == 11 || ((cView = ContentView.get(node)) && cView.ignoreEvent(event)))
            { return false; } }
    return true;
}
var handlers = /*@__PURE__*/Object.create(null);
var 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.
var brokenClipboardAPI = (browser.ie && browser.ie_version < 15) ||
    (browser.ios && browser.webkit_version < 604);
function capturePaste(view) {
    var parent = view.dom.parentNode;
    if (!parent)
        { return; }
    var target = parent.appendChild(document.createElement("textarea"));
    target.style.cssText = "position: fixed; left: -10000px; top: 10px";
    target.focus();
    setTimeout(function () {
        view.focus();
        target.remove();
        doPaste(view, target.value);
    }, 50);
}
function textFilter(state, facet, text) {
    for (var filter of state.facet(facet))
        text = filter(text, state);
    return text;
}
function doPaste(view, input) {
    input = textFilter(view.state, clipboardInputFilter, input);
    var state = view.state;
    var changes, i = 1, text = state.toText(input);
    var byLine = text.lines == state.selection.ranges.length;
    var linewise = lastLinewiseCopy != null && state.selection.ranges.every(function (r) { return r.empty; }) && lastLinewiseCopy == text.toString();
    if (linewise) {
        var lastLine = -1;
        changes = state.changeByRange(function (range) {
            var line = state.doc.lineAt(range.from);
            if (line.from == lastLine)
                { return { range: range }; }
            lastLine = line.from;
            var insert = state.toText((byLine ? text.line(i++).text : input) + state.lineBreak);
            return { changes: { from: line.from, insert: insert },
                range: EditorSelection.cursor(range.from + insert.length) };
        });
    }
    else if (byLine) {
        changes = state.changeByRange(function (range) {
            var 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 = function (view) {
    view.inputState.lastScrollTop = view.scrollDOM.scrollTop;
    view.inputState.lastScrollLeft = view.scrollDOM.scrollLeft;
};
handlers.keydown = function (view, event) {
    view.inputState.setSelectionOrigin("select");
    if (event.keyCode == 27 && view.inputState.tabFocusMode != 0)
        { view.inputState.tabFocusMode = Date.now() + 2000; }
    return false;
};
observers.touchstart = function (view, e) {
    view.inputState.lastTouchTime = Date.now();
    view.inputState.setSelectionOrigin("select.pointer");
};
observers.touchmove = function (view) {
    view.inputState.setSelectionOrigin("select.pointer");
};
handlers.mousedown = function (view, event) {
    view.observer.flush();
    if (view.inputState.lastTouchTime > Date.now() - 2000)
        { return false; } // Ignore touch interaction
    var style = null;
    for (var makeStyle of view.state.facet(mouseSelectionStyle)) {
        style = makeStyle(view, event);
        if (style)
            { break; }
    }
    if (!style && event.button == 0)
        { style = basicMouseSelection(view, event); }
    if (style) {
        var mustFocus = !view.hasFocus;
        view.inputState.startMouseSelection(new MouseSelection(view, event, style, mustFocus));
        if (mustFocus)
            { view.observer.ignore(function () {
                focusPreventScroll(view.contentDOM);
                var active = view.root.activeElement;
                if (active && !active.contains(view.contentDOM))
                    { active.blur(); }
            }); }
        var mouseSel = view.inputState.mouseSelection;
        if (mouseSel) {
            mouseSel.start(event);
            return mouseSel.dragging === false;
        }
    }
    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
        var visual = LineView.find(view.docView, pos), line = view.state.doc.lineAt(visual ? visual.posAtEnd : pos);
        var 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);
    }
}
var inside = function (x, y, rect) { return y >= rect.top && y <= rect.bottom && x >= rect.left && x <= rect.right; };
// Try to determine, for the given coordinates, associated with the
// given position, whether they are related to the element before or
// the element after the position.
function findPositionSide(view, pos, x, y) {
    var line = LineView.find(view.docView, pos);
    if (!line)
        { return 1; }
    var off = pos - line.posAtStart;
    // Line boundaries point into the line
    if (off == 0)
        { return 1; }
    if (off == line.length)
        { return -1; }
    // Positions on top of an element point at that element
    var before = line.coordsAt(off, -1);
    if (before && inside(x, y, before))
        { return -1; }
    var after = line.coordsAt(off, 1);
    if (after && inside(x, y, after))
        { return 1; }
    // This is probably a line wrap point. Pick before if the point is
    // above its bottom.
    return before && before.bottom >= y ? -1 : 1;
}
function queryPos(view, event) {
    var pos = view.posAtCoords({ x: event.clientX, y: event.clientY }, false);
    return { pos: pos, bias: findPositionSide(view, pos, event.clientX, event.clientY) };
}
var BadMouseDetail = browser.ie && browser.ie_version <= 11;
var lastMouseDown = null, lastMouseDownCount = 0, lastMouseDownTime = 0;
function getClickType(event) {
    if (!BadMouseDetail)
        { return event.detail; }
    var 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) {
    var start = queryPos(view, event), type = getClickType(event);
    var startSel = view.state.selection;
    return {
        update: function update(update$1) {
            if (update$1.docChanged) {
                start.pos = update$1.changes.mapPos(start.pos);
                startSel = startSel.map(update$1.changes);
            }
        },
        get: function get(event, extend, multiple) {
            var cur = queryPos(view, event), removed;
            var range = rangeForClick(view, cur.pos, cur.bias, type);
            if (start.pos != cur.pos && !extend) {
                var startRange = rangeForClick(view, start.pos, start.bias, type);
                var from = Math.min(startRange.from, range.from), to = Math.max(startRange.to, range.to);
                range = from < range.from ? EditorSelection.range(from, to) : EditorSelection.range(to, from);
            }
            if (extend)
                { return startSel.replaceRange(startSel.main.extend(range.from, range.to)); }
            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 (var i = 0; i < sel.ranges.length; i++) {
        var ref = sel.ranges[i];
        var from = ref.from;
        var to = ref.to;
        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 = function (view, event) {
    var ref = view.state;
    var range = ref.selection.main;
    if (event.target.draggable) {
        var cView = view.docView.nearest(event.target);
        if (cView && cView.isWidget) {
            var from = cView.posAtStart, to = from + cView.length;
            if (from >= range.to || to <= range.from)
                { range = EditorSelection.range(from, to); }
        }
    }
    var inputState = view.inputState;
    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 = function (view) {
    view.inputState.draggedContent = null;
    return false;
};
function dropText(view, event, text, direct) {
    text = textFilter(view.state, clipboardInputFilter, text);
    if (!text)
        { return; }
    var dropPos = view.posAtCoords({ x: event.clientX, y: event.clientY }, false);
    var ref = view.inputState;
    var draggedContent = ref.draggedContent;
    var del = direct && draggedContent && dragMovesSelection(view, event)
        ? { from: draggedContent.from, to: draggedContent.to } : null;
    var ins = { from: dropPos, insert: text };
    var changes = view.state.changes(del ? [del, ins] : ins);
    view.focus();
    view.dispatch({
        changes: changes,
        selection: { anchor: changes.mapPos(dropPos, -1), head: changes.mapPos(dropPos, 1) },
        userEvent: del ? "move.drop" : "input.drop"
    });
    view.inputState.draggedContent = null;
}
handlers.drop = function (view, event) {
    if (!event.dataTransfer)
        { return false; }
    if (view.state.readOnly)
        { return true; }
    var files = event.dataTransfer.files;
    if (files && files.length) { // For a file drop, read the file's text.
        var text = Array(files.length), read = 0;
        var finishFile = function () {
            if (++read == files.length)
                { dropText(view, event, text.filter(function (s) { return s != null; }).join(view.state.lineBreak), false); }
        };
        var loop = function ( i ) {
            var reader = new FileReader;
            reader.onerror = finishFile;
            reader.onload = function () {
                if (!/[\x00-\x08\x0e-\x1f]{2}/.test(reader.result))
                    { text[i] = reader.result; }
                finishFile();
            };
            reader.readAsText(files[i]);
        };

        for (var i = 0; i < files.length; i++) loop( i );
        return true;
    }
    else {
        var text$1 = event.dataTransfer.getData("Text");
        if (text$1) {
            dropText(view, event, text$1, true);
            return true;
        }
    }
    return false;
};
handlers.paste = function (view, event) {
    if (view.state.readOnly)
        { return true; }
    view.observer.flush();
    var 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
    var parent = view.dom.parentNode;
    if (!parent)
        { return; }
    var 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(function () {
        target.remove();
        view.focus();
    }, 50);
}
function copiedRange(state) {
    var content = [], ranges = [], linewise = false;
    for (var 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
        var upto = -1;
        for (var { from } of state.selection.ranges) {
            var 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: ranges, linewise: linewise };
}
var lastLinewiseCopy = null;
handlers.copy = handlers.cut = function (view, event) {
    var ref = copiedRange(view.state);
    var text = ref.text;
    var ranges = ref.ranges;
    var linewise = ref.linewise;
    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"
        }); }
    var data = brokenClipboardAPI ? null : event.clipboardData;
    if (data) {
        data.clearData();
        data.setData("text/plain", text);
        return true;
    }
    else {
        captureCopy(view, text);
        return false;
    }
};
var isFocusChange = /*@__PURE__*/Annotation.define();
function focusChangeTransaction(state, focus) {
    var effects = [];
    for (var getEffect of state.facet(focusChangeEffect)) {
        var effect = getEffect(state, focus);
        if (effect)
            { effects.push(effect); }
    }
    return effects ? state.update({ effects: effects, annotations: isFocusChange.of(true) }) : null;
}
function updateForFocusChange(view) {
    setTimeout(function () {
        var focus = view.hasFocus;
        if (focus != view.inputState.notifiedFocused) {
            var tr = focusChangeTransaction(view.state, focus);
            if (tr)
                { view.dispatch(tr); }
            else
                { view.update([]); }
        }
    }, 10);
}
observers.focus = function (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 = function (view) {
    view.observer.clearSelectionRange();
    updateForFocusChange(view);
};
observers.compositionstart = observers.compositionupdate = function (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 = function (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 compositon
        view.observer.flushSoon();
    }
    else if (view.inputState.compositionPendingChange) {
        // If we found pending records, schedule a flush.
        Promise.resolve().then(function () { return view.observer.flush(); });
    }
    else {
        // Otherwise, make sure that, if no changes come in soon, the
        // composition view is cleared.
        setTimeout(function () {
            if (view.inputState.composing < 0 && view.docView.hasComposition)
                { view.update([]); }
        }, 50);
    }
};
observers.contextmenu = function (view) {
    view.inputState.lastContextMenu = Date.now();
};
handlers.beforeinput = function (view, event) {
    var _a, _b;
    // In EditContext mode, we must handle insertReplacementText events
    // directly, to make spell checking corrections work
    if (event.inputType == "insertReplacementText" && view.observer.editContext) {
        var text = (_a = event.dataTransfer) === null || _a === void 0 ? void 0 : _a.getData("text/plain"), ranges = event.getTargetRanges();
        if (text && ranges.length) {
            var r = ranges[0];
            var from = view.posAtDOM(r.startContainer, r.startOffset), to = view.posAtDOM(r.endContainer, r.endOffset);
            applyDOMChangeInner(view, { from: from, to: 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).
    var pending;
    if (browser.chrome && browser.android && (pending = PendingKeys.find(function (key) { return key.inputType == event.inputType; }))) {
        view.observer.delayAndroidKey(pending.key, pending.keyCode);
        if (pending.key == "Backspace" || pending.key == "Delete") {
            var startViewHeight = ((_b = window.visualViewport) === null || _b === void 0 ? void 0 : _b.height) || 0;
            setTimeout(function () {
                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(function () { return observers.compositionend(view, event); }, 20);
    }
    return false;
};
var 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 https://github.com/codemirror/dev/issues/1082
// and https://bugzilla.mozilla.org/show_bug.cgi?id=995961
function firefoxCopyCutHack(doc) {
    if (!appliedFirefoxHack.has(doc)) {
        appliedFirefoxHack.add(doc);
        doc.addEventListener("copy", function () { });
        doc.addEventListener("cut", function () { });
    }
}

var wrappingWhiteSpace = ["pre-wrap", "normal", "pre-line", "break-spaces"];
// Used to track, during updateHeight, if any actual heights changed
var heightChangeFlag = false;
function clearHeightChangeFlag() { heightChangeFlag = false; }
var HeightOracle = function HeightOracle(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;
};
HeightOracle.prototype.heightForGap = function heightForGap (from, to) {
    var 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;
};
HeightOracle.prototype.heightForLine = function heightForLine (length) {
    if (!this.lineWrapping)
        { return this.lineHeight; }
    var lines = 1 + Math.max(0, Math.ceil((length - this.lineLength) / (this.lineLength - 5)));
    return lines * this.lineHeight;
};
HeightOracle.prototype.setDoc = function setDoc (doc) { this.doc = doc; return this; };
HeightOracle.prototype.mustRefreshForWrapping = function mustRefreshForWrapping (whiteSpace) {
    return (wrappingWhiteSpace.indexOf(whiteSpace) > -1) != this.lineWrapping;
};
HeightOracle.prototype.mustRefreshForHeights = function mustRefreshForHeights (lineHeights) {
    var newHeight = false;
    for (var i = 0; i < lineHeights.length; i++) {
        var 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;
};
HeightOracle.prototype.refresh = function refresh (whiteSpace, lineHeight, charWidth, textHeight, lineLength, knownHeights) {
    var lineWrapping = wrappingWhiteSpace.indexOf(whiteSpace) > -1;
    var changed = Math.round(lineHeight) != Math.round(this.lineHeight) || this.lineWrapping != lineWrapping;
    this.lineWrapping = lineWrapping;
    this.lineHeight = lineHeight;
    this.charWidth = charWidth;
    this.textHeight = textHeight;
    this.lineLength = lineLength;
    if (changed) {
        this.heightSamples = {};
        for (var i = 0; i < knownHeights.length; i++) {
            var 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 nides. The `heights` array is a sequence of
// block heights, starting from position `from`.
var MeasuredHeights = function MeasuredHeights(from, heights) {
    this.from = from;
    this.heights = heights;
    this.index = 0;
};

var prototypeAccessors$13 = { more: { configurable: true } };
prototypeAccessors$13.more.get = function () { return this.index < this.heights.length; };

Object.defineProperties( MeasuredHeights.prototype, prototypeAccessors$13 );
/**
Record used to represent information about a block-level element
in the editor view.
*/
var BlockInfo = function BlockInfo(
/**
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-create line breaks for
text blocks.
*/
_content) {
    this.from = from;
    this.length = length;
    this.top = top;
    this.height = height;
    this._content = _content;
};

var prototypeAccessors$14 = { type: { configurable: true },to: { configurable: true },bottom: { configurable: true },widget: { configurable: true },widgetLineBreaks: { configurable: true } };
/**
The type of element this is. When querying lines, this may be
an array of all the blocks that make up the line.
*/
prototypeAccessors$14.type.get = function () {
    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.
*/
prototypeAccessors$14.to.get = function () { return this.from + this.length; };
/**
The bottom position of the element.
*/
prototypeAccessors$14.bottom.get = function () { return this.top + this.height; };
/**
If this is a widget block, this will return the widget
associated with it.
*/
prototypeAccessors$14.widget.get = function () {
    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.
*/
prototypeAccessors$14.widgetLineBreaks.get = function () {
    return typeof this._content == "number" ? this._content : 0;
};
/**
@internal
*/
BlockInfo.prototype.join = function join (other) {
    var 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);
};

Object.defineProperties( BlockInfo.prototype, prototypeAccessors$14 );
var QueryType = /*@__PURE__*/(function (QueryType) {
    QueryType[QueryType["ByPos"] = 0] = "ByPos";
    QueryType[QueryType["ByHeight"] = 1] = "ByHeight";
    QueryType[QueryType["ByPosNoHeight"] = 2] = "ByPosNoHeight";
return QueryType})(QueryType || (QueryType = {}));
var Epsilon$1 = 1e-3;
var HeightMap = function HeightMap(length, // The number of characters covered
height, // Height of this part of the document
flags /* Flag.Outdated */) {
    if ( flags === void 0 ) flags = 2;

    this.length = length;
    this.height = height;
    this.flags = flags;
};

var prototypeAccessors$15 = { outdated: { configurable: true } };
prototypeAccessors$15.outdated.get = function () { return (this.flags & 2 /* Flag.Outdated */) > 0; };
prototypeAccessors$15.outdated.set = function (value) { this.flags = (value ? 2 /* Flag.Outdated */ : 0) | (this.flags & ~2 /* Flag.Outdated */); };
HeightMap.prototype.setHeight = function setHeight (height) {
    if (this.height != height) {
        if (Math.abs(this.height - height) > Epsilon$1)
            { 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)
HeightMap.prototype.replace = function replace (_from, _to, nodes) {
    return HeightMap.of(nodes);
};
// Again, these are base cases, and are overridden for branch and gap nodes.
HeightMap.prototype.decomposeLeft = function decomposeLeft (_to, result) { result.push(this); };
HeightMap.prototype.decomposeRight = function decomposeRight (_from, result) { result.push(this); };
HeightMap.prototype.applyChanges = function applyChanges (decorations, oldDoc, oracle, changes) {
    var me = this, doc = oracle.doc;
    for (var i = changes.length - 1; i >= 0; i--) {
        var ref = changes[i];
            var fromA = ref.fromA;
            var toA = ref.toA;
            var fromB = ref.fromB;
            var toB = ref.toB;
        var start = me.lineAt(fromA, QueryType.ByPosNoHeight, oracle.setDoc(oldDoc), 0, 0);
        var 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;
        var nodes = NodeBuilder.build(oracle.setDoc(doc), decorations, fromB, toB);
        me = replace$1(me, me.replace(fromA, toA, nodes));
    }
    return me.updateHeight(oracle, 0);
};
HeightMap.empty = function empty () { return new HeightMapText(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).
HeightMap.of = function of (nodes) {
    if (nodes.length == 1)
        { return nodes[0]; }
    var i = 0, j = nodes.length, before = 0, after = 0;
    for (;;) {
        if (i == j) {
            if (before > after * 2) {
                var 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) {
                var split$1 = nodes[j];
                if (split$1.break)
                    { nodes.splice(j, 1, split$1.left, null, split$1.right); }
                else
                    { nodes.splice(j, 1, split$1.left, split$1.right); }
                j += 2 + split$1.break;
                after -= split$1.size;
            }
            else {
                break;
            }
        }
        else if (before < after) {
            var next = nodes[i++];
            if (next)
                { before += next.size; }
        }
        else {
            var next$1 = nodes[--j];
            if (next$1)
                { after += next$1.size; }
        }
    }
    var 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)));
};

Object.defineProperties( HeightMap.prototype, prototypeAccessors$15 );
function replace$1(old, val) {
    if (old == val)
        { return old; }
    if (old.constructor != val.constructor)
        { heightChangeFlag = true; }
    return val;
}
HeightMap.prototype.size = 1;
var HeightMapBlock = /*@__PURE__*/(function (HeightMap) {
    function HeightMapBlock(length, height, deco) {
        HeightMap.call(this, length, height);
        this.deco = deco;
    }

    if ( HeightMap ) HeightMapBlock.__proto__ = HeightMap;
    HeightMapBlock.prototype = Object.create( HeightMap && HeightMap.prototype );
    HeightMapBlock.prototype.constructor = HeightMapBlock;
    HeightMapBlock.prototype.blockAt = function blockAt (_height, _oracle, top, offset) {
        return new BlockInfo(offset, this.length, top, this.height, this.deco || 0);
    };
    HeightMapBlock.prototype.lineAt = function lineAt (_value, _type, oracle, top, offset) {
        return this.blockAt(0, oracle, top, offset);
    };
    HeightMapBlock.prototype.forEachLine = function forEachLine (from, to, oracle, top, offset, f) {
        if (from <= offset + this.length && to >= offset)
            { f(this.blockAt(0, oracle, top, offset)); }
    };
    HeightMapBlock.prototype.updateHeight = function updateHeight (oracle, offset, _force, measured) {
        if ( offset === void 0 ) offset = 0;

        if (measured && measured.from <= offset && measured.more)
            { this.setHeight(measured.heights[measured.index++]); }
        this.outdated = false;
        return this;
    };
    HeightMapBlock.prototype.toString = function toString () { return ("block(" + (this.length) + ")"); };

    return HeightMapBlock;
}(HeightMap));
var HeightMapText = /*@__PURE__*/(function (HeightMapBlock) {
    function HeightMapText(length, height) {
        HeightMapBlock.call(this, 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
    }

    if ( HeightMapBlock ) HeightMapText.__proto__ = HeightMapBlock;
    HeightMapText.prototype = Object.create( HeightMapBlock && HeightMapBlock.prototype );
    HeightMapText.prototype.constructor = HeightMapText;
    HeightMapText.prototype.blockAt = function blockAt (_height, _oracle, top, offset) {
        return new BlockInfo(offset, this.length, top, this.height, this.breaks);
    };
    HeightMapText.prototype.replace = function replace (_from, _to, nodes) {
        var 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); }
            else
                { node.height = this.height; }
            if (!this.outdated)
                { node.outdated = false; }
            return node;
        }
        else {
            return HeightMap.of(nodes);
        }
    };
    HeightMapText.prototype.updateHeight = function updateHeight (oracle, offset, force, measured) {
        if ( offset === void 0 ) offset = 0;
        if ( force === void 0 ) force = false;

        if (measured && measured.from <= offset && measured.more)
            { this.setHeight(measured.heights[measured.index++]); }
        else if (force || this.outdated)
            { this.setHeight(Math.max(this.widgetHeight, oracle.heightForLine(this.length - this.collapsed)) +
                this.breaks * oracle.lineHeight); }
        this.outdated = false;
        return this;
    };
    HeightMapText.prototype.toString = function toString () {
        return ("line(" + (this.length) + (this.collapsed ? -this.collapsed : "") + (this.widgetHeight ? ":" + this.widgetHeight : "") + ")");
    };

    return HeightMapText;
}(HeightMapBlock));
var HeightMapGap = /*@__PURE__*/(function (HeightMap) {
    function HeightMapGap(length) { HeightMap.call(this, length, 0); }

    if ( HeightMap ) HeightMapGap.__proto__ = HeightMap;
    HeightMapGap.prototype = Object.create( HeightMap && HeightMap.prototype );
    HeightMapGap.prototype.constructor = HeightMapGap;
    HeightMapGap.prototype.heightMetrics = function heightMetrics (oracle, offset) {
        var firstLine = oracle.doc.lineAt(offset).number, lastLine = oracle.doc.lineAt(offset + this.length).number;
        var lines = lastLine - firstLine + 1;
        var perLine, perChar = 0;
        if (oracle.lineWrapping) {
            var 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: firstLine, lastLine: lastLine, perLine: perLine, perChar: perChar };
    };
    HeightMapGap.prototype.blockAt = function blockAt (height, oracle, top, offset) {
        var ref = this.heightMetrics(oracle, offset);
        var firstLine = ref.firstLine;
        var lastLine = ref.lastLine;
        var perLine = ref.perLine;
        var perChar = ref.perChar;
        if (oracle.lineWrapping) {
            var guess = offset + (height < oracle.lineHeight ? 0
                : Math.round(Math.max(0, Math.min(1, (height - top) / this.height)) * this.length));
            var line = oracle.doc.lineAt(guess), lineHeight = perLine + line.length * perChar;
            var lineTop = Math.max(top, height - lineHeight / 2);
            return new BlockInfo(line.from, line.length, lineTop, lineHeight, 0);
        }
        else {
            var line$1 = Math.max(0, Math.min(lastLine - firstLine, Math.floor((height - top) / perLine)));
            var ref$1 = oracle.doc.line(firstLine + line$1);
            var from = ref$1.from;
            var length = ref$1.length;
            return new BlockInfo(from, length, top + perLine * line$1, perLine, 0);
        }
    };
    HeightMapGap.prototype.lineAt = function lineAt (value, type, oracle, top, offset) {
        if (type == QueryType.ByHeight)
            { return this.blockAt(value, oracle, top, offset); }
        if (type == QueryType.ByPosNoHeight) {
            var ref = oracle.doc.lineAt(value);
            var from = ref.from;
            var to = ref.to;
            return new BlockInfo(from, to - from, 0, 0, 0);
        }
        var ref$1 = this.heightMetrics(oracle, offset);
        var firstLine = ref$1.firstLine;
        var perLine = ref$1.perLine;
        var perChar = ref$1.perChar;
        var line = oracle.doc.lineAt(value), lineHeight = perLine + line.length * perChar;
        var linesAbove = line.number - firstLine;
        var 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);
    };
    HeightMapGap.prototype.forEachLine = function forEachLine (from, to, oracle, top, offset, f) {
        from = Math.max(from, offset);
        to = Math.min(to, offset + this.length);
        var ref = this.heightMetrics(oracle, offset);
        var firstLine = ref.firstLine;
        var perLine = ref.perLine;
        var perChar = ref.perChar;
        for (var pos = from, lineTop = top; pos <= to;) {
            var line = oracle.doc.lineAt(pos);
            if (pos == from) {
                var linesAbove = line.number - firstLine;
                lineTop += perLine * linesAbove + perChar * (from - offset - linesAbove);
            }
            var lineHeight = perLine + perChar * line.length;
            f(new BlockInfo(line.from, line.length, lineTop, lineHeight, 0));
            lineTop += lineHeight;
            pos = line.to + 1;
        }
    };
    HeightMapGap.prototype.replace = function replace (from, to, nodes) {
        var after = this.length - to;
        if (after > 0) {
            var 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) {
            var 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);
    };
    HeightMapGap.prototype.decomposeLeft = function decomposeLeft (to, result) {
        result.push(new HeightMapGap(to - 1), null);
    };
    HeightMapGap.prototype.decomposeRight = function decomposeRight (from, result) {
        result.push(null, new HeightMapGap(this.length - from - 1));
    };
    HeightMapGap.prototype.updateHeight = function updateHeight (oracle, offset, force, measured) {
        if ( offset === void 0 ) offset = 0;
        if ( force === void 0 ) force = false;

        var 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).
            var 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) {
                var len = oracle.doc.lineAt(pos).length;
                if (nodes.length)
                    { nodes.push(null); }
                var height = measured.heights[measured.index++];
                if (singleHeight == -1)
                    { singleHeight = height; }
                else if (Math.abs(height - singleHeight) >= Epsilon$1)
                    { singleHeight = -2; }
                var line = new HeightMapText(len, height);
                line.outdated = false;
                nodes.push(line);
                pos += len + 1;
            }
            if (pos <= end)
                { nodes.push(null, new HeightMapGap(end - pos).updateHeight(oracle, pos)); }
            var result = HeightMap.of(nodes);
            if (singleHeight < 0 || Math.abs(result.height - this.height) >= Epsilon$1 ||
                Math.abs(singleHeight - this.heightMetrics(oracle, offset).perLine) >= Epsilon$1)
                { heightChangeFlag = true; }
            return replace$1(this, result);
        }
        else if (force || this.outdated) {
            this.setHeight(oracle.heightForGap(offset, offset + this.length));
            this.outdated = false;
        }
        return this;
    };
    HeightMapGap.prototype.toString = function toString () { return ("gap(" + (this.length) + ")"); };

    return HeightMapGap;
}(HeightMap));
var HeightMapBranch = /*@__PURE__*/(function (HeightMap) {
    function HeightMapBranch(left, brk, right) {
        HeightMap.call(this, 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;
    }

    if ( HeightMap ) HeightMapBranch.__proto__ = HeightMap;
    HeightMapBranch.prototype = Object.create( HeightMap && HeightMap.prototype );
    HeightMapBranch.prototype.constructor = HeightMapBranch;

    var prototypeAccessors$16 = { break: { configurable: true } };
    prototypeAccessors$16.break.get = function () { return this.flags & 1 /* Flag.Break */; };
    HeightMapBranch.prototype.blockAt = function blockAt (height, oracle, top, offset) {
        var 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);
    };
    HeightMapBranch.prototype.lineAt = function lineAt (value, type, oracle, top, offset) {
        var rightTop = top + this.left.height, rightOffset = offset + this.left.length + this.break;
        var left = type == QueryType.ByHeight ? value < rightTop : value < rightOffset;
        var 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; }
        var 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); }
    };
    HeightMapBranch.prototype.forEachLine = function forEachLine (from, to, oracle, top, offset, f) {
        var 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 {
            var 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); }
        }
    };
    HeightMapBranch.prototype.replace = function replace (from, to, nodes) {
        var 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)); }
        var result = [];
        if (from > 0)
            { this.decomposeLeft(from, result); }
        var left = result.length;
        for (var node of nodes)
            result.push(node);
        if (from > 0)
            { mergeGaps(result, left - 1); }
        if (to < this.length) {
            var right = result.length;
            this.decomposeRight(to, result);
            mergeGaps(result, right);
        }
        return HeightMap.of(result);
    };
    HeightMapBranch.prototype.decomposeLeft = function decomposeLeft (to, result) {
        var 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); }
    };
    HeightMapBranch.prototype.decomposeRight = function decomposeRight (from, result) {
        var 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);
    };
    HeightMapBranch.prototype.balanced = function 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$1(this.left, left);
        this.right = replace$1(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;
    };
    HeightMapBranch.prototype.updateHeight = function updateHeight (oracle, offset, force, measured) {
        if ( offset === void 0 ) offset = 0;
        if ( force === void 0 ) force = false;

        var ref = this;
        var left = ref.left;
        var right = ref.right;
        var 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;
    };
    HeightMapBranch.prototype.toString = function toString () { return this.left + (this.break ? " " : "-") + this.right; };

    Object.defineProperties( HeightMapBranch.prototype, prototypeAccessors$16 );

    return HeightMapBranch;
}(HeightMap));
function mergeGaps(nodes, around) {
    var 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)); }
}
var relevantWidgetHeight = 5;
var NodeBuilder = function NodeBuilder(pos, oracle) {
    this.pos = pos;
    this.oracle = oracle;
    this.nodes = [];
    this.lineStart = -1;
    this.lineEnd = -1;
    this.covering = null;
    this.writtenTo = pos;
};

var prototypeAccessors$17 = { isCovered: { configurable: true } };
prototypeAccessors$17.isCovered.get = function () {
    return this.covering && this.nodes[this.nodes.length - 1] == this.covering;
};
NodeBuilder.prototype.span = function span (_from, to) {
    if (this.lineStart > -1) {
        var 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)); }
        this.writtenTo = end;
        if (to > end) {
            this.nodes.push(null);
            this.writtenTo++;
            this.lineStart = -1;
        }
    }
    this.pos = to;
};
NodeBuilder.prototype.point = function point (from, to, deco) {
    if (from < to || deco.heightRelevant) {
        var height = deco.widget ? deco.widget.estimatedHeight : 0;
        var breaks = deco.widget ? deco.widget.lineBreaks : 0;
        if (height < 0)
            { height = this.oracle.lineHeight; }
        var 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; }
};
NodeBuilder.prototype.enterLine = function enterLine () {
    if (this.lineStart > -1)
        { return; }
    var ref = this.oracle.doc.lineAt(this.pos);
        var from = ref.from;
        var to = ref.to;
    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)); }
    this.writtenTo = this.pos;
};
NodeBuilder.prototype.blankContent = function blankContent (from, to) {
    var gap = new HeightMapGap(to - from);
    if (this.oracle.doc.lineAt(from).to == to)
        { gap.flags |= 4 /* Flag.SingleLine */; }
    return gap;
};
NodeBuilder.prototype.ensureLine = function ensureLine () {
    this.enterLine();
    var last = this.nodes.length ? this.nodes[this.nodes.length - 1] : null;
    if (last instanceof HeightMapText)
        { return last; }
    var line = new HeightMapText(0, -1);
    this.nodes.push(line);
    return line;
};
NodeBuilder.prototype.addBlock = function addBlock (block) {
    this.enterLine();
    var 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; }
};
NodeBuilder.prototype.addLineDeco = function addLineDeco (height, breaks, length) {
    var 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;
};
NodeBuilder.prototype.finish = function finish (from) {
    var 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)); }
    else if (this.writtenTo < this.pos || last == null)
        { this.nodes.push(this.blankContent(this.writtenTo, this.pos)); }
    var pos = from;
    for (var 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.
NodeBuilder.build = function build (oracle, decorations, from, to) {
    var builder = new NodeBuilder(from, oracle);
    RangeSet.spans(decorations, from, to, builder, 0);
    return builder.finish(from);
};

Object.defineProperties( NodeBuilder.prototype, prototypeAccessors$17 );
function heightRelevantDecoChanges(a, b, diff) {
    var comp = new DecorationComparator;
    RangeSet.compare(a, b, diff, comp, 0);
    return comp.changes;
}
var DecorationComparator = function DecorationComparator() {
    this.changes = [];
};
DecorationComparator.prototype.compareRange = function compareRange () { };
DecorationComparator.prototype.comparePoint = function comparePoint (from, to, a, b) {
    if (from < to || a && a.heightRelevant || b && b.heightRelevant)
        { addRange(from, to, this.changes, 5); }
};

function visiblePixelRange(dom, paddingTop) {
    var rect = dom.getBoundingClientRect();
    var doc = dom.ownerDocument, win = doc.defaultView || window;
    var left = Math.max(0, rect.left), right = Math.min(win.innerWidth, rect.right);
    var top = Math.max(0, rect.top), bottom = Math.min(win.innerHeight, rect.bottom);
    for (var parent = dom.parentNode; parent && parent != doc.body;) {
        if (parent.nodeType == 1) {
            var elt = parent;
            var style = window.getComputedStyle(elt);
            if ((elt.scrollHeight > elt.clientHeight || elt.scrollWidth > elt.clientWidth) &&
                style.overflow != "visible") {
                var 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 fullPixelRange(dom, paddingTop) {
    var 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.
var LineGap = function LineGap(from, to, size, displaySize) {
    this.from = from;
    this.to = to;
    this.size = size;
    this.displaySize = displaySize;
};
LineGap.same = function same (a, b) {
    if (a.length != b.length)
        { return false; }
    for (var i = 0; i < a.length; i++) {
        var gA = a[i], gB = b[i];
        if (gA.from != gB.from || gA.to != gB.to || gA.size != gB.size)
            { return false; }
    }
    return true;
};
LineGap.prototype.draw = function draw (viewState, wrapping) {
    return Decoration.replace({
        widget: new LineGapWidget(this.displaySize * (wrapping ? viewState.scaleY : viewState.scaleX), wrapping)
    }).range(this.from, this.to);
};
var LineGapWidget = /*@__PURE__*/(function (WidgetType) {
    function LineGapWidget(size, vertical) {
        WidgetType.call(this);
        this.size = size;
        this.vertical = vertical;
    }

    if ( WidgetType ) LineGapWidget.__proto__ = WidgetType;
    LineGapWidget.prototype = Object.create( WidgetType && WidgetType.prototype );
    LineGapWidget.prototype.constructor = LineGapWidget;

    var prototypeAccessors$18 = { estimatedHeight: { configurable: true } };
    LineGapWidget.prototype.eq = function eq (other) { return other.size == this.size && other.vertical == this.vertical; };
    LineGapWidget.prototype.toDOM = function toDOM () {
        var 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;
    };
    prototypeAccessors$18.estimatedHeight.get = function () { return this.vertical ? this.size : -1; };

    Object.defineProperties( LineGapWidget.prototype, prototypeAccessors$18 );

    return LineGapWidget;
}(WidgetType));
var ViewState = function ViewState(state) {
    var this$1$1 = this;

    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
    this.scrollTop = 0; // Last seen scrollDOM.scrollTop, scaled
    this.scrolledToBottom = false;
    // The CSS-transformation scale of the editor (transformed size /
    // concrete size)
    this.scaleX = 1;
    this.scaleY = 1;
    // 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;
    var guessWrapping = state.facet(contentAttributes).some(function (v) { return typeof v != "function" && v.class == "cm-lineWrapping"; });
    this.heightOracle = new HeightOracle(guessWrapping);
    this.stateDeco = state.facet(decorations).filter(function (d) { return typeof d != "function"; });
    this.heightMap = HeightMap.empty().applyChanges(this.stateDeco, Text.empty, this.heightOracle.setDoc(state.doc), [new ChangedRange(0, 0, 0, state.doc.length)]);
    for (var 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(function (gap) { return gap.draw(this$1$1, false); }));
    this.computeVisibleRanges();
};

var prototypeAccessors$19 = { visibleTop: { configurable: true },visibleBottom: { configurable: true },docHeight: { configurable: true },contentHeight: { configurable: true } };
ViewState.prototype.updateForViewport = function updateForViewport () {
        var this$1$1 = this;

    var viewports = [this.viewport];
        var ref = this.state.selection;
        var main = ref.main;
    var loop = function ( i ) {
        var pos = i ? main.head : main.anchor;
        if (!viewports.some(function (ref) {
                var from = ref.from;
                var to = ref.to;

                return pos >= from && pos <= to;
            })) {
            var ref$1 = this$1$1.lineBlockAt(pos);
                var from = ref$1.from;
                var to = ref$1.to;
            viewports.push(new Viewport(from, to));
        }
    };

        for (var i = 0; i <= 1; i++) loop( i );
    this.viewports = viewports.sort(function (a, b) { return a.from - b.from; });
    return this.updateScaler();
};
ViewState.prototype.updateScaler = function updateScaler () {
    var 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 */;
};
ViewState.prototype.updateViewportLines = function updateViewportLines () {
        var this$1$1 = this;

    this.viewportLines = [];
    this.heightMap.forEachLine(this.viewport.from, this.viewport.to, this.heightOracle.setDoc(this.state.doc), 0, 0, function (block) {
        this$1$1.viewportLines.push(scaleBlock(block, this$1$1.scaler));
    });
};
ViewState.prototype.update = function update (update$1, scrollTarget) {
        if ( scrollTarget === void 0 ) scrollTarget = null;

    this.state = update$1.state;
    var prevDeco = this.stateDeco;
    this.stateDeco = this.state.facet(decorations).filter(function (d) { return typeof d != "function"; });
    var contentChanges = update$1.changedRanges;
    var heightChanges = ChangedRange.extendWithRanges(contentChanges, heightRelevantDecoChanges(prevDeco, this.stateDeco, update$1 ? update$1.changes : ChangeSet.empty(this.state.doc.length)));
    var prevHeight = this.heightMap.height;
    var scrollAnchor = this.scrolledToBottom ? null : this.scrollAnchorAt(this.scrollTop);
    clearHeightChangeFlag();
    this.heightMap = this.heightMap.applyChanges(this.stateDeco, update$1.startState.doc, this.heightOracle.setDoc(this.state.doc), heightChanges);
    if (this.heightMap.height != prevHeight || heightChangeFlag)
        { update$1.flags |= 2 /* UpdateFlag.Height */; }
    if (scrollAnchor) {
        this.scrollAnchorPos = update$1.changes.mapPos(scrollAnchor.from, -1);
        this.scrollAnchorHeight = scrollAnchor.top;
    }
    else {
        this.scrollAnchorPos = -1;
        this.scrollAnchorHeight = this.heightMap.height;
    }
    var viewport = heightChanges.length ? this.mapViewport(this.viewport, update$1.changes) : this.viewport;
    if (scrollTarget && (scrollTarget.range.head < viewport.from || scrollTarget.range.head > viewport.to) ||
        !this.viewportIsAppropriate(viewport))
        { viewport = this.getViewport(0, scrollTarget); }
    var viewportChange = viewport.from != this.viewport.from || viewport.to != this.viewport.to;
    this.viewport = viewport;
    update$1.flags |= this.updateForViewport();
    if (viewportChange || !update$1.changes.empty || (update$1.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$1.changes))); }
    update$1.flags |= this.computeVisibleRanges();
    if (scrollTarget)
        { this.scrollTarget = scrollTarget; }
    if (!this.mustEnforceCursorAssoc && update$1.selectionSet && update$1.view.lineWrapping &&
        update$1.state.selection.main.empty && update$1.state.selection.main.assoc &&
        !update$1.state.facet(nativeSelectionHidden))
        { this.mustEnforceCursorAssoc = true; }
};
ViewState.prototype.measure = function measure (view) {
    var dom = view.contentDOM, style = window.getComputedStyle(dom);
    var oracle = this.heightOracle;
    var whiteSpace = style.whiteSpace;
    this.defaultTextDirection = style.direction == "rtl" ? Direction.RTL : Direction.LTR;
    var refresh = this.heightOracle.mustRefreshForWrapping(whiteSpace);
    var domRect = dom.getBoundingClientRect();
    var measureContent = refresh || this.mustMeasureContent || this.contentDOMHeight != domRect.height;
    this.contentDOMHeight = domRect.height;
    this.mustMeasureContent = false;
    var result = 0, bias = 0;
    if (domRect.width && domRect.height) {
        var ref = getScale(dom, domRect);
            var scaleX = ref.scaleX;
            var scaleY = ref.scaleY;
        if (scaleX > .005 && Math.abs(this.scaleX - scaleX) > .005 ||
            scaleY > .005 && Math.abs(this.scaleY - scaleY) > .005) {
            this.scaleX = scaleX;
            this.scaleY = scaleY;
            result |= 8 /* UpdateFlag.Geometry */;
            refresh = measureContent = true;
        }
    }
    // Vertical padding
    var paddingTop = (parseInt(style.paddingTop) || 0) * this.scaleY;
    var paddingBottom = (parseInt(style.paddingBottom) || 0) * this.scaleY;
    if (this.paddingTop != paddingTop || this.paddingBottom != paddingBottom) {
        this.paddingTop = paddingTop;
        this.paddingBottom = paddingBottom;
        result |= 8 /* UpdateFlag.Geometry */ | 2 /* UpdateFlag.Height */;
    }
    if (this.editorWidth != view.scrollDOM.clientWidth) {
        if (oracle.lineWrapping)
            { measureContent = true; }
        this.editorWidth = view.scrollDOM.clientWidth;
        result |= 8 /* UpdateFlag.Geometry */;
    }
    var scrollTop = view.scrollDOM.scrollTop * this.scaleY;
    if (this.scrollTop != scrollTop) {
        this.scrollAnchorHeight = -1;
        this.scrollTop = scrollTop;
    }
    this.scrolledToBottom = isScrolledToBottom(view.scrollDOM);
    // Pixel viewport
    var pixelViewport = (this.printing ? fullPixelRange : visiblePixelRange)(dom, this.paddingTop);
    var dTop = pixelViewport.top - this.pixelViewport.top, dBottom = pixelViewport.bottom - this.pixelViewport.bottom;
    this.pixelViewport = pixelViewport;
    var 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)
        { return 0; }
    var contentWidth = domRect.width;
    if (this.contentDOMWidth != contentWidth || this.editorHeight != view.scrollDOM.clientHeight) {
        this.contentDOMWidth = domRect.width;
        this.editorHeight = view.scrollDOM.clientHeight;
        result |= 8 /* UpdateFlag.Geometry */;
    }
    if (measureContent) {
        var lineHeights = view.docView.measureVisibleLineHeights(this.viewport);
        if (oracle.mustRefreshForHeights(lineHeights))
            { refresh = true; }
        if (refresh || oracle.lineWrapping && Math.abs(contentWidth - this.contentDOMWidth) > oracle.charWidth) {
            var ref$1 = view.docView.measureTextSize();
                var lineHeight = ref$1.lineHeight;
                var charWidth = ref$1.charWidth;
                var textHeight = ref$1.textHeight;
            refresh = lineHeight > 0 && oracle.refresh(whiteSpace, lineHeight, charWidth, textHeight, contentWidth / charWidth, lineHeights);
            if (refresh) {
                view.docView.minWidth = 0;
                result |= 8 /* 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 (var vp of this.viewports) {
            var 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 */; }
    }
    var 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;
};
prototypeAccessors$19.visibleTop.get = function () { return this.scaler.fromDOM(this.pixelViewport.top); };
prototypeAccessors$19.visibleBottom.get = function () { return this.scaler.fromDOM(this.pixelViewport.bottom); };
ViewState.prototype.getViewport = function 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
    var marginTop = 0.5 - Math.max(-0.5, Math.min(0.5, bias / 1000 /* VP.Margin */ / 2));
    var map = this.heightMap, oracle = this.heightOracle;
    var ref = this;
        var visibleTop = ref.visibleTop;
        var visibleBottom = ref.visibleBottom;
    var 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) {
        var ref$1 = scrollTarget.range;
            var head = ref$1.head;
        if (head < viewport.from || head > viewport.to) {
            var viewHeight = Math.min(this.editorHeight, this.pixelViewport.bottom - this.pixelViewport.top);
            var 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;
};
ViewState.prototype.mapViewport = function mapViewport (viewport, changes) {
    var 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.
ViewState.prototype.viewportIsAppropriate = function viewportIsAppropriate (ref, bias) {
        var from = ref.from;
        var to = ref.to;
        if ( bias === void 0 ) bias = 0;

    if (!this.inView)
        { return true; }
    var ref$1 = this.heightMap.lineAt(from, QueryType.ByPos, this.heightOracle, 0, 0);
        var top = ref$1.top;
    var ref$2 = this.heightMap.lineAt(to, QueryType.ByPos, this.heightOracle, 0, 0);
        var bottom = ref$2.bottom;
    var ref$3 = this;
        var visibleTop = ref$3.visibleTop;
        var visibleBottom = ref$3.visibleBottom;
    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 */);
};
ViewState.prototype.mapLineGaps = function mapLineGaps (gaps, changes) {
    if (!gaps.length || changes.empty)
        { return gaps; }
    var mapped = [];
    for (var 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.
ViewState.prototype.ensureLineGaps = function ensureLineGaps (current, mayMeasure) {
        var this$1$1 = this;

    var wrapping = this.heightOracle.lineWrapping;
    var 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 []; }
    var gaps = [];
    var addGap = function (from, to, line, structure) {
        if (to - from < halfMargin)
            { return; }
        var sel = this$1$1.state.selection.main, avoid = [sel.from];
        if (!sel.empty)
            { avoid.push(sel.to); }
        for (var 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;
            }
        }
        var gap = find(current, function (gap) { return gap.from >= line.from && gap.to <= line.to &&
            Math.abs(gap.from - from) < halfMargin && Math.abs(gap.to - to) < halfMargin &&
            !avoid.some(function (pos) { return 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(function (r) { return r.from <= to && r.to >= to; })) {
                var lineStart = mayMeasure.moveToLineBoundary(EditorSelection.cursor(to), false, true).head;
                if (lineStart > from)
                    { to = lineStart; }
            }
            var size = this$1$1.gapSize(line, from, to, structure);
            var displaySize = wrapping || size < 2000000 /* VP.MaxHorizGap */ ? size : 2000000 /* VP.MaxHorizGap */;
            gap = new LineGap(from, to, size, displaySize);
        }
        gaps.push(gap);
    };
    var checkLine = function (line) {
        if (line.length < doubleMargin || line.type != BlockType.Text)
            { return; }
        var structure = lineStructure(line.from, line.to, this$1$1.stateDeco);
        if (structure.total < doubleMargin)
            { return; }
        var target = this$1$1.scrollTarget ? this$1$1.scrollTarget.range.head : null;
        var viewFrom, viewTo;
        if (wrapping) {
            var marginHeight = (margin / this$1$1.heightOracle.lineLength) * this$1$1.heightOracle.lineHeight;
            var top, bot;
            if (target != null) {
                var targetFrac = findFraction(structure, target);
                var spaceFrac = ((this$1$1.visibleBottom - this$1$1.visibleTop) / 2 + marginHeight) / line.height;
                top = targetFrac - spaceFrac;
                bot = targetFrac + spaceFrac;
            }
            else {
                top = (this$1$1.visibleTop - line.top - marginHeight) / line.height;
                bot = (this$1$1.visibleBottom - line.top + marginHeight) / line.height;
            }
            viewFrom = findPosition(structure, top);
            viewTo = findPosition(structure, bot);
        }
        else {
            var totalWidth = structure.total * this$1$1.heightOracle.charWidth;
            var marginWidth = margin * this$1$1.heightOracle.charWidth;
            var horizOffset = 0;
            if (totalWidth > 2000000 /* VP.MaxHorizGap */)
                { for (var old of current) {
                    if (old.from >= line.from && old.from < line.to && old.size != old.displaySize &&
                        old.from * this$1$1.heightOracle.charWidth + horizOffset < this$1$1.pixelViewport.left)
                        { horizOffset = old.size - old.displaySize; }
                } }
            var pxLeft = this$1$1.pixelViewport.left + horizOffset, pxRight = this$1$1.pixelViewport.right + horizOffset;
            var left, right;
            if (target != null) {
                var targetFrac$1 = findFraction(structure, target);
                var spaceFrac$1 = ((pxRight - pxLeft) / 2 + marginWidth) / totalWidth;
                left = targetFrac$1 - spaceFrac$1;
                right = targetFrac$1 + spaceFrac$1;
            }
            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 (var line of this.viewportLines) {
        if (Array.isArray(line.type))
            { line.type.forEach(checkLine); }
        else
            { checkLine(line); }
    }
    return gaps;
};
ViewState.prototype.gapSize = function gapSize (line, from, to, structure) {
    var fraction = findFraction(structure, to) - findFraction(structure, from);
    if (this.heightOracle.lineWrapping) {
        return line.height * fraction;
    }
    else {
        return structure.total * this.heightOracle.charWidth * fraction;
    }
};
ViewState.prototype.updateLineGaps = function updateLineGaps (gaps) {
        var this$1$1 = this;

    if (!LineGap.same(gaps, this.lineGaps)) {
        this.lineGaps = gaps;
        this.lineGapDeco = Decoration.set(gaps.map(function (gap) { return gap.draw(this$1$1, this$1$1.heightOracle.lineWrapping); }));
    }
};
ViewState.prototype.computeVisibleRanges = function computeVisibleRanges () {
    var deco = this.stateDeco;
    if (this.lineGaps.length)
        { deco = deco.concat(this.lineGapDeco); }
    var ranges = [];
    RangeSet.spans(deco, this.viewport.from, this.viewport.to, {
        span: function span(from, to) { ranges.push({ from: from, to: to }); },
        point: function point() { }
    }, 20);
    var changed = ranges.length != this.visibleRanges.length ||
        this.visibleRanges.some(function (r, i) { return r.from != ranges[i].from || r.to != ranges[i].to; });
    this.visibleRanges = ranges;
    return changed ? 4 /* UpdateFlag.Viewport */ : 0;
};
ViewState.prototype.lineBlockAt = function lineBlockAt (pos) {
    return (pos >= this.viewport.from && pos <= this.viewport.to &&
        this.viewportLines.find(function (b) { return b.from <= pos && b.to >= pos; })) ||
        scaleBlock(this.heightMap.lineAt(pos, QueryType.ByPos, this.heightOracle, 0, 0), this.scaler);
};
ViewState.prototype.lineBlockAtHeight = function lineBlockAtHeight (height) {
    return (height >= this.viewportLines[0].top && height <= this.viewportLines[this.viewportLines.length - 1].bottom &&
        this.viewportLines.find(function (l) { return l.top <= height && l.bottom >= height; })) ||
        scaleBlock(this.heightMap.lineAt(this.scaler.fromDOM(height), QueryType.ByHeight, this.heightOracle, 0, 0), this.scaler);
};
ViewState.prototype.scrollAnchorAt = function scrollAnchorAt (scrollTop) {
    var block = this.lineBlockAtHeight(scrollTop + 8);
    return block.from >= this.viewport.from || this.viewportLines[0].top - scrollTop > 200 ? block : this.viewportLines[0];
};
ViewState.prototype.elementAtHeight = function elementAtHeight (height) {
    return scaleBlock(this.heightMap.blockAt(this.scaler.fromDOM(height), this.heightOracle, 0, 0), this.scaler);
};
prototypeAccessors$19.docHeight.get = function () {
    return this.scaler.toDOM(this.heightMap.height);
};
prototypeAccessors$19.contentHeight.get = function () {
    return this.docHeight + this.paddingTop + this.paddingBottom;
};

Object.defineProperties( ViewState.prototype, prototypeAccessors$19 );
var Viewport = function Viewport(from, to) {
    this.from = from;
    this.to = to;
};
function lineStructure(from, to, stateDeco) {
    var ranges = [], pos = from, total = 0;
    RangeSet.spans(stateDeco, from, to, {
        span: function span() { },
        point: function 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: to });
        total += to - pos;
    }
    return { total: total, ranges: ranges };
}
function findPosition(ref, ratio) {
    var total = ref.total;
    var ranges = ref.ranges;

    if (ratio <= 0)
        { return ranges[0].from; }
    if (ratio >= 1)
        { return ranges[ranges.length - 1].to; }
    var dist = Math.floor(total * ratio);
    for (var i = 0;; i++) {
        var ref$1 = ranges[i];
        var from = ref$1.from;
        var to = ref$1.to;
        var size = to - from;
        if (dist <= size)
            { return from + dist; }
        dist -= size;
    }
}
function findFraction(structure, pos) {
    var counted = 0;
    for (var { from, to } of structure.ranges) {
        if (pos <= to) {
            counted += pos - from;
            break;
        }
        counted += to - from;
    }
    return counted / structure.total;
}
function find(array, f) {
    for (var 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.
var IdScaler = {
    toDOM: function toDOM(n) { return n; },
    fromDOM: function fromDOM(n) { return n; },
    scale: 1,
    eq: function eq(other) { return other == this; }
};
// When the height is too big (> VP.MaxDOMHeight), scale down the
// regions outside the viewports so that the total height is
// VP.MaxDOMHeight.
var BigScaler = function BigScaler(oracle, heightMap, viewports) {
    var vpHeight = 0, base = 0, domBase = 0;
    this.viewports = viewports.map(function (ref) {
        var from = ref.from;
        var to = ref.to;

        var top = heightMap.lineAt(from, QueryType.ByPos, oracle, 0, 0).top;
        var bottom = heightMap.lineAt(to, QueryType.ByPos, oracle, 0, 0).bottom;
        vpHeight += bottom - top;
        return { from: from, to: to, top: top, bottom: bottom, domTop: 0, domBottom: 0 };
    });
    this.scale = (7000000 /* VP.MaxDOMHeight */ - vpHeight) / (heightMap.height - vpHeight);
    for (var obj of this.viewports) {
        obj.domTop = domBase + (obj.top - base) * this.scale;
        domBase = obj.domBottom = obj.domTop + (obj.bottom - obj.top);
        base = obj.bottom;
    }
};
BigScaler.prototype.toDOM = function toDOM (n) {
    for (var i = 0, base = 0, domBase = 0;; i++) {
        var 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;
    }
};
BigScaler.prototype.fromDOM = function fromDOM (n) {
    for (var i = 0, base = 0, domBase = 0;; i++) {
        var 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;
    }
};
BigScaler.prototype.eq = function eq (other) {
    if (!(other instanceof BigScaler))
        { return false; }
    return this.scale == other.scale && this.viewports.length == other.viewports.length &&
        this.viewports.every(function (vp, i) { return vp.from == other.viewports[i].from && vp.to == other.viewports[i].to; });
};
function scaleBlock(block, scaler) {
    if (scaler.scale == 1)
        { return block; }
    var 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(function (b) { return scaleBlock(b, scaler); }) : block._content);
}

var theme = /*@__PURE__*/Facet.define({ combine: function (strs) { return strs.join(" "); } });
var darkTheme = /*@__PURE__*/Facet.define({ combine: function (values) { return values.indexOf(true) > -1; } });
var baseThemeID = /*@__PURE__*/StyleModule.newName(), baseLightID = /*@__PURE__*/StyleModule.newName(), baseDarkID = /*@__PURE__*/StyleModule.newName();
var lightDarkIDs = { "&light": "." + baseLightID, "&dark": "." + baseDarkID };
function buildTheme(main, spec, scopes) {
    return new StyleModule(spec, {
        finish: function finish(sel) {
            return /&/.test(sel) ? sel.replace(/&\w*/, function (m) {
                if (m == "&")
                    { return main; }
                if (!scopes || !scopes[m])
                    { throw new RangeError(("Unsupported selector: " + m)); }
                return scopes[m];
            }) : main + " " + sel;
        }
    });
}
var 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", // https://github.com/codemirror/dev/issues/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": {
        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: "#444"
    },
    ".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",
        insetInlineStart: 0,
        zIndex: 200
    },
    "&light .cm-gutters": {
        backgroundColor: "#f5f5f5",
        color: "#6c6c6c",
        borderRight: "1px solid #ddd"
    },
    "&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-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",
    },
    ".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);

var observeOptions = {
    childList: true,
    characterData: true,
    subtree: true,
    attributes: true,
    characterDataOldValue: true
};
// IE11 has very broken mutation observers, so we also listen to
// DOMCharacterDataModified there
var useCharData = browser.ie && browser.ie_version <= 11;
var DOMObserver = function DOMObserver(view) {
    var this$1$1 = this;

    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(function (mutations) {
        for (var mut of mutations)
            this$1$1.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(function (m) { return m.type == "childList" && m.removedNodes.length ||
                m.type == "characterData" && m.oldValue.length > m.target.nodeValue.length; }))
            { this$1$1.flushSoon(); }
        else
            { this$1$1.flush(); }
    });
    if (window.EditContext && 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 = function (event) {
            this$1$1.queue.push({ target: event.target,
                type: "characterData",
                oldValue: event.prevValue });
            this$1$1.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(function () {
            var _a;
            if (((_a = this$1$1.view.docView) === null || _a === void 0 ? void 0 : _a.lastUpdate) < Date.now() - 75)
                { this$1$1.onResize(); }
        });
        this.resizeScroll.observe(view.scrollDOM);
    }
    this.addWindowListeners(this.win = view.win);
    this.start();
    if (typeof IntersectionObserver == "function") {
        this.intersection = new IntersectionObserver(function (entries) {
            if (this$1$1.parentCheck < 0)
                { this$1$1.parentCheck = setTimeout(this$1$1.listenForScroll.bind(this$1$1), 1000); }
            if (entries.length > 0 && (entries[entries.length - 1].intersectionRatio > 0) != this$1$1.intersecting) {
                this$1$1.intersecting = !this$1$1.intersecting;
                if (this$1$1.intersecting != this$1$1.view.inView)
                    { this$1$1.onScrollChanged(document.createEvent("Event")); }
            }
        }, { threshold: [0, .001] });
        this.intersection.observe(this.dom);
        this.gapIntersection = new IntersectionObserver(function (entries) {
            if (entries.length > 0 && entries[entries.length - 1].intersectionRatio > 0)
                { this$1$1.onScrollChanged(document.createEvent("Event")); }
        }, {});
    }
    this.listenForScroll();
    this.readSelectionRange();
};
DOMObserver.prototype.onScrollChanged = function onScrollChanged (e) {
    this.view.inputState.runHandlers("scroll", e);
    if (this.intersecting)
        { this.view.measure(); }
};
DOMObserver.prototype.onScroll = function onScroll (e) {
    if (this.intersecting)
        { this.flush(false); }
    if (this.editContext)
        { this.view.requestMeasure(this.editContext.measureReq); }
    this.onScrollChanged(e);
};
DOMObserver.prototype.onResize = function onResize () {
        var this$1$1 = this;

    if (this.resizeTimeout < 0)
        { this.resizeTimeout = setTimeout(function () {
            this$1$1.resizeTimeout = -1;
            this$1$1.view.requestMeasure();
        }, 50); }
};
DOMObserver.prototype.onPrint = function onPrint (event) {
        var this$1$1 = this;

    if ((event.type == "change" || !event.type) && !event.matches)
        { return; }
    this.view.viewState.printing = true;
    this.view.measure();
    setTimeout(function () {
        this$1$1.view.viewState.printing = false;
        this$1$1.view.requestMeasure();
    }, 500);
};
DOMObserver.prototype.updateGaps = function updateGaps (gaps) {
    if (this.gapIntersection && (gaps.length != this.gaps.length || this.gaps.some(function (g, i) { return g != gaps[i]; }))) {
        this.gapIntersection.disconnect();
        for (var gap of gaps)
            this.gapIntersection.observe(gap);
        this.gaps = gaps;
    }
};
DOMObserver.prototype.onSelectionChange = function onSelectionChange (event) {
    var wasChanged = this.selectionChanged;
    if (!this.readSelectionRange() || this.delayedAndroidKey)
        { return; }
    var ref = this;
        var view = ref.view;
        var sel = this.selectionRange;
    if (view.state.facet(editable) ? view.root.activeElement != this.dom : !hasSelection(this.dom, sel))
        { return; }
    var context = sel.anchorNode && view.docView.nearest(sel.anchorNode);
    if (context && context.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); }
};
DOMObserver.prototype.readSelectionRange = function readSelectionRange () {
    var ref = this;
        var view = ref.view;
    // The Selection object is broken in shadow roots in Safari. See
    // https://github.com/codemirror/dev/issues/414
    var selection = getSelection$1(view.root);
    if (!selection)
        { return false; }
    var 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; }
    var 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;
};
DOMObserver.prototype.setSelectionRange = function setSelectionRange (anchor, head) {
    this.selectionRange.set(anchor.node, anchor.offset, head.node, head.offset);
    this.selectionChanged = false;
};
DOMObserver.prototype.clearSelectionRange = function clearSelectionRange () {
    this.selectionRange.set(null, 0, null, 0);
};
DOMObserver.prototype.listenForScroll = function listenForScroll () {
    this.parentCheck = -1;
    var i = 0, changed = null;
    for (var 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 (var dom$1 of this.scrollTargets)
            dom$1.removeEventListener("scroll", this.onScroll);
        for (var dom$2 of this.scrollTargets = changed)
            dom$2.addEventListener("scroll", this.onScroll);
    }
};
DOMObserver.prototype.ignore = function ignore (f) {
    if (!this.active)
        { return f(); }
    try {
        this.stop();
        return f();
    }
    finally {
        this.start();
        this.clear();
    }
};
DOMObserver.prototype.start = function start () {
    if (this.active)
        { return; }
    this.observer.observe(this.dom, observeOptions);
    if (useCharData)
        { this.dom.addEventListener("DOMCharacterDataModified", this.onCharData); }
    this.active = true;
};
DOMObserver.prototype.stop = function stop () {
    if (!this.active)
        { return; }
    this.active = false;
    this.observer.disconnect();
    if (useCharData)
        { this.dom.removeEventListener("DOMCharacterDataModified", this.onCharData); }
};
// Throw away any pending changes
DOMObserver.prototype.clear = function 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.
DOMObserver.prototype.delayAndroidKey = function delayAndroidKey (key, keyCode) {
        var this$1$1 = this;

    var _a;
    if (!this.delayedAndroidKey) {
        var flush = function () {
            var key = this$1$1.delayedAndroidKey;
            if (key) {
                this$1$1.clearDelayedAndroidKey();
                this$1$1.view.inputState.lastKeyCode = key.keyCode;
                this$1$1.view.inputState.lastKeyTime = Date.now();
                var flushed = this$1$1.flush();
                if (!flushed && key.force)
                    { dispatchKey(this$1$1.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: key, keyCode: 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)
        }; }
};
DOMObserver.prototype.clearDelayedAndroidKey = function clearDelayedAndroidKey () {
    this.win.cancelAnimationFrame(this.flushingAndroidKey);
    this.delayedAndroidKey = null;
    this.flushingAndroidKey = -1;
};
DOMObserver.prototype.flushSoon = function flushSoon () {
        var this$1$1 = this;

    if (this.delayedFlush < 0)
        { this.delayedFlush = this.view.win.requestAnimationFrame(function () { this$1$1.delayedFlush = -1; this$1$1.flush(); }); }
};
DOMObserver.prototype.forceFlush = function forceFlush () {
    if (this.delayedFlush >= 0) {
        this.view.win.cancelAnimationFrame(this.delayedFlush);
        this.delayedFlush = -1;
    }
    this.flush();
};
DOMObserver.prototype.pendingRecords = function pendingRecords () {
    for (var mut of this.observer.takeRecords())
        this.queue.push(mut);
    return this.queue;
};
DOMObserver.prototype.processRecords = function processRecords () {
        var assign;

    var records = this.pendingRecords();
    if (records.length)
        { this.queue = []; }
    var from = -1, to = -1, typeOver = false;
    for (var record of records) {
        var range = this.readMutation(record);
        if (!range)
            { continue; }
        if (range.typeOver)
            { typeOver = true; }
        if (from == -1) {
            ((assign = range, from = assign.from, to = assign.to));
        }
        else {
            from = Math.min(range.from, from);
            to = Math.max(range.to, to);
        }
    }
    return { from: from, to: to, typeOver: typeOver };
};
DOMObserver.prototype.readChange = function readChange () {
    var ref = this.processRecords();
        var from = ref.from;
        var to = ref.to;
        var typeOver = ref.typeOver;
    var 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;
    var 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
DOMObserver.prototype.flush = function flush (readSelection) {
        if ( readSelection === void 0 ) 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(); }
    var domChange = this.readChange();
    if (!domChange) {
        this.view.requestMeasure();
        return false;
    }
    var startState = this.view.state;
    var 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 && !domChange.newSel.main.eq(this.view.state.selection.main)))
        { this.view.update([]); }
    return handled;
};
DOMObserver.prototype.readMutation = function readMutation (rec) {
    var cView = this.view.docView.nearest(rec.target);
    if (!cView || cView.ignoreMutation(rec))
        { return null; }
    cView.markDirty(rec.type == "attributes");
    if (rec.type == "attributes")
        { cView.flags |= 4 /* ViewFlag.AttrsDirty */; }
    if (rec.type == "childList") {
        var childBefore = findChild(cView, rec.previousSibling || rec.target.previousSibling, -1);
        var childAfter = findChild(cView, rec.nextSibling || rec.target.nextSibling, 1);
        return { from: childBefore ? cView.posAfter(childBefore) : cView.posAtStart,
            to: childAfter ? cView.posBefore(childAfter) : cView.posAtEnd, typeOver: false };
    }
    else if (rec.type == "characterData") {
        return { from: cView.posAtStart, to: cView.posAtEnd, typeOver: rec.target.nodeValue == rec.oldValue };
    }
    else {
        return null;
    }
};
DOMObserver.prototype.setWindow = function setWindow (win) {
    if (win != this.win) {
        this.removeWindowListeners(this.win);
        this.win = win;
        this.addWindowListeners(this.win);
    }
};
DOMObserver.prototype.addWindowListeners = function 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);
};
DOMObserver.prototype.removeWindowListeners = function 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);
};
DOMObserver.prototype.update = function update (update$1) {
    if (this.editContext) {
        this.editContext.update(update$1);
        if (update$1.startState.facet(editable) != update$1.state.facet(editable))
            { update$1.view.contentDOM.editContext = update$1.state.facet(editable) ? this.editContext.editContext : null; }
    }
};
DOMObserver.prototype.destroy = function 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 (var 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(cView, dom, dir) {
    while (dom) {
        var curView = ContentView.get(dom);
        if (curView && curView.parent == cView)
            { return curView; }
        var parent = dom.parentNode;
        dom = parent != cView.dom ? parent : dir > 0 ? dom.nextSibling : dom.previousSibling;
    }
    return null;
}
function buildSelectionRangeFromRange(view, range) {
    var assign;

    var anchorNode = range.startContainer, anchorOffset = range.startOffset;
    var focusNode = range.endContainer, focusOffset = range.endOffset;
    var curAnchor = view.docView.domAtPos(view.state.selection.main.anchor);
    // 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))
        { (assign = [focusNode, focusOffset, anchorNode, anchorOffset], anchorNode = assign[0], anchorOffset = assign[1], focusNode = assign[2], focusOffset = assign[3]); }
    return { anchorNode: anchorNode, anchorOffset: anchorOffset, focusNode: focusNode, focusOffset: focusOffset };
}
// Used to work around a Safari Selection/shadow DOM bug (#414)
function safariSelectionRangeHack(view, selection) {
    if (selection.getComposedRanges) {
        var range = selection.getComposedRanges(view.root)[0];
        if (range)
            { return buildSelectionRangeFromRange(view, range); }
    }
    var 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;
}
var EditContextManager = function EditContextManager(view) {
    var this$1$1 = this;

    // 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);
    this.resetRange(view.state);
    var 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 = function (e) {
        var ref = view.state.selection.main;
        var anchor = ref.anchor;
        var change = { from: this$1$1.toEditorPos(e.updateRangeStart),
            to: this$1$1.toEditorPos(e.updateRangeEnd),
            insert: Text.of(e.text.split("\n")) };
        // If the window doesn't include the anchor, assume changes
        // adjacent to a side go up to the anchor.
        if (change.from == this$1$1.from && anchor < this$1$1.from)
            { change.from = anchor; }
        else if (change.to == this$1$1.to && anchor > this$1$1.to)
            { change.to = anchor; }
        // Edit contexts sometimes fire empty changes
        if (change.from == change.to && !change.insert.length)
            { return; }
        this$1$1.pendingContextChange = change;
        if (!view.state.readOnly)
            { applyDOMChangeInner(view, change, EditorSelection.single(this$1$1.toEditorPos(e.selectionStart), this$1$1.toEditorPos(e.selectionEnd))); }
        // If the transaction didn't flush our change, revert it so
        // that the context is in sync with the editor state again.
        if (this$1$1.pendingContextChange) {
            this$1$1.revertPending(view.state);
            this$1$1.setSelection(view.state);
        }
    };
    this.handlers.characterboundsupdate = function (e) {
        var rects = [], prev = null;
        for (var i = this$1$1.toEditorPos(e.rangeStart), end = this$1$1.toEditorPos(e.rangeEnd); i < end; i++) {
            var 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 = function (e) {
        var deco = [];
        for (var format of e.getTextFormats()) {
            var lineStyle = format.underlineStyle, thickness = format.underlineThickness;
            if (lineStyle != "None" && thickness != "None") {
                var style = "text-decoration: underline " + (lineStyle == "Dashed" ? "dashed " : lineStyle == "Squiggle" ? "wavy " : "") + (thickness == "Thin" ? 1 : 2) + "px";
                deco.push(Decoration.mark({ attributes: { style: style } })
                    .range(this$1$1.toEditorPos(format.rangeStart), this$1$1.toEditorPos(format.rangeEnd)));
            }
        }
        view.dispatch({ effects: setEditContextFormatting.of(Decoration.set(deco)) });
    };
    this.handlers.compositionstart = function () {
        if (view.inputState.composing < 0) {
            view.inputState.composing = 0;
            view.inputState.compositionFirstChange = true;
        }
    };
    this.handlers.compositionend = function () {
        view.inputState.composing = -1;
        view.inputState.compositionFirstChange = null;
    };
    for (var event in this.handlers)
        { context.addEventListener(event, this.handlers[event]); }
    this.measureReq = { read: function (view) {
            this$1$1.editContext.updateControlBounds(view.contentDOM.getBoundingClientRect());
            var sel = getSelection$1(view.root);
            if (sel && sel.rangeCount)
                { this$1$1.editContext.updateSelectionBounds(sel.getRangeAt(0).getBoundingClientRect()); }
        } };
};
EditContextManager.prototype.applyEdits = function applyEdits (update) {
        var this$1$1 = this;

    var off = 0, abort = false, pending = this.pendingContextChange;
    update.changes.iterChanges(function (fromA, toA, _fromB, _toB, insert) {
        if (abort)
            { return; }
        var dLen = insert.length - (toA - fromA);
        if (pending && toA >= pending.to) {
            if (pending.from == fromA && pending.to == toA && pending.insert.eq(insert)) {
                pending = this$1$1.pendingContextChange = null; // Match
                off += dLen;
                this$1$1.to += dLen;
                return;
            }
            else { // Mismatch, revert
                pending = null;
                this$1$1.revertPending(update.state);
            }
        }
        fromA += off;
        toA += off;
        if (toA <= this$1$1.from) { // Before the window
            this$1$1.from += dLen;
            this$1$1.to += dLen;
        }
        else if (fromA < this$1$1.to) { // Overlaps with window
            if (fromA < this$1$1.from || toA > this$1$1.to || (this$1$1.to - this$1$1.from) + insert.length > 30000 /* CxVp.MaxSize */) {
                abort = true;
                return;
            }
            this$1$1.editContext.updateText(this$1$1.toContextPos(fromA), this$1$1.toContextPos(toA), insert.toString());
            this$1$1.to += dLen;
        }
        off += dLen;
    });
    if (pending && !abort)
        { this.revertPending(update.state); }
    return !abort;
};
EditContextManager.prototype.update = function update (update$1) {
    var reverted = this.pendingContextChange;
    if (!this.applyEdits(update$1) || !this.rangeIsValid(update$1.state)) {
        this.pendingContextChange = null;
        this.resetRange(update$1.state);
        this.editContext.updateText(0, this.editContext.text.length, update$1.state.doc.sliceString(this.from, this.to));
        this.setSelection(update$1.state);
    }
    else if (update$1.docChanged || update$1.selectionSet || reverted) {
        this.setSelection(update$1.state);
    }
    if (update$1.geometryChanged || update$1.docChanged || update$1.selectionSet)
        { update$1.view.requestMeasure(this.measureReq); }
};
EditContextManager.prototype.resetRange = function resetRange (state) {
    var ref = state.selection.main;
        var head = ref.head;
    this.from = Math.max(0, head - 10000 /* CxVp.Margin */);
    this.to = Math.min(state.doc.length, head + 10000 /* CxVp.Margin */);
};
EditContextManager.prototype.revertPending = function revertPending (state) {
    var 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));
};
EditContextManager.prototype.setSelection = function setSelection (state) {
    var ref = state.selection;
        var main = ref.main;
    var start = this.toContextPos(Math.max(this.from, Math.min(this.to, main.anchor)));
    var end = this.toContextPos(main.head);
    if (this.editContext.selectionStart != start || this.editContext.selectionEnd != end)
        { this.editContext.updateSelection(start, end); }
};
EditContextManager.prototype.rangeIsValid = function rangeIsValid (state) {
    var ref = state.selection.main;
        var head = ref.head;
    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);
};
EditContextManager.prototype.toEditorPos = function toEditorPos (contextPos) { return contextPos + this.from; };
EditContextManager.prototype.toContextPos = function toContextPos (editorPos) { return editorPos - this.from; };
EditContextManager.prototype.destroy = function destroy () {
    for (var 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.
*/
var EditorView = function EditorView(config) {
    var this$1$1 = this;
    if ( config === void 0 ) 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); }
    var dispatch = config.dispatch;
    this.dispatchTransactions = config.dispatchTransactions ||
        (dispatch && (function (trs) { return trs.forEach(function (tr) { return dispatch(tr, this$1$1); }); })) ||
        (function (trs) { return this$1$1.update(trs); });
    this.dispatch = this.dispatch.bind(this);
    this._root = (config.root || getRoot(config.parent) || document);
    this.viewState = new ViewState(config.state || EditorState.create(config));
    if (config.scrollTo && config.scrollTo.is(scrollIntoView$1))
        { this.viewState.scrollTarget = config.scrollTo.value.clip(this.viewState.state); }
    this.plugins = this.state.facet(viewPlugin).map(function (spec) { return new PluginInstance(spec); });
    for (var 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(function () { return this$1$1.requestMeasure(); }); }
};

var prototypeAccessors$20 = { state: { configurable: true },viewport: { configurable: true },visibleRanges: { configurable: true },inView: { configurable: true },composing: { configurable: true },compositionStarted: { configurable: true },root: { configurable: true },win: { configurable: true },themeClasses: { configurable: true },documentTop: { configurable: true },documentPadding: { configurable: true },scaleX: { configurable: true },scaleY: { configurable: true },viewportLineBlocks: { configurable: true },contentHeight: { configurable: true },defaultCharacterWidth: { configurable: true },defaultLineHeight: { configurable: true },textDirection: { configurable: true },lineWrapping: { configurable: true },hasFocus: { configurable: true } };
prototypeAccessors$20.state.get = function () { 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.
*/
prototypeAccessors$20.viewport.get = function () { 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.
*/
prototypeAccessors$20.visibleRanges.get = function () { return this.viewState.visibleRanges; };
/**
Returns false when the editor is entirely scrolled out of view
or otherwise hidden.
*/
prototypeAccessors$20.inView.get = function () { 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.
*/
prototypeAccessors$20.composing.get = function () { return 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.
*/
prototypeAccessors$20.compositionStarted.get = function () { return this.inputState.composing >= 0; };
/**
The document or shadow root that the view lives in.
*/
prototypeAccessors$20.root.get = function () { return this._root; };
/**
@internal
*/
prototypeAccessors$20.win.get = function () { return this.dom.ownerDocument.defaultView || window; };

EditorView.prototype.dispatch = function dispatch () {
        var ref;

        var input = [], len = arguments.length;
        while ( len-- ) input[ len ] = arguments[ len ];
    var trs = input.length == 1 && input[0] instanceof Transaction ? input
        : input.length == 1 && Array.isArray(input[0]) ? input[0]
            : [(ref = this.state).update.apply(ref, 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.
*/
EditorView.prototype.update = function update (transactions) {
        var this$1$1 = this;

    if (this.updateState != 0 /* UpdateState.Idle */)
        { throw new Error("Calls to EditorView.update are not allowed while an update is in progress"); }
    var redrawn = false, attrsChanged = false, update;
    var state = this.state;
    for (var 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;
    }
    var focus = this.hasFocus, focusFlag = 0, dispatchFocus = null;
    if (transactions.some(function (tr) { return 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.
    var 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;
    var scrollTarget = this.viewState.scrollTarget;
    try {
        this.updateState = 2 /* UpdateState.Updating */;
        for (var tr$1 of transactions) {
            if (scrollTarget)
                { scrollTarget = scrollTarget.map(tr$1.changes); }
            if (tr$1.scrollIntoView) {
                var ref = tr$1.state.selection;
                    var main = ref.main;
                scrollTarget = new ScrollTarget(main.empty ? main : EditorSelection.cursor(main.head, main.head > main.anchor ? -1 : 1));
            }
            for (var e of tr$1.effects)
                if (e.is(scrollIntoView$1))
                    { 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(function (tr) { return 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 (var listener of this.state.facet(updateListener)) {
            try {
                listener(update);
            }
            catch (e$1) {
                logException(this.state, e$1, "update listener");
            }
        } }
    if (dispatchFocus || domChange)
        { Promise.resolve().then(function () {
            if (dispatchFocus && this$1$1.state == dispatchFocus.startState)
                { this$1$1.dispatch(dispatchFocus); }
            if (domChange) {
                if (!applyDOMChange(this$1$1, domChange) && pendingKey.force)
                    { dispatchKey(this$1$1.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.)
*/
EditorView.prototype.setState = function 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 */;
    var hadFocus = this.hasFocus;
    try {
        for (var plugin of this.plugins)
            plugin.destroy(this);
        this.viewState = new ViewState(newState);
        this.plugins = newState.facet(viewPlugin).map(function (spec) { return new PluginInstance(spec); });
        this.pluginMap.clear();
        for (var plugin$1 of this.plugins)
            plugin$1.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();
};
EditorView.prototype.updatePlugins = function updatePlugins (update) {
    var prevSpecs = update.startState.facet(viewPlugin), specs = update.state.facet(viewPlugin);
    if (prevSpecs != specs) {
        var newPlugins = [];
        for (var spec of specs) {
            var found = prevSpecs.indexOf(spec);
            if (found < 0) {
                newPlugins.push(new PluginInstance(spec));
            }
            else {
                var plugin = this.plugins[found];
                plugin.mustUpdate = update;
                newPlugins.push(plugin);
            }
        }
        for (var plugin$1 of this.plugins)
            if (plugin$1.mustUpdate != update)
                { plugin$1.destroy(this); }
        this.plugins = newPlugins;
        this.pluginMap.clear();
    }
    else {
        for (var p of this.plugins)
            p.mustUpdate = update;
    }
    for (var i = 0; i < this.plugins.length; i++)
        { this.plugins[i].update(this); }
    if (prevSpecs != specs)
        { this.inputState.ensureHandlers(this.plugins); }
};
EditorView.prototype.docViewUpdate = function docViewUpdate () {
    for (var plugin of this.plugins) {
        var val = plugin.value;
        if (val && val.docViewUpdate) {
            try {
                val.docViewUpdate(this);
            }
            catch (e) {
                logException(this.state, e, "doc view update listener");
            }
        }
    }
};
/**
@internal
*/
EditorView.prototype.measure = function measure (flush) {
        var this$1$1 = this;
        var assign;

        if ( flush === void 0 ) 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(); }
    var updated = null;
    var sDOM = this.scrollDOM, scrollTop = sDOM.scrollTop * this.scaleY;
    var ref = this.viewState;
        var scrollAnchorPos = ref.scrollAnchorPos;
        var scrollAnchorHeight = ref.scrollAnchorHeight;
    if (Math.abs(scrollTop - this.viewState.scrollTop) > 1)
        { scrollAnchorHeight = -1; }
    this.viewState.scrollAnchorHeight = -1;
    try {
        for (var i = 0;; i++) {
            if (scrollAnchorHeight < 0) {
                if (isScrolledToBottom(sDOM)) {
                    scrollAnchorPos = -1;
                    scrollAnchorHeight = this.viewState.heightMap.height;
                }
                else {
                    var block = this.viewState.scrollAnchorAt(scrollTop);
                    scrollAnchorPos = block.from;
                    scrollAnchorHeight = block.top;
                }
            }
            this.updateState = 1 /* UpdateState.Measuring */;
            var changed = this.viewState.measure(this);
            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;
            }
            var measuring = [];
            // Only run measure requests in this cycle when the viewport didn't change
            if (!(changed & 4 /* UpdateFlag.Viewport */))
                { (assign = [measuring, this.measureRequests], this.measureRequests = assign[0], measuring = assign[1]); }
            var measured = measuring.map(function (m) {
                try {
                    return m.read(this$1$1);
                }
                catch (e) {
                    logException(this$1$1.state, e);
                    return BadMeasure;
                }
            });
            var 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 (var i$1 = 0; i$1 < measuring.length; i$1++)
                { if (measured[i$1] != BadMeasure) {
                    try {
                        var m = measuring[i$1];
                        if (m.write)
                            { m.write(measured[i$1], 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 {
                        var newAnchorHeight = scrollAnchorPos < 0 ? this.viewState.heightMap.height :
                            this.viewState.lineBlockAt(scrollAnchorPos).top;
                        var diff = newAnchorHeight - scrollAnchorHeight;
                        if (diff > 1 || diff < -1) {
                            scrollTop = scrollTop + diff;
                            sDOM.scrollTop = scrollTop / this.scaleY;
                            scrollAnchorHeight = -1;
                            continue;
                        }
                    }
                }
                break;
            }
        }
    }
    finally {
        this.updateState = 0 /* UpdateState.Idle */;
        this.measureScheduled = -1;
    }
    if (updated && !updated.empty)
        { for (var listener of this.state.facet(updateListener))
            listener(updated); }
};
/**
Get the CSS classes for the currently active editor themes.
*/
prototypeAccessors$20.themeClasses.get = function () {
    return baseThemeID + " " +
        (this.state.facet(darkTheme) ? baseDarkID : baseLightID) + " " +
        this.state.facet(theme);
};
EditorView.prototype.updateAttrs = function updateAttrs$1 () {
        var this$1$1 = this;

    var editorAttrs = attrsFromFacet(this, editorAttributes, {
        class: "cm-editor" + (this.hasFocus ? " cm-focused " : " ") + this.themeClasses
    });
    var contentAttrs = {
        spellcheck: "false",
        autocorrect: "off",
        autocapitalize: "off",
        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);
    var changed = this.observer.ignore(function () {
        var changedContent = updateAttrs(this$1$1.contentDOM, this$1$1.contentAttrs, contentAttrs);
        var changedEditor = updateAttrs(this$1$1.dom, this$1$1.editorAttrs, editorAttrs);
        return changedContent || changedEditor;
    });
    this.editorAttrs = editorAttrs;
    this.contentAttrs = contentAttrs;
    return changed;
};
EditorView.prototype.showAnnouncements = function showAnnouncements (trs) {
    var first = true;
    for (var tr of trs)
        for (var effect of tr.effects)
            if (effect.is(EditorView.announce)) {
                if (first)
                    { this.announceDOM.textContent = ""; }
                first = false;
                var div = this.announceDOM.appendChild(document.createElement("div"));
                div.textContent = effect.value;
            }
};
EditorView.prototype.mountStyles = function mountStyles () {
    this.styleModules = this.state.facet(styleModule);
    var nonce = this.state.facet(EditorView.cspNonce);
    StyleModule.mount(this.root, this.styleModules.concat(baseTheme$1).reverse(), nonce ? { nonce: nonce } : undefined);
};
EditorView.prototype.readMeasured = function 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.
*/
EditorView.prototype.requestMeasure = function requestMeasure (request) {
        var this$1$1 = this;

    if (this.measureScheduled < 0)
        { this.measureScheduled = this.win.requestAnimationFrame(function () { return this$1$1.measure(); }); }
    if (request) {
        if (this.measureRequests.indexOf(request) > -1)
            { return; }
        if (request.key != null)
            { for (var 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.
*/
EditorView.prototype.plugin = function plugin (plugin$1) {
    var known = this.pluginMap.get(plugin$1);
    if (known === undefined || known && known.spec != plugin$1)
        { this.pluginMap.set(plugin$1, known = this.plugins.find(function (p) { return p.spec == plugin$1; }) || 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.
*/
prototypeAccessors$20.documentTop.get = function () {
    return this.contentDOM.getBoundingClientRect().top + this.viewState.paddingTop;
};
/**
Reports the padding above and below the document.
*/
prototypeAccessors$20.documentPadding.get = function () {
    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.
*/
prototypeAccessors$20.scaleX.get = function () { return this.viewState.scaleX; };
/**
Provide the CSS transformed scale along the Y axis.
*/
prototypeAccessors$20.scaleY.get = function () { 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)).
*/
EditorView.prototype.elementAtHeight = function 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).
*/
EditorView.prototype.lineBlockAtHeight = function 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);
*/
prototypeAccessors$20.viewportLineBlocks.get = function () {
    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.
*/
EditorView.prototype.lineBlockAt = function lineBlockAt (pos) {
    return this.viewState.lineBlockAt(pos);
};
/**
The editor's total content height.
*/
prototypeAccessors$20.contentHeight.get = function () {
    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.
*/
EditorView.prototype.moveByChar = function moveByChar$1 (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.
*/
EditorView.prototype.moveByGroup = function moveByGroup (start, forward) {
        var this$1$1 = this;

    return skipAtoms(this, start, moveByChar(this, start, forward, function (initial) { return byGroup(this$1$1, 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.
*/
EditorView.prototype.visualLineSide = function visualLineSide (line, end) {
    var order = this.bidiSpans(line), dir = this.textDirectionAt(line.from);
    var 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.
*/
EditorView.prototype.moveToLineBoundary = function moveToLineBoundary$1 (start, forward, includeWrap) {
        if ( includeWrap === void 0 ) 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.
*/
EditorView.prototype.moveVertically = function moveVertically$1 (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).
*/
EditorView.prototype.domAtPos = function domAtPos (pos) {
    return this.docView.domAtPos(pos);
};
/**
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.
*/
EditorView.prototype.posAtDOM = function posAtDOM (node, offset) {
        if ( offset === void 0 ) offset = 0;

    return this.docView.posFromDOM(node, offset);
};
EditorView.prototype.posAtCoords = function posAtCoords$1 (coords, precise) {
        if ( precise === void 0 ) 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).
*/
EditorView.prototype.coordsAtPos = function coordsAtPos (pos, side) {
        if ( side === void 0 ) side = 1;

    this.readMeasured();
    var rect = this.docView.coordsAt(pos, side);
    if (!rect || rect.left == rect.right)
        { return rect; }
    var line = this.state.doc.lineAt(pos), order = this.bidiSpans(line);
    var 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.
*/
EditorView.prototype.coordsForChar = function 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).
*/
prototypeAccessors$20.defaultCharacterWidth.get = function () { return this.viewState.heightOracle.charWidth; };
/**
The default height of a line in the editor. May not be accurate
for all lines.
*/
prototypeAccessors$20.defaultLineHeight.get = function () { 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.
*/
prototypeAccessors$20.textDirection.get = function () { 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.
*/
EditorView.prototype.textDirectionAt = function textDirectionAt (pos) {
    var 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).
*/
prototypeAccessors$20.lineWrapping.get = function () { 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.
*/
EditorView.prototype.bidiSpans = function bidiSpans (line) {
    if (line.length > MaxBidiLine)
        { return trivialOrder(line.length); }
    var dir = this.textDirectionAt(line.from), isolates;
    for (var 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); }
    var 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.
*/
prototypeAccessors$20.hasFocus.get = function () {
    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.
*/
EditorView.prototype.focus = function focus () {
        var this$1$1 = this;

    this.observer.ignore(function () {
        focusPreventScroll(this$1$1.contentDOM);
        this$1$1.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.
*/
EditorView.prototype.setRoot = function 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.
*/
EditorView.prototype.destroy = function destroy () {
    if (this.root.activeElement == this.contentDOM)
        { this.contentDOM.blur(); }
    for (var 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.
*/
EditorView.scrollIntoView = function scrollIntoView$1$1 (pos, options) {
        if ( options === void 0 ) options = {};

    return scrollIntoView$1.of(new ScrollTarget(typeof pos == "number" ? EditorSelection.cursor(pos) : pos, options.y, options.x, options.yMargin, options.xMargin));
};
/**
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.
*/
EditorView.prototype.scrollSnapshot = function scrollSnapshot () {
    var ref$1 = this.scrollDOM;
        var scrollTop = ref$1.scrollTop;
        var scrollLeft = ref$1.scrollLeft;
    var ref = this.viewState.scrollAnchorAt(scrollTop);
    return scrollIntoView$1.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.
*/
EditorView.prototype.setTabFocusMode = function 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.
*/
EditorView.domEventHandlers = function domEventHandlers (handlers) {
    return ViewPlugin.define(function () { return ({}); }, { 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`.
*/
EditorView.domEventObservers = function domEventObservers (observers) {
    return ViewPlugin.define(function () { return ({}); }, { eventObservers: observers });
};
/**
Create a theme extension. The first argument can be a
[`style-mod`](https://github.com/marijnh/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).
*/
EditorView.theme = function theme$1 (spec, options) {
    var prefix = StyleModule.newName();
    var 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.
*/
EditorView.baseTheme = function baseTheme (spec) {
    return Prec.lowest(styleModule.of(buildTheme("." + baseThemeID, spec, lightDarkIDs)));
};
/**
Retrieve an editor view instance from the view's DOM
representation.
*/
EditorView.findFromDOM = function findFromDOM (dom) {
    var _a;
    var content = dom.querySelector(".cm-content");
    var cView = content && ContentView.get(content) || ContentView.get(dom);
    return ((_a = cView === null || cView === void 0 ? void 0 : cView.rootView) === null || _a === void 0 ? void 0 : _a.view) || null;
};

Object.defineProperties( EditorView.prototype, prototypeAccessors$20 );
/**
Facet to add a [style
module](https://github.com/marijnh/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;
/**
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;
/**
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).
*/
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: function (values) { return 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
var MaxBidiLine = 4096;
var BadMeasure = {};
var CachedOrder = function CachedOrder(from, to, dir, isolates, fresh, order) {
    this.from = from;
    this.to = to;
    this.dir = dir;
    this.isolates = isolates;
    this.fresh = fresh;
    this.order = order;
};
CachedOrder.update = function update (cache, changes) {
    if (changes.empty && !cache.some(function (c) { return c.fresh; }))
        { return cache; }
    var result = [], lastDir = cache.length ? cache[cache.length - 1].dir : Direction.LTR;
    for (var i = Math.max(0, cache.length - 10); i < cache.length; i++) {
        var 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 (var sources = view.state.facet(facet), i = sources.length - 1; i >= 0; i--) {
        var source = sources[i], value = typeof source == "function" ? source(view) : source;
        if (value)
            { combineAttrs(value, base); }
    }
    return base;
}

var currentPlatform = browser.mac ? "mac" : browser.windows ? "win" : browser.linux ? "linux" : "key";
function normalizeKeyName(name, platform) {
    var parts = name.split(/-(?!$)/);
    var result = parts[parts.length - 1];
    if (result == "Space")
        { result = " "; }
    var alt, ctrl, shift, meta;
    for (var i = 0; i < parts.length - 1; ++i) {
        var mod = parts[i];
        if (/^(cmd|meta|m)$/i.test(mod))
            { meta = true; }
        else if (/^a(lt)?$/i.test(mod))
            { alt = true; }
        else if (/^(c|ctrl|control)$/i.test(mod))
            { ctrl = true; }
        else if (/^s(hift)?$/i.test(mod))
            { shift = true; }
        else if (/^mod$/i.test(mod)) {
            if (platform == "mac")
                { meta = true; }
            else
                { ctrl = true; }
        }
        else
            { throw new Error("Unrecognized modifier name: " + mod); }
    }
    if (alt)
        { result = "Alt-" + result; }
    if (ctrl)
        { result = "Ctrl-" + result; }
    if (meta)
        { result = "Meta-" + result; }
    if (shift)
        { result = "Shift-" + result; }
    return result;
}
function modifiers(name, event, shift) {
    if (event.altKey)
        { name = "Alt-" + name; }
    if (event.ctrlKey)
        { name = "Ctrl-" + name; }
    if (event.metaKey)
        { name = "Meta-" + name; }
    if (shift !== false && event.shiftKey)
        { name = "Shift-" + name; }
    return name;
}
var handleKeyEvents = /*@__PURE__*/Prec.default(/*@__PURE__*/EditorView.domEventHandlers({
    keydown: function keydown(event, view) {
        return runHandlers(getKeymap(view.state), event, view, "editor");
    }
}));
/**
Facet used for registering keymaps.

You can add multiple keymaps to an editor. Their priorities
determine their precedence (the ones specified early or with high
priority get checked first). When a handler has returned `true`
for a given key, no further handlers are called.
*/
var keymap$3 = /*@__PURE__*/Facet.define({ enables: handleKeyEvents });
var Keymaps = /*@__PURE__*/new WeakMap();
// This is hidden behind an indirection, rather than directly computed
// by the facet, to keep internal types out of the facet's type.
function getKeymap(state) {
    var bindings = state.facet(keymap$3);
    var map = Keymaps.get(bindings);
    if (!map)
        { Keymaps.set(bindings, map = buildKeymap$1(bindings.reduce(function (a, b) { return a.concat(b); }, []))); }
    return map;
}
var storedPrefix = null;
var PrefixTimeout = 4000;
function buildKeymap$1(bindings, platform) {
    if ( platform === void 0 ) platform = currentPlatform;

    var bound = Object.create(null);
    var isPrefix = Object.create(null);
    var checkPrefix = function (name, is) {
        var current = isPrefix[name];
        if (current == null)
            { isPrefix[name] = is; }
        else if (current != is)
            { throw new Error("Key binding " + name + " is used both as a regular binding and as a multi-stroke prefix"); }
    };
    var add = function (scope, key, command, preventDefault, stopPropagation) {
        var _a, _b;
        var scopeObj = bound[scope] || (bound[scope] = Object.create(null));
        var parts = key.split(/ (?!$)/).map(function (k) { return normalizeKeyName(k, platform); });
        var loop = function ( i ) {
            var prefix = parts.slice(0, i).join(" ");
            checkPrefix(prefix, true);
            if (!scopeObj[prefix])
                { scopeObj[prefix] = {
                    preventDefault: true,
                    stopPropagation: false,
                    run: [function (view) {
                            var ourObj = storedPrefix = { view: view, prefix: prefix, scope: scope };
                            setTimeout(function () { if (storedPrefix == ourObj)
                                { storedPrefix = null; } }, PrefixTimeout);
                            return true;
                        }]
                }; }
        };

        for (var i = 1; i < parts.length; i++) loop( i );
        var full = parts.join(" ");
        checkPrefix(full, false);
        var binding = scopeObj[full] || (scopeObj[full] = {
            preventDefault: false,
            stopPropagation: false,
            run: ((_b = (_a = scopeObj._any) === null || _a === void 0 ? void 0 : _a.run) === null || _b === void 0 ? void 0 : _b.slice()) || []
        });
        if (command)
            { binding.run.push(command); }
        if (preventDefault)
            { binding.preventDefault = true; }
        if (stopPropagation)
            { binding.stopPropagation = true; }
    };
    for (var b of bindings) {
        var scopes = b.scope ? b.scope.split(" ") : ["editor"];
        if (b.any)
            { var loop = function () {
                var scopeObj = bound[scope] || (bound[scope] = Object.create(null));
                if (!scopeObj._any)
                    { scopeObj._any = { preventDefault: false, stopPropagation: false, run: [] }; }
                var any = b.any;
                for (var key in scopeObj)
                    { scopeObj[key].run.push(function (view) { return any(view, currentKeyEvent); }); }
            };

                for (var scope of scopes) loop(); }
        var name = b[platform] || b.key;
        if (!name)
            { continue; }
        for (var scope$1 of scopes) {
            add(scope$1, name, b.run, b.preventDefault, b.stopPropagation);
            if (b.shift)
                { add(scope$1, "Shift-" + name, b.shift, b.preventDefault, b.stopPropagation); }
        }
    }
    return bound;
}
var currentKeyEvent = null;
function runHandlers(map, event, view, scope) {
    currentKeyEvent = event;
    var name = keyName(event);
    var charCode = codePointAt(name, 0), isChar = codePointSize(charCode) == name.length && name != " ";
    var prefix = "", handled = false, prevented = false, stopPropagation = false;
    if (storedPrefix && storedPrefix.view == view && storedPrefix.scope == scope) {
        prefix = storedPrefix.prefix + " ";
        if (modifierCodes.indexOf(event.keyCode) < 0) {
            prevented = true;
            storedPrefix = null;
        }
    }
    var ran = new Set;
    var runFor = function (binding) {
        if (binding) {
            for (var cmd of binding.run)
                if (!ran.has(cmd)) {
                    ran.add(cmd);
                    if (cmd(view)) {
                        if (binding.stopPropagation)
                            { stopPropagation = true; }
                        return true;
                    }
                }
            if (binding.preventDefault) {
                if (binding.stopPropagation)
                    { stopPropagation = true; }
                prevented = true;
            }
        }
        return false;
    };
    var scopeObj = map[scope], baseName, shiftName;
    if (scopeObj) {
        if (runFor(scopeObj[prefix + modifiers(name, event, !isChar)])) {
            handled = true;
        }
        else if (isChar && (event.altKey || event.metaKey || event.ctrlKey) &&
            // Ctrl-Alt may be used for AltGr on Windows
            !(browser.windows && event.ctrlKey && event.altKey) &&
            (baseName = base$2[event.keyCode]) && baseName != name) {
            if (runFor(scopeObj[prefix + modifiers(baseName, event, true)])) {
                handled = true;
            }
            else if (event.shiftKey && (shiftName = shift[event.keyCode]) != name && shiftName != baseName &&
                runFor(scopeObj[prefix + modifiers(shiftName, event, false)])) {
                handled = true;
            }
        }
        else if (isChar && event.shiftKey &&
            runFor(scopeObj[prefix + modifiers(name, event, true)])) {
            handled = true;
        }
        if (!handled && runFor(scopeObj._any))
            { handled = true; }
    }
    if (prevented)
        { handled = true; }
    if (handled && stopPropagation)
        { event.stopPropagation(); }
    currentKeyEvent = null;
    return handled;
}

/**
Implementation of [`LayerMarker`](https://codemirror.net/6/docs/ref/#view.LayerMarker) that creates
a rectangle at a given set of coordinates.
*/
var RectangleMarker = function RectangleMarker(className, 
/**
The left position of the marker (in pixels, document-relative).
*/
left, 
/**
The top position of the marker.
*/
top, 
/**
The width of the marker, or null if it shouldn't get a width assigned.
*/
width, 
/**
The height of the marker.
*/
height) {
    this.className = className;
    this.left = left;
    this.top = top;
    this.width = width;
    this.height = height;
};
RectangleMarker.prototype.draw = function draw () {
    var elt = document.createElement("div");
    elt.className = this.className;
    this.adjust(elt);
    return elt;
};
RectangleMarker.prototype.update = function update (elt, prev) {
    if (prev.className != this.className)
        { return false; }
    this.adjust(elt);
    return true;
};
RectangleMarker.prototype.adjust = function adjust (elt) {
    elt.style.left = this.left + "px";
    elt.style.top = this.top + "px";
    if (this.width != null)
        { elt.style.width = this.width + "px"; }
    elt.style.height = this.height + "px";
};
RectangleMarker.prototype.eq = function eq (p) {
    return this.left == p.left && this.top == p.top && this.width == p.width && this.height == p.height &&
        this.className == p.className;
};
/**
Create a set of rectangles for the given selection range,
assigning them theclass`className`. Will create a single
rectangle for empty ranges, and a set of selection-style
rectangles covering the range's content (in a bidi-aware
way) for non-empty ones.
*/
RectangleMarker.forRange = function forRange (view, className, range) {
    if (range.empty) {
        var pos = view.coordsAtPos(range.head, range.assoc || 1);
        if (!pos)
            { return []; }
        var base = getBase(view);
        return [new RectangleMarker(className, pos.left - base.left, pos.top - base.top, null, pos.bottom - pos.top)];
    }
    else {
        return rectanglesForRange(view, className, range);
    }
};
function getBase(view) {
    var rect = view.scrollDOM.getBoundingClientRect();
    var left = view.textDirection == Direction.LTR ? rect.left : rect.right - view.scrollDOM.clientWidth * view.scaleX;
    return { left: left - view.scrollDOM.scrollLeft * view.scaleX, top: rect.top - view.scrollDOM.scrollTop * view.scaleY };
}
function wrappedLine(view, pos, side, inside) {
    var coords = view.coordsAtPos(pos, side * 2);
    if (!coords)
        { return inside; }
    var editorRect = view.dom.getBoundingClientRect();
    var y = (coords.top + coords.bottom) / 2;
    var left = view.posAtCoords({ x: editorRect.left + 1, y: y });
    var right = view.posAtCoords({ x: editorRect.right - 1, y: y });
    if (left == null || right == null)
        { return inside; }
    return { from: Math.max(inside.from, Math.min(left, right)), to: Math.min(inside.to, Math.max(left, right)) };
}
function rectanglesForRange(view, className, range) {
    if (range.to <= view.viewport.from || range.from >= view.viewport.to)
        { return []; }
    var from = Math.max(range.from, view.viewport.from), to = Math.min(range.to, view.viewport.to);
    var ltr = view.textDirection == Direction.LTR;
    var content = view.contentDOM, contentRect = content.getBoundingClientRect(), base = getBase(view);
    var lineElt = content.querySelector(".cm-line"), lineStyle = lineElt && window.getComputedStyle(lineElt);
    var leftSide = contentRect.left +
        (lineStyle ? parseInt(lineStyle.paddingLeft) + Math.min(0, parseInt(lineStyle.textIndent)) : 0);
    var rightSide = contentRect.right - (lineStyle ? parseInt(lineStyle.paddingRight) : 0);
    var startBlock = blockAt(view, from), endBlock = blockAt(view, to);
    var visualStart = startBlock.type == BlockType.Text ? startBlock : null;
    var visualEnd = endBlock.type == BlockType.Text ? endBlock : null;
    if (visualStart && (view.lineWrapping || startBlock.widgetLineBreaks))
        { visualStart = wrappedLine(view, from, 1, visualStart); }
    if (visualEnd && (view.lineWrapping || endBlock.widgetLineBreaks))
        { visualEnd = wrappedLine(view, to, -1, visualEnd); }
    if (visualStart && visualEnd && visualStart.from == visualEnd.from && visualStart.to == visualEnd.to) {
        return pieces(drawForLine(range.from, range.to, visualStart));
    }
    else {
        var top = visualStart ? drawForLine(range.from, null, visualStart) : drawForWidget(startBlock, false);
        var bottom = visualEnd ? drawForLine(null, range.to, visualEnd) : drawForWidget(endBlock, true);
        var between = [];
        if ((visualStart || startBlock).to < (visualEnd || endBlock).from - (visualStart && visualEnd ? 1 : 0) ||
            startBlock.widgetLineBreaks > 1 && top.bottom + view.defaultLineHeight / 2 < bottom.top)
            { between.push(piece(leftSide, top.bottom, rightSide, bottom.top)); }
        else if (top.bottom < bottom.top && view.elementAtHeight((top.bottom + bottom.top) / 2).type == BlockType.Text)
            { top.bottom = bottom.top = (top.bottom + bottom.top) / 2; }
        return pieces(top).concat(between).concat(pieces(bottom));
    }
    function piece(left, top, right, bottom) {
        return new RectangleMarker(className, left - base.left, top - base.top - 0.01 /* C.Epsilon */, right - left, bottom - top + 0.01 /* C.Epsilon */);
    }
    function pieces(ref) {
        var top = ref.top;
        var bottom = ref.bottom;
        var horizontal = ref.horizontal;

        var pieces = [];
        for (var i = 0; i < horizontal.length; i += 2)
            { pieces.push(piece(horizontal[i], top, horizontal[i + 1], bottom)); }
        return pieces;
    }
    // Gets passed from/to in line-local positions
    function drawForLine(from, to, line) {
        var top = 1e9, bottom = -1e9, horizontal = [];
        function addSpan(from, fromOpen, to, toOpen, dir) {
            // Passing 2/-2 is a kludge to force the view to return
            // coordinates on the proper side of block widgets, since
            // normalizing the side there, though appropriate for most
            // coordsAtPos queries, would break selection drawing.
            var fromCoords = view.coordsAtPos(from, (from == line.to ? -2 : 2));
            var toCoords = view.coordsAtPos(to, (to == line.from ? 2 : -2));
            if (!fromCoords || !toCoords)
                { return; }
            top = Math.min(fromCoords.top, toCoords.top, top);
            bottom = Math.max(fromCoords.bottom, toCoords.bottom, bottom);
            if (dir == Direction.LTR)
                { horizontal.push(ltr && fromOpen ? leftSide : fromCoords.left, ltr && toOpen ? rightSide : toCoords.right); }
            else
                { horizontal.push(!ltr && toOpen ? leftSide : toCoords.left, !ltr && fromOpen ? rightSide : fromCoords.right); }
        }
        var start = from !== null && from !== void 0 ? from : line.from, end = to !== null && to !== void 0 ? to : line.to;
        // Split the range by visible range and document line
        for (var r of view.visibleRanges)
            if (r.to > start && r.from < end) {
                for (var pos = Math.max(r.from, start), endPos = Math.min(r.to, end);;) {
                    var docLine = view.state.doc.lineAt(pos);
                    for (var span of view.bidiSpans(docLine)) {
                        var spanFrom = span.from + docLine.from, spanTo = span.to + docLine.from;
                        if (spanFrom >= endPos)
                            { break; }
                        if (spanTo > pos)
                            { addSpan(Math.max(spanFrom, pos), from == null && spanFrom <= start, Math.min(spanTo, endPos), to == null && spanTo >= end, span.dir); }
                    }
                    pos = docLine.to + 1;
                    if (pos >= endPos)
                        { break; }
                }
            }
        if (horizontal.length == 0)
            { addSpan(start, from == null, end, to == null, view.textDirection); }
        return { top: top, bottom: bottom, horizontal: horizontal };
    }
    function drawForWidget(block, top) {
        var y = contentRect.top + (top ? block.top : block.bottom);
        return { top: y, bottom: y, horizontal: [] };
    }
}
function sameMarker(a, b) {
    return a.constructor == b.constructor && a.eq(b);
}
var LayerView = function LayerView(view, layer) {
    this.view = view;
    this.layer = layer;
    this.drawn = [];
    this.scaleX = 1;
    this.scaleY = 1;
    this.measureReq = { read: this.measure.bind(this), write: this.draw.bind(this) };
    this.dom = view.scrollDOM.appendChild(document.createElement("div"));
    this.dom.classList.add("cm-layer");
    if (layer.above)
        { this.dom.classList.add("cm-layer-above"); }
    if (layer.class)
        { this.dom.classList.add(layer.class); }
    this.scale();
    this.dom.setAttribute("aria-hidden", "true");
    this.setOrder(view.state);
    view.requestMeasure(this.measureReq);
    if (layer.mount)
        { layer.mount(this.dom, view); }
};
LayerView.prototype.update = function update (update$1) {
    if (update$1.startState.facet(layerOrder) != update$1.state.facet(layerOrder))
        { this.setOrder(update$1.state); }
    if (this.layer.update(update$1, this.dom) || update$1.geometryChanged) {
        this.scale();
        update$1.view.requestMeasure(this.measureReq);
    }
};
LayerView.prototype.docViewUpdate = function docViewUpdate (view) {
    if (this.layer.updateOnDocViewUpdate !== false)
        { view.requestMeasure(this.measureReq); }
};
LayerView.prototype.setOrder = function setOrder (state) {
    var pos = 0, order = state.facet(layerOrder);
    while (pos < order.length && order[pos] != this.layer)
        { pos++; }
    this.dom.style.zIndex = String((this.layer.above ? 150 : -1) - pos);
};
LayerView.prototype.measure = function measure () {
    return this.layer.markers(this.view);
};
LayerView.prototype.scale = function scale () {
    var ref = this.view;
        var scaleX = ref.scaleX;
        var scaleY = ref.scaleY;
    if (scaleX != this.scaleX || scaleY != this.scaleY) {
        this.scaleX = scaleX;
        this.scaleY = scaleY;
        this.dom.style.transform = "scale(" + (1 / scaleX) + ", " + (1 / scaleY) + ")";
    }
};
LayerView.prototype.draw = function draw (markers) {
        var this$1$1 = this;

    if (markers.length != this.drawn.length || markers.some(function (p, i) { return !sameMarker(p, this$1$1.drawn[i]); })) {
        var old = this.dom.firstChild, oldI = 0;
        for (var marker of markers) {
            if (marker.update && old && marker.constructor && this.drawn[oldI].constructor &&
                marker.update(old, this.drawn[oldI])) {
                old = old.nextSibling;
                oldI++;
            }
            else {
                this.dom.insertBefore(marker.draw(), old);
            }
        }
        while (old) {
            var next = old.nextSibling;
            old.remove();
            old = next;
        }
        this.drawn = markers;
    }
};
LayerView.prototype.destroy = function destroy () {
    if (this.layer.destroy)
        { this.layer.destroy(this.dom, this.view); }
    this.dom.remove();
};
var layerOrder = /*@__PURE__*/Facet.define();
/**
Define a layer.
*/
function layer(config) {
    return [
        ViewPlugin.define(function (v) { return new LayerView(v, config); }),
        layerOrder.of(config)
    ];
}

var CanHidePrimary = !browser.ios; // FIXME test IE
var selectionConfig = /*@__PURE__*/Facet.define({
    combine: function combine(configs) {
        return combineConfig(configs, {
            cursorBlinkRate: 1200,
            drawRangeCursor: true
        }, {
            cursorBlinkRate: function (a, b) { return Math.min(a, b); },
            drawRangeCursor: function (a, b) { return a || b; }
        });
    }
});
/**
Returns an extension that hides the browser's native selection and
cursor, replacing the selection with a background behind the text
(with the `cm-selectionBackground` class), and the
cursors with elements overlaid over the code (using
`cm-cursor-primary` and `cm-cursor-secondary`).

This allows the editor to display secondary selection ranges, and
tends to produce a type of selection more in line with that users
expect in a text editor (the native selection styling will often
leave gaps between lines and won't fill the horizontal space after
a line when the selection continues past it).

It does have a performance cost, in that it requires an extra DOM
layout cycle for many updates (the selection is drawn based on DOM
layout information that's only available after laying out the
content).
*/
function drawSelection(config) {
    if ( config === void 0 ) config = {};

    return [
        selectionConfig.of(config),
        cursorLayer,
        selectionLayer,
        hideNativeSelection,
        nativeSelectionHidden.of(true)
    ];
}
function configChanged(update) {
    return update.startState.facet(selectionConfig) != update.state.facet(selectionConfig);
}
var cursorLayer = /*@__PURE__*/layer({
    above: true,
    markers: function markers(view) {
        var state = view.state;
        var conf = state.facet(selectionConfig);
        var cursors = [];
        for (var r of state.selection.ranges) {
            var prim = r == state.selection.main;
            if (r.empty ? !prim || CanHidePrimary : conf.drawRangeCursor) {
                var className = prim ? "cm-cursor cm-cursor-primary" : "cm-cursor cm-cursor-secondary";
                var cursor = r.empty ? r : EditorSelection.cursor(r.head, r.head > r.anchor ? -1 : 1);
                for (var piece of RectangleMarker.forRange(view, className, cursor))
                    cursors.push(piece);
            }
        }
        return cursors;
    },
    update: function update(update$1, dom) {
        if (update$1.transactions.some(function (tr) { return tr.selection; }))
            { dom.style.animationName = dom.style.animationName == "cm-blink" ? "cm-blink2" : "cm-blink"; }
        var confChange = configChanged(update$1);
        if (confChange)
            { setBlinkRate(update$1.state, dom); }
        return update$1.docChanged || update$1.selectionSet || confChange;
    },
    mount: function mount(dom, view) {
        setBlinkRate(view.state, dom);
    },
    class: "cm-cursorLayer"
});
function setBlinkRate(state, dom) {
    dom.style.animationDuration = state.facet(selectionConfig).cursorBlinkRate + "ms";
}
var selectionLayer = /*@__PURE__*/layer({
    above: false,
    markers: function markers(view) {
        return view.state.selection.ranges.map(function (r) { return r.empty ? [] : RectangleMarker.forRange(view, "cm-selectionBackground", r); })
            .reduce(function (a, b) { return a.concat(b); });
    },
    update: function update(update$1, dom) {
        return update$1.docChanged || update$1.selectionSet || update$1.viewportChanged || configChanged(update$1);
    },
    class: "cm-selectionLayer"
});
var themeSpec = {
    ".cm-line": {
        "& ::selection, &::selection": { backgroundColor: "transparent !important" },
    },
    ".cm-content": {
        "& :focus": {
            caretColor: "initial !important",
            "&::selection, & ::selection": {
                backgroundColor: "Highlight !important"
            }
        }
    }
};
if (CanHidePrimary)
    { themeSpec[".cm-line"].caretColor = themeSpec[".cm-content"].caretColor = "transparent !important"; }
var hideNativeSelection = /*@__PURE__*/Prec.highest(/*@__PURE__*/EditorView.theme(themeSpec));

var Outside = "-10000px";
var TooltipViewManager = function TooltipViewManager(view, facet, createTooltipView, removeTooltipView) {
    this.facet = facet;
    this.createTooltipView = createTooltipView;
    this.removeTooltipView = removeTooltipView;
    this.input = view.state.facet(facet);
    this.tooltips = this.input.filter(function (t) { return t; });
    var prev = null;
    this.tooltipViews = this.tooltips.map(function (t) { return prev = createTooltipView(t, prev); });
};
TooltipViewManager.prototype.update = function update (update$1, above) {
    var _a;
    var input = update$1.state.facet(this.facet);
    var tooltips = input.filter(function (x) { return x; });
    if (input === this.input) {
        for (var t of this.tooltipViews)
            if (t.update)
                { t.update(update$1); }
        return false;
    }
    var tooltipViews = [], newAbove = above ? [] : null;
    for (var i = 0; i < tooltips.length; i++) {
        var tip = tooltips[i], known = -1;
        if (!tip)
            { continue; }
        for (var i$1 = 0; i$1 < this.tooltips.length; i$1++) {
            var other = this.tooltips[i$1];
            if (other && other.create == tip.create)
                { known = i$1; }
        }
        if (known < 0) {
            tooltipViews[i] = this.createTooltipView(tip, i ? tooltipViews[i - 1] : null);
            if (newAbove)
                { newAbove[i] = !!tip.above; }
        }
        else {
            var tooltipView = tooltipViews[i] = this.tooltipViews[known];
            if (newAbove)
                { newAbove[i] = above[known]; }
            if (tooltipView.update)
                { tooltipView.update(update$1); }
        }
    }
    for (var t$1 of this.tooltipViews)
        if (tooltipViews.indexOf(t$1) < 0) {
            this.removeTooltipView(t$1);
            (_a = t$1.destroy) === null || _a === void 0 ? void 0 : _a.call(t$1);
        }
    if (above) {
        newAbove.forEach(function (val, i) { return above[i] = val; });
        above.length = newAbove.length;
    }
    this.input = input;
    this.tooltips = tooltips;
    this.tooltipViews = tooltipViews;
    return true;
};
function windowSpace(view) {
    var win = view.win;
    return { top: 0, left: 0, bottom: win.innerHeight, right: win.innerWidth };
}
var tooltipConfig = /*@__PURE__*/Facet.define({
    combine: function (values) {
        var _a, _b, _c;
        return ({
            position: browser.ios ? "absolute" : ((_a = values.find(function (conf) { return conf.position; })) === null || _a === void 0 ? void 0 : _a.position) || "fixed",
            parent: ((_b = values.find(function (conf) { return conf.parent; })) === null || _b === void 0 ? void 0 : _b.parent) || null,
            tooltipSpace: ((_c = values.find(function (conf) { return conf.tooltipSpace; })) === null || _c === void 0 ? void 0 : _c.tooltipSpace) || windowSpace,
        });
    }
});
var knownHeight = /*@__PURE__*/new WeakMap();
var tooltipPlugin = /*@__PURE__*/ViewPlugin.fromClass(/*@__PURE__*/(function () {
    function anonymous$3(view) {
    var this$1$1 = this;

        this.view = view;
        this.above = [];
        this.inView = true;
        this.madeAbsolute = false;
        this.lastTransaction = 0;
        this.measureTimeout = -1;
        var 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(function () { return this$1$1.measureSoon(); }) : null;
        this.manager = new TooltipViewManager(view, showTooltip, function (t, p) { return this$1$1.createTooltip(t, p); }, function (t) {
            if (this$1$1.resizeObserver)
                { this$1$1.resizeObserver.unobserve(t.dom); }
            t.dom.remove();
        });
        this.above = this.manager.tooltips.map(function (t) { return !!t.above; });
        this.intersectionObserver = typeof IntersectionObserver == "function" ? new IntersectionObserver(function (entries) {
            if (Date.now() > this$1$1.lastTransaction - 50 &&
                entries.length > 0 && entries[entries.length - 1].intersectionRatio < 1)
                { this$1$1.measureSoon(); }
        }, { threshold: [1] }) : null;
        this.observeIntersection();
        view.win.addEventListener("resize", this.measureSoon = this.measureSoon.bind(this));
        this.maybeMeasure();
    }
    anonymous$3.prototype.createContainer = function 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;
        }
    };
    anonymous$3.prototype.observeIntersection = function observeIntersection () {
        if (this.intersectionObserver) {
            this.intersectionObserver.disconnect();
            for (var tooltip of this.manager.tooltipViews)
                this.intersectionObserver.observe(tooltip.dom);
        }
    };
    anonymous$3.prototype.measureSoon = function measureSoon () {
        var this$1$1 = this;

        if (this.measureTimeout < 0)
            { this.measureTimeout = setTimeout(function () {
                this$1$1.measureTimeout = -1;
                this$1$1.maybeMeasure();
            }, 50); }
    };
    anonymous$3.prototype.update = function update (update$1) {
        if (update$1.transactions.length)
            { this.lastTransaction = Date.now(); }
        var updated = this.manager.update(update$1, this.above);
        if (updated)
            { this.observeIntersection(); }
        var shouldMeasure = updated || update$1.geometryChanged;
        var newConfig = update$1.state.facet(tooltipConfig);
        if (newConfig.position != this.position && !this.madeAbsolute) {
            this.position = newConfig.position;
            for (var 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 (var t$1 of this.manager.tooltipViews)
                this.container.appendChild(t$1.dom);
            shouldMeasure = true;
        }
        else if (this.parent && this.view.themeClasses != this.classes) {
            this.classes = this.container.className = this.view.themeClasses;
        }
        if (shouldMeasure)
            { this.maybeMeasure(); }
    };
    anonymous$3.prototype.createTooltip = function createTooltip (tooltip, prev) {
        var tooltipView = tooltip.create(this.view);
        var before = prev ? prev.dom : null;
        tooltipView.dom.classList.add("cm-tooltip");
        if (tooltip.arrow && !tooltipView.dom.querySelector(".cm-tooltip > .cm-tooltip-arrow")) {
            var 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;
    };
    anonymous$3.prototype.destroy = function destroy () {
        var _a, _b, _c;
        this.view.win.removeEventListener("resize", this.measureSoon);
        for (var 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);
    };
    anonymous$3.prototype.readMeasure = function readMeasure () {
        var this$1$1 = this;
        var assign;

        var editor = this.view.dom.getBoundingClientRect();
        var scaleX = 1, scaleY = 1, makeAbsolute = false;
        if (this.position == "fixed" && this.manager.tooltipViews.length) {
            var ref = this.manager.tooltipViews[0];
            var dom = ref.dom;
            if (browser.gecko) {
                // Firefox sets the element's `offsetParent` to the
                // transformed element when a transform interferes with fixed
                // positioning.
                makeAbsolute = dom.offsetParent != this.container.ownerDocument.body;
            }
            else if (dom.style.top == Outside && dom.style.left == "0px") {
                // On other browsers, we have to awkwardly try and use other
                // information to detect a transform.
                var rect = dom.getBoundingClientRect();
                makeAbsolute = Math.abs(rect.top + 10000) > 1 || Math.abs(rect.left) > 1;
            }
        }
        if (makeAbsolute || this.position == "absolute") {
            if (this.parent) {
                var rect$1 = this.parent.getBoundingClientRect();
                if (rect$1.width && rect$1.height) {
                    scaleX = rect$1.width / this.parent.offsetWidth;
                    scaleY = rect$1.height / this.parent.offsetHeight;
                }
            }
            else {
                ((assign = this.view.viewState, scaleX = assign.scaleX, scaleY = assign.scaleY));
            }
        }
        return {
            editor: editor,
            parent: this.parent ? this.container.getBoundingClientRect() : editor,
            pos: this.manager.tooltips.map(function (t, i) {
                var tv = this$1$1.manager.tooltipViews[i];
                return tv.getCoords ? tv.getCoords(t.pos) : this$1$1.view.coordsAtPos(t.pos);
            }),
            size: this.manager.tooltipViews.map(function (ref) {
                var dom = ref.dom;

                return dom.getBoundingClientRect();
        }),
            space: this.view.state.facet(tooltipConfig).tooltipSpace(this.view),
            scaleX: scaleX, scaleY: scaleY, makeAbsolute: makeAbsolute
        };
    };
    anonymous$3.prototype.writeMeasure = function writeMeasure (measured) {
        var _a;
        if (measured.makeAbsolute) {
            this.madeAbsolute = true;
            this.position = "absolute";
            for (var t of this.manager.tooltipViews)
                t.dom.style.position = "absolute";
        }
        var editor = measured.editor;
        var space = measured.space;
        var scaleX = measured.scaleX;
        var scaleY = measured.scaleY;
        var others = [];
        for (var i = 0; i < this.manager.tooltips.length; i++) {
            var tooltip = this.manager.tooltips[i], tView = this.manager.tooltipViews[i];
            var dom = tView.dom;
            var pos = measured.pos[i], size = measured.size[i];
            // Hide tooltips that are outside of the editor.
            if (!pos || pos.bottom <= Math.max(editor.top, space.top) ||
                pos.top >= Math.min(editor.bottom, space.bottom) ||
                pos.right < Math.max(editor.left, space.left) - .1 ||
                pos.left > Math.min(editor.right, space.right) + .1) {
                dom.style.top = Outside;
                continue;
            }
            var arrow = tooltip.arrow ? tView.dom.querySelector(".cm-tooltip-arrow") : null;
            var arrowHeight = arrow ? 7 /* Arrow.Size */ : 0;
            var width = size.right - size.left, height = (_a = knownHeight.get(tView)) !== null && _a !== void 0 ? _a : size.bottom - size.top;
            var offset = tView.offset || noOffset, ltr = this.view.textDirection == Direction.LTR;
            var 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);
            var above = this.above[i];
            if (!tooltip.strictSide && (above
                ? pos.top - (size.bottom - size.top) - offset.y < space.top
                : pos.bottom + (size.bottom - size.top) + offset.y > space.bottom) &&
                above == (space.bottom - pos.bottom > pos.top - space.top))
                { above = this.above[i] = !above; }
            var 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 = "";
            }
            var top = above ? pos.top - height - arrowHeight - offset.y : pos.bottom + arrowHeight + offset.y;
            var right = left + width;
            if (tView.overlap !== true)
                { for (var 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";
                dom.style.left = (left - measured.parent.left) / scaleX + "px";
            }
            else {
                dom.style.top = top / scaleY + "px";
                dom.style.left = left / scaleX + "px";
            }
            if (arrow) {
                var 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: left, top: top, right: 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); }
        }
    };
    anonymous$3.prototype.maybeMeasure = function 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 (var tv of this.manager.tooltipViews)
                        tv.dom.style.top = Outside; }
            }
        }
    };

    return anonymous$3;
}()), {
    eventObservers: {
        scroll: function scroll() { this.maybeMeasure(); }
    }
});
var baseTheme$2 = /*@__PURE__*/EditorView.baseTheme({
    ".cm-tooltip": {
        zIndex: 100,
        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) + "px"),
        width: ((7 /* Arrow.Size */ * 2) + "px"),
        position: "absolute",
        zIndex: -1,
        overflow: "hidden",
        "&:before, &:after": {
            content: "''",
            position: "absolute",
            width: 0,
            height: 0,
            borderLeft: ((7) + "px solid transparent"),
            borderRight: ((7) + "px solid transparent"),
        },
        ".cm-tooltip-above &": {
            bottom: ("-" + (7) + "px"),
            "&:before": {
                borderTop: ((7) + "px solid #bbb"),
            },
            "&:after": {
                borderTop: ((7) + "px solid #f5f5f5"),
                bottom: "1px"
            }
        },
        ".cm-tooltip-below &": {
            top: ("-" + (7) + "px"),
            "&:before": {
                borderBottom: ((7) + "px solid #bbb"),
            },
            "&:after": {
                borderBottom: ((7) + "px solid #f5f5f5"),
                top: "1px"
            }
        },
    },
    "&dark .cm-tooltip .cm-tooltip-arrow": {
        "&:before": {
            borderTopColor: "#333338",
            borderBottomColor: "#333338"
        },
        "&:after": {
            borderTopColor: "transparent",
            borderBottomColor: "transparent"
        }
    }
});
var noOffset = { x: 0, y: 0 };
/**
Facet to which an extension can add a value to show a tooltip.
*/
var showTooltip = /*@__PURE__*/Facet.define({
    enables: [tooltipPlugin, baseTheme$2]
});
var showHoverTooltip = /*@__PURE__*/Facet.define({
    combine: function (inputs) { return inputs.reduce(function (a, i) { return a.concat(i); }, []); }
});
var HoverTooltipHost = function HoverTooltipHost(view) {
    var this$1$1 = this;

    this.view = view;
    this.mounted = false;
    this.dom = document.createElement("div");
    this.dom.classList.add("cm-tooltip-hover");
    this.manager = new TooltipViewManager(view, showHoverTooltip, function (t, p) { return this$1$1.createHostedView(t, p); }, function (t) { return t.dom.remove(); });
};

var prototypeAccessors$21 = { offset: { configurable: true },getCoords: { configurable: true },overlap: { configurable: true },resize: { configurable: true } };
HoverTooltipHost.create = function create (view) {
    return new HoverTooltipHost(view);
};

HoverTooltipHost.prototype.createHostedView = function createHostedView (tooltip, prev) {
    var 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;
};
HoverTooltipHost.prototype.mount = function mount (view) {
    for (var hostedView of this.manager.tooltipViews) {
        if (hostedView.mount)
            { hostedView.mount(view); }
    }
    this.mounted = true;
};
HoverTooltipHost.prototype.positioned = function positioned (space) {
    for (var hostedView of this.manager.tooltipViews) {
        if (hostedView.positioned)
            { hostedView.positioned(space); }
    }
};
HoverTooltipHost.prototype.update = function update (update$1) {
    this.manager.update(update$1);
};
HoverTooltipHost.prototype.destroy = function destroy () {
    var _a;
    for (var t of this.manager.tooltipViews)
        (_a = t.destroy) === null || _a === void 0 ? void 0 : _a.call(t);
};
HoverTooltipHost.prototype.passProp = function passProp (name) {
    var value = undefined;
    for (var view of this.manager.tooltipViews) {
        var given = view[name];
        if (given !== undefined) {
            if (value === undefined)
                { value = given; }
            else if (value !== given)
                { return undefined; }
        }
    }
    return value;
};
prototypeAccessors$21.offset.get = function () { return this.passProp("offset"); };
prototypeAccessors$21.getCoords.get = function () { return this.passProp("getCoords"); };
prototypeAccessors$21.overlap.get = function () { return this.passProp("overlap"); };
prototypeAccessors$21.resize.get = function () { return this.passProp("resize"); };

Object.defineProperties( HoverTooltipHost.prototype, prototypeAccessors$21 );
var HoverPlugin = function HoverPlugin(view, source, field, setHover, hoverTime) {
    this.view = view;
    this.source = source;
    this.field = field;
    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));
};

var prototypeAccessors$22 = { active: { configurable: true },tooltip: { configurable: true } };
HoverPlugin.prototype.update = function update () {
        var this$1$1 = this;

    if (this.pending) {
        this.pending = null;
        clearTimeout(this.restartTimeout);
        this.restartTimeout = setTimeout(function () { return this$1$1.startHover(); }, 20);
    }
};
prototypeAccessors$22.active.get = function () {
    return this.view.state.field(this.field);
};
HoverPlugin.prototype.checkHover = function checkHover () {
    this.hoverTimeout = -1;
    if (this.active.length)
        { return; }
    var hovered = Date.now() - this.lastMove.time;
    if (hovered < this.hoverTime)
        { this.hoverTimeout = setTimeout(this.checkHover, this.hoverTime - hovered); }
    else
        { this.startHover(); }
};
HoverPlugin.prototype.startHover = function startHover () {
        var this$1$1 = this;

    clearTimeout(this.restartTimeout);
    var ref = this;
        var view = ref.view;
        var lastMove = ref.lastMove;
    var desc = view.docView.nearest(lastMove.target);
    if (!desc)
        { return; }
    var pos, side = 1;
    if (desc instanceof WidgetView) {
        pos = desc.posAtStart;
    }
    else {
        pos = view.posAtCoords(lastMove);
        if (pos == null)
            { return; }
        var 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; }
        var bidi = view.bidiSpans(view.state.doc.lineAt(pos)).find(function (s) { return s.from <= pos && s.to >= pos; });
        var rtl = bidi && bidi.dir == Direction.RTL ? -1 : 1;
        side = (lastMove.x < posCoords.left ? -rtl : rtl);
    }
    var open = this.source(view, pos, side);
    if (open === null || open === void 0 ? void 0 : open.then) {
        var pending = this.pending = { pos: pos };
        open.then(function (result) {
            if (this$1$1.pending == pending) {
                this$1$1.pending = null;
                if (result && !(Array.isArray(result) && !result.length))
                    { view.dispatch({ effects: this$1$1.setHover.of(Array.isArray(result) ? result : [result]) }); }
            }
        }, function (e) { return logException(view.state, e, "hover tooltip"); });
    }
    else if (open && !(Array.isArray(open) && !open.length)) {
        view.dispatch({ effects: this.setHover.of(Array.isArray(open) ? open : [open]) });
    }
};
prototypeAccessors$22.tooltip.get = function () {
    var plugin = this.view.plugin(tooltipPlugin);
    var index = plugin ? plugin.manager.tooltips.findIndex(function (t) { return t.create == HoverTooltipHost.create; }) : -1;
    return index > -1 ? plugin.manager.tooltipViews[index] : null;
};
HoverPlugin.prototype.mousemove = function 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); }
    var ref = this;
        var active = ref.active;
        var tooltip = ref.tooltip;
    if (active.length && tooltip && !isInTooltip(tooltip.dom, event) || this.pending) {
        var ref$1 = active[0] || this.pending;
            var pos = ref$1.pos;
            var 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;
        }
    }
};
HoverPlugin.prototype.mouseleave = function mouseleave (event) {
    clearTimeout(this.hoverTimeout);
    this.hoverTimeout = -1;
    var ref = this;
        var active = ref.active;
    if (active.length) {
        var ref$1 = this;
            var tooltip = ref$1.tooltip;
        var inTooltip = tooltip && tooltip.dom.contains(event.relatedTarget);
        if (!inTooltip)
            { this.view.dispatch({ effects: this.setHover.of([]) }); }
        else
            { this.watchTooltipLeave(tooltip.dom); }
    }
};
HoverPlugin.prototype.watchTooltipLeave = function watchTooltipLeave (tooltip) {
        var this$1$1 = this;

    var watch = function (event) {
        tooltip.removeEventListener("mouseleave", watch);
        if (this$1$1.active.length && !this$1$1.view.dom.contains(event.relatedTarget))
            { this$1$1.view.dispatch({ effects: this$1$1.setHover.of([]) }); }
    };
    tooltip.addEventListener("mouseleave", watch);
};
HoverPlugin.prototype.destroy = function destroy () {
    clearTimeout(this.hoverTimeout);
    this.view.dom.removeEventListener("mouseleave", this.mouseleave);
    this.view.dom.removeEventListener("mousemove", this.mousemove);
};

Object.defineProperties( HoverPlugin.prototype, prototypeAccessors$22 );
var tooltipMargin = 4;
function isInTooltip(tooltip, event) {
    var ref = tooltip.getBoundingClientRect();
    var left = ref.left;
    var right = ref.right;
    var top = ref.top;
    var bottom = ref.bottom;
    var arrow;
    if (arrow = tooltip.querySelector(".cm-tooltip-arrow")) {
        var 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) {
    var rect = view.scrollDOM.getBoundingClientRect();
    var 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; }
    var pos = view.posAtCoords({ x: x, y: y }, false);
    return pos >= from && pos <= to;
}

/**
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.
*/
var GutterMarker = /*@__PURE__*/(function (RangeValue) {
    function GutterMarker () {
        RangeValue.apply(this, arguments);
    }

    if ( RangeValue ) GutterMarker.__proto__ = RangeValue;
    GutterMarker.prototype = Object.create( RangeValue && RangeValue.prototype );
    GutterMarker.prototype.constructor = GutterMarker;

    GutterMarker.prototype.compare = function compare (other) {
        return this == other || this.constructor == other.constructor && this.eq(other);
    };
    /**
    Compare this marker to another marker of the same type.
    */
    GutterMarker.prototype.eq = function eq (other) { return false; };
    /**
    Called if the marker has a `toDOM` method and its representation
    was removed from a gutter.
    */
    GutterMarker.prototype.destroy = function destroy (dom) { };

    return GutterMarker;
}(RangeValue));
GutterMarker.prototype.elementClass = "";
GutterMarker.prototype.toDOM = undefined;
GutterMarker.prototype.mapMode = MapMode.TrackBefore;
GutterMarker.prototype.startSide = GutterMarker.prototype.endSide = -1;
GutterMarker.prototype.point = true;
/**
Facet used to add a class to all gutter elements for a given line.
Markers given to this facet should _only_ define an
[`elementclass`](https://codemirror.net/6/docs/ref/#view.GutterMarker.elementClass), not a
[`toDOM`](https://codemirror.net/6/docs/ref/#view.GutterMarker.toDOM) (or the marker will appear
in all gutters for the line).
*/
var gutterLineClass = /*@__PURE__*/Facet.define();
/**
Facet used to add a class to all gutter elements next to a widget.
Should not provide widgets with a `toDOM` method.
*/
var gutterWidgetClass = /*@__PURE__*/Facet.define();
var activeGutters = /*@__PURE__*/Facet.define();
var unfixGutters = /*@__PURE__*/Facet.define({
    combine: function (values) { return values.some(function (x) { return x; }); }
});
/**
The gutter-drawing plugin is automatically enabled when you add a
gutter, but you can use this function to explicitly configure it.

Unless `fixed` is explicitly set to `false`, the gutters are
fixed, meaning they don't scroll along with the content
horizontally (except on Internet Explorer, which doesn't support
CSS [`position:
sticky`](https://developer.mozilla.org/en-US/docs/Web/CSS/position#sticky)).
*/
function gutters(config) {
    var result = [
        gutterView ];
    if (config && config.fixed === false)
        { result.push(unfixGutters.of(true)); }
    return result;
}
var gutterView = /*@__PURE__*/ViewPlugin.fromClass(/*@__PURE__*/(function () {
    function anonymous$5(view) {
        this.view = view;
        this.prevViewport = view.viewport;
        this.dom = document.createElement("div");
        this.dom.className = "cm-gutters";
        this.dom.setAttribute("aria-hidden", "true");
        this.dom.style.minHeight = (this.view.contentHeight / this.view.scaleY) + "px";
        this.gutters = view.state.facet(activeGutters).map(function (conf) { return new SingleGutterView(view, conf); });
        for (var gutter of this.gutters)
            this.dom.appendChild(gutter.dom);
        this.fixed = !view.state.facet(unfixGutters);
        if (this.fixed) {
            // FIXME IE11 fallback, which doesn't support position: sticky,
            // by using position: relative + event handlers that realign the
            // gutter (or just force fixed=false on IE11?)
            this.dom.style.position = "sticky";
        }
        this.syncGutters(false);
        view.scrollDOM.insertBefore(this.dom, view.contentDOM);
    }
    anonymous$5.prototype.update = function update (update$1) {
        if (this.updateGutters(update$1)) {
            // Detach during sync when the viewport changed significantly
            // (such as during scrolling), since for large updates that is
            // faster.
            var vpA = this.prevViewport, vpB = update$1.view.viewport;
            var vpOverlap = Math.min(vpA.to, vpB.to) - Math.max(vpA.from, vpB.from);
            this.syncGutters(vpOverlap < (vpB.to - vpB.from) * 0.8);
        }
        if (update$1.geometryChanged) {
            this.dom.style.minHeight = (this.view.contentHeight / this.view.scaleY) + "px";
        }
        if (this.view.state.facet(unfixGutters) != !this.fixed) {
            this.fixed = !this.fixed;
            this.dom.style.position = this.fixed ? "sticky" : "";
        }
        this.prevViewport = update$1.view.viewport;
    };
    anonymous$5.prototype.syncGutters = function syncGutters (detach) {
        var this$1$1 = this;

        var after = this.dom.nextSibling;
        if (detach)
            { this.dom.remove(); }
        var lineClasses = RangeSet.iter(this.view.state.facet(gutterLineClass), this.view.viewport.from);
        var classSet = [];
        var contexts = this.gutters.map(function (gutter) { return new UpdateContext(gutter, this$1$1.view.viewport, -this$1$1.view.documentPadding.top); });
        for (var line of this.view.viewportLineBlocks) {
            if (classSet.length)
                { classSet = []; }
            if (Array.isArray(line.type)) {
                var first = true;
                for (var b of line.type) {
                    if (b.type == BlockType.Text && first) {
                        advanceCursor(lineClasses, classSet, b.from);
                        for (var cx of contexts)
                            cx.line(this.view, b, classSet);
                        first = false;
                    }
                    else if (b.widget) {
                        for (var cx$1 of contexts)
                            cx$1.widget(this.view, b);
                    }
                }
            }
            else if (line.type == BlockType.Text) {
                advanceCursor(lineClasses, classSet, line.from);
                for (var cx$2 of contexts)
                    cx$2.line(this.view, line, classSet);
            }
            else if (line.widget) {
                for (var cx$3 of contexts)
                    cx$3.widget(this.view, line);
            }
        }
        for (var cx$4 of contexts)
            cx$4.finish();
        if (detach)
            { this.view.scrollDOM.insertBefore(this.dom, after); }
    };
    anonymous$5.prototype.updateGutters = function updateGutters (update) {
        var prev = update.startState.facet(activeGutters), cur = update.state.facet(activeGutters);
        var change = update.docChanged || update.heightChanged || update.viewportChanged ||
            !RangeSet.eq(update.startState.facet(gutterLineClass), update.state.facet(gutterLineClass), update.view.viewport.from, update.view.viewport.to);
        if (prev == cur) {
            for (var gutter of this.gutters)
                if (gutter.update(update))
                    { change = true; }
        }
        else {
            change = true;
            var gutters = [];
            for (var conf of cur) {
                var known = prev.indexOf(conf);
                if (known < 0) {
                    gutters.push(new SingleGutterView(this.view, conf));
                }
                else {
                    this.gutters[known].update(update);
                    gutters.push(this.gutters[known]);
                }
            }
            for (var g of this.gutters) {
                g.dom.remove();
                if (gutters.indexOf(g) < 0)
                    { g.destroy(); }
            }
            for (var g$1 of gutters)
                this.dom.appendChild(g$1.dom);
            this.gutters = gutters;
        }
        return change;
    };
    anonymous$5.prototype.destroy = function destroy () {
        for (var view of this.gutters)
            view.destroy();
        this.dom.remove();
    };

    return anonymous$5;
}()), {
    provide: function (plugin) { return EditorView.scrollMargins.of(function (view) {
        var value = view.plugin(plugin);
        if (!value || value.gutters.length == 0 || !value.fixed)
            { return null; }
        return view.textDirection == Direction.LTR
            ? { left: value.dom.offsetWidth * view.scaleX }
            : { right: value.dom.offsetWidth * view.scaleX };
    }); }
});
function asArray(val) { return (Array.isArray(val) ? val : [val]); }
function advanceCursor(cursor, collect, pos) {
    while (cursor.value && cursor.from <= pos) {
        if (cursor.from == pos)
            { collect.push(cursor.value); }
        cursor.next();
    }
}
var UpdateContext = function UpdateContext(gutter, viewport, height) {
    this.gutter = gutter;
    this.height = height;
    this.i = 0;
    this.cursor = RangeSet.iter(gutter.markers, viewport.from);
};
UpdateContext.prototype.addElement = function addElement (view, block, markers) {
    var ref = this;
        var gutter = ref.gutter;
        var above = (block.top - this.height) / view.scaleY, height = block.height / view.scaleY;
    if (this.i == gutter.elements.length) {
        var newElt = new GutterElement(view, height, above, markers);
        gutter.elements.push(newElt);
        gutter.dom.appendChild(newElt.dom);
    }
    else {
        gutter.elements[this.i].update(view, height, above, markers);
    }
    this.height = block.bottom;
    this.i++;
};
UpdateContext.prototype.line = function line (view, line$1, extraMarkers) {
    var localMarkers = [];
    advanceCursor(this.cursor, localMarkers, line$1.from);
    if (extraMarkers.length)
        { localMarkers = localMarkers.concat(extraMarkers); }
    var forLine = this.gutter.config.lineMarker(view, line$1, localMarkers);
    if (forLine)
        { localMarkers.unshift(forLine); }
    var gutter = this.gutter;
    if (localMarkers.length == 0 && !gutter.config.renderEmptyElements)
        { return; }
    this.addElement(view, line$1, localMarkers);
};
UpdateContext.prototype.widget = function widget (view, block) {
    var marker = this.gutter.config.widgetMarker(view, block.widget, block), markers = marker ? [marker] : null;
    for (var cls of view.state.facet(gutterWidgetClass)) {
        var marker$1 = cls(view, block.widget, block);
        if (marker$1)
            { (markers || (markers = [])).push(marker$1); }
    }
    if (markers)
        { this.addElement(view, block, markers); }
};
UpdateContext.prototype.finish = function finish () {
    var gutter = this.gutter;
    while (gutter.elements.length > this.i) {
        var last = gutter.elements.pop();
        gutter.dom.removeChild(last.dom);
        last.destroy();
    }
};
var SingleGutterView = function SingleGutterView(view, config) {
    var this$1$1 = this;

    this.view = view;
    this.config = config;
    this.elements = [];
    this.spacer = null;
    this.dom = document.createElement("div");
    this.dom.className = "cm-gutter" + (this.config.class ? " " + this.config.class : "");
    var loop = function ( prop ) {
        this$1$1.dom.addEventListener(prop, function (event) {
            var target = event.target, y;
            if (target != this$1$1.dom && this$1$1.dom.contains(target)) {
                while (target.parentNode != this$1$1.dom)
                    { target = target.parentNode; }
                var rect = target.getBoundingClientRect();
                y = (rect.top + rect.bottom) / 2;
            }
            else {
                y = event.clientY;
            }
            var line = view.lineBlockAtHeight(y - view.documentTop);
            if (config.domEventHandlers[prop](view, line, event))
                { event.preventDefault(); }
        });
    };

    for (var prop in config.domEventHandlers) loop( prop );
    this.markers = asArray(config.markers(view));
    if (config.initialSpacer) {
        this.spacer = new GutterElement(view, 0, 0, [config.initialSpacer(view)]);
        this.dom.appendChild(this.spacer.dom);
        this.spacer.dom.style.cssText += "visibility: hidden; pointer-events: none";
    }
};
SingleGutterView.prototype.update = function update (update$1) {
    var prevMarkers = this.markers;
    this.markers = asArray(this.config.markers(update$1.view));
    if (this.spacer && this.config.updateSpacer) {
        var updated = this.config.updateSpacer(this.spacer.markers[0], update$1);
        if (updated != this.spacer.markers[0])
            { this.spacer.update(update$1.view, 0, 0, [updated]); }
    }
    var vp = update$1.view.viewport;
    return !RangeSet.eq(this.markers, prevMarkers, vp.from, vp.to) ||
        (this.config.lineMarkerChange ? this.config.lineMarkerChange(update$1) : false);
};
SingleGutterView.prototype.destroy = function destroy () {
    for (var elt of this.elements)
        elt.destroy();
};
var GutterElement = function GutterElement(view, height, above, markers) {
    this.height = -1;
    this.above = 0;
    this.markers = [];
    this.dom = document.createElement("div");
    this.dom.className = "cm-gutterElement";
    this.update(view, height, above, markers);
};
GutterElement.prototype.update = function update (view, height, above, markers) {
    if (this.height != height) {
        this.height = height;
        this.dom.style.height = height + "px";
    }
    if (this.above != above)
        { this.dom.style.marginTop = (this.above = above) ? above + "px" : ""; }
    if (!sameMarkers(this.markers, markers))
        { this.setMarkers(view, markers); }
};
GutterElement.prototype.setMarkers = function setMarkers (view, markers) {
    var cls = "cm-gutterElement", domPos = this.dom.firstChild;
    for (var iNew = 0, iOld = 0;;) {
        var skipTo = iOld, marker = iNew < markers.length ? markers[iNew++] : null, matched = false;
        if (marker) {
            var c = marker.elementClass;
            if (c)
                { cls += " " + c; }
            for (var i = iOld; i < this.markers.length; i++)
                { if (this.markers[i].compare(marker)) {
                    skipTo = i;
                    matched = true;
                    break;
                } }
        }
        else {
            skipTo = this.markers.length;
        }
        while (iOld < skipTo) {
            var next = this.markers[iOld++];
            if (next.toDOM) {
                next.destroy(domPos);
                var after = domPos.nextSibling;
                domPos.remove();
                domPos = after;
            }
        }
        if (!marker)
            { break; }
        if (marker.toDOM) {
            if (matched)
                { domPos = domPos.nextSibling; }
            else
                { this.dom.insertBefore(marker.toDOM(view), domPos); }
        }
        if (matched)
            { iOld++; }
    }
    this.dom.className = cls;
    this.markers = markers;
};
GutterElement.prototype.destroy = function destroy () {
    this.setMarkers(null, []); // First argument not used unless creating markers
};
function sameMarkers(a, b) {
    if (a.length != b.length)
        { return false; }
    for (var i = 0; i < a.length; i++)
        { if (!a[i].compare(b[i]))
            { return false; } }
    return true;
}
/**
Facet used to provide markers to the line number gutter.
*/
var lineNumberMarkers = /*@__PURE__*/Facet.define();
/**
Facet used to create markers in the line number gutter next to widgets.
*/
var lineNumberWidgetMarker = /*@__PURE__*/Facet.define();
var lineNumberConfig = /*@__PURE__*/Facet.define({
    combine: function combine(values) {
        return combineConfig(values, { formatNumber: String, domEventHandlers: {} }, {
            domEventHandlers: function domEventHandlers(a, b) {
                var result = Object.assign({}, a);
                var loop = function ( event ) {
                    var exists = result[event], add = b[event];
                    result[event] = exists ? function (view, line, event) { return exists(view, line, event) || add(view, line, event); } : add;
                };

                for (var event in b) loop( event );
                return result;
            }
        });
    }
});
var NumberMarker = /*@__PURE__*/(function (GutterMarker) {
    function NumberMarker(number) {
        GutterMarker.call(this);
        this.number = number;
    }

    if ( GutterMarker ) NumberMarker.__proto__ = GutterMarker;
    NumberMarker.prototype = Object.create( GutterMarker && GutterMarker.prototype );
    NumberMarker.prototype.constructor = NumberMarker;
    NumberMarker.prototype.eq = function eq (other) { return this.number == other.number; };
    NumberMarker.prototype.toDOM = function toDOM () { return document.createTextNode(this.number); };

    return NumberMarker;
}(GutterMarker));
function formatNumber(view, number) {
    return view.state.facet(lineNumberConfig).formatNumber(number, view.state);
}
var lineNumberGutter = /*@__PURE__*/activeGutters.compute([lineNumberConfig], function (state) { return ({
    class: "cm-lineNumbers",
    renderEmptyElements: false,
    markers: function markers(view) { return view.state.facet(lineNumberMarkers); },
    lineMarker: function lineMarker(view, line, others) {
        if (others.some(function (m) { return m.toDOM; }))
            { return null; }
        return new NumberMarker(formatNumber(view, view.state.doc.lineAt(line.from).number));
    },
    widgetMarker: function (view, widget, block) {
        for (var m of view.state.facet(lineNumberWidgetMarker)) {
            var result = m(view, widget, block);
            if (result)
                { return result; }
        }
        return null;
    },
    lineMarkerChange: function (update) { return update.startState.facet(lineNumberConfig) != update.state.facet(lineNumberConfig); },
    initialSpacer: function initialSpacer(view) {
        return new NumberMarker(formatNumber(view, maxLineNumber(view.state.doc.lines)));
    },
    updateSpacer: function updateSpacer(spacer, update) {
        var max = formatNumber(update.view, maxLineNumber(update.view.state.doc.lines));
        return max == spacer.number ? spacer : new NumberMarker(max);
    },
    domEventHandlers: state.facet(lineNumberConfig).domEventHandlers
}); });
/**
Create a line number gutter extension.
*/
function lineNumbers(config) {
    if ( config === void 0 ) config = {};

    return [
        lineNumberConfig.of(config),
        gutters(),
        lineNumberGutter
    ];
}
function maxLineNumber(lines) {
    var last = 9;
    while (last < lines)
        { last = last * 10 + 9; }
    return last;
}/**
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 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) {
        this.tree = tree;
        this.overlay = overlay;
        this.parser = parser;
    }
    /**
    @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 */);
/**
A node set holds a collection of node types. It is used to
compactly represent trees by storing their type ids, rather than a
full pointer to the type object, in a numeric array. Each parser
[has](#lr.LRParser.nodeSet) a node set, and [tree
buffers](#common.TreeBuffer) can only store collections of nodes
from the same set. A set can have a maximum of 2**16 (65536) node
types in it, so that the ids fit into 16-bit typed array slots.
*/
class NodeSet {
    /**
    Create a set with the given types. The `id` property of each
    type should correspond to its position within the array.
    */
    constructor(
    /**
    The node types in this set, by id.
    */
    types) {
        this.types = types;
        for (let i = 0; i < types.length; i++)
            if (types[i].id != i)
                throw new RangeError("Node type ids should correspond to array positions when creating a node set");
    }
    /**
    Create a copy of this set with some node properties added. The
    arguments to this method can be created with
    [`NodeProp.add`](#common.NodeProp.add).
    */
    extend(...props) {
        let newTypes = [];
        for (let type of this.types) {
            let newProps = null;
            for (let source of props) {
                let add = source(type);
                if (add) {
                    if (!newProps)
                        newProps = Object.assign({}, type.props);
                    newProps[add[0].id] = add[1];
                }
            }
            newTypes.push(newProps ? new NodeType(type.name, newProps, type.id, type.flags) : type);
        }
        return new NodeSet(newTypes);
    }
}
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";
})(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, 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;
                if (!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);
                }
            }
            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 */); }
    enter(pos, side, mode = 0) {
        let mounted;
        if (!(mode & IterMode.IgnoreOverlays) && (mounted = MountedTree.get(this._tree)) && mounted.overlay) {
            let rPos = pos - this.from;
            for (let { from, to } of mounted.overlay) {
                if ((side > 0 ? from <= rPos : from < rPos) &&
                    (side < 0 ? 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.parent; 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 */); }
    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, 
    /**
    @internal
    */
    mode = 0) {
        this.mode = mode;
        /**
        @internal
        */
        this.buffer = null;
        this.stack = [];
        /**
        @internal
        */
        this.index = 0;
        this.bufferNode = null;
        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 traveral. 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 (this.nextSibling())
                    break;
                if (!depth)
                    return;
                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, 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.node, 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;
        while (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);
                        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);
            localChildren.reverse();
            localPositions.reverse();
            if (localInRepeat > -1 && lastGroup > 0) {
                let make = makeBalanced(type);
                node = balanceRange(type, localChildren, localPositions, 0, localChildren.length, 0, end - start, make, make);
            }
            else {
                node = makeTree(type, localChildren, localPositions, end - start, lookAheadAtStart - end);
            }
        }
        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) {
        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);
        };
    }
    function makeRepeatLeaf(children, positions, base, i, from, to, type, lookAhead) {
        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));
        positions.push(from - base);
    }
    function makeTree(type, children, positions, length, lookAhead = 0, 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 */)
                        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);
}
/**
Provides a way to associate values with pieces of trees. As long
as that part of the tree is reused, the associated values can be
retrieved from an updated tree.
*/
class NodeWeakMap {
    constructor() {
        this.map = new WeakMap();
    }
    setBuffer(buffer, index, value) {
        let inner = this.map.get(buffer);
        if (!inner)
            this.map.set(buffer, inner = new Map);
        inner.set(index, value);
    }
    getBuffer(buffer, index) {
        let inner = this.map.get(buffer);
        return inner && inner.get(index);
    }
    /**
    Set the value for this syntax node.
    */
    set(node, value) {
        if (node instanceof BufferNode)
            this.setBuffer(node.context.buffer, node.index, value);
        else if (node instanceof TreeNode)
            this.map.set(node.tree, value);
    }
    /**
    Retrieve value for this syntax node, if it exists in the map.
    */
    get(node) {
        return node instanceof BufferNode ? this.getBuffer(node.context.buffer, node.index)
            : node instanceof TreeNode ? this.map.get(node.tree) : undefined;
    }
    /**
    Set the value for the node that a cursor currently points to.
    */
    cursorSet(cursor, value) {
        if (cursor.buffer)
            this.setBuffer(cursor.buffer.buffer, cursor.index, value);
        else
            this.map.set(cursor.tree, value);
    }
    /**
    Retrieve the value for the node that a cursor currently points
    to.
    */
    cursorGet(cursor) {
        return cursor.buffer ? this.getBuffer(cursor.buffer.buffer, cursor.index) : this.map.get(cursor.tree);
    }
}

/**
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.withProps(
  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();
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$1 = Tag.define;
const comment$1 = t$1(), name = t$1(), typeName = t$1(name), propertyName = t$1(name), literal = t$1(), string = t$1(literal), number = t$1(literal), content = t$1(), heading$2 = t$1(content), keyword = t$1(), operator = t$1(), punctuation = t$1(), bracket = t$1(punctuation), meta = t$1();
/**
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: comment$1,
    /**
    A line [comment](#highlight.tags.comment).
    */
    lineComment: t$1(comment$1),
    /**
    A block [comment](#highlight.tags.comment).
    */
    blockComment: t$1(comment$1),
    /**
    A documentation [comment](#highlight.tags.comment).
    */
    docComment: t$1(comment$1),
    /**
    Any kind of identifier.
    */
    name,
    /**
    The [name](#highlight.tags.name) of a variable.
    */
    variableName: t$1(name),
    /**
    A type [name](#highlight.tags.name).
    */
    typeName: typeName,
    /**
    A tag name (subtag of [`typeName`](#highlight.tags.typeName)).
    */
    tagName: t$1(typeName),
    /**
    A property or field [name](#highlight.tags.name).
    */
    propertyName: propertyName,
    /**
    An attribute name (subtag of [`propertyName`](#highlight.tags.propertyName)).
    */
    attributeName: t$1(propertyName),
    /**
    The [name](#highlight.tags.name) of a class.
    */
    className: t$1(name),
    /**
    A label [name](#highlight.tags.name).
    */
    labelName: t$1(name),
    /**
    A namespace [name](#highlight.tags.name).
    */
    namespace: t$1(name),
    /**
    The [name](#highlight.tags.name) of a macro.
    */
    macroName: t$1(name),
    /**
    A literal value.
    */
    literal,
    /**
    A string [literal](#highlight.tags.literal).
    */
    string,
    /**
    A documentation [string](#highlight.tags.string).
    */
    docString: t$1(string),
    /**
    A character literal (subtag of [string](#highlight.tags.string)).
    */
    character: t$1(string),
    /**
    An attribute value (subtag of [string](#highlight.tags.string)).
    */
    attributeValue: t$1(string),
    /**
    A number [literal](#highlight.tags.literal).
    */
    number,
    /**
    An integer [number](#highlight.tags.number) literal.
    */
    integer: t$1(number),
    /**
    A floating-point [number](#highlight.tags.number) literal.
    */
    float: t$1(number),
    /**
    A boolean [literal](#highlight.tags.literal).
    */
    bool: t$1(literal),
    /**
    Regular expression [literal](#highlight.tags.literal).
    */
    regexp: t$1(literal),
    /**
    An escape [literal](#highlight.tags.literal), for example a
    backslash escape in a string.
    */
    escape: t$1(literal),
    /**
    A color [literal](#highlight.tags.literal).
    */
    color: t$1(literal),
    /**
    A URL [literal](#highlight.tags.literal).
    */
    url: t$1(literal),
    /**
    A language keyword.
    */
    keyword,
    /**
    The [keyword](#highlight.tags.keyword) for the self or this
    object.
    */
    self: t$1(keyword),
    /**
    The [keyword](#highlight.tags.keyword) for null.
    */
    null: t$1(keyword),
    /**
    A [keyword](#highlight.tags.keyword) denoting some atomic value.
    */
    atom: t$1(keyword),
    /**
    A [keyword](#highlight.tags.keyword) that represents a unit.
    */
    unit: t$1(keyword),
    /**
    A modifier [keyword](#highlight.tags.keyword).
    */
    modifier: t$1(keyword),
    /**
    A [keyword](#highlight.tags.keyword) that acts as an operator.
    */
    operatorKeyword: t$1(keyword),
    /**
    A control-flow related [keyword](#highlight.tags.keyword).
    */
    controlKeyword: t$1(keyword),
    /**
    A [keyword](#highlight.tags.keyword) that defines something.
    */
    definitionKeyword: t$1(keyword),
    /**
    A [keyword](#highlight.tags.keyword) related to defining or
    interfacing with modules.
    */
    moduleKeyword: t$1(keyword),
    /**
    An operator.
    */
    operator,
    /**
    An [operator](#highlight.tags.operator) that dereferences something.
    */
    derefOperator: t$1(operator),
    /**
    Arithmetic-related [operator](#highlight.tags.operator).
    */
    arithmeticOperator: t$1(operator),
    /**
    Logical [operator](#highlight.tags.operator).
    */
    logicOperator: t$1(operator),
    /**
    Bit [operator](#highlight.tags.operator).
    */
    bitwiseOperator: t$1(operator),
    /**
    Comparison [operator](#highlight.tags.operator).
    */
    compareOperator: t$1(operator),
    /**
    [Operator](#highlight.tags.operator) that updates its operand.
    */
    updateOperator: t$1(operator),
    /**
    [Operator](#highlight.tags.operator) that defines something.
    */
    definitionOperator: t$1(operator),
    /**
    Type-related [operator](#highlight.tags.operator).
    */
    typeOperator: t$1(operator),
    /**
    Control-flow [operator](#highlight.tags.operator).
    */
    controlOperator: t$1(operator),
    /**
    Program or markup punctuation.
    */
    punctuation,
    /**
    [Punctuation](#highlight.tags.punctuation) that separates
    things.
    */
    separator: t$1(punctuation),
    /**
    Bracket-style [punctuation](#highlight.tags.punctuation).
    */
    bracket,
    /**
    Angle [brackets](#highlight.tags.bracket) (usually `<` and `>`
    tokens).
    */
    angleBracket: t$1(bracket),
    /**
    Square [brackets](#highlight.tags.bracket) (usually `[` and `]`
    tokens).
    */
    squareBracket: t$1(bracket),
    /**
    Parentheses (usually `(` and `)` tokens). Subtag of
    [bracket](#highlight.tags.bracket).
    */
    paren: t$1(bracket),
    /**
    Braces (usually `{` and `}` tokens). Subtag of
    [bracket](#highlight.tags.bracket).
    */
    brace: t$1(bracket),
    /**
    Content, for example plain text in XML or markup documents.
    */
    content,
    /**
    [Content](#highlight.tags.content) that represents a heading.
    */
    heading: heading$2,
    /**
    A level 1 [heading](#highlight.tags.heading).
    */
    heading1: t$1(heading$2),
    /**
    A level 2 [heading](#highlight.tags.heading).
    */
    heading2: t$1(heading$2),
    /**
    A level 3 [heading](#highlight.tags.heading).
    */
    heading3: t$1(heading$2),
    /**
    A level 4 [heading](#highlight.tags.heading).
    */
    heading4: t$1(heading$2),
    /**
    A level 5 [heading](#highlight.tags.heading).
    */
    heading5: t$1(heading$2),
    /**
    A level 6 [heading](#highlight.tags.heading).
    */
    heading6: t$1(heading$2),
    /**
    A prose [content](#highlight.tags.content) separator (such as a horizontal rule).
    */
    contentSeparator: t$1(content),
    /**
    [Content](#highlight.tags.content) that represents a list.
    */
    list: t$1(content),
    /**
    [Content](#highlight.tags.content) that represents a quote.
    */
    quote: t$1(content),
    /**
    [Content](#highlight.tags.content) that is emphasized.
    */
    emphasis: t$1(content),
    /**
    [Content](#highlight.tags.content) that is styled strong.
    */
    strong: t$1(content),
    /**
    [Content](#highlight.tags.content) that is part of a link.
    */
    link: t$1(content),
    /**
    [Content](#highlight.tags.content) that is styled as code or
    monospace.
    */
    monospace: t$1(content),
    /**
    [Content](#highlight.tags.content) that has a strike-through
    style.
    */
    strikethrough: t$1(content),
    /**
    Inserted text in a change-tracking format.
    */
    inserted: t$1(),
    /**
    Deleted text.
    */
    deleted: t$1(),
    /**
    Changed text.
    */
    changed: t$1(),
    /**
    An invalid or unsyntactic element.
    */
    invalid: t$1(),
    /**
    Metadata or meta-instruction.
    */
    meta,
    /**
    [Metadata](#highlight.tags.meta) that applies to the entire
    document.
    */
    documentMeta: t$1(meta),
    /**
    [Metadata](#highlight.tags.meta) that annotates or adds
    attributes to a given syntactic element.
    */
    annotation: t$1(meta),
    /**
    Processing instruction or preprocessor directive. Subtag of
    [meta](#highlight.tags.meta).
    */
    processingInstruction: t$1(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.
*/
var languageDataProp = /*@__PURE__*/new NodeProp();
/**
Helper function to define a facet (to be added to the top syntax
node(s) for a language via
[`languageDataProp`](https://codemirror.net/6/docs/ref/#language.languageDataProp)), that will be
used to associate language data with the language. You
probably only need this when subclassing
[`Language`](https://codemirror.net/6/docs/ref/#language.Language).
*/
function defineLanguageFacet(baseData) {
    return Facet.define({
        combine: baseData ? function (values) { return values.concat(baseData); } : undefined
    });
}
/**
Syntax node prop used to register sublanguages. Should be added to
the top level node type for the language.
*/
var 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.
*/
var Language = function Language(
/**
The [language data](https://codemirror.net/6/docs/ref/#state.EditorState.languageDataAt) facet
used for this language.
*/
data, parser, extraExtensions, 
/**
A language name.
*/
name) {
    if ( extraExtensions === void 0 ) extraExtensions = [];
    if ( name === void 0 ) 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: function get() { return syntaxTree(this); } }); }
    this.parser = parser;
    this.extension = [
        language.of(this),
        EditorState.languageData.of(function (state, pos, side) {
            var top = topNodeAt(state, pos, side), data = top.type.prop(languageDataProp);
            if (!data)
                { return []; }
            var base = state.facet(data), sub = top.type.prop(sublanguageProp);
            if (sub) {
                var innerNode = top.resolve(pos - top.from, side);
                for (var sublang of sub)
                    if (sublang.test(innerNode, state)) {
                        var data$1 = state.facet(sublang.facet);
                        return sublang.type == "replace" ? data$1 : data$1.concat(base);
                    }
            }
            return base;
        })
    ].concat(extraExtensions);
};

var prototypeAccessors$2 = { allowsNesting: { configurable: true } };
/**
Query whether this language is active at the given position.
*/
Language.prototype.isActiveAt = function isActiveAt (state, pos, side) {
        if ( side === void 0 ) 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.
*/
Language.prototype.findRegions = function findRegions (state) {
        var this$1$1 = this;

    var 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 []; }
    var result = [];
    var explore = function (tree, from) {
        if (tree.prop(languageDataProp) == this$1$1.data) {
            result.push({ from: from, to: from + tree.length });
            return;
        }
        var mount = tree.prop(NodeProp.mounted);
        if (mount) {
            if (mount.tree.prop(languageDataProp) == this$1$1.data) {
                if (mount.overlay)
                    { for (var 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) {
                var size = result.length;
                explore(mount.tree, mount.overlay[0].from + from);
                if (result.length > size)
                    { return; }
            }
        }
        for (var i = 0; i < tree.children.length; i++) {
            var 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.
*/
prototypeAccessors$2.allowsNesting.get = function () { return true; };

Object.defineProperties( Language.prototype, prototypeAccessors$2 );
/**
@internal
*/
Language.setState = /*@__PURE__*/StateEffect.define();
function topNodeAt(state, pos, side) {
    var topLang = state.facet(language), tree = syntaxTree(state).topNode;
    if (!topLang || topLang.allowsNesting) {
        for (var node = tree; node; node = node.enter(pos, side, IterMode.ExcludeBuffers))
            { if (node.type.isTop)
                { tree = node; } }
    }
    return tree;
}
/**
A subclass of [`Language`](https://codemirror.net/6/docs/ref/#language.Language) for use with Lezer
[LR parsers](https://lezer.codemirror.net/docs/ref#lr.LRParser)
parsers.
*/
var LRLanguage = /*@__PURE__*/(function (Language) {
    function LRLanguage(data, parser, name) {
        Language.call(this, data, parser, [], name);
        this.parser = parser;
    }

    if ( Language ) LRLanguage.__proto__ = Language;
    LRLanguage.prototype = Object.create( Language && Language.prototype );
    LRLanguage.prototype.constructor = LRLanguage;

    var prototypeAccessors$1 = { allowsNesting: { configurable: true } };
    /**
    Define a language from a parser.
    */
    LRLanguage.define = function define (spec) {
        var data = defineLanguageFacet(spec.languageData);
        return new LRLanguage(data, spec.parser.configure({
            props: [languageDataProp.add(function (type) { return type.isTop ? data : undefined; })]
        }), spec.name);
    };
    /**
    Create a new instance of this language with a reconfigured
    version of its parser and optionally a new name.
    */
    LRLanguage.prototype.configure = function configure (options, name) {
        return new LRLanguage(this.data, this.parser.configure(options), name || this.name);
    };
    prototypeAccessors$1.allowsNesting.get = function () { return this.parser.hasWrappers(); };

    Object.defineProperties( LRLanguage.prototype, prototypeAccessors$1 );

    return LRLanguage;
}(Language));
/**
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) {
    var 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.
*/
var DocInput = function DocInput(doc) {
    this.doc = doc;
    this.cursorPos = 0;
    this.string = "";
    this.cursor = doc.iter();
};

var prototypeAccessors$2$1 = { length: { configurable: true },lineChunks: { configurable: true } };
prototypeAccessors$2$1.length.get = function () { return this.doc.length; };
DocInput.prototype.syncTo = function syncTo (pos) {
    this.string = this.cursor.next(pos - this.cursorPos).value;
    this.cursorPos = pos + this.string.length;
    return this.cursorPos - this.string.length;
};
DocInput.prototype.chunk = function chunk (pos) {
    this.syncTo(pos);
    return this.string;
};
prototypeAccessors$2$1.lineChunks.get = function () { return true; };
DocInput.prototype.read = function read (from, to) {
    var 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); }
};

Object.defineProperties( DocInput.prototype, prototypeAccessors$2$1 );
var currentContext = null;
/**
A parse context provided to parsers working on the editor content.
*/
var ParseContext = function ParseContext(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) {
    if ( fragments === void 0 ) fragments = [];

    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
*/
ParseContext.create = function create (parser, state, viewport) {
    return new ParseContext(parser, state, [], Tree.empty, 0, viewport, [], null);
};
ParseContext.prototype.startParse = function startParse () {
    return this.parser.startParse(new DocInput(this.state.doc), this.fragments);
};
/**
@internal
*/
ParseContext.prototype.work = function work (until, upto) {
        var this$1$1 = this;

    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(function () {
        var _a;
        if (typeof until == "number") {
            var endTime = Date.now() + until;
            until = function () { return Date.now() > endTime; };
        }
        if (!this$1$1.parse)
            { this$1$1.parse = this$1$1.startParse(); }
        if (upto != null && (this$1$1.parse.stoppedAt == null || this$1$1.parse.stoppedAt > upto) &&
            upto < this$1$1.state.doc.length)
            { this$1$1.parse.stopAt(upto); }
        for (;;) {
            var done = this$1$1.parse.advance();
            if (done) {
                this$1$1.fragments = this$1$1.withoutTempSkipped(TreeFragment.addTree(done, this$1$1.fragments, this$1$1.parse.stoppedAt != null));
                this$1$1.treeLen = (_a = this$1$1.parse.stoppedAt) !== null && _a !== void 0 ? _a : this$1$1.state.doc.length;
                this$1$1.tree = done;
                this$1$1.parse = null;
                if (this$1$1.treeLen < (upto !== null && upto !== void 0 ? upto : this$1$1.state.doc.length))
                    { this$1$1.parse = this$1$1.startParse(); }
                else
                    { return true; }
            }
            if (until())
                { return false; }
        }
    });
};
/**
@internal
*/
ParseContext.prototype.takeTree = function takeTree () {
        var this$1$1 = this;

    var 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(function () { while (!(tree = this$1$1.parse.advance())) { } });
        this.treeLen = pos;
        this.tree = tree;
        this.fragments = this.withoutTempSkipped(TreeFragment.addTree(this.tree, this.fragments, true));
        this.parse = null;
    }
};
ParseContext.prototype.withContext = function withContext (f) {
    var prev = currentContext;
    currentContext = this;
    try {
        return f();
    }
    finally {
        currentContext = prev;
    }
};
ParseContext.prototype.withoutTempSkipped = function withoutTempSkipped (fragments) {
    for (var r = (void 0); r = this.tempSkipped.pop();)
        { fragments = cutFragments(fragments, r.from, r.to); }
    return fragments;
};
/**
@internal
*/
ParseContext.prototype.changes = function changes (changes$1, newState) {
    var ref = this;
        var fragments = ref.fragments;
        var tree = ref.tree;
        var treeLen = ref.treeLen;
        var viewport = ref.viewport;
        var skipped = ref.skipped;
    this.takeTree();
    if (!changes$1.empty) {
        var ranges = [];
        changes$1.iterChangedRanges(function (fromA, toA, fromB, toB) { return ranges.push({ fromA: fromA, toA: toA, fromB: fromB, toB: toB }); });
        fragments = TreeFragment.applyChanges(fragments, ranges);
        tree = Tree.empty;
        treeLen = 0;
        viewport = { from: changes$1.mapPos(viewport.from, -1), to: changes$1.mapPos(viewport.to, 1) };
        if (this.skipped.length) {
            skipped = [];
            for (var r of this.skipped) {
                var from = changes$1.mapPos(r.from, 1), to = changes$1.mapPos(r.to, -1);
                if (from < to)
                    { skipped.push({ from: from, to: to }); }
            }
        }
    }
    return new ParseContext(this.parser, newState, fragments, tree, treeLen, viewport, skipped, this.scheduleOn);
};
/**
@internal
*/
ParseContext.prototype.updateViewport = function updateViewport (viewport) {
    if (this.viewport.from == viewport.from && this.viewport.to == viewport.to)
        { return false; }
    this.viewport = viewport;
    var startLen = this.skipped.length;
    for (var i = 0; i < this.skipped.length; i++) {
        var ref = this.skipped[i];
            var from = ref.from;
            var to = ref.to;
        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
*/
ParseContext.prototype.reset = function 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.
*/
ParseContext.prototype.skipUntilInView = function skipUntilInView (from, to) {
    this.skipped.push({ from: from, to: 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.
*/
ParseContext.getSkippingParser = function getSkippingParser (until) {
    return new /*@__PURE__*/(function (Parser) {
            function anonymous () {
                Parser.apply(this, arguments);
            }

            if ( Parser ) anonymous.__proto__ = Parser;
            anonymous.prototype = Object.create( Parser && Parser.prototype );
            anonymous.prototype.constructor = anonymous;

            anonymous.prototype.createParse = function createParse (input, fragments, ranges) {
            var from = ranges[0].from, to = ranges[ranges.length - 1].to;
            var parser = {
                parsedPos: from,
                advance: function advance() {
                    var cx = currentContext;
                    if (cx) {
                        for (var 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: function stopAt() { }
            };
            return parser;
        };

            return anonymous;
        }(Parser));
};
/**
@internal
*/
ParseContext.prototype.isDone = function isDone (upto) {
    upto = Math.min(upto, this.state.doc.length);
    var 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.
*/
ParseContext.get = function get () { return currentContext; };
function cutFragments(fragments, from, to) {
    return TreeFragment.applyChanges(fragments, [{ fromA: from, toA: to, fromB: from, toB: to }]);
}
var LanguageState = function LanguageState(
// 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;
};
LanguageState.prototype.apply = function apply (tr) {
    if (!tr.docChanged && this.tree == this.context.tree)
        { return this; }
    var 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.
    var 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);
};
LanguageState.init = function init (state) {
    var vpTo = Math.min(3000 /* Work.InitViewport */, state.doc.length);
    var 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: function update(value, tr) {
        for (var 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);
    }
});
var requestIdle = function (callback) {
    var timeout = setTimeout(function () { return callback(); }, 500 /* Work.MaxPause */);
    return function () { return clearTimeout(timeout); };
};
if (typeof requestIdleCallback != "undefined")
    { requestIdle = function (callback) {
        var idle = -1, timeout = setTimeout(function () {
            idle = requestIdleCallback(callback, { timeout: 500 /* Work.MaxPause */ - 100 /* Work.MinPause */ });
        }, 100 /* Work.MinPause */);
        return function () { return idle < 0 ? clearTimeout(timeout) : cancelIdleCallback(idle); };
    }; }
var isInputPending = typeof navigator != "undefined" && ((_a = navigator.scheduling) === null || _a === void 0 ? void 0 : _a.isInputPending)
    ? function () { return navigator.scheduling.isInputPending(); } : null;
var parseWorker = /*@__PURE__*/ViewPlugin.fromClass(/*@__PURE__*/(function () {
    function ParseWorker(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();
    }
    ParseWorker.prototype.update = function update (update$1) {
        var cx = this.view.state.field(Language.state).context;
        if (cx.updateViewport(update$1.view.viewport) || this.view.viewport.to > cx.treeLen)
            { this.scheduleWork(); }
        if (update$1.docChanged || update$1.selectionSet) {
            if (this.view.hasFocus)
                { this.chunkBudget += 50 /* Work.ChangeBonus */; }
            this.scheduleWork();
        }
        this.checkAsyncSchedule(cx);
    };
    ParseWorker.prototype.scheduleWork = function scheduleWork () {
        if (this.working)
            { return; }
        var ref = this.view;
        var state = ref.state;
        var field = state.field(Language.state);
        if (field.tree != field.context.tree || !field.context.isDone(state.doc.length))
            { this.working = requestIdle(this.work); }
    };
    ParseWorker.prototype.work = function work (deadline) {
        this.working = null;
        var 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
        var ref = this.view;
        var state = ref.state;
        var vpTo = ref.viewport.to;
        var field = state.field(Language.state);
        if (field.tree == field.context.tree && field.context.isDone(vpTo + 100000 /* Work.MaxParseAhead */))
            { return; }
        var endTime = Date.now() + Math.min(this.chunkBudget, 100 /* Work.Slice */, deadline && !isInputPending ? Math.max(25 /* Work.MinSlice */, deadline.timeRemaining() - 5) : 1e9);
        var viewportFirst = field.context.treeLen < vpTo && state.doc.length > vpTo + 1000;
        var done = field.context.work(function () {
            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);
    };
    ParseWorker.prototype.checkAsyncSchedule = function checkAsyncSchedule (cx) {
        var this$1$1 = this;

        if (cx.scheduleOn) {
            this.workScheduled++;
            cx.scheduleOn
                .then(function () { return this$1$1.scheduleWork(); })
                .catch(function (err) { return logException(this$1$1.view.state, err); })
                .then(function () { return this$1$1.workScheduled--; });
            cx.scheduleOn = null;
        }
    };
    ParseWorker.prototype.destroy = function destroy () {
        if (this.working)
            { this.working(); }
    };
    ParseWorker.prototype.isWorking = function isWorking () {
        return !!(this.working || this.workScheduled > 0);
    };

    return ParseWorker;
}()), {
    eventHandlers: { focus: function 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.
*/
var language = /*@__PURE__*/Facet.define({
    combine: function combine(languages) { return languages.length ? languages[0] : null; },
    enables: function (language) { return [
        Language.state,
        parseWorker,
        EditorView.contentAttributes.compute([language], function (state) {
            var lang = state.facet(language);
            return lang && lang.name ? { "data-language": lang.name } : {};
        })
    ]; }
});
/**
This class bundles a [language](https://codemirror.net/6/docs/ref/#language.Language) with an
optional set of supporting extensions. Language packages are
encouraged to export a function that optionally takes a
configuration object and returns a `LanguageSupport` instance, as
the main way for client code to use the package.
*/
var LanguageSupport = function LanguageSupport(
/**
The language object.
*/
language, 
/**
An optional set of supporting extensions. When nesting a
language in another language, the outer language is encouraged
to include the supporting extensions for its inner languages
in its own set of support extensions.
*/
support) {
    if ( support === void 0 ) support = [];

    this.language = language;
    this.support = support;
    this.extension = [language, support];
};

/**
Facet that defines a way to provide a function that computes the
appropriate indentation depth, as a column number (see
[`indentString`](https://codemirror.net/6/docs/ref/#language.indentString)), at the start of a given
line. A return value of `null` indicates no indentation can be
determined, and the line should inherit the indentation of the one
above it. A return value of `undefined` defers to the next indent
service.
*/
var indentService = /*@__PURE__*/Facet.define();
/**
Facet for overriding the unit by which indentation happens. Should
be a string consisting either entirely of the same whitespace
character. When not set, this defaults to 2 spaces.
*/
var indentUnit = /*@__PURE__*/Facet.define({
    combine: function (values) {
        if (!values.length)
            { return "  "; }
        var unit = values[0];
        if (!unit || /\S/.test(unit) || Array.from(unit).some(function (e) { return e != unit[0]; }))
            { throw new Error("Invalid indent unit: " + JSON.stringify(values[0])); }
        return unit;
    }
});
/**
Return the _column width_ of an indent unit in the state.
Determined by the [`indentUnit`](https://codemirror.net/6/docs/ref/#language.indentUnit)
facet, and [`tabSize`](https://codemirror.net/6/docs/ref/#state.EditorState^tabSize) when that
contains tabs.
*/
function getIndentUnit(state) {
    var unit = state.facet(indentUnit);
    return unit.charCodeAt(0) == 9 ? state.tabSize * unit.length : unit.length;
}
/**
Create an indentation string that covers columns 0 to `cols`.
Will use tabs for as much of the columns as possible when the
[`indentUnit`](https://codemirror.net/6/docs/ref/#language.indentUnit) facet contains
tabs.
*/
function indentString(state, cols) {
    var result = "", ts = state.tabSize, ch = state.facet(indentUnit)[0];
    if (ch == "\t") {
        while (cols >= ts) {
            result += "\t";
            cols -= ts;
        }
        ch = " ";
    }
    for (var i = 0; i < cols; i++)
        { result += ch; }
    return result;
}
/**
Get the indentation, as a column number, at the given position.
Will first consult any [indent services](https://codemirror.net/6/docs/ref/#language.indentService)
that are registered, and if none of those return an indentation,
this will check the syntax tree for the [indent node
prop](https://codemirror.net/6/docs/ref/#language.indentNodeProp) and use that if found. Returns a
number when an indentation could be determined, and null
otherwise.
*/
function getIndentation(context, pos) {
    if (context instanceof EditorState)
        { context = new IndentContext(context); }
    for (var service of context.state.facet(indentService)) {
        var result = service(context, pos);
        if (result !== undefined)
            { return result; }
    }
    var tree = syntaxTree(context.state);
    return tree.length >= pos ? syntaxIndentation(context, tree, pos) : null;
}
/**
Indentation contexts are used when calling [indentation
services](https://codemirror.net/6/docs/ref/#language.indentService). They provide helper utilities
useful in indentation logic, and can selectively override the
indentation reported for some lines.
*/
var IndentContext = function IndentContext(
/**
The editor state.
*/
state, 
/**
@internal
*/
options) {
    if ( options === void 0 ) options = {};

    this.state = state;
    this.options = options;
    this.unit = getIndentUnit(state);
};

var prototypeAccessors$3 = { simulatedBreak: { configurable: true } };
/**
Get a description of the line at the given position, taking
[simulated line
breaks](https://codemirror.net/6/docs/ref/#language.IndentContext.constructor^options.simulateBreak)
into account. If there is such a break at `pos`, the `bias`
argument determines whether the part of the line line before or
after the break is used.
*/
IndentContext.prototype.lineAt = function lineAt (pos, bias) {
        if ( bias === void 0 ) bias = 1;

    var line = this.state.doc.lineAt(pos);
    var ref = this.options;
        var simulateBreak = ref.simulateBreak;
        var simulateDoubleBreak = ref.simulateDoubleBreak;
    if (simulateBreak != null && simulateBreak >= line.from && simulateBreak <= line.to) {
        if (simulateDoubleBreak && simulateBreak == pos)
            { return { text: "", from: pos }; }
        else if (bias < 0 ? simulateBreak < pos : simulateBreak <= pos)
            { return { text: line.text.slice(simulateBreak - line.from), from: simulateBreak }; }
        else
            { return { text: line.text.slice(0, simulateBreak - line.from), from: line.from }; }
    }
    return line;
};
/**
Get the text directly after `pos`, either the entire line
or the next 100 characters, whichever is shorter.
*/
IndentContext.prototype.textAfterPos = function textAfterPos (pos, bias) {
        if ( bias === void 0 ) bias = 1;

    if (this.options.simulateDoubleBreak && pos == this.options.simulateBreak)
        { return ""; }
    var ref = this.lineAt(pos, bias);
        var text = ref.text;
        var from = ref.from;
    return text.slice(pos - from, Math.min(text.length, pos + 100 - from));
};
/**
Find the column for the given position.
*/
IndentContext.prototype.column = function column (pos, bias) {
        if ( bias === void 0 ) bias = 1;

    var ref = this.lineAt(pos, bias);
        var text = ref.text;
        var from = ref.from;
    var result = this.countColumn(text, pos - from);
    var override = this.options.overrideIndentation ? this.options.overrideIndentation(from) : -1;
    if (override > -1)
        { result += override - this.countColumn(text, text.search(/\S|$/)); }
    return result;
};
/**
Find the column position (taking tabs into account) of the given
position in the given string.
*/
IndentContext.prototype.countColumn = function countColumn$1 (line, pos) {
        if ( pos === void 0 ) pos = line.length;

    return countColumn(line, this.state.tabSize, pos);
};
/**
Find the indentation column of the line at the given point.
*/
IndentContext.prototype.lineIndent = function lineIndent (pos, bias) {
        if ( bias === void 0 ) bias = 1;

    var ref = this.lineAt(pos, bias);
        var text = ref.text;
        var from = ref.from;
    var override = this.options.overrideIndentation;
    if (override) {
        var overriden = override(from);
        if (overriden > -1)
            { return overriden; }
    }
    return this.countColumn(text, text.search(/\S|$/));
};
/**
Returns the [simulated line
break](https://codemirror.net/6/docs/ref/#language.IndentContext.constructor^options.simulateBreak)
for this context, if any.
*/
prototypeAccessors$3.simulatedBreak.get = function () {
    return this.options.simulateBreak || null;
};

Object.defineProperties( IndentContext.prototype, prototypeAccessors$3 );
/**
A syntax tree node prop used to associate indentation strategies
with node types. Such a strategy is a function from an indentation
context to a column number (see also
[`indentString`](https://codemirror.net/6/docs/ref/#language.indentString)) or null, where null
indicates that no definitive indentation can be determined.
*/
var indentNodeProp = /*@__PURE__*/new NodeProp();
// Compute the indentation for a given position from the syntax tree.
function syntaxIndentation(cx, ast, pos) {
    var stack = ast.resolveStack(pos);
    var inner = stack.node.enterUnfinishedNodesBefore(pos);
    if (inner != stack.node) {
        var add = [];
        for (var cur = inner; cur != stack.node; cur = cur.parent)
            { add.push(cur); }
        for (var i = add.length - 1; i >= 0; i--)
            { stack = { node: add[i], next: stack }; }
    }
    return indentFor(stack, cx, pos);
}
function indentFor(stack, cx, pos) {
    for (var cur = stack; cur; cur = cur.next) {
        var strategy = indentStrategy(cur.node);
        if (strategy)
            { return strategy(TreeIndentContext.create(cx, pos, cur)); }
    }
    return 0;
}
function ignoreClosed(cx) {
    return cx.pos == cx.options.simulateBreak && cx.options.simulateDoubleBreak;
}
function indentStrategy(tree) {
    var strategy = tree.type.prop(indentNodeProp);
    if (strategy)
        { return strategy; }
    var first = tree.firstChild, close;
    if (first && (close = first.type.prop(NodeProp.closedBy))) {
        var last = tree.lastChild, closed = last && close.indexOf(last.name) > -1;
        return function (cx) { return delimitedStrategy(cx, true, 1, undefined, closed && !ignoreClosed(cx) ? last.from : undefined); };
    }
    return tree.parent == null ? topIndent : null;
}
function topIndent() { return 0; }
/**
Objects of this type provide context information and helper
methods to indentation functions registered on syntax nodes.
*/
var TreeIndentContext = /*@__PURE__*/(function (IndentContext) {
    function TreeIndentContext(base, 
    /**
    The position at which indentation is being computed.
    */
    pos, 
    /**
    @internal
    */
    context) {
        IndentContext.call(this, base.state, base.options);
        this.base = base;
        this.pos = pos;
        this.context = context;
    }

    if ( IndentContext ) TreeIndentContext.__proto__ = IndentContext;
    TreeIndentContext.prototype = Object.create( IndentContext && IndentContext.prototype );
    TreeIndentContext.prototype.constructor = TreeIndentContext;

    var prototypeAccessors$4 = { node: { configurable: true },textAfter: { configurable: true },baseIndent: { configurable: true } };
    /**
    The syntax tree node to which the indentation strategy
    applies.
    */
    prototypeAccessors$4.node.get = function () { return this.context.node; };
    /**
    @internal
    */
    TreeIndentContext.create = function create (base, pos, context) {
        return new TreeIndentContext(base, pos, context);
    };
    /**
    Get the text directly after `this.pos`, either the entire line
    or the next 100 characters, whichever is shorter.
    */
    prototypeAccessors$4.textAfter.get = function () {
        return this.textAfterPos(this.pos);
    };
    /**
    Get the indentation at the reference line for `this.node`, which
    is the line on which it starts, unless there is a node that is
    _not_ a parent of this node covering the start of that line. If
    so, the line at the start of that node is tried, again skipping
    on if it is covered by another such node.
    */
    prototypeAccessors$4.baseIndent.get = function () {
        return this.baseIndentFor(this.node);
    };
    /**
    Get the indentation for the reference line of the given node
    (see [`baseIndent`](https://codemirror.net/6/docs/ref/#language.TreeIndentContext.baseIndent)).
    */
    TreeIndentContext.prototype.baseIndentFor = function baseIndentFor (node) {
        var line = this.state.doc.lineAt(node.from);
        // Skip line starts that are covered by a sibling (or cousin, etc)
        for (;;) {
            var atBreak = node.resolve(line.from);
            while (atBreak.parent && atBreak.parent.from == atBreak.from)
                { atBreak = atBreak.parent; }
            if (isParent(atBreak, node))
                { break; }
            line = this.state.doc.lineAt(atBreak.from);
        }
        return this.lineIndent(line.from);
    };
    /**
    Continue looking for indentations in the node's parent nodes,
    and return the result of that.
    */
    TreeIndentContext.prototype.continue = function continue$1 () {
        return indentFor(this.context.next, this.base, this.pos);
    };

    Object.defineProperties( TreeIndentContext.prototype, prototypeAccessors$4 );

    return TreeIndentContext;
}(IndentContext));
function isParent(parent, of) {
    for (var cur = of; cur; cur = cur.parent)
        { if (parent == cur)
            { return true; } }
    return false;
}
// Check whether a delimited node is aligned (meaning there are
// non-skipped nodes on the same line as the opening delimiter). And
// if so, return the opening token.
function bracketedAligned(context) {
    var tree = context.node;
    var openToken = tree.childAfter(tree.from), last = tree.lastChild;
    if (!openToken)
        { return null; }
    var sim = context.options.simulateBreak;
    var openLine = context.state.doc.lineAt(openToken.from);
    var lineEnd = sim == null || sim <= openLine.from ? openLine.to : Math.min(openLine.to, sim);
    for (var pos = openToken.to;;) {
        var next = tree.childAfter(pos);
        if (!next || next == last)
            { return null; }
        if (!next.type.isSkipped) {
            if (next.from >= lineEnd)
                { return null; }
            var space = /^ */.exec(openLine.text.slice(openToken.to - openLine.from))[0].length;
            return { from: openToken.from, to: openToken.to + space };
        }
        pos = next.to;
    }
}
/**
An indentation strategy for delimited (usually bracketed) nodes.
Will, by default, indent one unit more than the parent's base
indent unless the line starts with a closing token. When `align`
is true and there are non-skipped nodes on the node's opening
line, the content of the node will be aligned with the end of the
opening node, like this:

    foo(bar,
        baz)
*/
function delimitedIndent(ref) {
    var closing = ref.closing;
    var align = ref.align; if ( align === void 0 ) align = true;
    var units = ref.units; if ( units === void 0 ) units = 1;

    return function (context) { return delimitedStrategy(context, align, units, closing); };
}
function delimitedStrategy(context, align, units, closing, closedAt) {
    var after = context.textAfter, space = after.match(/^\s*/)[0].length;
    var closed = closing && after.slice(space, space + closing.length) == closing || closedAt == context.pos + space;
    var aligned = align ? bracketedAligned(context) : null;
    if (aligned)
        { return closed ? context.column(aligned.from) : context.column(aligned.to); }
    return context.baseIndent + (closed ? 0 : context.unit * units);
}
/**
An indentation strategy that aligns a node's content to its base
indentation.
*/
var flatIndent = function (context) { return context.baseIndent; };
/**
Creates an indentation strategy that, by default, indents
continued lines one unit more than the node's base indentation.
You can provide `except` to prevent indentation of lines that
match a pattern (for example `/^else\b/` in `if`/`else`
constructs), and you can change the amount of units used with the
`units` option.
*/
function continuedIndent(ref) {
    if ( ref === void 0 ) ref = {};
    var except = ref.except;
    var units = ref.units; if ( units === void 0 ) units = 1;

    return function (context) {
        var matchExcept = except && except.test(context.textAfter);
        return context.baseIndent + (matchExcept ? 0 : units * context.unit);
    };
}
/**
This node prop is used to associate folding information with
syntax node types. Given a syntax node, it should check whether
that tree is foldable and return the range that can be collapsed
when it is.
*/
var foldNodeProp = /*@__PURE__*/new NodeProp();
/**
[Fold](https://codemirror.net/6/docs/ref/#language.foldNodeProp) function that folds everything but
the first and the last child of a syntax node. Useful for nodes
that start and end with delimiters.
*/
function foldInside(node) {
    var first = node.firstChild, last = node.lastChild;
    return first && first.to < last.from ? { from: first.to, to: last.type.isError ? node.to : last.from } : null;
}

/**
A highlight style associates CSS styles with higlighting
[tags](https://lezer.codemirror.net/docs/ref#highlight.Tag).
*/
var HighlightStyle = function HighlightStyle(
/**
The tag styles used to create this highlight style.
*/
specs, options) {
    this.specs = specs;
    var modSpec;
    function def(spec) {
        var cls = StyleModule.newName();
        (modSpec || (modSpec = Object.create(null)))["." + cls] = spec;
        return cls;
    }
    var all = typeof options.all == "string" ? options.all : options.all ? def(options.all) : undefined;
    var scopeOpt = options.scope;
    this.scope = scopeOpt instanceof Language ? function (type) { return type.prop(languageDataProp) == scopeOpt.data; }
        : scopeOpt ? function (type) { return type == scopeOpt; } : undefined;
    this.style = tagHighlighter(specs.map(function (style) { return ({
        tag: style.tag,
        class: style.class || def(Object.assign({}, style, { tag: null }))
    }); }), {
        all: 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.
*/
HighlightStyle.define = function define (specs, options) {
    return new HighlightStyle(specs, options || {});
};
var highlighterFacet = /*@__PURE__*/Facet.define();
var fallbackHighlighter = /*@__PURE__*/Facet.define({
    combine: function combine(values) { return values.length ? [values[0]] : null; }
});
function getHighlighters(state) {
    var 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) {
    var ext = [treeHighlighter], themeType;
    if (highlighter instanceof HighlightStyle) {
        if (highlighter.module)
            { ext.push(EditorView.styleModule.of(highlighter.module)); }
        themeType = highlighter.themeType;
    }
    if (options === null || options === void 0 ? void 0 : options.fallback)
        { ext.push(fallbackHighlighter.of(highlighter)); }
    else if (themeType)
        { ext.push(highlighterFacet.computeN([EditorView.darkTheme], function (state) {
            return state.facet(EditorView.darkTheme) == (themeType == "dark") ? [highlighter] : [];
        })); }
    else
        { ext.push(highlighterFacet.of(highlighter)); }
    return ext;
}
var TreeHighlighter = function TreeHighlighter(view) {
    this.markCache = Object.create(null);
    this.tree = syntaxTree(view.state);
    this.decorations = this.buildDeco(view, getHighlighters(view.state));
    this.decoratedTo = view.viewport.to;
};
TreeHighlighter.prototype.update = function update (update$1) {
    var tree = syntaxTree(update$1.state), highlighters = getHighlighters(update$1.state);
    var styleChange = highlighters != getHighlighters(update$1.startState);
    var ref = update$1.view;
        var viewport = ref.viewport;
        var decoratedToMapped = update$1.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$1.changes);
        this.decoratedTo = decoratedToMapped;
    }
    else if (tree != this.tree || update$1.viewportChanged || styleChange) {
        this.tree = tree;
        this.decorations = this.buildDeco(update$1.view, highlighters);
        this.decoratedTo = viewport.to;
    }
};
TreeHighlighter.prototype.buildDeco = function buildDeco (view, highlighters) {
        var this$1$1 = this;

    if (!highlighters || !this.tree.length)
        { return Decoration.none; }
    var builder = new RangeSetBuilder();
    for (var { from, to } of view.visibleRanges) {
        highlightTree(this.tree, highlighters, function (from, to, style) {
            builder.add(from, to, this$1$1.markCache[style] || (this$1$1.markCache[style] = Decoration.mark({ class: style })));
        }, from, to);
    }
    return builder.finish();
};
var treeHighlighter = /*@__PURE__*/Prec.high(/*@__PURE__*/ViewPlugin.fromClass(TreeHighlighter, {
    decorations: function (v) { return v.decorations; }
}));
/**
A default highlight style (works well with light themes).
*/
var defaultHighlightStyle = /*@__PURE__*/HighlightStyle.define([
    { tag: tags.meta,
        color: "#404740" },
    { tag: tags.link,
        textDecoration: "underline" },
    { tag: tags.heading,
        textDecoration: "underline",
        fontWeight: "bold" },
    { tag: tags.emphasis,
        fontStyle: "italic" },
    { tag: tags.strong,
        fontWeight: "bold" },
    { tag: tags.strikethrough,
        textDecoration: "line-through" },
    { tag: tags.keyword,
        color: "#708" },
    { tag: [tags.atom, tags.bool, tags.url, tags.contentSeparator, tags.labelName],
        color: "#219" },
    { tag: [tags.literal, tags.inserted],
        color: "#164" },
    { tag: [tags.string, tags.deleted],
        color: "#a11" },
    { tag: [tags.regexp, tags.escape, /*@__PURE__*/tags.special(tags.string)],
        color: "#e40" },
    { tag: /*@__PURE__*/tags.definition(tags.variableName),
        color: "#00f" },
    { tag: /*@__PURE__*/tags.local(tags.variableName),
        color: "#30a" },
    { tag: [tags.typeName, tags.namespace],
        color: "#085" },
    { tag: tags.className,
        color: "#167" },
    { tag: [/*@__PURE__*/tags.special(tags.variableName), tags.macroName],
        color: "#256" },
    { tag: /*@__PURE__*/tags.definition(tags.propertyName),
        color: "#00c" },
    { tag: tags.comment,
        color: "#940" },
    { tag: tags.invalid,
        color: "#f00" }
]);
var DefaultScanDist = 10000, DefaultBrackets = "()[]{}";
/**
When larger syntax nodes, such as HTML tags, are marked as
opening/closing, it can be a bit messy to treat the whole node as
a matchable bracket. This node prop allows you to define, for such
a node, a ‘handle’—the part of the node that is highlighted, and
that the cursor must be on to activate highlighting in the first
place.
*/
var bracketMatchingHandle = /*@__PURE__*/new NodeProp();
function matchingNodes(node, dir, brackets) {
    var byProp = node.prop(dir < 0 ? NodeProp.openedBy : NodeProp.closedBy);
    if (byProp)
        { return byProp; }
    if (node.name.length == 1) {
        var index = brackets.indexOf(node.name);
        if (index > -1 && index % 2 == (dir < 0 ? 1 : 0))
            { return [brackets[index + dir]]; }
    }
    return null;
}
function findHandle(node) {
    var hasHandle = node.type.prop(bracketMatchingHandle);
    return hasHandle ? hasHandle(node.node) : node;
}
/**
Find the matching bracket for the token at `pos`, scanning
direction `dir`. Only the `brackets` and `maxScanDistance`
properties are used from `config`, if given. Returns null if no
bracket was found at `pos`, or a match result otherwise.
*/
function matchBrackets(state, pos, dir, config) {
    if ( config === void 0 ) config = {};

    var maxScanDistance = config.maxScanDistance || DefaultScanDist, brackets = config.brackets || DefaultBrackets;
    var tree = syntaxTree(state), node = tree.resolveInner(pos, dir);
    for (var cur = node; cur; cur = cur.parent) {
        var matches = matchingNodes(cur.type, dir, brackets);
        if (matches && cur.from < cur.to) {
            var handle = findHandle(cur);
            if (handle && (dir > 0 ? pos >= handle.from && pos < handle.to : pos > handle.from && pos <= handle.to))
                { return matchMarkedBrackets(state, pos, dir, cur, handle, matches, brackets); }
        }
    }
    return matchPlainBrackets(state, pos, dir, tree, node.type, maxScanDistance, brackets);
}
function matchMarkedBrackets(_state, _pos, dir, token, handle, matching, brackets) {
    var parent = token.parent, firstToken = { from: handle.from, to: handle.to };
    var depth = 0, cursor = parent === null || parent === void 0 ? void 0 : parent.cursor();
    if (cursor && (dir < 0 ? cursor.childBefore(token.from) : cursor.childAfter(token.to)))
        { do {
            if (dir < 0 ? cursor.to <= token.from : cursor.from >= token.to) {
                if (depth == 0 && matching.indexOf(cursor.type.name) > -1 && cursor.from < cursor.to) {
                    var endHandle = findHandle(cursor);
                    return { start: firstToken, end: endHandle ? { from: endHandle.from, to: endHandle.to } : undefined, matched: true };
                }
                else if (matchingNodes(cursor.type, dir, brackets)) {
                    depth++;
                }
                else if (matchingNodes(cursor.type, -dir, brackets)) {
                    if (depth == 0) {
                        var endHandle$1 = findHandle(cursor);
                        return {
                            start: firstToken,
                            end: endHandle$1 && endHandle$1.from < endHandle$1.to ? { from: endHandle$1.from, to: endHandle$1.to } : undefined,
                            matched: false
                        };
                    }
                    depth--;
                }
            }
        } while (dir < 0 ? cursor.prevSibling() : cursor.nextSibling()); }
    return { start: firstToken, matched: false };
}
function matchPlainBrackets(state, pos, dir, tree, tokenType, maxScanDistance, brackets) {
    var startCh = dir < 0 ? state.sliceDoc(pos - 1, pos) : state.sliceDoc(pos, pos + 1);
    var bracket = brackets.indexOf(startCh);
    if (bracket < 0 || (bracket % 2 == 0) != (dir > 0))
        { return null; }
    var startToken = { from: dir < 0 ? pos - 1 : pos, to: dir > 0 ? pos + 1 : pos };
    var iter = state.doc.iterRange(pos, dir > 0 ? state.doc.length : 0), depth = 0;
    for (var distance = 0; !(iter.next()).done && distance <= maxScanDistance;) {
        var text = iter.value;
        if (dir < 0)
            { distance += text.length; }
        var basePos = pos + distance * dir;
        for (var pos$1 = dir > 0 ? 0 : text.length - 1, end = dir > 0 ? text.length : -1; pos$1 != end; pos$1 += dir) {
            var found = brackets.indexOf(text[pos$1]);
            if (found < 0 || tree.resolveInner(basePos + pos$1, 1).type != tokenType)
                { continue; }
            if ((found % 2 == 0) == (dir > 0)) {
                depth++;
            }
            else if (depth == 1) { // Closing
                return { start: startToken, end: { from: basePos + pos$1, to: basePos + pos$1 + 1 }, matched: (found >> 1) == (bracket >> 1) };
            }
            else {
                depth--;
            }
        }
        if (dir > 0)
            { distance += text.length; }
    }
    return iter.done ? { start: startToken, matched: false } : null;
}
var noTokens = /*@__PURE__*/Object.create(null);
var typeArray = [NodeType.none];
var warned = [];
// Cache of node types by name and tags
var byTag = /*@__PURE__*/Object.create(null);
var defaultTable = /*@__PURE__*/Object.create(null);
for (var [legacyName, name$1] 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$1);
function warnForPart(part, msg) {
    if (warned.indexOf(part) > -1)
        { return; }
    warned.push(part);
    console.warn(msg);
}
function createTokenType(extra, tagStr) {
    var obj;

    var tags$1 = [];
    for (var name$1 of tagStr.split(" ")) {
        var found = [];
        for (var part of name$1.split(".")) {
            var 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 (var tag of found)
            tags$1.push(tag);
    }
    if (!tags$1.length)
        { return 0; }
    var name = tagStr.replace(/ /g, "_"), key = name + " " + tags$1.map(function (t) { return t.id; });
    var known = byTag[key];
    if (known)
        { return known.id; }
    var type = byTag[key] = NodeType.define({
        id: typeArray.length,
        name: name,
        props: [styleTags(( obj = {}, obj[name] = tags$1, obj ))]
    });
    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 }),
    auto: /*@__PURE__*/Decoration.mark({ class: "cm-iso", inclusive: true, attributes: { dir: "auto" }, bidiIsolate: null })
});/**
Comment or uncomment the current selection. Will use line comments
if available, otherwise falling back to block comments.
*/
var toggleComment = function (target) {
    var state = target.state;
    var line = state.doc.lineAt(state.selection.main.from), config = getConfig(target.state, line.from);
    return config.line ? toggleLineComment(target) : config.block ? toggleBlockCommentByLine(target) : false;
};
function command(f, option) {
    return function (ref) {
        var state = ref.state;
        var dispatch = ref.dispatch;

        if (state.readOnly)
            { return false; }
        var tr = f(option, state);
        if (!tr)
            { return false; }
        dispatch(state.update(tr));
        return true;
    };
}
/**
Comment or uncomment the current selection using line comments.
The line comment syntax is taken from the
[`commentTokens`](https://codemirror.net/6/docs/ref/#commands.CommentTokens) [language
data](https://codemirror.net/6/docs/ref/#state.EditorState.languageDataAt).
*/
var toggleLineComment = /*@__PURE__*/command(changeLineComment, 0 /* CommentOption.Toggle */);
/**
Comment or uncomment the current selection using block comments.
The block comment syntax is taken from the
[`commentTokens`](https://codemirror.net/6/docs/ref/#commands.CommentTokens) [language
data](https://codemirror.net/6/docs/ref/#state.EditorState.languageDataAt).
*/
var toggleBlockComment = /*@__PURE__*/command(changeBlockComment, 0 /* CommentOption.Toggle */);
/**
Comment or uncomment the lines around the current selection using
block comments.
*/
var toggleBlockCommentByLine = /*@__PURE__*/command(function (o, s) { return changeBlockComment(o, s, selectedLineRanges(s)); }, 0 /* CommentOption.Toggle */);
function getConfig(state, pos) {
    var data = state.languageDataAt("commentTokens", pos);
    return data.length ? data[0] : {};
}
var SearchMargin = 50;
/**
Determines if the given range is block-commented in the given
state.
*/
function findBlockComment(state, ref, from, to) {
    var open = ref.open;
    var close = ref.close;

    var textBefore = state.sliceDoc(from - SearchMargin, from);
    var textAfter = state.sliceDoc(to, to + SearchMargin);
    var spaceBefore = /\s*$/.exec(textBefore)[0].length, spaceAfter = /^\s*/.exec(textAfter)[0].length;
    var beforeOff = textBefore.length - spaceBefore;
    if (textBefore.slice(beforeOff - open.length, beforeOff) == open &&
        textAfter.slice(spaceAfter, spaceAfter + close.length) == close) {
        return { open: { pos: from - spaceBefore, margin: spaceBefore && 1 },
            close: { pos: to + spaceAfter, margin: spaceAfter && 1 } };
    }
    var startText, endText;
    if (to - from <= 2 * SearchMargin) {
        startText = endText = state.sliceDoc(from, to);
    }
    else {
        startText = state.sliceDoc(from, from + SearchMargin);
        endText = state.sliceDoc(to - SearchMargin, to);
    }
    var startSpace = /^\s*/.exec(startText)[0].length, endSpace = /\s*$/.exec(endText)[0].length;
    var endOff = endText.length - endSpace - close.length;
    if (startText.slice(startSpace, startSpace + open.length) == open &&
        endText.slice(endOff, endOff + close.length) == close) {
        return { open: { pos: from + startSpace + open.length,
                margin: /\s/.test(startText.charAt(startSpace + open.length)) ? 1 : 0 },
            close: { pos: to - endSpace - close.length,
                margin: /\s/.test(endText.charAt(endOff - 1)) ? 1 : 0 } };
    }
    return null;
}
function selectedLineRanges(state) {
    var ranges = [];
    for (var r of state.selection.ranges) {
        var fromLine = state.doc.lineAt(r.from);
        var toLine = r.to <= fromLine.to ? fromLine : state.doc.lineAt(r.to);
        var last = ranges.length - 1;
        if (last >= 0 && ranges[last].to > fromLine.from)
            { ranges[last].to = toLine.to; }
        else
            { ranges.push({ from: fromLine.from + /^\s*/.exec(fromLine.text)[0].length, to: toLine.to }); }
    }
    return ranges;
}
// Performs toggle, comment and uncomment of block comments in
// languages that support them.
function changeBlockComment(option, state, ranges) {
    if ( ranges === void 0 ) ranges = state.selection.ranges;

    var tokens = ranges.map(function (r) { return getConfig(state, r.from).block; });
    if (!tokens.every(function (c) { return c; }))
        { return null; }
    var comments = ranges.map(function (r, i) { return findBlockComment(state, tokens[i], r.from, r.to); });
    if (option != 2 /* CommentOption.Uncomment */ && !comments.every(function (c) { return c; })) {
        return { changes: state.changes(ranges.map(function (range, i) {
                if (comments[i])
                    { return []; }
                return [{ from: range.from, insert: tokens[i].open + " " }, { from: range.to, insert: " " + tokens[i].close }];
            })) };
    }
    else if (option != 1 /* CommentOption.Comment */ && comments.some(function (c) { return c; })) {
        var changes = [];
        for (var i = 0, comment = (void 0); i < comments.length; i++)
            { if (comment = comments[i]) {
                var token = tokens[i];
                var open = comment.open;
                var close = comment.close;
                changes.push({ from: open.pos - token.open.length, to: open.pos + open.margin }, { from: close.pos - close.margin, to: close.pos + token.close.length });
            } }
        return { changes: changes };
    }
    return null;
}
// Performs toggle, comment and uncomment of line comments.
function changeLineComment(option, state, ranges) {
    if ( ranges === void 0 ) ranges = state.selection.ranges;

    var lines = [];
    var prevLine = -1;
    for (var { from, to } of ranges) {
        var startI = lines.length, minIndent = 1e9;
        var token = getConfig(state, from).line;
        if (!token)
            { continue; }
        for (var pos = from; pos <= to;) {
            var line = state.doc.lineAt(pos);
            if (line.from > prevLine && (from == to || to > line.from)) {
                prevLine = line.from;
                var indent = /^\s*/.exec(line.text)[0].length;
                var empty = indent == line.length;
                var comment = line.text.slice(indent, indent + token.length) == token ? indent : -1;
                if (indent < line.text.length && indent < minIndent)
                    { minIndent = indent; }
                lines.push({ line: line, comment: comment, token: token, indent: indent, empty: empty, single: false });
            }
            pos = line.to + 1;
        }
        if (minIndent < 1e9)
            { for (var i = startI; i < lines.length; i++)
                { if (lines[i].indent < lines[i].line.text.length)
                    { lines[i].indent = minIndent; } } }
        if (lines.length == startI + 1)
            { lines[startI].single = true; }
    }
    if (option != 2 /* CommentOption.Uncomment */ && lines.some(function (l) { return l.comment < 0 && (!l.empty || l.single); })) {
        var changes = [];
        for (var { line: line$1, token: token$1, indent: indent$1, empty: empty$1, single } of lines)
            if (single || !empty$1)
                { changes.push({ from: line$1.from + indent$1, insert: token$1 + " " }); }
        var changeSet = state.changes(changes);
        return { changes: changeSet, selection: state.selection.map(changeSet, 1) };
    }
    else if (option != 1 /* CommentOption.Comment */ && lines.some(function (l) { return l.comment >= 0; })) {
        var changes$1 = [];
        for (var { line: line$2, comment: comment$1, token: token$2 } of lines)
            if (comment$1 >= 0) {
                var from$1 = line$2.from + comment$1, to$1 = from$1 + token$2.length;
                if (line$2.text[to$1 - line$2.from] == " ")
                    { to$1++; }
                changes$1.push({ from: from$1, to: to$1 });
            }
        return { changes: changes$1 };
    }
    return null;
}

function updateSel(sel, by) {
    return EditorSelection.create(sel.ranges.map(by), sel.mainIndex);
}
function setSel(state, selection) {
    return state.update({ selection: selection, scrollIntoView: true, userEvent: "select" });
}
function moveSel(ref, how) {
    var state = ref.state;
    var dispatch = ref.dispatch;

    var selection = updateSel(state.selection, how);
    if (selection.eq(state.selection, true))
        { return false; }
    dispatch(setSel(state, selection));
    return true;
}
function rangeEnd(range, forward) {
    return EditorSelection.cursor(forward ? range.to : range.from);
}
function cursorByChar(view, forward) {
    return moveSel(view, function (range) { return range.empty ? view.moveByChar(range, forward) : rangeEnd(range, forward); });
}
function ltrAtCursor(view) {
    return view.textDirectionAt(view.state.selection.main.head) == Direction.LTR;
}
/**
Move the selection one character to the left (which is backward in
left-to-right text, forward in right-to-left text).
*/
var cursorCharLeft = function (view) { return cursorByChar(view, !ltrAtCursor(view)); };
/**
Move the selection one character to the right.
*/
var cursorCharRight = function (view) { return cursorByChar(view, ltrAtCursor(view)); };
function cursorByGroup(view, forward) {
    return moveSel(view, function (range) { return range.empty ? view.moveByGroup(range, forward) : rangeEnd(range, forward); });
}
/**
Move the selection to the left across one group of word or
non-word (but also non-space) characters.
*/
var cursorGroupLeft = function (view) { return cursorByGroup(view, !ltrAtCursor(view)); };
/**
Move the selection one group to the right.
*/
var cursorGroupRight = function (view) { return cursorByGroup(view, ltrAtCursor(view)); };
function interestingNode(state, node, bracketProp) {
    if (node.type.prop(bracketProp))
        { return true; }
    var len = node.to - node.from;
    return len && (len > 2 || /[^\s,.;:]/.test(state.sliceDoc(node.from, node.to))) || node.firstChild;
}
function moveBySyntax(state, start, forward) {
    var pos = syntaxTree(state).resolveInner(start.head);
    var bracketProp = forward ? NodeProp.closedBy : NodeProp.openedBy;
    // Scan forward through child nodes to see if there's an interesting
    // node ahead.
    for (var at = start.head;;) {
        var next = forward ? pos.childAfter(at) : pos.childBefore(at);
        if (!next)
            { break; }
        if (interestingNode(state, next, bracketProp))
            { pos = next; }
        else
            { at = forward ? next.to : next.from; }
    }
    var bracket = pos.type.prop(bracketProp), match, newPos;
    if (bracket && (match = forward ? matchBrackets(state, pos.from, 1) : matchBrackets(state, pos.to, -1)) && match.matched)
        { newPos = forward ? match.end.to : match.end.from; }
    else
        { newPos = forward ? pos.to : pos.from; }
    return EditorSelection.cursor(newPos, forward ? -1 : 1);
}
/**
Move the cursor over the next syntactic element to the left.
*/
var cursorSyntaxLeft = function (view) { return moveSel(view, function (range) { return moveBySyntax(view.state, range, !ltrAtCursor(view)); }); };
/**
Move the cursor over the next syntactic element to the right.
*/
var cursorSyntaxRight = function (view) { return moveSel(view, function (range) { return moveBySyntax(view.state, range, ltrAtCursor(view)); }); };
function cursorByLine(view, forward) {
    return moveSel(view, function (range) {
        if (!range.empty)
            { return rangeEnd(range, forward); }
        var moved = view.moveVertically(range, forward);
        return moved.head != range.head ? moved : view.moveToLineBoundary(range, forward);
    });
}
/**
Move the selection one line up.
*/
var cursorLineUp = function (view) { return cursorByLine(view, false); };
/**
Move the selection one line down.
*/
var cursorLineDown = function (view) { return cursorByLine(view, true); };
function pageInfo(view) {
    var selfScroll = view.scrollDOM.clientHeight < view.scrollDOM.scrollHeight - 2;
    var marginTop = 0, marginBottom = 0, height;
    if (selfScroll) {
        for (var source of view.state.facet(EditorView.scrollMargins)) {
            var margins = source(view);
            if (margins === null || margins === void 0 ? void 0 : margins.top)
                { marginTop = Math.max(margins === null || margins === void 0 ? void 0 : margins.top, marginTop); }
            if (margins === null || margins === void 0 ? void 0 : margins.bottom)
                { marginBottom = Math.max(margins === null || margins === void 0 ? void 0 : margins.bottom, marginBottom); }
        }
        height = view.scrollDOM.clientHeight - marginTop - marginBottom;
    }
    else {
        height = (view.dom.ownerDocument.defaultView || window).innerHeight;
    }
    return { marginTop: marginTop, marginBottom: marginBottom, selfScroll: selfScroll,
        height: Math.max(view.defaultLineHeight, height - 5) };
}
function cursorByPage(view, forward) {
    var page = pageInfo(view);
    var state = view.state;
    var selection = updateSel(state.selection, function (range) {
        return range.empty ? view.moveVertically(range, forward, page.height)
            : rangeEnd(range, forward);
    });
    if (selection.eq(state.selection))
        { return false; }
    var effect;
    if (page.selfScroll) {
        var startPos = view.coordsAtPos(state.selection.main.head);
        var scrollRect = view.scrollDOM.getBoundingClientRect();
        var scrollTop = scrollRect.top + page.marginTop, scrollBottom = scrollRect.bottom - page.marginBottom;
        if (startPos && startPos.top > scrollTop && startPos.bottom < scrollBottom)
            { effect = EditorView.scrollIntoView(selection.main.head, { y: "start", yMargin: startPos.top - scrollTop }); }
    }
    view.dispatch(setSel(state, selection), { effects: effect });
    return true;
}
/**
Move the selection one page up.
*/
var cursorPageUp = function (view) { return cursorByPage(view, false); };
/**
Move the selection one page down.
*/
var cursorPageDown = function (view) { return cursorByPage(view, true); };
function moveByLineBoundary(view, start, forward) {
    var line = view.lineBlockAt(start.head), moved = view.moveToLineBoundary(start, forward);
    if (moved.head == start.head && moved.head != (forward ? line.to : line.from))
        { moved = view.moveToLineBoundary(start, forward, false); }
    if (!forward && moved.head == line.from && line.length) {
        var space = /^\s*/.exec(view.state.sliceDoc(line.from, Math.min(line.from + 100, line.to)))[0].length;
        if (space && start.head != line.from + space)
            { moved = EditorSelection.cursor(line.from + space); }
    }
    return moved;
}
/**
Move the selection to the next line wrap point, or to the end of
the line if there isn't one left on this line.
*/
var cursorLineBoundaryForward = function (view) { return moveSel(view, function (range) { return moveByLineBoundary(view, range, true); }); };
/**
Move the selection to previous line wrap point, or failing that to
the start of the line. If the line is indented, and the cursor
isn't already at the end of the indentation, this will move to the
end of the indentation instead of the start of the line.
*/
var cursorLineBoundaryBackward = function (view) { return moveSel(view, function (range) { return moveByLineBoundary(view, range, false); }); };
/**
Move the selection one line wrap point to the left.
*/
var cursorLineBoundaryLeft = function (view) { return moveSel(view, function (range) { return moveByLineBoundary(view, range, !ltrAtCursor(view)); }); };
/**
Move the selection one line wrap point to the right.
*/
var cursorLineBoundaryRight = function (view) { return moveSel(view, function (range) { return moveByLineBoundary(view, range, ltrAtCursor(view)); }); };
/**
Move the selection to the start of the line.
*/
var cursorLineStart = function (view) { return moveSel(view, function (range) { return EditorSelection.cursor(view.lineBlockAt(range.head).from, 1); }); };
/**
Move the selection to the end of the line.
*/
var cursorLineEnd = function (view) { return moveSel(view, function (range) { return EditorSelection.cursor(view.lineBlockAt(range.head).to, -1); }); };
function toMatchingBracket(state, dispatch, extend) {
    var found = false, selection = updateSel(state.selection, function (range) {
        var matching = matchBrackets(state, range.head, -1)
            || matchBrackets(state, range.head, 1)
            || (range.head > 0 && matchBrackets(state, range.head - 1, 1))
            || (range.head < state.doc.length && matchBrackets(state, range.head + 1, -1));
        if (!matching || !matching.end)
            { return range; }
        found = true;
        var head = matching.start.from == range.head ? matching.end.to : matching.end.from;
        return extend ? EditorSelection.range(range.anchor, head) : EditorSelection.cursor(head);
    });
    if (!found)
        { return false; }
    dispatch(setSel(state, selection));
    return true;
}
/**
Move the selection to the bracket matching the one it is currently
on, if any.
*/
var cursorMatchingBracket = function (ref) {
    var state = ref.state;
    var dispatch = ref.dispatch;

    return toMatchingBracket(state, dispatch, false);
};
function extendSel(view, how) {
    var selection = updateSel(view.state.selection, function (range) {
        var head = how(range);
        return EditorSelection.range(range.anchor, head.head, head.goalColumn, head.bidiLevel || undefined);
    });
    if (selection.eq(view.state.selection))
        { return false; }
    view.dispatch(setSel(view.state, selection));
    return true;
}
function selectByChar(view, forward) {
    return extendSel(view, function (range) { return view.moveByChar(range, forward); });
}
/**
Move the selection head one character to the left, while leaving
the anchor in place.
*/
var selectCharLeft = function (view) { return selectByChar(view, !ltrAtCursor(view)); };
/**
Move the selection head one character to the right.
*/
var selectCharRight = function (view) { return selectByChar(view, ltrAtCursor(view)); };
function selectByGroup(view, forward) {
    return extendSel(view, function (range) { return view.moveByGroup(range, forward); });
}
/**
Move the selection head one [group](https://codemirror.net/6/docs/ref/#commands.cursorGroupLeft) to
the left.
*/
var selectGroupLeft = function (view) { return selectByGroup(view, !ltrAtCursor(view)); };
/**
Move the selection head one group to the right.
*/
var selectGroupRight = function (view) { return selectByGroup(view, ltrAtCursor(view)); };
/**
Move the selection head over the next syntactic element to the left.
*/
var selectSyntaxLeft = function (view) { return extendSel(view, function (range) { return moveBySyntax(view.state, range, !ltrAtCursor(view)); }); };
/**
Move the selection head over the next syntactic element to the right.
*/
var selectSyntaxRight = function (view) { return extendSel(view, function (range) { return moveBySyntax(view.state, range, ltrAtCursor(view)); }); };
function selectByLine(view, forward) {
    return extendSel(view, function (range) { return view.moveVertically(range, forward); });
}
/**
Move the selection head one line up.
*/
var selectLineUp = function (view) { return selectByLine(view, false); };
/**
Move the selection head one line down.
*/
var selectLineDown = function (view) { return selectByLine(view, true); };
function selectByPage(view, forward) {
    return extendSel(view, function (range) { return view.moveVertically(range, forward, pageInfo(view).height); });
}
/**
Move the selection head one page up.
*/
var selectPageUp = function (view) { return selectByPage(view, false); };
/**
Move the selection head one page down.
*/
var selectPageDown = function (view) { return selectByPage(view, true); };
/**
Move the selection head to the next line boundary.
*/
var selectLineBoundaryForward = function (view) { return extendSel(view, function (range) { return moveByLineBoundary(view, range, true); }); };
/**
Move the selection head to the previous line boundary.
*/
var selectLineBoundaryBackward = function (view) { return extendSel(view, function (range) { return moveByLineBoundary(view, range, false); }); };
/**
Move the selection head one line boundary to the left.
*/
var selectLineBoundaryLeft = function (view) { return extendSel(view, function (range) { return moveByLineBoundary(view, range, !ltrAtCursor(view)); }); };
/**
Move the selection head one line boundary to the right.
*/
var selectLineBoundaryRight = function (view) { return extendSel(view, function (range) { return moveByLineBoundary(view, range, ltrAtCursor(view)); }); };
/**
Move the selection head to the start of the line.
*/
var selectLineStart = function (view) { return extendSel(view, function (range) { return EditorSelection.cursor(view.lineBlockAt(range.head).from); }); };
/**
Move the selection head to the end of the line.
*/
var selectLineEnd = function (view) { return extendSel(view, function (range) { return EditorSelection.cursor(view.lineBlockAt(range.head).to); }); };
/**
Move the selection to the start of the document.
*/
var cursorDocStart = function (ref) {
    var state = ref.state;
    var dispatch = ref.dispatch;

    dispatch(setSel(state, { anchor: 0 }));
    return true;
};
/**
Move the selection to the end of the document.
*/
var cursorDocEnd = function (ref) {
    var state = ref.state;
    var dispatch = ref.dispatch;

    dispatch(setSel(state, { anchor: state.doc.length }));
    return true;
};
/**
Move the selection head to the start of the document.
*/
var selectDocStart = function (ref) {
    var state = ref.state;
    var dispatch = ref.dispatch;

    dispatch(setSel(state, { anchor: state.selection.main.anchor, head: 0 }));
    return true;
};
/**
Move the selection head to the end of the document.
*/
var selectDocEnd = function (ref) {
    var state = ref.state;
    var dispatch = ref.dispatch;

    dispatch(setSel(state, { anchor: state.selection.main.anchor, head: state.doc.length }));
    return true;
};
/**
Select the entire document.
*/
var selectAll = function (ref) {
    var state = ref.state;
    var dispatch = ref.dispatch;

    dispatch(state.update({ selection: { anchor: 0, head: state.doc.length }, userEvent: "select" }));
    return true;
};
/**
Expand the selection to cover entire lines.
*/
var selectLine = function (ref) {
    var state = ref.state;
    var dispatch = ref.dispatch;

    var ranges = selectedLineBlocks(state).map(function (ref) {
        var from = ref.from;
        var to = ref.to;

        return EditorSelection.range(from, Math.min(to + 1, state.doc.length));
    });
    dispatch(state.update({ selection: EditorSelection.create(ranges), userEvent: "select" }));
    return true;
};
/**
Select the next syntactic construct that is larger than the
selection. Note that this will only work insofar as the language
[provider](https://codemirror.net/6/docs/ref/#language.language) you use builds up a full
syntax tree.
*/
var selectParentSyntax = function (ref) {
    var state = ref.state;
    var dispatch = ref.dispatch;

    var selection = updateSel(state.selection, function (range) {
        var tree = syntaxTree(state), stack = tree.resolveStack(range.from, 1);
        if (range.empty) {
            var stackBefore = tree.resolveStack(range.from, -1);
            if (stackBefore.node.from >= stack.node.from && stackBefore.node.to <= stack.node.to)
                { stack = stackBefore; }
        }
        for (var cur = stack; cur; cur = cur.next) {
            var node = cur.node;
            if (((node.from < range.from && node.to >= range.to) ||
                (node.to > range.to && node.from <= range.from)) &&
                cur.next)
                { return EditorSelection.range(node.to, node.from); }
        }
        return range;
    });
    if (selection.eq(state.selection))
        { return false; }
    dispatch(setSel(state, selection));
    return true;
};
/**
Simplify the current selection. When multiple ranges are selected,
reduce it to its main range. Otherwise, if the selection is
non-empty, convert it to a cursor selection.
*/
var simplifySelection = function (ref) {
    var state = ref.state;
    var dispatch = ref.dispatch;

    var cur = state.selection, selection = null;
    if (cur.ranges.length > 1)
        { selection = EditorSelection.create([cur.main]); }
    else if (!cur.main.empty)
        { selection = EditorSelection.create([EditorSelection.cursor(cur.main.head)]); }
    if (!selection)
        { return false; }
    dispatch(setSel(state, selection));
    return true;
};
function deleteBy(target, by) {
    if (target.state.readOnly)
        { return false; }
    var event = "delete.selection";
    var state = target.state;
    var changes = state.changeByRange(function (range) {
        var from = range.from;
        var to = range.to;
        if (from == to) {
            var towards = by(range);
            if (towards < from) {
                event = "delete.backward";
                towards = skipAtomic(target, towards, false);
            }
            else if (towards > from) {
                event = "delete.forward";
                towards = skipAtomic(target, towards, true);
            }
            from = Math.min(from, towards);
            to = Math.max(to, towards);
        }
        else {
            from = skipAtomic(target, from, false);
            to = skipAtomic(target, to, true);
        }
        return from == to ? { range: range } : { changes: { from: from, to: to }, range: EditorSelection.cursor(from, from < range.head ? -1 : 1) };
    });
    if (changes.changes.empty)
        { return false; }
    target.dispatch(state.update(changes, {
        scrollIntoView: true,
        userEvent: event,
        effects: event == "delete.selection" ? EditorView.announce.of(state.phrase("Selection deleted")) : undefined
    }));
    return true;
}
function skipAtomic(target, pos, forward) {
    if (target instanceof EditorView)
        { for (var ranges of target.state.facet(EditorView.atomicRanges).map(function (f) { return f(target); }))
            ranges.between(pos, pos, function (from, to) {
                if (from < pos && to > pos)
                    { pos = forward ? to : from; }
            }); }
    return pos;
}
var deleteByChar = function (target, forward, byIndentUnit) { return deleteBy(target, function (range) {
    var pos = range.from;
    var state = target.state;
    var line = state.doc.lineAt(pos), before, targetPos;
    if (byIndentUnit && !forward && pos > line.from && pos < line.from + 200 &&
        !/[^ \t]/.test(before = line.text.slice(0, pos - line.from))) {
        if (before[before.length - 1] == "\t")
            { return pos - 1; }
        var col = countColumn(before, state.tabSize), drop = col % getIndentUnit(state) || getIndentUnit(state);
        for (var i = 0; i < drop && before[before.length - 1 - i] == " "; i++)
            { pos--; }
        targetPos = pos;
    }
    else {
        targetPos = findClusterBreak(line.text, pos - line.from, forward, forward) + line.from;
        if (targetPos == pos && line.number != (forward ? state.doc.lines : 1))
            { targetPos += forward ? 1 : -1; }
        else if (!forward && /[\ufe00-\ufe0f]/.test(line.text.slice(targetPos - line.from, pos - line.from)))
            { targetPos = findClusterBreak(line.text, targetPos - line.from, false, false) + line.from; }
    }
    return targetPos;
}); };
/**
Delete the selection, or, for cursor selections, the character or
indentation unit before the cursor.
*/
var deleteCharBackward = function (view) { return deleteByChar(view, false, true); };
/**
Delete the selection or the character after the cursor.
*/
var deleteCharForward = function (view) { return deleteByChar(view, true, false); };
var deleteByGroup = function (target, forward) { return deleteBy(target, function (range) {
    var pos = range.head;
    var state = target.state;
    var line = state.doc.lineAt(pos);
    var categorize = state.charCategorizer(pos);
    for (var cat = null;;) {
        if (pos == (forward ? line.to : line.from)) {
            if (pos == range.head && line.number != (forward ? state.doc.lines : 1))
                { pos += forward ? 1 : -1; }
            break;
        }
        var next = findClusterBreak(line.text, pos - line.from, forward) + line.from;
        var nextChar = line.text.slice(Math.min(pos, next) - line.from, Math.max(pos, next) - line.from);
        var nextCat = categorize(nextChar);
        if (cat != null && nextCat != cat)
            { break; }
        if (nextChar != " " || pos != range.head)
            { cat = nextCat; }
        pos = next;
    }
    return pos;
}); };
/**
Delete the selection or backward until the end of the next
[group](https://codemirror.net/6/docs/ref/#view.EditorView.moveByGroup), only skipping groups of
whitespace when they consist of a single space.
*/
var deleteGroupBackward = function (target) { return deleteByGroup(target, false); };
/**
Delete the selection or forward until the end of the next group.
*/
var deleteGroupForward = function (target) { return deleteByGroup(target, true); };
/**
Delete the selection, or, if it is a cursor selection, delete to
the end of the line. If the cursor is directly at the end of the
line, delete the line break after it.
*/
var deleteToLineEnd = function (view) { return deleteBy(view, function (range) {
    var lineEnd = view.lineBlockAt(range.head).to;
    return range.head < lineEnd ? lineEnd : Math.min(view.state.doc.length, range.head + 1);
}); };
/**
Delete the selection, or, if it is a cursor selection, delete to
the start of the line or the next line wrap before the cursor.
*/
var deleteLineBoundaryBackward = function (view) { return deleteBy(view, function (range) {
    var lineStart = view.moveToLineBoundary(range, false).head;
    return range.head > lineStart ? lineStart : Math.max(0, range.head - 1);
}); };
/**
Delete the selection, or, if it is a cursor selection, delete to
the end of the line or the next line wrap after the cursor.
*/
var deleteLineBoundaryForward = function (view) { return deleteBy(view, function (range) {
    var lineStart = view.moveToLineBoundary(range, true).head;
    return range.head < lineStart ? lineStart : Math.min(view.state.doc.length, range.head + 1);
}); };
/**
Replace each selection range with a line break, leaving the cursor
on the line before the break.
*/
var splitLine = function (ref) {
    var state = ref.state;
    var dispatch = ref.dispatch;

    if (state.readOnly)
        { return false; }
    var changes = state.changeByRange(function (range) {
        return { changes: { from: range.from, to: range.to, insert: Text.of(["", ""]) },
            range: EditorSelection.cursor(range.from) };
    });
    dispatch(state.update(changes, { scrollIntoView: true, userEvent: "input" }));
    return true;
};
/**
Flip the characters before and after the cursor(s).
*/
var transposeChars = function (ref) {
    var state = ref.state;
    var dispatch = ref.dispatch;

    if (state.readOnly)
        { return false; }
    var changes = state.changeByRange(function (range) {
        if (!range.empty || range.from == 0 || range.from == state.doc.length)
            { return { range: range }; }
        var pos = range.from, line = state.doc.lineAt(pos);
        var from = pos == line.from ? pos - 1 : findClusterBreak(line.text, pos - line.from, false) + line.from;
        var to = pos == line.to ? pos + 1 : findClusterBreak(line.text, pos - line.from, true) + line.from;
        return { changes: { from: from, to: to, insert: state.doc.slice(pos, to).append(state.doc.slice(from, pos)) },
            range: EditorSelection.cursor(to) };
    });
    if (changes.changes.empty)
        { return false; }
    dispatch(state.update(changes, { scrollIntoView: true, userEvent: "move.character" }));
    return true;
};
function selectedLineBlocks(state) {
    var blocks = [], upto = -1;
    for (var range of state.selection.ranges) {
        var startLine = state.doc.lineAt(range.from), endLine = state.doc.lineAt(range.to);
        if (!range.empty && range.to == endLine.from)
            { endLine = state.doc.lineAt(range.to - 1); }
        if (upto >= startLine.number) {
            var prev = blocks[blocks.length - 1];
            prev.to = endLine.to;
            prev.ranges.push(range);
        }
        else {
            blocks.push({ from: startLine.from, to: endLine.to, ranges: [range] });
        }
        upto = endLine.number + 1;
    }
    return blocks;
}
function moveLine(state, dispatch, forward) {
    if (state.readOnly)
        { return false; }
    var changes = [], ranges = [];
    for (var block of selectedLineBlocks(state)) {
        if (forward ? block.to == state.doc.length : block.from == 0)
            { continue; }
        var nextLine = state.doc.lineAt(forward ? block.to + 1 : block.from - 1);
        var size = nextLine.length + 1;
        if (forward) {
            changes.push({ from: block.to, to: nextLine.to }, { from: block.from, insert: nextLine.text + state.lineBreak });
            for (var r of block.ranges)
                ranges.push(EditorSelection.range(Math.min(state.doc.length, r.anchor + size), Math.min(state.doc.length, r.head + size)));
        }
        else {
            changes.push({ from: nextLine.from, to: block.from }, { from: block.to, insert: state.lineBreak + nextLine.text });
            for (var r$1 of block.ranges)
                ranges.push(EditorSelection.range(r$1.anchor - size, r$1.head - size));
        }
    }
    if (!changes.length)
        { return false; }
    dispatch(state.update({
        changes: changes,
        scrollIntoView: true,
        selection: EditorSelection.create(ranges, state.selection.mainIndex),
        userEvent: "move.line"
    }));
    return true;
}
/**
Move the selected lines up one line.
*/
var moveLineUp = function (ref) {
    var state = ref.state;
    var dispatch = ref.dispatch;

    return moveLine(state, dispatch, false);
};
/**
Move the selected lines down one line.
*/
var moveLineDown = function (ref) {
    var state = ref.state;
    var dispatch = ref.dispatch;

    return moveLine(state, dispatch, true);
};
function copyLine(state, dispatch, forward) {
    if (state.readOnly)
        { return false; }
    var changes = [];
    for (var block of selectedLineBlocks(state)) {
        if (forward)
            { changes.push({ from: block.from, insert: state.doc.slice(block.from, block.to) + state.lineBreak }); }
        else
            { changes.push({ from: block.to, insert: state.lineBreak + state.doc.slice(block.from, block.to) }); }
    }
    dispatch(state.update({ changes: changes, scrollIntoView: true, userEvent: "input.copyline" }));
    return true;
}
/**
Create a copy of the selected lines. Keep the selection in the top copy.
*/
var copyLineUp = function (ref) {
    var state = ref.state;
    var dispatch = ref.dispatch;

    return copyLine(state, dispatch, false);
};
/**
Create a copy of the selected lines. Keep the selection in the bottom copy.
*/
var copyLineDown = function (ref) {
    var state = ref.state;
    var dispatch = ref.dispatch;

    return copyLine(state, dispatch, true);
};
/**
Delete selected lines.
*/
var deleteLine = function (view) {
    if (view.state.readOnly)
        { return false; }
    var state = view.state;
    var changes = state.changes(selectedLineBlocks(state).map(function (ref) {
        var from = ref.from;
        var to = ref.to;

        if (from > 0)
            { from--; }
        else if (to < state.doc.length)
            { to++; }
        return { from: from, to: to };
    }));
    var selection = updateSel(state.selection, function (range) {
        var dist = undefined;
        if (view.lineWrapping) {
            var block = view.lineBlockAt(range.head), pos = view.coordsAtPos(range.head, range.assoc || 1);
            if (pos)
                { dist = (block.bottom + view.documentTop) - pos.bottom + view.defaultLineHeight / 2; }
        }
        return view.moveVertically(range, true, dist);
    }).map(changes);
    view.dispatch({ changes: changes, selection: selection, scrollIntoView: true, userEvent: "delete.line" });
    return true;
};
function isBetweenBrackets(state, pos) {
    if (/\(\)|\[\]|\{\}/.test(state.sliceDoc(pos - 1, pos + 1)))
        { return { from: pos, to: pos }; }
    var context = syntaxTree(state).resolveInner(pos);
    var before = context.childBefore(pos), after = context.childAfter(pos), closedBy;
    if (before && after && before.to <= pos && after.from >= pos &&
        (closedBy = before.type.prop(NodeProp.closedBy)) && closedBy.indexOf(after.name) > -1 &&
        state.doc.lineAt(before.to).from == state.doc.lineAt(after.from).from &&
        !/\S/.test(state.sliceDoc(before.to, after.from)))
        { return { from: before.to, to: after.from }; }
    return null;
}
/**
Replace the selection with a newline and indent the newly created
line(s). If the current line consists only of whitespace, this
will also delete that whitespace. When the cursor is between
matching brackets, an additional newline will be inserted after
the cursor.
*/
var insertNewlineAndIndent = /*@__PURE__*/newlineAndIndent(false);
/**
Create a blank, indented line below the current line.
*/
var insertBlankLine = /*@__PURE__*/newlineAndIndent(true);
function newlineAndIndent(atEof) {
    return function (ref) {
        var state = ref.state;
        var dispatch = ref.dispatch;

        if (state.readOnly)
            { return false; }
        var changes = state.changeByRange(function (range) {
            var assign;

            var from = range.from;
            var to = range.to;
            var line = state.doc.lineAt(from);
            var explode = !atEof && from == to && isBetweenBrackets(state, from);
            if (atEof)
                { from = to = (to <= line.to ? line : state.doc.lineAt(to)).to; }
            var cx = new IndentContext(state, { simulateBreak: from, simulateDoubleBreak: !!explode });
            var indent = getIndentation(cx, from);
            if (indent == null)
                { indent = countColumn(/^\s*/.exec(state.doc.lineAt(from).text)[0], state.tabSize); }
            while (to < line.to && /\s/.test(line.text[to - line.from]))
                { to++; }
            if (explode)
                { ((assign = explode, from = assign.from, to = assign.to)); }
            else if (from > line.from && from < line.from + 100 && !/\S/.test(line.text.slice(0, from)))
                { from = line.from; }
            var insert = ["", indentString(state, indent)];
            if (explode)
                { insert.push(indentString(state, cx.lineIndent(line.from, -1))); }
            return { changes: { from: from, to: to, insert: Text.of(insert) },
                range: EditorSelection.cursor(from + 1 + insert[1].length) };
        });
        dispatch(state.update(changes, { scrollIntoView: true, userEvent: "input" }));
        return true;
    };
}
function changeBySelectedLine(state, f) {
    var atLine = -1;
    return state.changeByRange(function (range) {
        var changes = [];
        for (var pos = range.from; pos <= range.to;) {
            var line = state.doc.lineAt(pos);
            if (line.number > atLine && (range.empty || range.to > line.from)) {
                f(line, changes, range);
                atLine = line.number;
            }
            pos = line.to + 1;
        }
        var changeSet = state.changes(changes);
        return { changes: changes,
            range: EditorSelection.range(changeSet.mapPos(range.anchor, 1), changeSet.mapPos(range.head, 1)) };
    });
}
/**
Auto-indent the selected lines. This uses the [indentation service
facet](https://codemirror.net/6/docs/ref/#language.indentService) as source for auto-indent
information.
*/
var indentSelection = function (ref) {
    var state = ref.state;
    var dispatch = ref.dispatch;

    if (state.readOnly)
        { return false; }
    var updated = Object.create(null);
    var context = new IndentContext(state, { overrideIndentation: function (start) {
            var found = updated[start];
            return found == null ? -1 : found;
        } });
    var changes = changeBySelectedLine(state, function (line, changes, range) {
        var indent = getIndentation(context, line.from);
        if (indent == null)
            { return; }
        if (!/\S/.test(line.text))
            { indent = 0; }
        var cur = /^\s*/.exec(line.text)[0];
        var norm = indentString(state, indent);
        if (cur != norm || range.from < line.from + cur.length) {
            updated[line.from] = indent;
            changes.push({ from: line.from, to: line.from + cur.length, insert: norm });
        }
    });
    if (!changes.changes.empty)
        { dispatch(state.update(changes, { userEvent: "indent" })); }
    return true;
};
/**
Add a [unit](https://codemirror.net/6/docs/ref/#language.indentUnit) of indentation to all selected
lines.
*/
var indentMore = function (ref) {
    var state = ref.state;
    var dispatch = ref.dispatch;

    if (state.readOnly)
        { return false; }
    dispatch(state.update(changeBySelectedLine(state, function (line, changes) {
        changes.push({ from: line.from, insert: state.facet(indentUnit) });
    }), { userEvent: "input.indent" }));
    return true;
};
/**
Remove a [unit](https://codemirror.net/6/docs/ref/#language.indentUnit) of indentation from all
selected lines.
*/
var indentLess = function (ref) {
    var state = ref.state;
    var dispatch = ref.dispatch;

    if (state.readOnly)
        { return false; }
    dispatch(state.update(changeBySelectedLine(state, function (line, changes) {
        var space = /^\s*/.exec(line.text)[0];
        if (!space)
            { return; }
        var col = countColumn(space, state.tabSize), keep = 0;
        var insert = indentString(state, Math.max(0, col - getIndentUnit(state)));
        while (keep < space.length && keep < insert.length && space.charCodeAt(keep) == insert.charCodeAt(keep))
            { keep++; }
        changes.push({ from: line.from + keep, to: line.from + space.length, insert: insert.slice(keep) });
    }), { userEvent: "delete.dedent" }));
    return true;
};
/**
Enables or disables
[tab-focus mode](https://codemirror.net/6/docs/ref/#view.EditorView.setTabFocusMode). While on, this
prevents the editor's key bindings from capturing Tab or
Shift-Tab, making it possible for the user to move focus out of
the editor with the keyboard.
*/
var toggleTabFocusMode = function (view) {
    view.setTabFocusMode();
    return true;
};
/**
Array of key bindings containing the Emacs-style bindings that are
available on macOS by default.

 - Ctrl-b: [`cursorCharLeft`](https://codemirror.net/6/docs/ref/#commands.cursorCharLeft) ([`selectCharLeft`](https://codemirror.net/6/docs/ref/#commands.selectCharLeft) with Shift)
 - Ctrl-f: [`cursorCharRight`](https://codemirror.net/6/docs/ref/#commands.cursorCharRight) ([`selectCharRight`](https://codemirror.net/6/docs/ref/#commands.selectCharRight) with Shift)
 - Ctrl-p: [`cursorLineUp`](https://codemirror.net/6/docs/ref/#commands.cursorLineUp) ([`selectLineUp`](https://codemirror.net/6/docs/ref/#commands.selectLineUp) with Shift)
 - Ctrl-n: [`cursorLineDown`](https://codemirror.net/6/docs/ref/#commands.cursorLineDown) ([`selectLineDown`](https://codemirror.net/6/docs/ref/#commands.selectLineDown) with Shift)
 - Ctrl-a: [`cursorLineStart`](https://codemirror.net/6/docs/ref/#commands.cursorLineStart) ([`selectLineStart`](https://codemirror.net/6/docs/ref/#commands.selectLineStart) with Shift)
 - Ctrl-e: [`cursorLineEnd`](https://codemirror.net/6/docs/ref/#commands.cursorLineEnd) ([`selectLineEnd`](https://codemirror.net/6/docs/ref/#commands.selectLineEnd) with Shift)
 - Ctrl-d: [`deleteCharForward`](https://codemirror.net/6/docs/ref/#commands.deleteCharForward)
 - Ctrl-h: [`deleteCharBackward`](https://codemirror.net/6/docs/ref/#commands.deleteCharBackward)
 - Ctrl-k: [`deleteToLineEnd`](https://codemirror.net/6/docs/ref/#commands.deleteToLineEnd)
 - Ctrl-Alt-h: [`deleteGroupBackward`](https://codemirror.net/6/docs/ref/#commands.deleteGroupBackward)
 - Ctrl-o: [`splitLine`](https://codemirror.net/6/docs/ref/#commands.splitLine)
 - Ctrl-t: [`transposeChars`](https://codemirror.net/6/docs/ref/#commands.transposeChars)
 - Ctrl-v: [`cursorPageDown`](https://codemirror.net/6/docs/ref/#commands.cursorPageDown)
 - Alt-v: [`cursorPageUp`](https://codemirror.net/6/docs/ref/#commands.cursorPageUp)
*/
var emacsStyleKeymap = [
    { key: "Ctrl-b", run: cursorCharLeft, shift: selectCharLeft, preventDefault: true },
    { key: "Ctrl-f", run: cursorCharRight, shift: selectCharRight },
    { key: "Ctrl-p", run: cursorLineUp, shift: selectLineUp },
    { key: "Ctrl-n", run: cursorLineDown, shift: selectLineDown },
    { key: "Ctrl-a", run: cursorLineStart, shift: selectLineStart },
    { key: "Ctrl-e", run: cursorLineEnd, shift: selectLineEnd },
    { key: "Ctrl-d", run: deleteCharForward },
    { key: "Ctrl-h", run: deleteCharBackward },
    { key: "Ctrl-k", run: deleteToLineEnd },
    { key: "Ctrl-Alt-h", run: deleteGroupBackward },
    { key: "Ctrl-o", run: splitLine },
    { key: "Ctrl-t", run: transposeChars },
    { key: "Ctrl-v", run: cursorPageDown } ];
/**
An array of key bindings closely sticking to platform-standard or
widely used bindings. (This includes the bindings from
[`emacsStyleKeymap`](https://codemirror.net/6/docs/ref/#commands.emacsStyleKeymap), with their `key`
property changed to `mac`.)

 - ArrowLeft: [`cursorCharLeft`](https://codemirror.net/6/docs/ref/#commands.cursorCharLeft) ([`selectCharLeft`](https://codemirror.net/6/docs/ref/#commands.selectCharLeft) with Shift)
 - ArrowRight: [`cursorCharRight`](https://codemirror.net/6/docs/ref/#commands.cursorCharRight) ([`selectCharRight`](https://codemirror.net/6/docs/ref/#commands.selectCharRight) with Shift)
 - Ctrl-ArrowLeft (Alt-ArrowLeft on macOS): [`cursorGroupLeft`](https://codemirror.net/6/docs/ref/#commands.cursorGroupLeft) ([`selectGroupLeft`](https://codemirror.net/6/docs/ref/#commands.selectGroupLeft) with Shift)
 - Ctrl-ArrowRight (Alt-ArrowRight on macOS): [`cursorGroupRight`](https://codemirror.net/6/docs/ref/#commands.cursorGroupRight) ([`selectGroupRight`](https://codemirror.net/6/docs/ref/#commands.selectGroupRight) with Shift)
 - Cmd-ArrowLeft (on macOS): [`cursorLineStart`](https://codemirror.net/6/docs/ref/#commands.cursorLineStart) ([`selectLineStart`](https://codemirror.net/6/docs/ref/#commands.selectLineStart) with Shift)
 - Cmd-ArrowRight (on macOS): [`cursorLineEnd`](https://codemirror.net/6/docs/ref/#commands.cursorLineEnd) ([`selectLineEnd`](https://codemirror.net/6/docs/ref/#commands.selectLineEnd) with Shift)
 - ArrowUp: [`cursorLineUp`](https://codemirror.net/6/docs/ref/#commands.cursorLineUp) ([`selectLineUp`](https://codemirror.net/6/docs/ref/#commands.selectLineUp) with Shift)
 - ArrowDown: [`cursorLineDown`](https://codemirror.net/6/docs/ref/#commands.cursorLineDown) ([`selectLineDown`](https://codemirror.net/6/docs/ref/#commands.selectLineDown) with Shift)
 - Cmd-ArrowUp (on macOS): [`cursorDocStart`](https://codemirror.net/6/docs/ref/#commands.cursorDocStart) ([`selectDocStart`](https://codemirror.net/6/docs/ref/#commands.selectDocStart) with Shift)
 - Cmd-ArrowDown (on macOS): [`cursorDocEnd`](https://codemirror.net/6/docs/ref/#commands.cursorDocEnd) ([`selectDocEnd`](https://codemirror.net/6/docs/ref/#commands.selectDocEnd) with Shift)
 - Ctrl-ArrowUp (on macOS): [`cursorPageUp`](https://codemirror.net/6/docs/ref/#commands.cursorPageUp) ([`selectPageUp`](https://codemirror.net/6/docs/ref/#commands.selectPageUp) with Shift)
 - Ctrl-ArrowDown (on macOS): [`cursorPageDown`](https://codemirror.net/6/docs/ref/#commands.cursorPageDown) ([`selectPageDown`](https://codemirror.net/6/docs/ref/#commands.selectPageDown) with Shift)
 - PageUp: [`cursorPageUp`](https://codemirror.net/6/docs/ref/#commands.cursorPageUp) ([`selectPageUp`](https://codemirror.net/6/docs/ref/#commands.selectPageUp) with Shift)
 - PageDown: [`cursorPageDown`](https://codemirror.net/6/docs/ref/#commands.cursorPageDown) ([`selectPageDown`](https://codemirror.net/6/docs/ref/#commands.selectPageDown) with Shift)
 - Home: [`cursorLineBoundaryBackward`](https://codemirror.net/6/docs/ref/#commands.cursorLineBoundaryBackward) ([`selectLineBoundaryBackward`](https://codemirror.net/6/docs/ref/#commands.selectLineBoundaryBackward) with Shift)
 - End: [`cursorLineBoundaryForward`](https://codemirror.net/6/docs/ref/#commands.cursorLineBoundaryForward) ([`selectLineBoundaryForward`](https://codemirror.net/6/docs/ref/#commands.selectLineBoundaryForward) with Shift)
 - Ctrl-Home (Cmd-Home on macOS): [`cursorDocStart`](https://codemirror.net/6/docs/ref/#commands.cursorDocStart) ([`selectDocStart`](https://codemirror.net/6/docs/ref/#commands.selectDocStart) with Shift)
 - Ctrl-End (Cmd-Home on macOS): [`cursorDocEnd`](https://codemirror.net/6/docs/ref/#commands.cursorDocEnd) ([`selectDocEnd`](https://codemirror.net/6/docs/ref/#commands.selectDocEnd) with Shift)
 - Enter: [`insertNewlineAndIndent`](https://codemirror.net/6/docs/ref/#commands.insertNewlineAndIndent)
 - Ctrl-a (Cmd-a on macOS): [`selectAll`](https://codemirror.net/6/docs/ref/#commands.selectAll)
 - Backspace: [`deleteCharBackward`](https://codemirror.net/6/docs/ref/#commands.deleteCharBackward)
 - Delete: [`deleteCharForward`](https://codemirror.net/6/docs/ref/#commands.deleteCharForward)
 - Ctrl-Backspace (Alt-Backspace on macOS): [`deleteGroupBackward`](https://codemirror.net/6/docs/ref/#commands.deleteGroupBackward)
 - Ctrl-Delete (Alt-Delete on macOS): [`deleteGroupForward`](https://codemirror.net/6/docs/ref/#commands.deleteGroupForward)
 - Cmd-Backspace (macOS): [`deleteLineBoundaryBackward`](https://codemirror.net/6/docs/ref/#commands.deleteLineBoundaryBackward).
 - Cmd-Delete (macOS): [`deleteLineBoundaryForward`](https://codemirror.net/6/docs/ref/#commands.deleteLineBoundaryForward).
*/
var standardKeymap = /*@__PURE__*/[
    { key: "ArrowLeft", run: cursorCharLeft, shift: selectCharLeft, preventDefault: true },
    { key: "Mod-ArrowLeft", mac: "Alt-ArrowLeft", run: cursorGroupLeft, shift: selectGroupLeft, preventDefault: true },
    { mac: "Cmd-ArrowLeft", run: cursorLineBoundaryLeft, shift: selectLineBoundaryLeft, preventDefault: true },
    { key: "ArrowRight", run: cursorCharRight, shift: selectCharRight, preventDefault: true },
    { key: "Mod-ArrowRight", mac: "Alt-ArrowRight", run: cursorGroupRight, shift: selectGroupRight, preventDefault: true },
    { mac: "Cmd-ArrowRight", run: cursorLineBoundaryRight, shift: selectLineBoundaryRight, preventDefault: true },
    { key: "ArrowUp", run: cursorLineUp, shift: selectLineUp, preventDefault: true },
    { mac: "Cmd-ArrowUp", run: cursorDocStart, shift: selectDocStart },
    { mac: "Ctrl-ArrowUp", run: cursorPageUp, shift: selectPageUp },
    { key: "ArrowDown", run: cursorLineDown, shift: selectLineDown, preventDefault: true },
    { mac: "Cmd-ArrowDown", run: cursorDocEnd, shift: selectDocEnd },
    { mac: "Ctrl-ArrowDown", run: cursorPageDown, shift: selectPageDown },
    { key: "PageUp", run: cursorPageUp, shift: selectPageUp },
    { key: "PageDown", run: cursorPageDown, shift: selectPageDown },
    { key: "Home", run: cursorLineBoundaryBackward, shift: selectLineBoundaryBackward, preventDefault: true },
    { key: "Mod-Home", run: cursorDocStart, shift: selectDocStart },
    { key: "End", run: cursorLineBoundaryForward, shift: selectLineBoundaryForward, preventDefault: true },
    { key: "Mod-End", run: cursorDocEnd, shift: selectDocEnd },
    { key: "Enter", run: insertNewlineAndIndent },
    { key: "Mod-a", run: selectAll },
    { key: "Backspace", run: deleteCharBackward, shift: deleteCharBackward },
    { key: "Delete", run: deleteCharForward },
    { key: "Mod-Backspace", mac: "Alt-Backspace", run: deleteGroupBackward },
    { key: "Mod-Delete", mac: "Alt-Delete", run: deleteGroupForward },
    { mac: "Mod-Backspace", run: deleteLineBoundaryBackward },
    { mac: "Mod-Delete", run: deleteLineBoundaryForward }
].concat(/*@__PURE__*/emacsStyleKeymap.map(function (b) { return ({ mac: b.key, run: b.run, shift: b.shift }); }));
/**
The default keymap. Includes all bindings from
[`standardKeymap`](https://codemirror.net/6/docs/ref/#commands.standardKeymap) plus the following:

- Alt-ArrowLeft (Ctrl-ArrowLeft on macOS): [`cursorSyntaxLeft`](https://codemirror.net/6/docs/ref/#commands.cursorSyntaxLeft) ([`selectSyntaxLeft`](https://codemirror.net/6/docs/ref/#commands.selectSyntaxLeft) with Shift)
- Alt-ArrowRight (Ctrl-ArrowRight on macOS): [`cursorSyntaxRight`](https://codemirror.net/6/docs/ref/#commands.cursorSyntaxRight) ([`selectSyntaxRight`](https://codemirror.net/6/docs/ref/#commands.selectSyntaxRight) with Shift)
- Alt-ArrowUp: [`moveLineUp`](https://codemirror.net/6/docs/ref/#commands.moveLineUp)
- Alt-ArrowDown: [`moveLineDown`](https://codemirror.net/6/docs/ref/#commands.moveLineDown)
- Shift-Alt-ArrowUp: [`copyLineUp`](https://codemirror.net/6/docs/ref/#commands.copyLineUp)
- Shift-Alt-ArrowDown: [`copyLineDown`](https://codemirror.net/6/docs/ref/#commands.copyLineDown)
- Escape: [`simplifySelection`](https://codemirror.net/6/docs/ref/#commands.simplifySelection)
- Ctrl-Enter (Cmd-Enter on macOS): [`insertBlankLine`](https://codemirror.net/6/docs/ref/#commands.insertBlankLine)
- Alt-l (Ctrl-l on macOS): [`selectLine`](https://codemirror.net/6/docs/ref/#commands.selectLine)
- Ctrl-i (Cmd-i on macOS): [`selectParentSyntax`](https://codemirror.net/6/docs/ref/#commands.selectParentSyntax)
- Ctrl-[ (Cmd-[ on macOS): [`indentLess`](https://codemirror.net/6/docs/ref/#commands.indentLess)
- Ctrl-] (Cmd-] on macOS): [`indentMore`](https://codemirror.net/6/docs/ref/#commands.indentMore)
- Ctrl-Alt-\\ (Cmd-Alt-\\ on macOS): [`indentSelection`](https://codemirror.net/6/docs/ref/#commands.indentSelection)
- Shift-Ctrl-k (Shift-Cmd-k on macOS): [`deleteLine`](https://codemirror.net/6/docs/ref/#commands.deleteLine)
- Shift-Ctrl-\\ (Shift-Cmd-\\ on macOS): [`cursorMatchingBracket`](https://codemirror.net/6/docs/ref/#commands.cursorMatchingBracket)
- Ctrl-/ (Cmd-/ on macOS): [`toggleComment`](https://codemirror.net/6/docs/ref/#commands.toggleComment).
- Shift-Alt-a: [`toggleBlockComment`](https://codemirror.net/6/docs/ref/#commands.toggleBlockComment).
- Ctrl-m (Alt-Shift-m on macOS): [`toggleTabFocusMode`](https://codemirror.net/6/docs/ref/#commands.toggleTabFocusMode).
*/
var defaultKeymap = /*@__PURE__*/[
    { key: "Alt-ArrowLeft", mac: "Ctrl-ArrowLeft", run: cursorSyntaxLeft, shift: selectSyntaxLeft },
    { key: "Alt-ArrowRight", mac: "Ctrl-ArrowRight", run: cursorSyntaxRight, shift: selectSyntaxRight },
    { key: "Alt-ArrowUp", run: moveLineUp },
    { key: "Shift-Alt-ArrowUp", run: copyLineUp },
    { key: "Alt-ArrowDown", run: moveLineDown },
    { key: "Shift-Alt-ArrowDown", run: copyLineDown },
    { key: "Escape", run: simplifySelection },
    { key: "Mod-Enter", run: insertBlankLine },
    { key: "Alt-l", mac: "Ctrl-l", run: selectLine },
    { key: "Mod-i", run: selectParentSyntax, preventDefault: true },
    { key: "Mod-[", run: indentLess },
    { key: "Mod-]", run: indentMore },
    { key: "Mod-Alt-\\", run: indentSelection },
    { key: "Shift-Mod-k", run: deleteLine },
    { key: "Shift-Mod-\\", run: cursorMatchingBracket },
    { key: "Mod-/", run: toggleComment },
    { key: "Alt-A", run: toggleBlockComment },
    { key: "Ctrl-m", mac: "Shift-Alt-m", run: toggleTabFocusMode } ].concat(standardKeymap);
/**
A binding that binds Tab to [`indentMore`](https://codemirror.net/6/docs/ref/#commands.indentMore) and
Shift-Tab to [`indentLess`](https://codemirror.net/6/docs/ref/#commands.indentLess).
Please see the [Tab example](../../examples/tab/) before using
this.
*/
var indentWithTab = { key: "Tab", run: indentMore, shift: indentLess };/**
A parse stack. These are used internally by the parser to track
parsing progress. They also provide some properties and methods
that external code such as a tokenizer can use to get information
about the parse state.
*/
class Stack {
    /**
    @internal
    */
    constructor(
    /**
    The parse that this stack is part of @internal
    */
    p, 
    /**
    Holds state, input pos, buffer index triplets for all but the
    top state @internal
    */
    stack, 
    /**
    The current parse state @internal
    */
    state, 
    // The position at which the next reduce should take place. This
    // can be less than `this.pos` when skipped expressions have been
    // added to the stack (which should be moved outside of the next
    // reduction)
    /**
    @internal
    */
    reducePos, 
    /**
    The input position up to which this stack has parsed.
    */
    pos, 
    /**
    The dynamic score of the stack, including dynamic precedence
    and error-recovery penalties
    @internal
    */
    score, 
    // The output buffer. Holds (type, start, end, size) quads
    // representing nodes created by the parser, where `size` is
    // amount of buffer array entries covered by this node.
    /**
    @internal
    */
    buffer, 
    // The base offset of the buffer. When stacks are split, the split
    // instance shared the buffer history with its parent up to
    // `bufferBase`, which is the absolute offset (including the
    // offset of previous splits) into the buffer at which this stack
    // starts writing.
    /**
    @internal
    */
    bufferBase, 
    /**
    @internal
    */
    curContext, 
    /**
    @internal
    */
    lookAhead = 0, 
    // A parent stack from which this was split off, if any. This is
    // set up so that it always points to a stack that has some
    // additional buffer content, never to a stack with an equal
    // `bufferBase`.
    /**
    @internal
    */
    parent) {
        this.p = p;
        this.stack = stack;
        this.state = state;
        this.reducePos = reducePos;
        this.pos = pos;
        this.score = score;
        this.buffer = buffer;
        this.bufferBase = bufferBase;
        this.curContext = curContext;
        this.lookAhead = lookAhead;
        this.parent = parent;
    }
    /**
    @internal
    */
    toString() {
        return `[${this.stack.filter((_, i) => i % 3 == 0).concat(this.state)}]@${this.pos}${this.score ? "!" + this.score : ""}`;
    }
    // Start an empty stack
    /**
    @internal
    */
    static start(p, state, pos = 0) {
        let cx = p.parser.context;
        return new Stack(p, [], state, pos, pos, 0, [], 0, cx ? new StackContext(cx, cx.start) : null, 0, null);
    }
    /**
    The stack's current [context](#lr.ContextTracker) value, if
    any. Its type will depend on the context tracker's type
    parameter, or it will be `null` if there is no context
    tracker.
    */
    get context() { return this.curContext ? this.curContext.context : null; }
    // Push a state onto the stack, tracking its start position as well
    // as the buffer base at that point.
    /**
    @internal
    */
    pushState(state, start) {
        this.stack.push(this.state, start, this.bufferBase + this.buffer.length);
        this.state = state;
    }
    // Apply a reduce action
    /**
    @internal
    */
    reduce(action) {
        var _a;
        let depth = action >> 19 /* Action.ReduceDepthShift */, type = action & 65535 /* Action.ValueMask */;
        let { parser } = this.p;
        let lookaheadRecord = this.reducePos < this.pos - 25 /* Lookahead.Margin */;
        if (lookaheadRecord)
            this.setLookAhead(this.pos);
        let dPrec = parser.dynamicPrecedence(type);
        if (dPrec)
            this.score += dPrec;
        if (depth == 0) {
            this.pushState(parser.getGoto(this.state, type, true), this.reducePos);
            // Zero-depth reductions are a special case—they add stuff to
            // the stack without popping anything off.
            if (type < parser.minRepeatTerm)
                this.storeNode(type, this.reducePos, this.reducePos, lookaheadRecord ? 8 : 4, true);
            this.reduceContext(type, this.reducePos);
            return;
        }
        // Find the base index into `this.stack`, content after which will
        // be dropped. Note that with `StayFlag` reductions we need to
        // consume two extra frames (the dummy parent node for the skipped
        // expression and the state that we'll be staying in, which should
        // be moved to `this.state`).
        let base = this.stack.length - ((depth - 1) * 3) - (action & 262144 /* Action.StayFlag */ ? 6 : 0);
        let start = base ? this.stack[base - 2] : this.p.ranges[0].from, size = this.reducePos - start;
        // This is a kludge to try and detect overly deep left-associative
        // trees, which will not increase the parse stack depth and thus
        // won't be caught by the regular stack-depth limit check.
        if (size >= 2000 /* Recover.MinBigReduction */ && !((_a = this.p.parser.nodeSet.types[type]) === null || _a === void 0 ? void 0 : _a.isAnonymous)) {
            if (start == this.p.lastBigReductionStart) {
                this.p.bigReductionCount++;
                this.p.lastBigReductionSize = size;
            }
            else if (this.p.lastBigReductionSize < size) {
                this.p.bigReductionCount = 1;
                this.p.lastBigReductionStart = start;
                this.p.lastBigReductionSize = size;
            }
        }
        let bufferBase = base ? this.stack[base - 1] : 0, count = this.bufferBase + this.buffer.length - bufferBase;
        // Store normal terms or `R -> R R` repeat reductions
        if (type < parser.minRepeatTerm || (action & 131072 /* Action.RepeatFlag */)) {
            let pos = parser.stateFlag(this.state, 1 /* StateFlag.Skipped */) ? this.pos : this.reducePos;
            this.storeNode(type, start, pos, count + 4, true);
        }
        if (action & 262144 /* Action.StayFlag */) {
            this.state = this.stack[base];
        }
        else {
            let baseStateID = this.stack[base - 3];
            this.state = parser.getGoto(baseStateID, type, true);
        }
        while (this.stack.length > base)
            this.stack.pop();
        this.reduceContext(type, start);
    }
    // Shift a value into the buffer
    /**
    @internal
    */
    storeNode(term, start, end, size = 4, mustSink = false) {
        if (term == 0 /* Term.Err */ &&
            (!this.stack.length || this.stack[this.stack.length - 1] < this.buffer.length + this.bufferBase)) {
            // Try to omit/merge adjacent error nodes
            let cur = this, top = this.buffer.length;
            if (top == 0 && cur.parent) {
                top = cur.bufferBase - cur.parent.bufferBase;
                cur = cur.parent;
            }
            if (top > 0 && cur.buffer[top - 4] == 0 /* Term.Err */ && cur.buffer[top - 1] > -1) {
                if (start == end)
                    return;
                if (cur.buffer[top - 2] >= start) {
                    cur.buffer[top - 2] = end;
                    return;
                }
            }
        }
        if (!mustSink || this.pos == end) { // Simple case, just append
            this.buffer.push(term, start, end, size);
        }
        else { // There may be skipped nodes that have to be moved forward
            let index = this.buffer.length;
            if (index > 0 && this.buffer[index - 4] != 0 /* Term.Err */) {
                let mustMove = false;
                for (let scan = index; scan > 0 && this.buffer[scan - 2] > end; scan -= 4) {
                    if (this.buffer[scan - 1] >= 0) {
                        mustMove = true;
                        break;
                    }
                }
                if (mustMove)
                    while (index > 0 && this.buffer[index - 2] > end) {
                        // Move this record forward
                        this.buffer[index] = this.buffer[index - 4];
                        this.buffer[index + 1] = this.buffer[index - 3];
                        this.buffer[index + 2] = this.buffer[index - 2];
                        this.buffer[index + 3] = this.buffer[index - 1];
                        index -= 4;
                        if (size > 4)
                            size -= 4;
                    }
            }
            this.buffer[index] = term;
            this.buffer[index + 1] = start;
            this.buffer[index + 2] = end;
            this.buffer[index + 3] = size;
        }
    }
    // Apply a shift action
    /**
    @internal
    */
    shift(action, type, start, end) {
        if (action & 131072 /* Action.GotoFlag */) {
            this.pushState(action & 65535 /* Action.ValueMask */, this.pos);
        }
        else if ((action & 262144 /* Action.StayFlag */) == 0) { // Regular shift
            let nextState = action, { parser } = this.p;
            if (end > this.pos || type <= parser.maxNode) {
                this.pos = end;
                if (!parser.stateFlag(nextState, 1 /* StateFlag.Skipped */))
                    this.reducePos = end;
            }
            this.pushState(nextState, start);
            this.shiftContext(type, start);
            if (type <= parser.maxNode)
                this.buffer.push(type, start, end, 4);
        }
        else { // Shift-and-stay, which means this is a skipped token
            this.pos = end;
            this.shiftContext(type, start);
            if (type <= this.p.parser.maxNode)
                this.buffer.push(type, start, end, 4);
        }
    }
    // Apply an action
    /**
    @internal
    */
    apply(action, next, nextStart, nextEnd) {
        if (action & 65536 /* Action.ReduceFlag */)
            this.reduce(action);
        else
            this.shift(action, next, nextStart, nextEnd);
    }
    // Add a prebuilt (reused) node into the buffer.
    /**
    @internal
    */
    useNode(value, next) {
        let index = this.p.reused.length - 1;
        if (index < 0 || this.p.reused[index] != value) {
            this.p.reused.push(value);
            index++;
        }
        let start = this.pos;
        this.reducePos = this.pos = start + value.length;
        this.pushState(next, start);
        this.buffer.push(index, start, this.reducePos, -1 /* size == -1 means this is a reused value */);
        if (this.curContext)
            this.updateContext(this.curContext.tracker.reuse(this.curContext.context, value, this, this.p.stream.reset(this.pos - value.length)));
    }
    // Split the stack. Due to the buffer sharing and the fact
    // that `this.stack` tends to stay quite shallow, this isn't very
    // expensive.
    /**
    @internal
    */
    split() {
        let parent = this;
        let off = parent.buffer.length;
        // Because the top of the buffer (after this.pos) may be mutated
        // to reorder reductions and skipped tokens, and shared buffers
        // should be immutable, this copies any outstanding skipped tokens
        // to the new buffer, and puts the base pointer before them.
        while (off > 0 && parent.buffer[off - 2] > parent.reducePos)
            off -= 4;
        let buffer = parent.buffer.slice(off), base = parent.bufferBase + off;
        // Make sure parent points to an actual parent with content, if there is such a parent.
        while (parent && base == parent.bufferBase)
            parent = parent.parent;
        return new Stack(this.p, this.stack.slice(), this.state, this.reducePos, this.pos, this.score, buffer, base, this.curContext, this.lookAhead, parent);
    }
    // Try to recover from an error by 'deleting' (ignoring) one token.
    /**
    @internal
    */
    recoverByDelete(next, nextEnd) {
        let isNode = next <= this.p.parser.maxNode;
        if (isNode)
            this.storeNode(next, this.pos, nextEnd, 4);
        this.storeNode(0 /* Term.Err */, this.pos, nextEnd, isNode ? 8 : 4);
        this.pos = this.reducePos = nextEnd;
        this.score -= 190 /* Recover.Delete */;
    }
    /**
    Check if the given term would be able to be shifted (optionally
    after some reductions) on this stack. This can be useful for
    external tokenizers that want to make sure they only provide a
    given token when it applies.
    */
    canShift(term) {
        for (let sim = new SimulatedStack(this);;) {
            let action = this.p.parser.stateSlot(sim.state, 4 /* ParseState.DefaultReduce */) || this.p.parser.hasAction(sim.state, term);
            if (action == 0)
                return false;
            if ((action & 65536 /* Action.ReduceFlag */) == 0)
                return true;
            sim.reduce(action);
        }
    }
    // Apply up to Recover.MaxNext recovery actions that conceptually
    // inserts some missing token or rule.
    /**
    @internal
    */
    recoverByInsert(next) {
        if (this.stack.length >= 300 /* Recover.MaxInsertStackDepth */)
            return [];
        let nextStates = this.p.parser.nextStates(this.state);
        if (nextStates.length > 4 /* Recover.MaxNext */ << 1 || this.stack.length >= 120 /* Recover.DampenInsertStackDepth */) {
            let best = [];
            for (let i = 0, s; i < nextStates.length; i += 2) {
                if ((s = nextStates[i + 1]) != this.state && this.p.parser.hasAction(s, next))
                    best.push(nextStates[i], s);
            }
            if (this.stack.length < 120 /* Recover.DampenInsertStackDepth */)
                for (let i = 0; best.length < 4 /* Recover.MaxNext */ << 1 && i < nextStates.length; i += 2) {
                    let s = nextStates[i + 1];
                    if (!best.some((v, i) => (i & 1) && v == s))
                        best.push(nextStates[i], s);
                }
            nextStates = best;
        }
        let result = [];
        for (let i = 0; i < nextStates.length && result.length < 4 /* Recover.MaxNext */; i += 2) {
            let s = nextStates[i + 1];
            if (s == this.state)
                continue;
            let stack = this.split();
            stack.pushState(s, this.pos);
            stack.storeNode(0 /* Term.Err */, stack.pos, stack.pos, 4, true);
            stack.shiftContext(nextStates[i], this.pos);
            stack.reducePos = this.pos;
            stack.score -= 200 /* Recover.Insert */;
            result.push(stack);
        }
        return result;
    }
    // Force a reduce, if possible. Return false if that can't
    // be done.
    /**
    @internal
    */
    forceReduce() {
        let { parser } = this.p;
        let reduce = parser.stateSlot(this.state, 5 /* ParseState.ForcedReduce */);
        if ((reduce & 65536 /* Action.ReduceFlag */) == 0)
            return false;
        if (!parser.validAction(this.state, reduce)) {
            let depth = reduce >> 19 /* Action.ReduceDepthShift */, term = reduce & 65535 /* Action.ValueMask */;
            let target = this.stack.length - depth * 3;
            if (target < 0 || parser.getGoto(this.stack[target], term, false) < 0) {
                let backup = this.findForcedReduction();
                if (backup == null)
                    return false;
                reduce = backup;
            }
            this.storeNode(0 /* Term.Err */, this.pos, this.pos, 4, true);
            this.score -= 100 /* Recover.Reduce */;
        }
        this.reducePos = this.pos;
        this.reduce(reduce);
        return true;
    }
    /**
    Try to scan through the automaton to find some kind of reduction
    that can be applied. Used when the regular ForcedReduce field
    isn't a valid action. @internal
    */
    findForcedReduction() {
        let { parser } = this.p, seen = [];
        let explore = (state, depth) => {
            if (seen.includes(state))
                return;
            seen.push(state);
            return parser.allActions(state, (action) => {
                if (action & (262144 /* Action.StayFlag */ | 131072 /* Action.GotoFlag */)) ;
                else if (action & 65536 /* Action.ReduceFlag */) {
                    let rDepth = (action >> 19 /* Action.ReduceDepthShift */) - depth;
                    if (rDepth > 1) {
                        let term = action & 65535 /* Action.ValueMask */, target = this.stack.length - rDepth * 3;
                        if (target >= 0 && parser.getGoto(this.stack[target], term, false) >= 0)
                            return (rDepth << 19 /* Action.ReduceDepthShift */) | 65536 /* Action.ReduceFlag */ | term;
                    }
                }
                else {
                    let found = explore(action, depth + 1);
                    if (found != null)
                        return found;
                }
            });
        };
        return explore(this.state, 0);
    }
    /**
    @internal
    */
    forceAll() {
        while (!this.p.parser.stateFlag(this.state, 2 /* StateFlag.Accepting */)) {
            if (!this.forceReduce()) {
                this.storeNode(0 /* Term.Err */, this.pos, this.pos, 4, true);
                break;
            }
        }
        return this;
    }
    /**
    Check whether this state has no further actions (assumed to be a direct descendant of the
    top state, since any other states must be able to continue
    somehow). @internal
    */
    get deadEnd() {
        if (this.stack.length != 3)
            return false;
        let { parser } = this.p;
        return parser.data[parser.stateSlot(this.state, 1 /* ParseState.Actions */)] == 65535 /* Seq.End */ &&
            !parser.stateSlot(this.state, 4 /* ParseState.DefaultReduce */);
    }
    /**
    Restart the stack (put it back in its start state). Only safe
    when this.stack.length == 3 (state is directly below the top
    state). @internal
    */
    restart() {
        this.storeNode(0 /* Term.Err */, this.pos, this.pos, 4, true);
        this.state = this.stack[0];
        this.stack.length = 0;
    }
    /**
    @internal
    */
    sameState(other) {
        if (this.state != other.state || this.stack.length != other.stack.length)
            return false;
        for (let i = 0; i < this.stack.length; i += 3)
            if (this.stack[i] != other.stack[i])
                return false;
        return true;
    }
    /**
    Get the parser used by this stack.
    */
    get parser() { return this.p.parser; }
    /**
    Test whether a given dialect (by numeric ID, as exported from
    the terms file) is enabled.
    */
    dialectEnabled(dialectID) { return this.p.parser.dialect.flags[dialectID]; }
    shiftContext(term, start) {
        if (this.curContext)
            this.updateContext(this.curContext.tracker.shift(this.curContext.context, term, this, this.p.stream.reset(start)));
    }
    reduceContext(term, start) {
        if (this.curContext)
            this.updateContext(this.curContext.tracker.reduce(this.curContext.context, term, this, this.p.stream.reset(start)));
    }
    /**
    @internal
    */
    emitContext() {
        let last = this.buffer.length - 1;
        if (last < 0 || this.buffer[last] != -3)
            this.buffer.push(this.curContext.hash, this.pos, this.pos, -3);
    }
    /**
    @internal
    */
    emitLookAhead() {
        let last = this.buffer.length - 1;
        if (last < 0 || this.buffer[last] != -4)
            this.buffer.push(this.lookAhead, this.pos, this.pos, -4);
    }
    updateContext(context) {
        if (context != this.curContext.context) {
            let newCx = new StackContext(this.curContext.tracker, context);
            if (newCx.hash != this.curContext.hash)
                this.emitContext();
            this.curContext = newCx;
        }
    }
    /**
    @internal
    */
    setLookAhead(lookAhead) {
        if (lookAhead > this.lookAhead) {
            this.emitLookAhead();
            this.lookAhead = lookAhead;
        }
    }
    /**
    @internal
    */
    close() {
        if (this.curContext && this.curContext.tracker.strict)
            this.emitContext();
        if (this.lookAhead > 0)
            this.emitLookAhead();
    }
}
class StackContext {
    constructor(tracker, context) {
        this.tracker = tracker;
        this.context = context;
        this.hash = tracker.strict ? tracker.hash(context) : 0;
    }
}
// Used to cheaply run some reductions to scan ahead without mutating
// an entire stack
class SimulatedStack {
    constructor(start) {
        this.start = start;
        this.state = start.state;
        this.stack = start.stack;
        this.base = this.stack.length;
    }
    reduce(action) {
        let term = action & 65535 /* Action.ValueMask */, depth = action >> 19 /* Action.ReduceDepthShift */;
        if (depth == 0) {
            if (this.stack == this.start.stack)
                this.stack = this.stack.slice();
            this.stack.push(this.state, 0, 0);
            this.base += 3;
        }
        else {
            this.base -= (depth - 1) * 3;
        }
        let goto = this.start.p.parser.getGoto(this.stack[this.base - 3], term, true);
        this.state = goto;
    }
}
// This is given to `Tree.build` to build a buffer, and encapsulates
// the parent-stack-walking necessary to read the nodes.
class StackBufferCursor {
    constructor(stack, pos, index) {
        this.stack = stack;
        this.pos = pos;
        this.index = index;
        this.buffer = stack.buffer;
        if (this.index == 0)
            this.maybeNext();
    }
    static create(stack, pos = stack.bufferBase + stack.buffer.length) {
        return new StackBufferCursor(stack, pos, pos - stack.bufferBase);
    }
    maybeNext() {
        let next = this.stack.parent;
        if (next != null) {
            this.index = this.stack.bufferBase - next.bufferBase;
            this.stack = next;
            this.buffer = next.buffer;
        }
    }
    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]; }
    next() {
        this.index -= 4;
        this.pos -= 4;
        if (this.index == 0)
            this.maybeNext();
    }
    fork() {
        return new StackBufferCursor(this.stack, this.pos, this.index);
    }
}

// See lezer-generator/src/encode.ts for comments about the encoding
// used here
function decodeArray(input, Type = Uint16Array) {
    if (typeof input != "string")
        return input;
    let array = null;
    for (let pos = 0, out = 0; pos < input.length;) {
        let value = 0;
        for (;;) {
            let next = input.charCodeAt(pos++), stop = false;
            if (next == 126 /* Encode.BigValCode */) {
                value = 65535 /* Encode.BigVal */;
                break;
            }
            if (next >= 92 /* Encode.Gap2 */)
                next--;
            if (next >= 34 /* Encode.Gap1 */)
                next--;
            let digit = next - 32 /* Encode.Start */;
            if (digit >= 46 /* Encode.Base */) {
                digit -= 46 /* Encode.Base */;
                stop = true;
            }
            value += digit;
            if (stop)
                break;
            value *= 46 /* Encode.Base */;
        }
        if (array)
            array[out++] = value;
        else
            array = new Type(value);
    }
    return array;
}

class CachedToken {
    constructor() {
        this.start = -1;
        this.value = -1;
        this.end = -1;
        this.extended = -1;
        this.lookAhead = 0;
        this.mask = 0;
        this.context = 0;
    }
}
const nullToken = new CachedToken;
/**
[Tokenizers](#lr.ExternalTokenizer) interact with the input
through this interface. It presents the input as a stream of
characters, tracking lookahead and hiding the complexity of
[ranges](#common.Parser.parse^ranges) from tokenizer code.
*/
class InputStream {
    /**
    @internal
    */
    constructor(
    /**
    @internal
    */
    input, 
    /**
    @internal
    */
    ranges) {
        this.input = input;
        this.ranges = ranges;
        /**
        @internal
        */
        this.chunk = "";
        /**
        @internal
        */
        this.chunkOff = 0;
        /**
        Backup chunk
        */
        this.chunk2 = "";
        this.chunk2Pos = 0;
        /**
        The character code of the next code unit in the input, or -1
        when the stream is at the end of the input.
        */
        this.next = -1;
        /**
        @internal
        */
        this.token = nullToken;
        this.rangeIndex = 0;
        this.pos = this.chunkPos = ranges[0].from;
        this.range = ranges[0];
        this.end = ranges[ranges.length - 1].to;
        this.readNext();
    }
    /**
    @internal
    */
    resolveOffset(offset, assoc) {
        let range = this.range, index = this.rangeIndex;
        let pos = this.pos + offset;
        while (pos < range.from) {
            if (!index)
                return null;
            let next = this.ranges[--index];
            pos -= range.from - next.to;
            range = next;
        }
        while (assoc < 0 ? pos > range.to : pos >= range.to) {
            if (index == this.ranges.length - 1)
                return null;
            let next = this.ranges[++index];
            pos += next.from - range.to;
            range = next;
        }
        return pos;
    }
    /**
    @internal
    */
    clipPos(pos) {
        if (pos >= this.range.from && pos < this.range.to)
            return pos;
        for (let range of this.ranges)
            if (range.to > pos)
                return Math.max(pos, range.from);
        return this.end;
    }
    /**
    Look at a code unit near the stream position. `.peek(0)` equals
    `.next`, `.peek(-1)` gives you the previous character, and so
    on.
    
    Note that looking around during tokenizing creates dependencies
    on potentially far-away content, which may reduce the
    effectiveness incremental parsing—when looking forward—or even
    cause invalid reparses when looking backward more than 25 code
    units, since the library does not track lookbehind.
    */
    peek(offset) {
        let idx = this.chunkOff + offset, pos, result;
        if (idx >= 0 && idx < this.chunk.length) {
            pos = this.pos + offset;
            result = this.chunk.charCodeAt(idx);
        }
        else {
            let resolved = this.resolveOffset(offset, 1);
            if (resolved == null)
                return -1;
            pos = resolved;
            if (pos >= this.chunk2Pos && pos < this.chunk2Pos + this.chunk2.length) {
                result = this.chunk2.charCodeAt(pos - this.chunk2Pos);
            }
            else {
                let i = this.rangeIndex, range = this.range;
                while (range.to <= pos)
                    range = this.ranges[++i];
                this.chunk2 = this.input.chunk(this.chunk2Pos = pos);
                if (pos + this.chunk2.length > range.to)
                    this.chunk2 = this.chunk2.slice(0, range.to - pos);
                result = this.chunk2.charCodeAt(0);
            }
        }
        if (pos >= this.token.lookAhead)
            this.token.lookAhead = pos + 1;
        return result;
    }
    /**
    Accept a token. By default, the end of the token is set to the
    current stream position, but you can pass an offset (relative to
    the stream position) to change that.
    */
    acceptToken(token, endOffset = 0) {
        let end = endOffset ? this.resolveOffset(endOffset, -1) : this.pos;
        if (end == null || end < this.token.start)
            throw new RangeError("Token end out of bounds");
        this.token.value = token;
        this.token.end = end;
    }
    /**
    Accept a token ending at a specific given position.
    */
    acceptTokenTo(token, endPos) {
        this.token.value = token;
        this.token.end = endPos;
    }
    getChunk() {
        if (this.pos >= this.chunk2Pos && this.pos < this.chunk2Pos + this.chunk2.length) {
            let { chunk, chunkPos } = this;
            this.chunk = this.chunk2;
            this.chunkPos = this.chunk2Pos;
            this.chunk2 = chunk;
            this.chunk2Pos = chunkPos;
            this.chunkOff = this.pos - this.chunkPos;
        }
        else {
            this.chunk2 = this.chunk;
            this.chunk2Pos = this.chunkPos;
            let nextChunk = this.input.chunk(this.pos);
            let end = this.pos + nextChunk.length;
            this.chunk = end > this.range.to ? nextChunk.slice(0, this.range.to - this.pos) : nextChunk;
            this.chunkPos = this.pos;
            this.chunkOff = 0;
        }
    }
    readNext() {
        if (this.chunkOff >= this.chunk.length) {
            this.getChunk();
            if (this.chunkOff == this.chunk.length)
                return this.next = -1;
        }
        return this.next = this.chunk.charCodeAt(this.chunkOff);
    }
    /**
    Move the stream forward N (defaults to 1) code units. Returns
    the new value of [`next`](#lr.InputStream.next).
    */
    advance(n = 1) {
        this.chunkOff += n;
        while (this.pos + n >= this.range.to) {
            if (this.rangeIndex == this.ranges.length - 1)
                return this.setDone();
            n -= this.range.to - this.pos;
            this.range = this.ranges[++this.rangeIndex];
            this.pos = this.range.from;
        }
        this.pos += n;
        if (this.pos >= this.token.lookAhead)
            this.token.lookAhead = this.pos + 1;
        return this.readNext();
    }
    setDone() {
        this.pos = this.chunkPos = this.end;
        this.range = this.ranges[this.rangeIndex = this.ranges.length - 1];
        this.chunk = "";
        return this.next = -1;
    }
    /**
    @internal
    */
    reset(pos, token) {
        if (token) {
            this.token = token;
            token.start = pos;
            token.lookAhead = pos + 1;
            token.value = token.extended = -1;
        }
        else {
            this.token = nullToken;
        }
        if (this.pos != pos) {
            this.pos = pos;
            if (pos == this.end) {
                this.setDone();
                return this;
            }
            while (pos < this.range.from)
                this.range = this.ranges[--this.rangeIndex];
            while (pos >= this.range.to)
                this.range = this.ranges[++this.rangeIndex];
            if (pos >= this.chunkPos && pos < this.chunkPos + this.chunk.length) {
                this.chunkOff = pos - this.chunkPos;
            }
            else {
                this.chunk = "";
                this.chunkOff = 0;
            }
            this.readNext();
        }
        return this;
    }
    /**
    @internal
    */
    read(from, to) {
        if (from >= this.chunkPos && to <= this.chunkPos + this.chunk.length)
            return this.chunk.slice(from - this.chunkPos, to - this.chunkPos);
        if (from >= this.chunk2Pos && to <= this.chunk2Pos + this.chunk2.length)
            return this.chunk2.slice(from - this.chunk2Pos, to - this.chunk2Pos);
        if (from >= this.range.from && to <= this.range.to)
            return this.input.read(from, to);
        let result = "";
        for (let r of this.ranges) {
            if (r.from >= to)
                break;
            if (r.to > from)
                result += this.input.read(Math.max(r.from, from), Math.min(r.to, to));
        }
        return result;
    }
}
/**
@internal
*/
class TokenGroup {
    constructor(data, id) {
        this.data = data;
        this.id = id;
    }
    token(input, stack) {
        let { parser } = stack.p;
        readToken(this.data, input, stack, this.id, parser.data, parser.tokenPrecTable);
    }
}
TokenGroup.prototype.contextual = TokenGroup.prototype.fallback = TokenGroup.prototype.extend = false;
/**
@hide
*/
class LocalTokenGroup {
    constructor(data, precTable, elseToken) {
        this.precTable = precTable;
        this.elseToken = elseToken;
        this.data = typeof data == "string" ? decodeArray(data) : data;
    }
    token(input, stack) {
        let start = input.pos, skipped = 0;
        for (;;) {
            let atEof = input.next < 0, nextPos = input.resolveOffset(1, 1);
            readToken(this.data, input, stack, 0, this.data, this.precTable);
            if (input.token.value > -1)
                break;
            if (this.elseToken == null)
                return;
            if (!atEof)
                skipped++;
            if (nextPos == null)
                break;
            input.reset(nextPos, input.token);
        }
        if (skipped) {
            input.reset(start, input.token);
            input.acceptToken(this.elseToken, skipped);
        }
    }
}
LocalTokenGroup.prototype.contextual = TokenGroup.prototype.fallback = TokenGroup.prototype.extend = false;
/**
`@external tokens` declarations in the grammar should resolve to
an instance of this class.
*/
class ExternalTokenizer {
    /**
    Create a tokenizer. The first argument is the function that,
    given an input stream, scans for the types of tokens it
    recognizes at the stream's position, and calls
    [`acceptToken`](#lr.InputStream.acceptToken) when it finds
    one.
    */
    constructor(
    /**
    @internal
    */
    token, options = {}) {
        this.token = token;
        this.contextual = !!options.contextual;
        this.fallback = !!options.fallback;
        this.extend = !!options.extend;
    }
}
// Tokenizer data is stored a big uint16 array containing, for each
// state:
//
//  - A group bitmask, indicating what token groups are reachable from
//    this state, so that paths that can only lead to tokens not in
//    any of the current groups can be cut off early.
//
//  - The position of the end of the state's sequence of accepting
//    tokens
//
//  - The number of outgoing edges for the state
//
//  - The accepting tokens, as (token id, group mask) pairs
//
//  - The outgoing edges, as (start character, end character, state
//    index) triples, with end character being exclusive
//
// This function interprets that data, running through a stream as
// long as new states with the a matching group mask can be reached,
// and updating `input.token` when it matches a token.
function readToken(data, input, stack, group, precTable, precOffset) {
    let state = 0, groupMask = 1 << group, { dialect } = stack.p.parser;
    scan: for (;;) {
        if ((groupMask & data[state]) == 0)
            break;
        let accEnd = data[state + 1];
        // Check whether this state can lead to a token in the current group
        // Accept tokens in this state, possibly overwriting
        // lower-precedence / shorter tokens
        for (let i = state + 3; i < accEnd; i += 2)
            if ((data[i + 1] & groupMask) > 0) {
                let term = data[i];
                if (dialect.allows(term) &&
                    (input.token.value == -1 || input.token.value == term ||
                        overrides(term, input.token.value, precTable, precOffset))) {
                    input.acceptToken(term);
                    break;
                }
            }
        let next = input.next, low = 0, high = data[state + 2];
        // Special case for EOF
        if (input.next < 0 && high > low && data[accEnd + high * 3 - 3] == 65535 /* Seq.End */) {
            state = data[accEnd + high * 3 - 1];
            continue scan;
        }
        // Do a binary search on the state's edges
        for (; low < high;) {
            let mid = (low + high) >> 1;
            let index = accEnd + mid + (mid << 1);
            let from = data[index], to = data[index + 1] || 0x10000;
            if (next < from)
                high = mid;
            else if (next >= to)
                low = mid + 1;
            else {
                state = data[index + 2];
                input.advance();
                continue scan;
            }
        }
        break;
    }
}
function findOffset(data, start, term) {
    for (let i = start, next; (next = data[i]) != 65535 /* Seq.End */; i++)
        if (next == term)
            return i - start;
    return -1;
}
function overrides(token, prev, tableData, tableOffset) {
    let iPrev = findOffset(tableData, tableOffset, prev);
    return iPrev < 0 || findOffset(tableData, tableOffset, token) < iPrev;
}

// Environment variable used to control console output
const verbose = typeof process != "undefined" && process.env && /\bparse\b/.test(process.env.LOG);
let stackIDs = null;
function cutAt(tree, pos, side) {
    let cursor = tree.cursor(IterMode.IncludeAnonymous);
    cursor.moveTo(pos);
    for (;;) {
        if (!(side < 0 ? cursor.childBefore(pos) : cursor.childAfter(pos)))
            for (;;) {
                if ((side < 0 ? cursor.to < pos : cursor.from > pos) && !cursor.type.isError)
                    return side < 0 ? Math.max(0, Math.min(cursor.to - 1, pos - 25 /* Lookahead.Margin */))
                        : Math.min(tree.length, Math.max(cursor.from + 1, pos + 25 /* Lookahead.Margin */));
                if (side < 0 ? cursor.prevSibling() : cursor.nextSibling())
                    break;
                if (!cursor.parent())
                    return side < 0 ? 0 : tree.length;
            }
    }
}
class FragmentCursor {
    constructor(fragments, nodeSet) {
        this.fragments = fragments;
        this.nodeSet = nodeSet;
        this.i = 0;
        this.fragment = null;
        this.safeFrom = -1;
        this.safeTo = -1;
        this.trees = [];
        this.start = [];
        this.index = [];
        this.nextFragment();
    }
    nextFragment() {
        let fr = this.fragment = this.i == this.fragments.length ? null : this.fragments[this.i++];
        if (fr) {
            this.safeFrom = fr.openStart ? cutAt(fr.tree, fr.from + fr.offset, 1) - fr.offset : fr.from;
            this.safeTo = fr.openEnd ? cutAt(fr.tree, fr.to + fr.offset, -1) - fr.offset : fr.to;
            while (this.trees.length) {
                this.trees.pop();
                this.start.pop();
                this.index.pop();
            }
            this.trees.push(fr.tree);
            this.start.push(-fr.offset);
            this.index.push(0);
            this.nextStart = this.safeFrom;
        }
        else {
            this.nextStart = 1e9;
        }
    }
    // `pos` must be >= any previously given `pos` for this cursor
    nodeAt(pos) {
        if (pos < this.nextStart)
            return null;
        while (this.fragment && this.safeTo <= pos)
            this.nextFragment();
        if (!this.fragment)
            return null;
        for (;;) {
            let last = this.trees.length - 1;
            if (last < 0) { // End of tree
                this.nextFragment();
                return null;
            }
            let top = this.trees[last], index = this.index[last];
            if (index == top.children.length) {
                this.trees.pop();
                this.start.pop();
                this.index.pop();
                continue;
            }
            let next = top.children[index];
            let start = this.start[last] + top.positions[index];
            if (start > pos) {
                this.nextStart = start;
                return null;
            }
            if (next instanceof Tree) {
                if (start == pos) {
                    if (start < this.safeFrom)
                        return null;
                    let end = start + next.length;
                    if (end <= this.safeTo) {
                        let lookAhead = next.prop(NodeProp.lookAhead);
                        if (!lookAhead || end + lookAhead < this.fragment.to)
                            return next;
                    }
                }
                this.index[last]++;
                if (start + next.length >= Math.max(this.safeFrom, pos)) { // Enter this node
                    this.trees.push(next);
                    this.start.push(start);
                    this.index.push(0);
                }
            }
            else {
                this.index[last]++;
                this.nextStart = start + next.length;
            }
        }
    }
}
class TokenCache {
    constructor(parser, stream) {
        this.stream = stream;
        this.tokens = [];
        this.mainToken = null;
        this.actions = [];
        this.tokens = parser.tokenizers.map(_ => new CachedToken);
    }
    getActions(stack) {
        let actionIndex = 0;
        let main = null;
        let { parser } = stack.p, { tokenizers } = parser;
        let mask = parser.stateSlot(stack.state, 3 /* ParseState.TokenizerMask */);
        let context = stack.curContext ? stack.curContext.hash : 0;
        let lookAhead = 0;
        for (let i = 0; i < tokenizers.length; i++) {
            if (((1 << i) & mask) == 0)
                continue;
            let tokenizer = tokenizers[i], token = this.tokens[i];
            if (main && !tokenizer.fallback)
                continue;
            if (tokenizer.contextual || token.start != stack.pos || token.mask != mask || token.context != context) {
                this.updateCachedToken(token, tokenizer, stack);
                token.mask = mask;
                token.context = context;
            }
            if (token.lookAhead > token.end + 25 /* Lookahead.Margin */)
                lookAhead = Math.max(token.lookAhead, lookAhead);
            if (token.value != 0 /* Term.Err */) {
                let startIndex = actionIndex;
                if (token.extended > -1)
                    actionIndex = this.addActions(stack, token.extended, token.end, actionIndex);
                actionIndex = this.addActions(stack, token.value, token.end, actionIndex);
                if (!tokenizer.extend) {
                    main = token;
                    if (actionIndex > startIndex)
                        break;
                }
            }
        }
        while (this.actions.length > actionIndex)
            this.actions.pop();
        if (lookAhead)
            stack.setLookAhead(lookAhead);
        if (!main && stack.pos == this.stream.end) {
            main = new CachedToken;
            main.value = stack.p.parser.eofTerm;
            main.start = main.end = stack.pos;
            actionIndex = this.addActions(stack, main.value, main.end, actionIndex);
        }
        this.mainToken = main;
        return this.actions;
    }
    getMainToken(stack) {
        if (this.mainToken)
            return this.mainToken;
        let main = new CachedToken, { pos, p } = stack;
        main.start = pos;
        main.end = Math.min(pos + 1, p.stream.end);
        main.value = pos == p.stream.end ? p.parser.eofTerm : 0 /* Term.Err */;
        return main;
    }
    updateCachedToken(token, tokenizer, stack) {
        let start = this.stream.clipPos(stack.pos);
        tokenizer.token(this.stream.reset(start, token), stack);
        if (token.value > -1) {
            let { parser } = stack.p;
            for (let i = 0; i < parser.specialized.length; i++)
                if (parser.specialized[i] == token.value) {
                    let result = parser.specializers[i](this.stream.read(token.start, token.end), stack);
                    if (result >= 0 && stack.p.parser.dialect.allows(result >> 1)) {
                        if ((result & 1) == 0 /* Specialize.Specialize */)
                            token.value = result >> 1;
                        else
                            token.extended = result >> 1;
                        break;
                    }
                }
        }
        else {
            token.value = 0 /* Term.Err */;
            token.end = this.stream.clipPos(start + 1);
        }
    }
    putAction(action, token, end, index) {
        // Don't add duplicate actions
        for (let i = 0; i < index; i += 3)
            if (this.actions[i] == action)
                return index;
        this.actions[index++] = action;
        this.actions[index++] = token;
        this.actions[index++] = end;
        return index;
    }
    addActions(stack, token, end, index) {
        let { state } = stack, { parser } = stack.p, { data } = parser;
        for (let set = 0; set < 2; set++) {
            for (let i = parser.stateSlot(state, set ? 2 /* ParseState.Skip */ : 1 /* ParseState.Actions */);; i += 3) {
                if (data[i] == 65535 /* Seq.End */) {
                    if (data[i + 1] == 1 /* Seq.Next */) {
                        i = pair(data, i + 2);
                    }
                    else {
                        if (index == 0 && data[i + 1] == 2 /* Seq.Other */)
                            index = this.putAction(pair(data, i + 2), token, end, index);
                        break;
                    }
                }
                if (data[i] == token)
                    index = this.putAction(pair(data, i + 1), token, end, index);
            }
        }
        return index;
    }
}
class Parse {
    constructor(parser, input, fragments, ranges) {
        this.parser = parser;
        this.input = input;
        this.ranges = ranges;
        this.recovering = 0;
        this.nextStackID = 0x2654; // ♔, ♕, ♖, ♗, ♘, ♙, ♠, ♡, ♢, ♣, ♤, ♥, ♦, ♧
        this.minStackPos = 0;
        this.reused = [];
        this.stoppedAt = null;
        this.lastBigReductionStart = -1;
        this.lastBigReductionSize = 0;
        this.bigReductionCount = 0;
        this.stream = new InputStream(input, ranges);
        this.tokens = new TokenCache(parser, this.stream);
        this.topTerm = parser.top[1];
        let { from } = ranges[0];
        this.stacks = [Stack.start(this, parser.top[0], from)];
        this.fragments = fragments.length && this.stream.end - from > parser.bufferLength * 4
            ? new FragmentCursor(fragments, parser.nodeSet) : null;
    }
    get parsedPos() {
        return this.minStackPos;
    }
    // Move the parser forward. This will process all parse stacks at
    // `this.pos` and try to advance them to a further position. If no
    // stack for such a position is found, it'll start error-recovery.
    //
    // When the parse is finished, this will return a syntax tree. When
    // not, it returns `null`.
    advance() {
        let stacks = this.stacks, pos = this.minStackPos;
        // This will hold stacks beyond `pos`.
        let newStacks = this.stacks = [];
        let stopped, stoppedTokens;
        // If a large amount of reductions happened with the same start
        // position, force the stack out of that production in order to
        // avoid creating a tree too deep to recurse through.
        // (This is an ugly kludge, because unfortunately there is no
        // straightforward, cheap way to check for this happening, due to
        // the history of reductions only being available in an
        // expensive-to-access format in the stack buffers.)
        if (this.bigReductionCount > 300 /* Rec.MaxLeftAssociativeReductionCount */ && stacks.length == 1) {
            let [s] = stacks;
            while (s.forceReduce() && s.stack.length && s.stack[s.stack.length - 2] >= this.lastBigReductionStart) { }
            this.bigReductionCount = this.lastBigReductionSize = 0;
        }
        // Keep advancing any stacks at `pos` until they either move
        // forward or can't be advanced. Gather stacks that can't be
        // advanced further in `stopped`.
        for (let i = 0; i < stacks.length; i++) {
            let stack = stacks[i];
            for (;;) {
                this.tokens.mainToken = null;
                if (stack.pos > pos) {
                    newStacks.push(stack);
                }
                else if (this.advanceStack(stack, newStacks, stacks)) {
                    continue;
                }
                else {
                    if (!stopped) {
                        stopped = [];
                        stoppedTokens = [];
                    }
                    stopped.push(stack);
                    let tok = this.tokens.getMainToken(stack);
                    stoppedTokens.push(tok.value, tok.end);
                }
                break;
            }
        }
        if (!newStacks.length) {
            let finished = stopped && findFinished(stopped);
            if (finished) {
                if (verbose)
                    console.log("Finish with " + this.stackID(finished));
                return this.stackToTree(finished);
            }
            if (this.parser.strict) {
                if (verbose && stopped)
                    console.log("Stuck with token " + (this.tokens.mainToken ? this.parser.getName(this.tokens.mainToken.value) : "none"));
                throw new SyntaxError("No parse at " + pos);
            }
            if (!this.recovering)
                this.recovering = 5 /* Rec.Distance */;
        }
        if (this.recovering && stopped) {
            let finished = this.stoppedAt != null && stopped[0].pos > this.stoppedAt ? stopped[0]
                : this.runRecovery(stopped, stoppedTokens, newStacks);
            if (finished) {
                if (verbose)
                    console.log("Force-finish " + this.stackID(finished));
                return this.stackToTree(finished.forceAll());
            }
        }
        if (this.recovering) {
            let maxRemaining = this.recovering == 1 ? 1 : this.recovering * 3 /* Rec.MaxRemainingPerStep */;
            if (newStacks.length > maxRemaining) {
                newStacks.sort((a, b) => b.score - a.score);
                while (newStacks.length > maxRemaining)
                    newStacks.pop();
            }
            if (newStacks.some(s => s.reducePos > pos))
                this.recovering--;
        }
        else if (newStacks.length > 1) {
            // Prune stacks that are in the same state, or that have been
            // running without splitting for a while, to avoid getting stuck
            // with multiple successful stacks running endlessly on.
            outer: for (let i = 0; i < newStacks.length - 1; i++) {
                let stack = newStacks[i];
                for (let j = i + 1; j < newStacks.length; j++) {
                    let other = newStacks[j];
                    if (stack.sameState(other) ||
                        stack.buffer.length > 500 /* Rec.MinBufferLengthPrune */ && other.buffer.length > 500 /* Rec.MinBufferLengthPrune */) {
                        if (((stack.score - other.score) || (stack.buffer.length - other.buffer.length)) > 0) {
                            newStacks.splice(j--, 1);
                        }
                        else {
                            newStacks.splice(i--, 1);
                            continue outer;
                        }
                    }
                }
            }
            if (newStacks.length > 12 /* Rec.MaxStackCount */)
                newStacks.splice(12 /* Rec.MaxStackCount */, newStacks.length - 12 /* Rec.MaxStackCount */);
        }
        this.minStackPos = newStacks[0].pos;
        for (let i = 1; i < newStacks.length; i++)
            if (newStacks[i].pos < this.minStackPos)
                this.minStackPos = newStacks[i].pos;
        return null;
    }
    stopAt(pos) {
        if (this.stoppedAt != null && this.stoppedAt < pos)
            throw new RangeError("Can't move stoppedAt forward");
        this.stoppedAt = pos;
    }
    // Returns an updated version of the given stack, or null if the
    // stack can't advance normally. When `split` and `stacks` are
    // given, stacks split off by ambiguous operations will be pushed to
    // `split`, or added to `stacks` if they move `pos` forward.
    advanceStack(stack, stacks, split) {
        let start = stack.pos, { parser } = this;
        let base = verbose ? this.stackID(stack) + " -> " : "";
        if (this.stoppedAt != null && start > this.stoppedAt)
            return stack.forceReduce() ? stack : null;
        if (this.fragments) {
            let strictCx = stack.curContext && stack.curContext.tracker.strict, cxHash = strictCx ? stack.curContext.hash : 0;
            for (let cached = this.fragments.nodeAt(start); cached;) {
                let match = this.parser.nodeSet.types[cached.type.id] == cached.type ? parser.getGoto(stack.state, cached.type.id) : -1;
                if (match > -1 && cached.length && (!strictCx || (cached.prop(NodeProp.contextHash) || 0) == cxHash)) {
                    stack.useNode(cached, match);
                    if (verbose)
                        console.log(base + this.stackID(stack) + ` (via reuse of ${parser.getName(cached.type.id)})`);
                    return true;
                }
                if (!(cached instanceof Tree) || cached.children.length == 0 || cached.positions[0] > 0)
                    break;
                let inner = cached.children[0];
                if (inner instanceof Tree && cached.positions[0] == 0)
                    cached = inner;
                else
                    break;
            }
        }
        let defaultReduce = parser.stateSlot(stack.state, 4 /* ParseState.DefaultReduce */);
        if (defaultReduce > 0) {
            stack.reduce(defaultReduce);
            if (verbose)
                console.log(base + this.stackID(stack) + ` (via always-reduce ${parser.getName(defaultReduce & 65535 /* Action.ValueMask */)})`);
            return true;
        }
        if (stack.stack.length >= 8400 /* Rec.CutDepth */) {
            while (stack.stack.length > 6000 /* Rec.CutTo */ && stack.forceReduce()) { }
        }
        let actions = this.tokens.getActions(stack);
        for (let i = 0; i < actions.length;) {
            let action = actions[i++], term = actions[i++], end = actions[i++];
            let last = i == actions.length || !split;
            let localStack = last ? stack : stack.split();
            let main = this.tokens.mainToken;
            localStack.apply(action, term, main ? main.start : localStack.pos, end);
            if (verbose)
                console.log(base + this.stackID(localStack) + ` (via ${(action & 65536 /* Action.ReduceFlag */) == 0 ? "shift"
                    : `reduce of ${parser.getName(action & 65535 /* Action.ValueMask */)}`} for ${parser.getName(term)} @ ${start}${localStack == stack ? "" : ", split"})`);
            if (last)
                return true;
            else if (localStack.pos > start)
                stacks.push(localStack);
            else
                split.push(localStack);
        }
        return false;
    }
    // Advance a given stack forward as far as it will go. Returns the
    // (possibly updated) stack if it got stuck, or null if it moved
    // forward and was given to `pushStackDedup`.
    advanceFully(stack, newStacks) {
        let pos = stack.pos;
        for (;;) {
            if (!this.advanceStack(stack, null, null))
                return false;
            if (stack.pos > pos) {
                pushStackDedup(stack, newStacks);
                return true;
            }
        }
    }
    runRecovery(stacks, tokens, newStacks) {
        let finished = null, restarted = false;
        for (let i = 0; i < stacks.length; i++) {
            let stack = stacks[i], token = tokens[i << 1], tokenEnd = tokens[(i << 1) + 1];
            let base = verbose ? this.stackID(stack) + " -> " : "";
            if (stack.deadEnd) {
                if (restarted)
                    continue;
                restarted = true;
                stack.restart();
                if (verbose)
                    console.log(base + this.stackID(stack) + " (restarted)");
                let done = this.advanceFully(stack, newStacks);
                if (done)
                    continue;
            }
            let force = stack.split(), forceBase = base;
            for (let j = 0; force.forceReduce() && j < 10 /* Rec.ForceReduceLimit */; j++) {
                if (verbose)
                    console.log(forceBase + this.stackID(force) + " (via force-reduce)");
                let done = this.advanceFully(force, newStacks);
                if (done)
                    break;
                if (verbose)
                    forceBase = this.stackID(force) + " -> ";
            }
            for (let insert of stack.recoverByInsert(token)) {
                if (verbose)
                    console.log(base + this.stackID(insert) + " (via recover-insert)");
                this.advanceFully(insert, newStacks);
            }
            if (this.stream.end > stack.pos) {
                if (tokenEnd == stack.pos) {
                    tokenEnd++;
                    token = 0 /* Term.Err */;
                }
                stack.recoverByDelete(token, tokenEnd);
                if (verbose)
                    console.log(base + this.stackID(stack) + ` (via recover-delete ${this.parser.getName(token)})`);
                pushStackDedup(stack, newStacks);
            }
            else if (!finished || finished.score < stack.score) {
                finished = stack;
            }
        }
        return finished;
    }
    // Convert the stack's buffer to a syntax tree.
    stackToTree(stack) {
        stack.close();
        return Tree.build({ buffer: StackBufferCursor.create(stack),
            nodeSet: this.parser.nodeSet,
            topID: this.topTerm,
            maxBufferLength: this.parser.bufferLength,
            reused: this.reused,
            start: this.ranges[0].from,
            length: stack.pos - this.ranges[0].from,
            minRepeatType: this.parser.minRepeatTerm });
    }
    stackID(stack) {
        let id = (stackIDs || (stackIDs = new WeakMap)).get(stack);
        if (!id)
            stackIDs.set(stack, id = String.fromCodePoint(this.nextStackID++));
        return id + stack;
    }
}
function pushStackDedup(stack, newStacks) {
    for (let i = 0; i < newStacks.length; i++) {
        let other = newStacks[i];
        if (other.pos == stack.pos && other.sameState(stack)) {
            if (newStacks[i].score < stack.score)
                newStacks[i] = stack;
            return;
        }
    }
    newStacks.push(stack);
}
class Dialect {
    constructor(source, flags, disabled) {
        this.source = source;
        this.flags = flags;
        this.disabled = disabled;
    }
    allows(term) { return !this.disabled || this.disabled[term] == 0; }
}
const id$3 = x => x;
/**
Context trackers are used to track stateful context (such as
indentation in the Python grammar, or parent elements in the XML
grammar) needed by external tokenizers. You declare them in a
grammar file as `@context exportName from "module"`.

Context values should be immutable, and can be updated (replaced)
on shift or reduce actions.

The export used in a `@context` declaration should be of this
type.
*/
class ContextTracker {
    /**
    Define a context tracker.
    */
    constructor(spec) {
        this.start = spec.start;
        this.shift = spec.shift || id$3;
        this.reduce = spec.reduce || id$3;
        this.reuse = spec.reuse || id$3;
        this.hash = spec.hash || (() => 0);
        this.strict = spec.strict !== false;
    }
}
/**
Holds the parse tables for a given grammar, as generated by
`lezer-generator`, and provides [methods](#common.Parser) to parse
content with.
*/
class LRParser extends Parser {
    /**
    @internal
    */
    constructor(spec) {
        super();
        /**
        @internal
        */
        this.wrappers = [];
        if (spec.version != 14 /* File.Version */)
            throw new RangeError(`Parser version (${spec.version}) doesn't match runtime version (${14 /* File.Version */})`);
        let nodeNames = spec.nodeNames.split(" ");
        this.minRepeatTerm = nodeNames.length;
        for (let i = 0; i < spec.repeatNodeCount; i++)
            nodeNames.push("");
        let topTerms = Object.keys(spec.topRules).map(r => spec.topRules[r][1]);
        let nodeProps = [];
        for (let i = 0; i < nodeNames.length; i++)
            nodeProps.push([]);
        function setProp(nodeID, prop, value) {
            nodeProps[nodeID].push([prop, prop.deserialize(String(value))]);
        }
        if (spec.nodeProps)
            for (let propSpec of spec.nodeProps) {
                let prop = propSpec[0];
                if (typeof prop == "string")
                    prop = NodeProp[prop];
                for (let i = 1; i < propSpec.length;) {
                    let next = propSpec[i++];
                    if (next >= 0) {
                        setProp(next, prop, propSpec[i++]);
                    }
                    else {
                        let value = propSpec[i + -next];
                        for (let j = -next; j > 0; j--)
                            setProp(propSpec[i++], prop, value);
                        i++;
                    }
                }
            }
        this.nodeSet = new NodeSet(nodeNames.map((name, i) => NodeType.define({
            name: i >= this.minRepeatTerm ? undefined : name,
            id: i,
            props: nodeProps[i],
            top: topTerms.indexOf(i) > -1,
            error: i == 0,
            skipped: spec.skippedNodes && spec.skippedNodes.indexOf(i) > -1
        })));
        if (spec.propSources)
            this.nodeSet = this.nodeSet.extend(...spec.propSources);
        this.strict = false;
        this.bufferLength = DefaultBufferLength;
        let tokenArray = decodeArray(spec.tokenData);
        this.context = spec.context;
        this.specializerSpecs = spec.specialized || [];
        this.specialized = new Uint16Array(this.specializerSpecs.length);
        for (let i = 0; i < this.specializerSpecs.length; i++)
            this.specialized[i] = this.specializerSpecs[i].term;
        this.specializers = this.specializerSpecs.map(getSpecializer);
        this.states = decodeArray(spec.states, Uint32Array);
        this.data = decodeArray(spec.stateData);
        this.goto = decodeArray(spec.goto);
        this.maxTerm = spec.maxTerm;
        this.tokenizers = spec.tokenizers.map(value => typeof value == "number" ? new TokenGroup(tokenArray, value) : value);
        this.topRules = spec.topRules;
        this.dialects = spec.dialects || {};
        this.dynamicPrecedences = spec.dynamicPrecedences || null;
        this.tokenPrecTable = spec.tokenPrec;
        this.termNames = spec.termNames || null;
        this.maxNode = this.nodeSet.types.length - 1;
        this.dialect = this.parseDialect();
        this.top = this.topRules[Object.keys(this.topRules)[0]];
    }
    createParse(input, fragments, ranges) {
        let parse = new Parse(this, input, fragments, ranges);
        for (let w of this.wrappers)
            parse = w(parse, input, fragments, ranges);
        return parse;
    }
    /**
    Get a goto table entry @internal
    */
    getGoto(state, term, loose = false) {
        let table = this.goto;
        if (term >= table[0])
            return -1;
        for (let pos = table[term + 1];;) {
            let groupTag = table[pos++], last = groupTag & 1;
            let target = table[pos++];
            if (last && loose)
                return target;
            for (let end = pos + (groupTag >> 1); pos < end; pos++)
                if (table[pos] == state)
                    return target;
            if (last)
                return -1;
        }
    }
    /**
    Check if this state has an action for a given terminal @internal
    */
    hasAction(state, terminal) {
        let data = this.data;
        for (let set = 0; set < 2; set++) {
            for (let i = this.stateSlot(state, set ? 2 /* ParseState.Skip */ : 1 /* ParseState.Actions */), next;; i += 3) {
                if ((next = data[i]) == 65535 /* Seq.End */) {
                    if (data[i + 1] == 1 /* Seq.Next */)
                        next = data[i = pair(data, i + 2)];
                    else if (data[i + 1] == 2 /* Seq.Other */)
                        return pair(data, i + 2);
                    else
                        break;
                }
                if (next == terminal || next == 0 /* Term.Err */)
                    return pair(data, i + 1);
            }
        }
        return 0;
    }
    /**
    @internal
    */
    stateSlot(state, slot) {
        return this.states[(state * 6 /* ParseState.Size */) + slot];
    }
    /**
    @internal
    */
    stateFlag(state, flag) {
        return (this.stateSlot(state, 0 /* ParseState.Flags */) & flag) > 0;
    }
    /**
    @internal
    */
    validAction(state, action) {
        return !!this.allActions(state, a => a == action ? true : null);
    }
    /**
    @internal
    */
    allActions(state, action) {
        let deflt = this.stateSlot(state, 4 /* ParseState.DefaultReduce */);
        let result = deflt ? action(deflt) : undefined;
        for (let i = this.stateSlot(state, 1 /* ParseState.Actions */); result == null; i += 3) {
            if (this.data[i] == 65535 /* Seq.End */) {
                if (this.data[i + 1] == 1 /* Seq.Next */)
                    i = pair(this.data, i + 2);
                else
                    break;
            }
            result = action(pair(this.data, i + 1));
        }
        return result;
    }
    /**
    Get the states that can follow this one through shift actions or
    goto jumps. @internal
    */
    nextStates(state) {
        let result = [];
        for (let i = this.stateSlot(state, 1 /* ParseState.Actions */);; i += 3) {
            if (this.data[i] == 65535 /* Seq.End */) {
                if (this.data[i + 1] == 1 /* Seq.Next */)
                    i = pair(this.data, i + 2);
                else
                    break;
            }
            if ((this.data[i + 2] & (65536 /* Action.ReduceFlag */ >> 16)) == 0) {
                let value = this.data[i + 1];
                if (!result.some((v, i) => (i & 1) && v == value))
                    result.push(this.data[i], value);
            }
        }
        return result;
    }
    /**
    Configure the parser. Returns a new parser instance that has the
    given settings modified. Settings not provided in `config` are
    kept from the original parser.
    */
    configure(config) {
        // Hideous reflection-based kludge to make it easy to create a
        // slightly modified copy of a parser.
        let copy = Object.assign(Object.create(LRParser.prototype), this);
        if (config.props)
            copy.nodeSet = this.nodeSet.extend(...config.props);
        if (config.top) {
            let info = this.topRules[config.top];
            if (!info)
                throw new RangeError(`Invalid top rule name ${config.top}`);
            copy.top = info;
        }
        if (config.tokenizers)
            copy.tokenizers = this.tokenizers.map(t => {
                let found = config.tokenizers.find(r => r.from == t);
                return found ? found.to : t;
            });
        if (config.specializers) {
            copy.specializers = this.specializers.slice();
            copy.specializerSpecs = this.specializerSpecs.map((s, i) => {
                let found = config.specializers.find(r => r.from == s.external);
                if (!found)
                    return s;
                let spec = Object.assign(Object.assign({}, s), { external: found.to });
                copy.specializers[i] = getSpecializer(spec);
                return spec;
            });
        }
        if (config.contextTracker)
            copy.context = config.contextTracker;
        if (config.dialect)
            copy.dialect = this.parseDialect(config.dialect);
        if (config.strict != null)
            copy.strict = config.strict;
        if (config.wrap)
            copy.wrappers = copy.wrappers.concat(config.wrap);
        if (config.bufferLength != null)
            copy.bufferLength = config.bufferLength;
        return copy;
    }
    /**
    Tells you whether any [parse wrappers](#lr.ParserConfig.wrap)
    are registered for this parser.
    */
    hasWrappers() {
        return this.wrappers.length > 0;
    }
    /**
    Returns the name associated with a given term. This will only
    work for all terms when the parser was generated with the
    `--names` option. By default, only the names of tagged terms are
    stored.
    */
    getName(term) {
        return this.termNames ? this.termNames[term] : String(term <= this.maxNode && this.nodeSet.types[term].name || term);
    }
    /**
    The eof term id is always allocated directly after the node
    types. @internal
    */
    get eofTerm() { return this.maxNode + 1; }
    /**
    The type of top node produced by the parser.
    */
    get topNode() { return this.nodeSet.types[this.top[1]]; }
    /**
    @internal
    */
    dynamicPrecedence(term) {
        let prec = this.dynamicPrecedences;
        return prec == null ? 0 : prec[term] || 0;
    }
    /**
    @internal
    */
    parseDialect(dialect) {
        let values = Object.keys(this.dialects), flags = values.map(() => false);
        if (dialect)
            for (let part of dialect.split(" ")) {
                let id = values.indexOf(part);
                if (id >= 0)
                    flags[id] = true;
            }
        let disabled = null;
        for (let i = 0; i < values.length; i++)
            if (!flags[i]) {
                for (let j = this.dialects[values[i]], id; (id = this.data[j++]) != 65535 /* Seq.End */;)
                    (disabled || (disabled = new Uint8Array(this.maxTerm + 1)))[id] = 1;
            }
        return new Dialect(dialect, flags, disabled);
    }
    /**
    Used by the output of the parser generator. Not available to
    user code. @hide
    */
    static deserialize(spec) {
        return new LRParser(spec);
    }
}
function pair(data, off) { return data[off] | (data[off + 1] << 16); }
function findFinished(stacks) {
    let best = null;
    for (let stack of stacks) {
        let stopped = stack.p.stoppedAt;
        if ((stack.pos == stack.p.stream.end || stopped != null && stack.pos > stopped) &&
            stack.p.parser.stateFlag(stack.state, 2 /* StateFlag.Accepting */) &&
            (!best || best.score < stack.score))
            best = stack;
    }
    return best;
}
function getSpecializer(spec) {
    if (spec.external) {
        let mask = spec.extend ? 1 /* Specialize.Extend */ : 0 /* Specialize.Specialize */;
        return (value, stack) => (spec.external(value, stack) << 1) | mask;
    }
    return spec.get;
}// This file was generated by lezer-generator. You probably shouldn't edit it.
const noSemi = 312,
  incdec = 1,
  incdecPrefix = 2,
  questionDot = 3,
  JSXStartTag = 4,
  insertSemi = 313,
  spaces = 315,
  newline$1 = 316,
  LineComment = 5,
  BlockComment = 6,
  Dialect_jsx = 0;

/* Hand-written tokenizers for JavaScript tokens that can't be
   expressed by lezer's built-in tokenizer. */

const space = [9, 10, 11, 12, 13, 32, 133, 160, 5760, 8192, 8193, 8194, 8195, 8196, 8197, 8198, 8199, 8200,
               8201, 8202, 8232, 8233, 8239, 8287, 12288];

const braceR = 125, semicolon = 59, slash = 47, star$4 = 42, plus$1 = 43, minus$1 = 45, lt$1 = 60, comma$1 = 44,
      question$3 = 63, dot$1 = 46;

const trackNewline = new ContextTracker({
  start: false,
  shift(context, term) {
    return term == LineComment || term == BlockComment || term == spaces ? context : term == newline$1
  },
  strict: false
});

const insertSemicolon = new ExternalTokenizer((input, stack) => {
  let {next} = input;
  if (next == braceR || next == -1 || stack.context)
    input.acceptToken(insertSemi);
}, {contextual: true, fallback: true});

const noSemicolon = new ExternalTokenizer((input, stack) => {
  let {next} = input, after;
  if (space.indexOf(next) > -1) return
  if (next == slash && ((after = input.peek(1)) == slash || after == star$4)) return
  if (next != braceR && next != semicolon && next != -1 && !stack.context)
    input.acceptToken(noSemi);
}, {contextual: true});

const operatorToken = new ExternalTokenizer((input, stack) => {
  let {next} = input;
  if (next == plus$1 || next == minus$1) {
    input.advance();
    if (next == input.next) {
      input.advance();
      let mayPostfix = !stack.context && stack.canShift(incdec);
      input.acceptToken(mayPostfix ? incdec : incdecPrefix);
    }
  } else if (next == question$3 && input.peek(1) == dot$1) {
    input.advance(); input.advance();
    if (input.next < 48 || input.next > 57) // No digit after
      input.acceptToken(questionDot);
  }
}, {contextual: true});

function identifierChar(ch, start) {
  return ch >= 65 && ch <= 90 || ch >= 97 && ch <= 122 || ch == 95 || ch >= 192 ||
    !start && ch >= 48 && ch <= 57
}

const jsx = new ExternalTokenizer((input, stack) => {
  if (input.next != lt$1 || !stack.dialectEnabled(Dialect_jsx)) return
  input.advance();
  if (input.next == slash) return
  // Scan for an identifier followed by a comma or 'extends', don't
  // treat this as a start tag if present.
  let back = 0;
  while (space.indexOf(input.next) > -1) { input.advance(); back++; }
  if (identifierChar(input.next, true)) {
    input.advance();
    back++;
    while (identifierChar(input.next, false)) { input.advance(); back++; }
    while (space.indexOf(input.next) > -1) { input.advance(); back++; }
    if (input.next == comma$1) return
    for (let i = 0;; i++) {
      if (i == 7) {
        if (!identifierChar(input.next, true)) return
        break
      }
      if (input.next != "extends".charCodeAt(i)) break
      input.advance();
      back++;
    }
  }
  input.acceptToken(JSXStartTag, -back);
});

const jsHighlight = styleTags({
  "get set async static": tags.modifier,
  "for while do if else switch try catch finally return throw break continue default case": tags.controlKeyword,
  "in of await yield void typeof delete instanceof": tags.operatorKeyword,
  "let var const using function class extends": tags.definitionKeyword,
  "import export from": tags.moduleKeyword,
  "with debugger as new": tags.keyword,
  TemplateString: tags.special(tags.string),
  super: tags.atom,
  BooleanLiteral: tags.bool,
  this: tags.self,
  null: tags.null,
  Star: tags.modifier,
  VariableName: tags.variableName,
  "CallExpression/VariableName TaggedTemplateExpression/VariableName": tags.function(tags.variableName),
  VariableDefinition: tags.definition(tags.variableName),
  Label: tags.labelName,
  PropertyName: tags.propertyName,
  PrivatePropertyName: tags.special(tags.propertyName),
  "CallExpression/MemberExpression/PropertyName": tags.function(tags.propertyName),
  "FunctionDeclaration/VariableDefinition": tags.function(tags.definition(tags.variableName)),
  "ClassDeclaration/VariableDefinition": tags.definition(tags.className),
  PropertyDefinition: tags.definition(tags.propertyName),
  PrivatePropertyDefinition: tags.definition(tags.special(tags.propertyName)),
  UpdateOp: tags.updateOperator,
  "LineComment Hashbang": tags.lineComment,
  BlockComment: tags.blockComment,
  Number: tags.number,
  String: tags.string,
  Escape: tags.escape,
  ArithOp: tags.arithmeticOperator,
  LogicOp: tags.logicOperator,
  BitOp: tags.bitwiseOperator,
  CompareOp: tags.compareOperator,
  RegExp: tags.regexp,
  Equals: tags.definitionOperator,
  Arrow: tags.function(tags.punctuation),
  ": Spread": tags.punctuation,
  "( )": tags.paren,
  "[ ]": tags.squareBracket,
  "{ }": tags.brace,
  "InterpolationStart InterpolationEnd": tags.special(tags.brace),
  ".": tags.derefOperator,
  ", ;": tags.separator,
  "@": tags.meta,

  TypeName: tags.typeName,
  TypeDefinition: tags.definition(tags.typeName),
  "type enum interface implements namespace module declare": tags.definitionKeyword,
  "abstract global Privacy readonly override": tags.modifier,
  "is keyof unique infer": tags.operatorKeyword,

  JSXAttributeValue: tags.attributeValue,
  JSXText: tags.content,
  "JSXStartTag JSXStartCloseTag JSXSelfCloseEndTag JSXEndTag": tags.angleBracket,
  "JSXIdentifier JSXNameSpacedName": tags.tagName,
  "JSXAttribute/JSXIdentifier JSXAttribute/JSXNameSpacedName": tags.attributeName,
  "JSXBuiltin/JSXIdentifier": tags.standard(tags.tagName)
});

// This file was generated by lezer-generator. You probably shouldn't edit it.
const spec_identifier = {__proto__:null,export:20, as:25, from:33, default:36, async:41, function:42, extends:54, this:58, true:66, false:66, null:78, void:82, typeof:86, super:102, new:136, delete:148, yield:157, await:161, class:166, public:229, private:229, protected:229, readonly:231, instanceof:250, satisfies:253, in:254, const:256, import:290, keyof:345, unique:349, infer:355, is:391, abstract:411, implements:413, type:415, let:418, var:420, using:423, interface:429, enum:433, namespace:439, module:441, declare:445, global:449, for:468, of:477, while:480, with:484, do:488, if:492, else:494, switch:498, case:504, try:510, catch:514, finally:518, return:522, throw:526, break:530, continue:534, debugger:538};
const spec_word = {__proto__:null,async:123, get:125, set:127, declare:189, public:191, private:191, protected:191, static:193, abstract:195, override:197, readonly:203, accessor:205, new:395};
const spec_LessThan = {__proto__:null,"<":187};
const parser = LRParser.deserialize({
  version: 14,
  states: "$BUQ%TQ^OOO%[Q^OOO'_Q`OOP(lOWOOO*zQ?NdO'#CiO+RO!bO'#CjO+aO#tO'#CjO+oO!0LbO'#D^O.QQ^O'#DdO.bQ^O'#DoO%[Q^O'#DwO0fQ^O'#EPOOQ?Mr'#EX'#EXO1PQWO'#EUOOQO'#Em'#EmOOQO'#Ih'#IhO1XQWO'#GpO1dQWO'#ElO1iQWO'#ElO3hQ?NdO'#JmO6[Q?NdO'#JnO6uQWO'#F[O6zQ&jO'#FsOOQ?Mr'#Fe'#FeO7VO,YO'#FeO7eQ7[O'#FzO9RQWO'#FyOOQ?Mr'#Jn'#JnOOQ?Mp'#Jm'#JmO9WQWO'#GtOOQU'#KZ'#KZO9cQWO'#IUO9hQ?MxO'#IVOOQU'#JZ'#JZOOQU'#IZ'#IZQ`Q^OOQ`Q^OOO9pQMnO'#DsO9wQ^O'#D{O:OQ^O'#D}O9^QWO'#GpO:VQ7[O'#CoO:eQWO'#EkO:pQWO'#EvO:uQ7[O'#FdO;dQWO'#GpOOQO'#K['#K[O;iQWO'#K[O;wQWO'#GxO;wQWO'#GyO;wQWO'#G{O9^QWO'#HOO<nQWO'#HRO>VQWO'#CeO>gQWO'#H_O>oQWO'#HeO>oQWO'#HgO`Q^O'#HiO>oQWO'#HkO>oQWO'#HnO>tQWO'#HtO>yQ?MyO'#HzO%[Q^O'#H|O?UQ?MyO'#IOO?aQ?MyO'#IQO9hQ?MxO'#ISO?lQ?NdO'#CiO@nQ`O'#DiQOQWOOO%[Q^O'#D}OAUQWO'#EQO:VQ7[O'#EkOAaQWO'#EkOAlQpO'#FdOOQU'#Cg'#CgOOQ?Mp'#Dn'#DnOOQ?Mp'#Jq'#JqO%[Q^O'#JqOOQO'#Jt'#JtOOQO'#Id'#IdOBlQ`O'#EdOOQ?Mp'#Ec'#EcOOQ?Mp'#Jx'#JxOChQ?NQO'#EdOCrQ`O'#ETOOQO'#Js'#JsODWQ`O'#JtOEeQ`O'#ETOCrQ`O'#EdPErO#@ItO'#CbPOOO)CDx)CDxOOOO'#I['#I[OE}O!bO,59UOOQ?Mr,59U,59UOOOO'#I]'#I]OF]O#tO,59UOFkQMnO'#D`OOOO'#I_'#I_OFrO!0LbO,59xOOQ?Mr,59x,59xOGQQ^O'#I`OGeQWO'#JoOIdQrO'#JoO+}Q^O'#JoOIkQWO,5:OOJRQWO'#EmOJ`QWO'#KOOJkQWO'#J}OJkQWO'#J}OJsQWO,5;ZOJxQWO'#J|OOQ?Mv,5:Z,5:ZOKPQ^O,5:ZOL}Q?NdO,5:cOMnQWO,5:kONXQ?MxO'#J{ON`QWO'#JzO9WQWO'#JzONtQWO'#JzON|QWO,5;YO! RQWO'#JzO!#WQrO'#JnOOQ?Mr'#Ci'#CiO%[Q^O'#EPO!#vQrO,5:pOOQQ'#Ju'#JuOOQO-E<f-E<fO9^QWO,5=[O!$^QWO,5=[O!$cQ^O,5;WO!&fQ7[O'#EhO!(PQWO,5;WO!(UQ^O'#DvO!(`Q`O,5;aO!(hQ`O,5;aO%[Q^O,5;aOOQU'#FS'#FSOOQU'#FU'#FUO%[Q^O,5;bO%[Q^O,5;bO%[Q^O,5;bO%[Q^O,5;bO%[Q^O,5;bO%[Q^O,5;bO%[Q^O,5;bO%[Q^O,5;bO%[Q^O,5;bO%[Q^O,5;bOOQU'#FY'#FYO!(vQ^O,5;sOOQ?Mr,5;x,5;xOOQ?Mr,5;y,5;yOOQ?Mr,5;{,5;{O%[Q^O'#IlO!*yQ?MxO,5<gO%[Q^O,5;bO!&fQ7[O,5;bO!+hQ7[O,5;bO!-YQ7[O'#EZO%[Q^O,5;vOOQ?Mr,5;z,5;zO!-aQ&jO'#FiO!.^Q&jO'#KSO!-xQ&jO'#KSO!.eQ&jO'#KSOOQO'#KS'#KSO!.yQ&jO,5<ROOOS,5<_,5<_O!/[Q^O'#FuOOOS'#Ik'#IkO7VO,YO,5<PO!/cQ&jO'#FwOOQ?Mr,5<P,5<PO!0SQ!LQO'#CvOOQ?Mr'#Cz'#CzO!0gO!0LbO'#DOO!1TQ7[O,5<dO!1[QWO,5<fO!2wQ$ISO'#GVO!3UQWO'#GWO!3ZQWO'#GWO!4yQ$ISO'#G[O!5uQ`O'#G`OOQO'#Gk'#GkO!+oQ7[O'#GjOOQO'#Gm'#GmO!+oQ7[O'#GlO!6hQ!LQO'#JgOOQ?Mr'#Jg'#JgO!6rQWO'#JfO!7QQWO'#JeO!7YQWO'#CuOOQ?Mr'#Cx'#CxO!7bQWO'#CzOOQ?Mr'#DS'#DSOOQ?Mr'#DU'#DUO1SQWO'#DWO!+oQ7[O'#F}O!+oQ7[O'#GPO!7gQWO'#GRO!7lQWO'#GSO!3ZQWO'#GYO!+oQ7[O'#G_O!7qQWO'#EnO!8`QWO,5<eOOQ?Mp'#Cr'#CrO!8hQWO'#EoO!9bQ`O'#EpOOQ?Mp'#J|'#J|O!9iQ?MxO'#K]O9hQ?MxO,5=`O`Q^O,5>pOOQU'#Jc'#JcOOQU,5>q,5>qOOQU-E<X-E<XO!;hQ?NdO,5:_O!9]Q`O,5:]O!>RQ?NdO,5:gO%[Q^O,5:gO!@iQ?NdO,5:iOOQO,5@v,5@vO!AYQ7[O,5=[O!AhQ?MxO'#JdO9RQWO'#JdO!AyQ?MxO,59ZO!BUQ`O,59ZO!B^Q7[O,59ZO:VQ7[O,59ZO!BiQWO,5;WO!BqQWO'#H^O!CVQWO'#K`O%[Q^O,5;|O!9]Q`O,5<OO!C_QWO,5=wO!CdQWO,5=wO!CiQWO,5=wO9hQ?MxO,5=wO;wQWO,5=gOOQO'#Cv'#CvO!CwQ`O,5=dO!DPQ7[O,5=eO!D[QWO,5=gO!DaQpO,5=jO!DiQWO'#K[O>tQWO'#HTO9^QWO'#HVO!DnQWO'#HVO:VQ7[O'#HXO!DsQWO'#HXOOQU,5=m,5=mO!DxQWO'#HYO!EZQWO'#CoO!E`QWO,59PO!EjQWO,59PO!GoQ^O,59POOQU,59P,59PO!HPQ?MxO,59PO%[Q^O,59PO!J[Q^O'#HaOOQU'#Hb'#HbOOQU'#Hc'#HcO`Q^O,5=yO!JrQWO,5=yO`Q^O,5>PO`Q^O,5>RO!JwQWO,5>TO`Q^O,5>VO!J|QWO,5>YO!KRQ^O,5>`OOQU,5>f,5>fO%[Q^O,5>fO9hQ?MxO,5>hOOQU,5>j,5>jO# ]QWO,5>jOOQU,5>l,5>lO# ]QWO,5>lOOQU,5>n,5>nO# yQ`O'#D[O%[Q^O'#JqO#!TQ`O'#JqO#!rQ`O'#DjO##TQ`O'#DjO#%fQ^O'#DjO#%mQWO'#JpO#%uQWO,5:TO#%zQWO'#EqO#&YQWO'#KPO#&bQWO,5;[O#&gQ`O'#DjO#&tQ`O'#ESOOQ?Mr,5:l,5:lO%[Q^O,5:lO#&{QWO,5:lO>tQWO,5;VO!BUQ`O,5;VO!B^Q7[O,5;VO:VQ7[O,5;VO#'TQWO,5@]O#'YQ(CYO,5:pOOQO-E<b-E<bO#(`Q?NQO,5;OOCrQ`O,5:oO#(jQ`O,5:oOCrQ`O,5;OO!AyQ?MxO,5:oOOQ?Mp'#Eg'#EgOOQO,5;O,5;OO%[Q^O,5;OO#(wQ?MxO,5;OO#)SQ?MxO,5;OO!BUQ`O,5:oOOQO,5;U,5;UO#)bQ?MxO,5;OPOOO'#IY'#IYP#)vO#@ItO,58|POOO,58|,58|OOOO-E<Y-E<YOOQ?Mr1G.p1G.pOOOO-E<Z-E<ZOOOO,59z,59zO#*RQpO,59zOOOO-E<]-E<]OOQ?Mr1G/d1G/dO#*WQrO,5>zO+}Q^O,5>zOOQO,5?Q,5?QO#*bQ^O'#I`OOQO-E<^-E<^O#*oQWO,5@ZO#*wQrO,5@ZO#+OQWO,5@iOOQ?Mr1G/j1G/jO%[Q^O,5@jO#+WQWO'#IfOOQO-E<d-E<dO#+OQWO,5@iOOQ?Mp1G0u1G0uOOQ?Mv1G/u1G/uOOQ?Mv1G0V1G0VO%[Q^O,5@gO#+lQ?MxO,5@gO#+}Q?MxO,5@gO#,UQWO,5@fO9WQWO,5@fO#,^QWO,5@fO#,lQWO'#IiO#,UQWO,5@fOOQ?Mp1G0t1G0tO!(`Q`O,5:rO!(kQ`O,5:rOOQQ,5:t,5:tO#-^QYO,5:tO#-fQ7[O1G2vO9^QWO1G2vOOQ?Mr1G0r1G0rO#-tQ?NdO1G0rO#.yQ?NbO,5;SOOQ?Mr'#GU'#GUO#/gQ?NdO'#JgO!$cQ^O1G0rO#1oQrO'#JrO%[Q^O'#JrO#1yQWO,5:bOOQ?Mr'#D['#D[OOQ?Mr1G0{1G0{O%[Q^O1G0{OOQ?Mr1G1e1G1eO#2OQWO1G0{O#4dQ?NdO1G0|O#4kQ?NdO1G0|O#7RQ?NdO1G0|O#7YQ?NdO1G0|O#9pQ?NdO1G0|O#<WQ?NdO1G0|O#<_Q?NdO1G0|O#<fQ?NdO1G0|O#>|Q?NdO1G0|O#?TQ?NdO1G0|O#AbQ07bO'#CiO#C]Q07bO1G1_O#CdQ07bO'#JnO#CwQ?NdO,5?WOOQ?Mp-E<j-E<jO#FUQ?NdO1G0|O#GRQ?NdO1G0|OOQ?Mr1G0|1G0|O#HRQ7[O'#JwO#H]QWO,5:uO#HbQ?NdO1G1bO#IUQ&jO,5<VO#I^Q&jO,5<WO#IfQ&jO'#FnO#I}QWO'#FmOOQO'#KT'#KTOOQO'#Ij'#IjO#JSQ&jO1G1mOOQ?Mr1G1m1G1mOOOS1G1x1G1xO#JeQ07bO'#JmO#JoQWO,5<aO!(vQ^O,5<aOOOS-E<i-E<iOOQ?Mr1G1k1G1kO#JtQ`O'#KSOOQ?Mr,5<c,5<cO#J|Q`O,5<cO#KRQ7[O'#DQOOOO'#I^'#I^O#KYO!0LbO,59jOOQ?Mr,59j,59jO%[Q^O1G2OO!7lQWO'#InO#KeQ7[O,5<xOOQ?Mr,5<u,5<uO!+oQ7[O'#IqO#LTQ7[O,5=UO!+oQ7[O'#IsO#LvQ7[O,5=WO!&fQ7[O,5=YOOQO1G2Q1G2QO#MQQpO'#CrO#MeQ$ISO'#EoO#NdQ`O'#G`O$ QQpO,5<qO$ XQWO'#KWO9WQWO'#KWO$ gQWO,5<sO!+oQ7[O,5<rO$ lQWO'#GXO$ }QWO,5<rO$!SQpO'#GUO$!aQpO'#KXO$!kQWO'#KXO!&fQ7[O'#KXO$!pQWO,5<vO$!uQ`O'#GaO!5pQ`O'#GaO$#WQWO'#GcO$#]QWO'#GeO!3ZQWO'#GhO$#bQ?MxO'#IpO$#mQ`O,5<zOOQ?Mv,5<z,5<zO$#tQ`O'#GaO$$SQ`O'#GbO$$[Q`O'#GbO$$aQ7[O,5=UO$$qQ7[O,5=WOOQ?Mr,5=Z,5=ZO!+oQ7[O,5@QO!+oQ7[O,5@QO$%RQWO'#IuO$%^QWO,5@PO$%fQWO,59aOOQ?Mr,59f,59fO$&YQ!LSO,59rOOQ?Mr'#Jk'#JkO$&{Q7[O,5<iO$'nQ7[O,5<kO@fQWO,5<mOOQ?Mr,5<n,5<nO$'xQWO,5<tO$'}Q7[O,5<yO$(_QWO'#JzO!$cQ^O1G2PO$(dQWO1G2PO9WQWO'#J}O9WQWO'#EqO%[Q^O'#EqO9WQWO'#IwO$(iQ?MxO,5@wOOQU1G2z1G2zOOQU1G4[1G4[OOQ?Mr1G/y1G/yOOQ?Mr1G/w1G/wO$*kQ?NdO1G0ROOQU1G2v1G2vO!&fQ7[O1G2vO%[Q^O1G2vO#-iQWO1G2vO$,oQ7[O'#EhOOQ?Mp,5@O,5@OO$,yQ?MxO,5@OOOQU1G.u1G.uO!AyQ?MxO1G.uO!BUQ`O1G.uO!B^Q7[O1G.uO$-[QWO1G0rO$-aQWO'#CiO$-lQWO'#KaO$-tQWO,5=xO$-yQWO'#KaO$.OQWO'#KaO$.^QWO'#I}O$.lQWO,5@zO$.tQrO1G1hOOQ?Mr1G1j1G1jO9^QWO1G3cO@fQWO1G3cO$.{QWO1G3cO$/QQWO1G3cOOQU1G3c1G3cO!D[QWO1G3RO!&fQ7[O1G3OO$/VQWO1G3OOOQU1G3P1G3PO!&fQ7[O1G3PO$/[QWO1G3PO$/dQ`O'#G}OOQU1G3R1G3RO!5pQ`O'#IyO!DaQpO1G3UOOQU1G3U1G3UOOQU,5=o,5=oO$/lQ7[O,5=qO9^QWO,5=qO$#]QWO,5=sO9RQWO,5=sO!BUQ`O,5=sO!B^Q7[O,5=sO:VQ7[O,5=sO$/zQWO'#K_O$0VQWO,5=tOOQU1G.k1G.kO$0[Q?MxO1G.kO@fQWO1G.kO$0gQWO1G.kO9hQ?MxO1G.kO$2oQrO,5@|O$2|QWO,5@|O9WQWO,5@|O$3XQ^O,5={O$3`QWO,5={OOQU1G3e1G3eO`Q^O1G3eOOQU1G3k1G3kOOQU1G3m1G3mO>oQWO1G3oO$3eQ^O1G3qO$7iQ^O'#HpOOQU1G3t1G3tO$7vQWO'#HvO>tQWO'#HxOOQU1G3z1G3zO$8OQ^O1G3zO9hQ?MxO1G4QOOQU1G4S1G4SOOQ?Mp'#G]'#G]O9hQ?MxO1G4UO9hQ?MxO1G4WO$<VQWO,5@]O!(vQ^O,5;]O9WQWO,5;]O>tQWO,5:UO!(vQ^O,5:UO!BUQ`O,5:UO$<[Q07bO,5:UOOQO,5;],5;]O$<fQ`O'#IaO$<|QWO,5@[OOQ?Mr1G/o1G/oO$=UQ`O'#IgO$=`QWO,5@kOOQ?Mp1G0v1G0vO##TQ`O,5:UOOQO'#Ic'#IcO$=hQ`O,5:nOOQ?Mv,5:n,5:nO#'OQWO1G0WOOQ?Mr1G0W1G0WO%[Q^O1G0WOOQ?Mr1G0q1G0qO>tQWO1G0qO!BUQ`O1G0qO!B^Q7[O1G0qOOQ?Mp1G5w1G5wO!AyQ?MxO1G0ZOOQO1G0j1G0jO%[Q^O1G0jO$=oQ?MxO1G0jO$=zQ?MxO1G0jO!BUQ`O1G0ZOCrQ`O1G0ZO$>YQ?MxO1G0jOOQO1G0Z1G0ZO$>nQ?NdO1G0jPOOO-E<W-E<WPOOO1G.h1G.hOOOO1G/f1G/fO$>xQpO,5<gO$?QQrO1G4fOOQO1G4l1G4lO%[Q^O,5>zO$?[QWO1G5uO$?dQWO1G6TO$?lQrO1G6UO9WQWO,5?QO$?vQ?NdO1G6RO%[Q^O1G6RO$@WQ?MxO1G6RO$@iQWO1G6QO$@iQWO1G6QO9WQWO1G6QO$@qQWO,5?TO9WQWO,5?TOOQO,5?T,5?TO$AVQWO,5?TO$(_QWO,5?TOOQO-E<g-E<gOOQQ1G0^1G0^OOQQ1G0`1G0`O#-aQWO1G0`OOQU7+(b7+(bO!&fQ7[O7+(bO%[Q^O7+(bO$AeQWO7+(bO$ApQ7[O7+(bO$BOQ?NdO,5=UO$DWQ?NdO,5=WO$F`Q?NdO,5=UO$HnQ?NdO,5=WO$J|Q?NdO,59rO$MRQ?NdO,5<iO% ZQ?NdO,5<kO%#cQ?NdO,5<yOOQ?Mr7+&^7+&^O%%qQ?NdO7+&^O%&eQ^O'#IbO%&rQWO,5@^O%&zQrO,5@^OOQ?Mr1G/|1G/|O%'UQWO7+&gOOQ?Mr7+&g7+&gO%'ZQ07bO,5:cO%[Q^O7+&yO%'eQ07bO,5:_O%'rQ07bO,5:gO%'|Q07bO,5:iO%(WQ7[O'#IeO%(bQWO,5@cOOQ?Mr1G0a1G0aOOQO1G1q1G1qOOQO1G1r1G1rO%(jQtO,5<YO!(vQ^O,5<XOOQO-E<h-E<hOOQ?Mr7+'X7+'XOOOS7+'d7+'dOOOS1G1{1G1{O%(uQWO1G1{OOQ?Mr1G1}1G1}OOOO,59l,59lO%(zQpO,59lOOOO-E<[-E<[OOQ?Mr1G/U1G/UO%)RQ?NdO7+'jOOQ?Mr,5?Y,5?YO%)uQpO,5?YOOQ?Mr1G2d1G2dP!&fQ7[O'#InPOQ?Mr-E<l-E<lO%*eQ7[O,5?]OOQ?Mr-E<o-E<oO%+WQ7[O,5?_OOQ?Mr-E<q-E<qO%+bQpO1G2tO%+iQpO'#CrO%,PQ7[O'#J}O%,WQ^O'#EqOOQ?Mr1G2]1G2]O%,bQWO'#ImO%,vQWO,5@rO%,vQWO,5@rO%-OQWO,5@rO%-ZQWO,5@rOOQO1G2_1G2_O%-iQ7[O1G2^O!+oQ7[O1G2^O%-yQ$ISO'#IoO%.WQWO,5@sO!&fQ7[O,5@sO%.`QpO,5@sOOQ?Mr1G2b1G2bOOQ?Mp,5<{,5<{OOQ?Mp,5<|,5<|O$(_QWO,5<|OCcQWO,5<|O!BUQ`O,5<{OOQO'#Gd'#GdO%.jQWO,5<}OOQ?Mp,5=P,5=PO$(_QWO,5=SOOQO,5?[,5?[OOQO-E<n-E<nOOQ?Mv1G2f1G2fO!5pQ`O,5<{O%.rQWO,5<|O$#WQWO,5<}O%.}Q`O,5<|O!+oQ7[O'#IqO%/nQ7[O1G2pO!+oQ7[O'#IsO%0aQ7[O1G2rO%0kQ7[O1G5lO%0uQ7[O1G5lOOQO,5?a,5?aOOQO-E<s-E<sOOQO1G.{1G.{O!9]Q`O,59tO%[Q^O,59tOOQ?Mr,5<h,5<hO%1SQWO1G2XO!+oQ7[O1G2`O%1XQ?NdO7+'kOOQ?Mr7+'k7+'kO!$cQ^O7+'kO%1{QWO,5;]OOQ?Mp,5?c,5?cOOQ?Mp-E<u-E<uO%2QQpO'#KYO#'OQWO7+(bO4UQrO7+(bO$AhQWO7+(bO%2[Q?NbO'#CiO%2oQ?NbO,5=QO%3aQWO,5=QOOQ?Mp1G5j1G5jOOQU7+$a7+$aO!AyQ?MxO7+$aO!BUQ`O7+$aO!$cQ^O7+&^O%3fQWO'#I|O%3}QWO,5@{OOQO1G3d1G3dO9^QWO,5@{O%3}QWO,5@{O%4VQWO,5@{OOQO,5?i,5?iOOQO-E<{-E<{OOQ?Mr7+'S7+'SO%4[QWO7+(}O9hQ?MxO7+(}O9^QWO7+(}O@fQWO7+(}OOQU7+(m7+(mO%4aQ?NbO7+(jO!&fQ7[O7+(jO%4kQpO7+(kOOQU7+(k7+(kO!&fQ7[O7+(kO%4rQWO'#K^O%4}QWO,5=iOOQO,5?e,5?eOOQO-E<w-E<wOOQU7+(p7+(pO%6aQ`O'#HWOOQU1G3]1G3]O!&fQ7[O1G3]O%[Q^O1G3]O%6hQWO1G3]O%6sQ7[O1G3]O9hQ?MxO1G3_O$#]QWO1G3_O9RQWO1G3_O!BUQ`O1G3_O!B^Q7[O1G3_O%7RQWO'#I{O%7gQWO,5@yO%7oQ`O,5@yOOQ?Mp1G3`1G3`OOQU7+$V7+$VO@fQWO7+$VO9hQ?MxO7+$VO%7zQWO7+$VO%[Q^O1G6hO%[Q^O1G6iO%8PQ?MxO1G6hO%8ZQ^O1G3gO%8bQWO1G3gO%8gQ^O1G3gOOQU7+)P7+)PO9hQ?MxO7+)ZO`Q^O7+)]OOQU'#Kd'#KdOOQU'#JO'#JOO%8nQ^O,5>[OOQU,5>[,5>[O%[Q^O'#HqO%8{QWO'#HsOOQU,5>b,5>bO9WQWO,5>bOOQU,5>d,5>dOOQU7+)f7+)fOOQU7+)l7+)lOOQU7+)p7+)pOOQU7+)r7+)rO%9QQ`O1G5wO%9fQ07bO1G0wO%9pQWO1G0wOOQO1G/p1G/pO%9{Q07bO1G/pO>tQWO1G/pO!(vQ^O'#DjOOQO,5>{,5>{OOQO-E<_-E<_OOQO,5?R,5?ROOQO-E<e-E<eO!BUQ`O1G/pOOQO-E<a-E<aOOQ?Mv1G0Y1G0YOOQ?Mr7+%r7+%rO#'OQWO7+%rOOQ?Mr7+&]7+&]O>tQWO7+&]O!BUQ`O7+&]OOQO7+%u7+%uO$>nQ?NdO7+&UOOQO7+&U7+&UO%[Q^O7+&UO%:VQ?MxO7+&UO!AyQ?MxO7+%uO!BUQ`O7+%uO%:bQ?MxO7+&UO%:pQ?NdO7++mO%[Q^O7++mO%;QQWO7++lO%;QQWO7++lOOQO1G4o1G4oO9WQWO1G4oO%;YQWO1G4oOOQQ7+%z7+%zO#'OQWO<<K|O4UQrO<<K|O%;hQWO<<K|OOQU<<K|<<K|O!&fQ7[O<<K|O%[Q^O<<K|O%;pQWO<<K|O%;{Q?NdO,5?]O%>TQ?NdO,5?_O%@]Q?NdO1G2^O%BkQ?NdO1G2pO%DsQ?NdO1G2rO%F{QrO,5>|O%[Q^O,5>|OOQO-E<`-E<`O%GVQWO1G5xOOQ?Mr<<JR<<JRO%G_Q07bO1G0rO%IfQ07bO1G0|O%ImQ07bO1G0|O%KnQ07bO1G0|O%KuQ07bO1G0|O%MvQ07bO1G0|O& wQ07bO1G0|O&!OQ07bO1G0|O&!VQ07bO1G0|O&$WQ07bO1G0|O&$_Q07bO1G0|O&$fQ?NdO<<JeO&&^Q07bO1G0|O&'ZQ07bO1G0|O&(ZQ07bO'#JgO&*^Q07bO1G1bO&*kQ07bO1G0RO&*uQ7[O,5?POOQO-E<c-E<cO!(vQ^O'#FpOOQO'#KU'#KUOOQO1G1t1G1tO&+PQWO1G1sO&+UQ07bO,5?WOOOS7+'g7+'gOOOO1G/W1G/WOOQ?Mr1G4t1G4tO!+oQ7[O7+(`O&-fQrO'#CiO&-pQWO,5?XO9WQWO,5?XOOQO-E<k-E<kO&.OQWO1G6^O&.OQWO1G6^O&.WQWO1G6^O&.cQ7[O7+'xO&.sQpO,5?ZO&.}QWO,5?ZO!&fQ7[O,5?ZOOQO-E<m-E<mO&/SQpO1G6_O&/^QWO1G6_OOQ?Mp1G2h1G2hO$(_QWO1G2hOOQ?Mp1G2g1G2gO&/fQWO1G2iO!&fQ7[O1G2iOOQ?Mp1G2n1G2nO!BUQ`O1G2gOCcQWO1G2hO&/kQWO1G2iO&/sQWO1G2hO$#WQWO1G2iO&0gQ7[O,5?]OOQ?Mr-E<p-E<pO&1YQ7[O,5?_OOQ?Mr-E<r-E<rO!+oQ7[O7++WOOQ?Mr1G/`1G/`O&1dQWO1G/`OOQ?Mr7+'s7+'sO&1iQ7[O7+'zO&1yQ?NdO<<KVOOQ?Mr<<KV<<KVO&2mQWO1G0wO!&fQ7[O'#IvO&2rQWO,5@tO&4tQrO<<K|O!&fQ7[O1G2lOOQU<<G{<<G{O!AyQ?MxO<<G{O&4{Q?NdO<<IxOOQ?Mr<<Ix<<IxOOQO,5?h,5?hO&5oQWO,5?hO&5tQWO,5?hOOQO-E<z-E<zO&6SQWO1G6gO&6SQWO1G6gO9^QWO1G6gO@fQWO<<LiOOQU<<Li<<LiO&6[QWO<<LiO9hQ?MxO<<LiOOQU<<LU<<LUO%4aQ?NbO<<LUOOQU<<LV<<LVO%4kQpO<<LVO&6aQ`O'#IxO&6lQWO,5@xO!(vQ^O,5@xOOQU1G3T1G3TO%,WQ^O'#JqOOQO'#Iz'#IzO9hQ?MxO'#IzO&6tQ`O,5=rOOQU,5=r,5=rO&6{Q`O'#EdO&7aQ`O'#GcO&7fQWO7+(wO&7kQWO7+(wOOQU7+(w7+(wO!&fQ7[O7+(wO%[Q^O7+(wO&7sQWO7+(wOOQU7+(y7+(yO9hQ?MxO7+(yO$#]QWO7+(yO9RQWO7+(yO!BUQ`O7+(yO&8OQWO,5?gOOQO-E<y-E<yOOQO'#HZ'#HZO&8ZQWO1G6eO9hQ?MxO<<GqOOQU<<Gq<<GqO@fQWO<<GqO&8cQWO7+,SO&8hQWO7+,TO%[Q^O7+,SO%[Q^O7+,TOOQU7+)R7+)RO&8mQWO7+)RO&8rQ^O7+)RO&8yQWO7+)ROOQU<<Lu<<LuOOQU<<Lw<<LwOOQU-E<|-E<|OOQU1G3v1G3vO&9OQWO,5>]OOQU,5>_,5>_O&9TQWO1G3|O9WQWO7+&cO!(vQ^O7+&cOOQO7+%[7+%[O&9YQ07bO1G6UO>tQWO7+%[OOQ?Mr<<I^<<I^OOQ?Mr<<Iw<<IwO>tQWO<<IwOOQO<<Ip<<IpO$>nQ?NdO<<IpO%[Q^O<<IpOOQO<<Ia<<IaO!AyQ?MxO<<IaO&9dQ?MxO<<IpO&9oQ?NdO<= XO&:PQWO<= WOOQO7+*Z7+*ZO9WQWO7+*ZOOQUANAhANAhO&:XQrOANAhO!&fQ7[OANAhO#'OQWOANAhO4UQrOANAhO&:`QWOANAhO%[Q^OANAhO&:hQ?NdO7+'xO&<vQ?NdO,5?]O&?OQ?NdO,5?_O&AWQ?NdO7+'zO&CfQrO1G4hO&CpQ07bO7+&^O&EqQ07bO,5=UO&GuQ07bO,5=WO&HVQ07bO,5=UO&HgQ07bO,5=WO&HwQ07bO,59rO&JzQ07bO,5<iO&LzQ07bO,5<kO' ]Q07bO,5<yO'#OQ07bO7+'jO'#]Q07bO7+'kO'#jQWO,5<[OOQO7+'_7+'_O'#oQ7[O<<KzOOQO1G4s1G4sO'#vQWO1G4sO'$RQWO1G4sO'$aQWO7++xO'$aQWO7++xO!&fQ7[O1G4uO'$iQpO1G4uO'$sQWO7++yOOQ?Mp7+(S7+(SO'${QWO7+(TO'%WQpO7+(TOOQ?Mp7+(R7+(RO$(_QWO7+(SO'%bQWO7+(TO!&fQ7[O7+(TOCcQWO7+(SO'%gQWO7+(TO'%oQ7[O<<NrOOQ?Mr7+$z7+$zO'%yQpO,5?bOOQO-E<t-E<tO'&TQ?NbO7+(WOOQUAN=gAN=gO9^QWO1G5SOOQO1G5S1G5SO'&eQWO1G5SO'&jQWO7+,RO'&jQWO7+,RO9hQ?MxOANBTO@fQWOANBTOOQUANBTANBTOOQUANApANApOOQUANAqANAqO'&rQWO,5?dOOQO-E<v-E<vO'&}Q07bO1G6dOOQO,5?f,5?fOOQO-E<x-E<xOOQU1G3^1G3^O%,WQ^O,5<}O''XQWO,5<}OOQU<<Lc<<LcO!&fQ7[O<<LcO&7fQWO<<LcO''^QWO<<LcO%[Q^O<<LcOOQU<<Le<<LeO9hQ?MxO<<LeO$#]QWO<<LeO9RQWO<<LeO''fQ`O1G5RO''qQWO7+,POOQUAN=]AN=]O9hQ?MxOAN=]OOQU<= n<= nOOQU<= o<= oO''yQWO<= nO'(OQWO<= oOOQU<<Lm<<LmO'(TQWO<<LmO'(YQ^O<<LmOOQU1G3w1G3wO>tQWO7+)hO'(aQWO<<I}O'(lQ07bO<<I}OOQO<<Hv<<HvOOQ?MrAN?cAN?cOOQOAN?[AN?[O$>nQ?NdOAN?[OOQOAN>{AN>{O%[Q^OAN?[OOQO<<Mu<<MuOOQUG27SG27SO!&fQ7[OG27SO#'OQWOG27SO'(vQrOG27SO4UQrOG27SO'(}QWOG27SO')VQ07bO<<JeO')dQ07bO1G2^O'+VQ07bO,5?]O'-VQ07bO,5?_O'/VQ07bO1G2pO'1VQ07bO1G2rO'3VQ07bO<<KVO'3dQ07bO<<IxOOQO1G1v1G1vO!+oQ7[OANAfOOQO7+*_7+*_O'3qQWO7+*_O'3|QWO<= dO'4UQpO7+*aOOQ?Mp<<Ko<<KoO$(_QWO<<KoOCcQWO<<KoO'4`QWO<<KoO!&fQ7[O<<KoOOQ?Mp<<Kn<<KnO'4kQpO<<KoO$(_QWO<<KnO'4uQWO<<KoO!&fQ7[O<<KoOOQO7+*n7+*nO9^QWO7+*nO'4zQWO<= mOOQUG27oG27oO9hQ?MxOG27oO!(vQ^O1G5OO'5SQWO7+,OO&7fQWOANA}OOQUANA}ANA}O!&fQ7[OANA}O'5[QWOANA}OOQUANBPANBPO9hQ?MxOANBPO$#]QWOANBPOOQO'#H['#H[OOQO7+*m7+*mOOQUG22wG22wOOQUANEYANEYOOQUANEZANEZOOQUANBXANBXO'5dQWOANBXOOQU<<MS<<MSO!(vQ^OAN?iOOQOG24vG24vO$>nQ?NdOG24vO#'OQWOLD,nOOQULD,nLD,nO!&fQ7[OLD,nO'5iQrOLD,nO'5pQ07bO7+'xO'7cQ07bO,5?]O'9cQ07bO,5?_O';cQ07bO7+'zO'=UQ7[OG27QOOQO<<My<<MyOOQ?MpANAZANAZO$(_QWOANAZOCcQWOANAZO'=fQpOANAZO'=mQWOANAZO!&fQ7[OANAZOOQ?MpANAYANAYO'=xQpOANAZOOQO<<NY<<NYOOQULD-ZLD-ZO'>SQ07bO7+*jOOQUG27iG27iO&7fQWOG27iO!&fQ7[OG27iOOQUG27kG27kO9hQ?MxOG27kOOQUG27sG27sO'>^Q07bOG25TOOQOLD*bLD*bOOQU!$(!Y!$(!YO#'OQWO!$(!YO!&fQ7[O!$(!YO'>hQ?NdOG27QOOQ?MpG26uG26uO$(_QWOG26uO'@vQWOG26uOCcQWOG26uO'ARQpOG26uO!&fQ7[OG26uOOQULD-TLD-TO&7fQWOLD-TOOQULD-VLD-VOOQU!)9Et!)9EtO#'OQWO!)9EtOOQ?MpLD,aLD,aO$(_QWOLD,aOCcQWOLD,aO'AYQWOLD,aO'AeQpOLD,aOOQU!$(!o!$(!oOOQU!.K;`!.K;`O'AlQ07bOG27QOOQ?Mp!$( {!$( {O$(_QWO!$( {OCcQWO!$( {O'C_QWO!$( {OOQ?Mp!)9Eg!)9EgO$(_QWO!)9EgOCcQWO!)9EgOOQ?Mp!.K;R!.K;RO$(_QWO!.K;ROOQ?Mp!4/0m!4/0mO!(vQ^O'#DwO1PQWO'#EUO'CjQrO'#JmO'CqQMnO'#DsO'CxQ^O'#D{O'DPQrO'#CiO'FgQrO'#CiO!(vQ^O'#D}O'FwQ^O,5;WO!(vQ^O,5;bO!(vQ^O,5;bO!(vQ^O,5;bO!(vQ^O,5;bO!(vQ^O,5;bO!(vQ^O,5;bO!(vQ^O,5;bO!(vQ^O,5;bO!(vQ^O,5;bO!(vQ^O,5;bO!(vQ^O'#IlO'HzQWO,5<gO!(vQ^O,5;bO'ISQ7[O,5;bO'JmQ7[O,5;bO!(vQ^O,5;vO!&fQ7[O'#GjO'ISQ7[O'#GjO!&fQ7[O'#GlO'ISQ7[O'#GlO1SQWO'#DWO1SQWO'#DWO!&fQ7[O'#F}O'ISQ7[O'#F}O!&fQ7[O'#GPO'ISQ7[O'#GPO!&fQ7[O'#G_O'ISQ7[O'#G_O!(vQ^O,5:gO'JtQ`O'#D[O!(vQ^O,5@jO'FwQ^O1G0rO'KOQ07bO'#CiO!(vQ^O1G2OO!&fQ7[O'#IqO'ISQ7[O'#IqO!&fQ7[O'#IsO'ISQ7[O'#IsO'KYQpO'#CrO!&fQ7[O,5<rO'ISQ7[O,5<rO'FwQ^O1G2PO!(vQ^O7+&yO!&fQ7[O1G2^O'ISQ7[O1G2^O!&fQ7[O'#IqO'ISQ7[O'#IqO!&fQ7[O'#IsO'ISQ7[O'#IsO!&fQ7[O1G2`O'ISQ7[O1G2`O'FwQ^O7+'kO'FwQ^O7+&^O!&fQ7[OANAfO'ISQ7[OANAfO'KmQWO'#ElO'KrQWO'#ElO'KzQWO'#F[O'LPQWO'#EvO'LUQWO'#KOO'LaQWO'#J|O'LlQWO,5;WO'LqQ7[O,5<dO'LxQWO'#GWO'L}QWO'#GWO'MSQWO,5<eO'M[QWO,5;WO'MdQ07bO1G1_O'MkQWO,5<rO'MpQWO,5<rO'MuQWO,5<tO'MzQWO,5<tO'NPQWO1G2PO'NUQWO1G0rO'NZQ7[O<<KzO'NbQ7[O<<KzO7eQ7[O'#FzO9RQWO'#FyOAaQWO'#EkO!(vQ^O,5;sO!3ZQWO'#GWO!3ZQWO'#GWO!3ZQWO'#GYO!3ZQWO'#GYO!+oQ7[O7+(`O!+oQ7[O7+(`O%+bQpO1G2tO%+bQpO1G2tO!&fQ7[O,5=YO!&fQ7[O,5=Y",
  stateData: "( f~O'wOS'xOSTOS'yRQ~OPYOQYOSfOY!VOaqOdzOeyOmkOoYOpkOqkOwkOyYO{YO!PWO!TkO!UkO![XO!fuO!iZO!lYO!mYO!nYO!pvO!rwO!uxO!y]O#t!PO$V|O%e}O%g!QO%i!OO%j!OO%k!OO%n!RO%p!SO%s!TO%t!TO%v!UO&S!WO&Y!XO&[!YO&^!ZO&`![O&c!]O&i!^O&o!_O&q!`O&s!aO&u!bO&w!cO(OSO(QTO(TUO([VO(j[O(yiO~OWtO~P`OPYOQYOSfOd!jOe!iOmkOoYOpkOqkOwkOyYO{YO!PWO!TkO!UkO![!eO!fuO!iZO!lYO!mYO!nYO!pvO!r!gO!u!hO$V!kO(O!dO(QTO(TUO([VO(j[O(yiO~Oa!wOp!nO!P!oO!_!yO!`!vO!a!vO!y;bO#Q!pO#R!pO#S!xO#T!pO#U!pO#X!zO#Y!zO(P!lO(QTO(TUO(`!mO(j!sO~O'y!{O~OP]XR]X[]Xa]Xo]X}]X!P]X!Y]X!i]X!m]X#O]X#P]X#]]X#hfX#k]X#l]X#m]X#n]X#o]X#p]X#q]X#r]X#s]X#u]X#w]X#y]X#z]X$P]X'u]X([]X(m]X(t]X(u]X~O!d%PX~P(qO_!}O(Q#PO(R!}O(S#PO~O_#QO(S#PO(T#PO(U#QO~Ou#SO!R#TO(]#TO(^#VO~OPYOQYOSfOd!jOe!iOmkOoYOpkOqkOwkOyYO{YO!PWO!TkO!UkO![!eO!fuO!iZO!lYO!mYO!nYO!pvO!r!gO!u!hO$V!kO(O;fO(QTO(TUO([VO(j[O(yiO~O!X#ZO!Y#WO!V(cP!V(qP~P+}O!Z#cO~P`OPYOQYOSfOd!jOe!iOoYOpkOqkOwkOyYO{YO!PWO!TkO!UkO![!eO!fuO!iZO!lYO!mYO!nYO!pvO!r!gO!u!hO$V!kO(QTO(TUO([VO(j[O(yiO~Om#mO!X#iO!y]O#f#lO#g#iO(O;gO!h(nP~P.iO!i#oO(O#nO~O!u#sO!y]O%e#tO~O#h#uO~O!d#vO#h#uO~OP$[OR#zO[$cOo$aO}#yO!P#{O!Y$_O!i#xO!m$[O#O$RO#k$OO#l$PO#m$PO#n$PO#o$QO#p$RO#q$RO#r$bO#s$RO#u$SO#w$UO#y$WO#z$XO([VO(m$YO(t#|O(u#}O~Oa(aX'u(aX's(aX!h(aX!V(aX![(aX%f(aX!d(aX~P1qO#P$dO#]$eO$P$eOP(bXR(bX[(bXo(bX}(bX!P(bX!Y(bX!i(bX!m(bX#O(bX#k(bX#l(bX#m(bX#n(bX#o(bX#p(bX#q(bX#r(bX#s(bX#u(bX#w(bX#y(bX#z(bX([(bX(m(bX(t(bX(u(bX![(bX%f(bX~Oa(bX'u(bX's(bX!V(bX!h(bXs(bX!d(bX~P4UO#]$eO~O$[$hO$^$gO$e$mO~OSfO![$nO$h$oO$j$qO~Oh%VOm%WOo%XOp$tOq$tOw%YOy%ZO{%[O!P${O![$|O!f%aO!i$xO#g%bO$V%_O$r%]O$t%^O$w%`O(O$sO(QTO(TUO([$uO(t$}O(u%POg(XP~O!i%cO~O!P%fO![%gO(O%eO~O!d%kO~Oa%lO'u%lO~O}%pO~P%[O(P!lO~P%[O%k%tO~P%[Oh%VO!i%cO(O%eO(P!lO~Oe%{O!i%cO(O%eO~O#s$RO~O}&QO![%}O!i&PO%g&TO(O%eO(P!lO(QTO(TUO`)SP~O!u#sO~O%p&VO!P)OX![)OX(O)OX~O(O&WO~O!r&]O#t!PO%g!QO%i!OO%j!OO%k!OO%n!RO%p!SO%s!TO%t!TO~Od&bOe&aO!u&_O%e&`O%x&^O~P;|Od&eOeyO![&dO!r&]O!uxO!y]O#t!PO%e}O%i!OO%j!OO%k!OO%n!RO%p!SO%s!TO%t!TO%v!UO~Ob&hO#]&kO%g&fO(P!lO~P=RO!i&lO!r&pO~O!i#oO~O![XO~Oa%lO't&xO'u%lO~Oa%lO't&{O'u%lO~Oa%lO't&}O'u%lO~O's]X!V]Xs]X!h]X&W]X![]X%f]X!d]X~P(qO!_'[O!`'TO!a'TO(P!lO(QTO(TUO~Op'RO!P'QO!X'UO(`'PO!Z(dP!Z(sP~P@YOk'_O![']O(O%eO~Oe'dO!i%cO(O%eO~O}&QO!i&PO~Op!nO!P!oO!y;bO#Q!pO#R!pO#T!pO#U!pO(P!lO(QTO(TUO(`!mO(j!sO~O!_'jO!`'iO!a'iO#S!pO#X'kO#Y'kO~PAtOa%lOh%VO!d#vO!i%cO'u%lO(m'mO~O!m'qO#]'oO~PCSOp!nO!P!oO(QTO(TUO(`!mO(j!sO~O![XOp(hX!P(hX!_(hX!`(hX!a(hX!y(hX#Q(hX#R(hX#S(hX#T(hX#U(hX#X(hX#Y(hX(P(hX(Q(hX(T(hX(`(hX(j(hX~O!`'iO!a'iO(P!lO~PCrO'z'uO'{'uO'|'wO~O_!}O(Q'yO(R!}O(S'yO~O_#QO(S'yO(T'yO(U#QO~Os'{O~P%[Ou#SO!R#TO(]#TO(^(OO~O!X(QO!V'SX!V'YX!Y'SX!Y'YX~P+}O!Y(SO!V(cX~OP$[OR#zO[$cOo$aO}#yO!P#{O!Y(SO!i#xO!m$[O#O$RO#k$OO#l$PO#m$PO#n$PO#o$QO#p$RO#q$RO#r$bO#s$RO#u$SO#w$UO#y$WO#z$XO([VO(m$YO(t#|O(u#}O~O!V(cX~PGmO!V(XO~O!V(pX!Y(pX!d(pX!h(pX(m(pX~O#](pX#h#aX!Z(pX~PIpO#](YO!V(rX!Y(rX~O!Y(ZO!V(qX~O!V(^O~O#]$eO~PIpO!Z(_O~P`OR#zO}#yO!P#{O!i#xO([VOP!ka[!kao!ka!Y!ka!m!ka#O!ka#k!ka#l!ka#m!ka#n!ka#o!ka#p!ka#q!ka#r!ka#s!ka#u!ka#w!ka#y!ka#z!ka(m!ka(t!ka(u!ka~Oa!ka'u!ka's!ka!V!ka!h!kas!ka![!ka%f!ka!d!ka~PKWO!h(`O~O!d#vO#](aO(m'mO!Y(oXa(oX'u(oX~O!h(oX~PMsO!P%fO![%gO!y]O#f(fO#g(eO(O%eO~O!Y(gO!h(nX~O!h(iO~O!P%fO![%gO#g(eO(O%eO~OP(bXR(bX[(bXo(bX}(bX!P(bX!Y(bX!i(bX!m(bX#O(bX#k(bX#l(bX#m(bX#n(bX#o(bX#p(bX#q(bX#r(bX#s(bX#u(bX#w(bX#y(bX#z(bX([(bX(m(bX(t(bX(u(bX~O!d#vO!h(bX~P! aOR(kO}(jO!i#xO#P$dO!y!xa!P!xa~O!u!xa%e!xa![!xa#f!xa#g!xa(O!xa~P!#bO!u(oO~OPYOQYOSfOd!jOe!iOmkOoYOpkOqkOwkOyYO{YO!PWO!TkO!UkO![XO!fuO!iZO!lYO!mYO!nYO!pvO!r!gO!u!hO$V!kO(O!dO(QTO(TUO([VO(j[O(yiO~Oh%VOm%WOo%XOp$tOq$tOw%YOy%ZO{<OO!P${O![$|O!f=`O!i$xO#g<UO$V%_O$r<QO$t<SO$w%`O(O(sO(QTO(TUO([$uO(t$}O(u%PO~O#h(uO~O!X(wO!h(fP~P%[O(`(yO(j[O~O!P({O!i#xO(`(yO(j[O~OP;aOQ;aOSfOd=[Oe!iOmkOo;aOpkOqkOwkOy;aO{;aO!PWO!TkO!UkO![!eO!f;dO!iZO!l;aO!m;aO!n;aO!p;eO!r;hO!u!hO$V!kO(O)YO(QTO(TUO([VO(j[O(y=YO~O!Y$_Oa$oa'u$oa's$oa!h$oa!V$oa![$oa%f$oa!d$oa~O#t)aO~P!&fOh%VOm%WOo%XOp$tOq$tOw%YOy%ZO{%[O!P${O![$|O!f%aO!i$xO#g%bO$V%_O$r%]O$t%^O$w%`O(O(sO(QTO(TUO([$uO(t$}O(u%PO~Og(kP~P!+oO})fO!d)eO![$]X$Y$]X$[$]X$^$]X$e$]X~O!d)eO![(vX$Y(vX$[(vX$^(vX$e(vX~O})fO~P!-xO})fO![(vX$Y(vX$[(vX$^(vX$e(vX~O![)hO$Y)lO$[)gO$^)gO$e)mO~O!X)pO~P!(vO$[$hO$^$gO$e)tO~Ok$xX}$xX!P$xX#P$xX(t$xX(u$xX~OgjXg$xXkjX!YjX#]jX~P!/nOu)vO(])wO(^)yO~Ok*SO}){O!P)|O(t$}O(u%PO~Og)zO~P!0rOg*TO~Oh%VOm%WOo%XOp$tOq$tOw%YOy%ZO{<OO!P*VO![*WO!f=`O!i$xO#g<UO$V%_O$r<QO$t<SO$w%`O(QTO(TUO([$uO(t$}O(u%PO~O!X*ZO(O*UO!h(zP~P!1aO#h*]O~O!i*^O~Oh%VOm%WOo%XOp$tOq$tOw%YOy%ZO{<OO!P${O![$|O!f=`O!i$xO#g<UO$V%_O$r<QO$t<SO$w%`O(O*`O(QTO(TUO([$uO(t$}O(u%PO~O!X*cO!V({P~P!3`Oo*oO!P*gO!_*mO!`*fO!a*fO!i*^O#X*nO%]*iO(P!lO(`!mO~O!Z*lO~P!5TO#P$dOk(ZX}(ZX!P(ZX(t(ZX(u(ZX!Y(ZX#](ZX~Og(ZX#}(ZX~P!5|Ok*tO#]*sOg(YX!Y(YX~O!Y*uOg(XX~O(O&WOg(XP~Op*xO~O!i*}O~O(O(sO~Om+RO!P%fO!X#iO![%gO!y]O#f#lO#g#iO(O%eO!h(nP~O!d#vO#h+SO~O!P%fO!X+UO!Y(ZO![%gO(O%eO!V(qP~Op'XO!P+WO!X+VO(QTO(TUO(`(yO~O!Z(sP~P!8|O!Y+XOa)PX'u)PX~OP$[OR#zO[$cOo$aO}#yO!P#{O!i#xO!m$[O#O$RO#k$OO#l$PO#m$PO#n$PO#o$QO#p$RO#q$RO#r$bO#s$RO#u$SO#w$UO#y$WO#z$XO([VO(m$YO(t#|O(u#}O~Oa!ga!Y!ga'u!ga's!ga!V!ga!h!gas!ga![!ga%f!ga!d!ga~P!9tOR#zO}#yO!P#{O!i#xO([VOP!oa[!oao!oa!Y!oa!m!oa#O!oa#k!oa#l!oa#m!oa#n!oa#o!oa#p!oa#q!oa#r!oa#s!oa#u!oa#w!oa#y!oa#z!oa(m!oa(t!oa(u!oa~Oa!oa'u!oa's!oa!V!oa!h!oas!oa![!oa%f!oa!d!oa~P!<[OR#zO}#yO!P#{O!i#xO([VOP!qa[!qao!qa!Y!qa!m!qa#O!qa#k!qa#l!qa#m!qa#n!qa#o!qa#p!qa#q!qa#r!qa#s!qa#u!qa#w!qa#y!qa#z!qa(m!qa(t!qa(u!qa~Oa!qa'u!qa's!qa!V!qa!h!qas!qa![!qa%f!qa!d!qa~P!>rOh%VOk+bO![']O%f+aO~O!d+dOa(WX![(WX'u(WX!Y(WX~Oa%lO![XO'u%lO~Oh%VO!i%cO~Oh%VO!i%cO(O%eO~O!d#vO#h(uO~Ob+oO%g+pO(O+lO(QTO(TUO!Z)TP~O!Y+qO`)SX~O[+uO~O`+vO~O![%}O(O%eO(P!lO`)SP~Oh%VO#]+{O~Oh%VOk,OO![$|O~O![,QO~O},SO![XO~O%k%tO~O!u,XO~Oe,^O~Ob,_O(O#nO(QTO(TUO!Z)RP~Oe%{O~O%g!QO(O&WO~P=RO[,dO`,cO~OPYOQYOSfOdzOeyOmkOoYOpkOqkOwkOyYO{YO!PWO!TkO!UkO!fuO!iZO!lYO!mYO!nYO!pvO!uxO!y]O%e}O(QTO(TUO([VO(j[O(yiO~O![!eO!r!gO$V!kO(O!dO~P!ErO`,cOa%lO'u%lO~OPYOQYOSfOd!jOe!iOmkOoYOpkOqkOwkOyYO{YO!PWO!TkO!UkO![!eO!fuO!iZO!lYO!mYO!nYO!pvO!u!hO$V!kO(O!dO(QTO(TUO([VO(j[O(yiO~Oa,iO!rwO#t!OO%i!OO%j!OO%k!OO~P!H[O!i&lO~O&Y,oO~O![,qO~O&k,sO&m,tOP&haQ&haS&haY&haa&had&hae&ham&hao&hap&haq&haw&hay&ha{&ha!P&ha!T&ha!U&ha![&ha!f&ha!i&ha!l&ha!m&ha!n&ha!p&ha!r&ha!u&ha!y&ha#t&ha$V&ha%e&ha%g&ha%i&ha%j&ha%k&ha%n&ha%p&ha%s&ha%t&ha%v&ha&S&ha&Y&ha&[&ha&^&ha&`&ha&c&ha&i&ha&o&ha&q&ha&s&ha&u&ha&w&ha's&ha(O&ha(Q&ha(T&ha([&ha(j&ha(y&ha!Z&ha&a&hab&ha&f&ha~O(O,yO~Oh!bX!Y!OX!Z!OX!d!OX!d!bX!i!bX#]!OX~O!Y!bX!Z!bX~P# bO!d-OO#],}Oh(eX!Y#eX!Y(eX!Z#eX!Z(eX!d(eX!i(eX~Oh%VO!d-QO!i%cO!Y!^X!Z!^X~Op!nO!P!oO(QTO(TUO(`!mO~OP;aOQ;aOSfOd=[Oe!iOmkOo;aOpkOqkOwkOy;aO{;aO!PWO!TkO!UkO![!eO!f;dO!iZO!l;aO!m;aO!n;aO!p;eO!r;hO!u!hO$V!kO(QTO(TUO([VO(j[O(y=YO~O(O<[O~P##fO!Y-UO!Z(dX~O!Z-WO~O!d-OO#],}O!Y#eX!Z#eX~O!Y-XO!Z(sX~O!Z-ZO~O!`-[O!a-[O(P!lO~P##TO!Z-_O~P'_Ok-bO![']O~O!V-gO~Op!xa!_!xa!`!xa!a!xa#Q!xa#R!xa#S!xa#T!xa#U!xa#X!xa#Y!xa(P!xa(Q!xa(T!xa(`!xa(j!xa~P!#bO!m-lO#]-jO~PCSO!`-nO!a-nO(P!lO~PCrOa%lO#]-jO'u%lO~Oa%lO!d#vO#]-jO'u%lO~Oa%lO!d#vO!m-lO#]-jO'u%lO(m'mO~O'z'uO'{'uO'|-sO~Os-tO~O!V'Sa!Y'Sa~P!9tO!X-xO!V'SX!Y'SX~P%[O!Y(SO!V(ca~O!V(ca~PGmO!Y(ZO!V(qa~O!P%fO!X-|O![%gO(O%eO!V'YX!Y'YX~O#].OO!Y(oa!h(oaa(oa'u(oa~O!d#vO~P#+lO!Y(gO!h(na~O!P%fO![%gO#g.SO(O%eO~Om.XO!P%fO!X.UO![%gO!y]O#f.WO#g.UO(O%eO!Y']X!h']X~OR.]O!i#xO~Oh%VOk.`O![']O%f._O~Oa#`i!Y#`i'u#`i's#`i!V#`i!h#`is#`i![#`i%f#`i!d#`i~P!9tOk=fO}){O!P)|O(t$}O(u%PO~O#h#[aa#[a#]#[a'u#[a!Y#[a!h#[a![#[a!V#[a~P#.hO#h(ZXP(ZXR(ZX[(ZXa(ZXo(ZX!i(ZX!m(ZX#O(ZX#k(ZX#l(ZX#m(ZX#n(ZX#o(ZX#p(ZX#q(ZX#r(ZX#s(ZX#u(ZX#w(ZX#y(ZX#z(ZX'u(ZX([(ZX(m(ZX!h(ZX!V(ZX's(ZXs(ZX![(ZX%f(ZX!d(ZX~P!5|O!Y.mO!h(fX~P!9tO!h.pO~O!V.rO~OP$[OR#zO}#yO!P#{O!i#xO!m$[O([VO[#jia#jio#ji!Y#ji#O#ji#l#ji#m#ji#n#ji#o#ji#p#ji#q#ji#r#ji#s#ji#u#ji#w#ji#y#ji#z#ji'u#ji(m#ji(t#ji(u#ji's#ji!V#ji!h#jis#ji![#ji%f#ji!d#ji~O#k#ji~P#2TO#k$OO~P#2TOP$[OR#zOo$aO}#yO!P#{O!i#xO!m$[O#k$OO#l$PO#m$PO#n$PO([VO[#jia#ji!Y#ji#O#ji#p#ji#q#ji#r#ji#s#ji#u#ji#w#ji#y#ji#z#ji'u#ji(m#ji(t#ji(u#ji's#ji!V#ji!h#jis#ji![#ji%f#ji!d#ji~O#o#ji~P#4rO#o$QO~P#4rOP$[OR#zO[$cOo$aO}#yO!P#{O!i#xO!m$[O#O$RO#k$OO#l$PO#m$PO#n$PO#o$QO#p$RO#q$RO#r$bO#s$RO([VOa#ji!Y#ji#w#ji#y#ji#z#ji'u#ji(m#ji(t#ji(u#ji's#ji!V#ji!h#jis#ji![#ji%f#ji!d#ji~O#u#ji~P#7aOP$[OR#zO[$cOo$aO}#yO!P#{O!i#xO!m$[O#O$RO#k$OO#l$PO#m$PO#n$PO#o$QO#p$RO#q$RO#r$bO#s$RO#u$SO([VO(u#}Oa#ji!Y#ji#y#ji#z#ji'u#ji(m#ji(t#ji's#ji!V#ji!h#jis#ji![#ji%f#ji!d#ji~O#w$UO~P#9wO#w#ji~P#9wO#u$SO~P#7aOP$[OR#zO[$cOo$aO}#yO!P#{O!i#xO!m$[O#O$RO#k$OO#l$PO#m$PO#n$PO#o$QO#p$RO#q$RO#r$bO#s$RO#u$SO#w$UO([VO(t#|O(u#}Oa#ji!Y#ji#z#ji'u#ji(m#ji's#ji!V#ji!h#jis#ji![#ji%f#ji!d#ji~O#y#ji~P#<mO#y$WO~P#<mOP]XR]X[]Xo]X}]X!P]X!i]X!m]X#O]X#P]X#]]X#hfX#k]X#l]X#m]X#n]X#o]X#p]X#q]X#r]X#s]X#u]X#w]X#y]X#z]X$P]X([]X(m]X(t]X(u]X!Y]X!Z]X~O#}]X~P#?[OP$[OR#zO[;xOo;vO}#yO!P#{O!i#xO!m$[O#O;mO#k;jO#l;kO#m;kO#n;kO#o;lO#p;mO#q;mO#r;wO#s;mO#u;nO#w;pO#y;rO#z;sO([VO(m$YO(t#|O(u#}O~O#}.tO~P#AiO#P$dO#];yO$P;yO#}(bX!Z(bX~P! aOa'`a!Y'`a'u'`a's'`a!h'`a!V'`as'`a!['`a%f'`a!d'`a~P!9tO[#jia#jio#ji!Y#ji#O#ji#o#ji#p#ji#q#ji#r#ji#s#ji#u#ji#w#ji#y#ji#z#ji'u#ji(m#ji's#ji!V#ji!h#jis#ji![#ji%f#ji!d#ji~OP$[OR#zO}#yO!P#{O!i#xO!m$[O#k$OO#l$PO#m$PO#n$PO([VO(t#ji(u#ji~P#DkOk=fO}){O!P)|O(t$}O(u%POP#jiR#ji!i#ji!m#ji#k#ji#l#ji#m#ji#n#ji([#ji~P#DkO!Y.xOg(kX~P!0rOg.zO~Oa$Oi!Y$Oi'u$Oi's$Oi!V$Oi!h$Ois$Oi![$Oi%f$Oi!d$Oi~P!9tO$[.{O$^.{O~O$[.|O$^.|O~O!d)eO#].}O![$bX$Y$bX$[$bX$^$bX$e$bX~O!X/OO~O![)hO$Y/QO$[)gO$^)gO$e/RO~O!Y;tO!Z(aX~P#AiO!Z/SO~O!d)eO$e(vX~O$e/UO~Os/VO~P!&fOu)vO(])wO(^/YO~O!V/^O~P!&fO(t$}Ok%^a}%^a!P%^a(u%^a!Y%^a#]%^a~Og%^a#}%^a~P#KlO(u%POk%`a}%`a!P%`a(t%`a!Y%`a#]%`a~Og%`a#}%`a~P#L_O!YfX!dfX!hfX!h$xX(mfX~P!/nO!X/gO!Y(ZO(O/fO!V(qP!V({P~P!1aOo*oO!_*mO!`*fO!a*fO!i*^O#X*nO%]*iO(P!lO~Op'XO!P/hO!X+VO!Z*lO(QTO(TUO(`<XO!Z(sP~P#MxO!h/iO~P#.hO!Y/jO!d#vO(m'mO!h(zX~O!h/oO~O!P%fO!X*ZO![%gO(O%eO!h(zP~O#h/qO~O!V$xX!Y$xX!d%PX~P!/nO!Y/rO!V({X~P#.hO!d/tO~O!V/vO~Oh%VOo/zO!d#vO!i%cO(m'mO~O(O/|O~O!d+dO~Oa%lO!Y0QO'u%lO~O!Z0SO~P!5TO!`0TO!a0TO(P!lO(`!mO~O!P0VO(`!mO~O#X0WO~Og%^a!Y%^a#]%^a#}%^a~P!0rOg%`a!Y%`a#]%`a#}%`a~P!0rO(O&WOg'iX!Y'iX~O!Y*uOg(Xa~Og0aO~OR0bO}0bO!P0cO#P$dOkza(tza(uza!Yza#]za~Ogza#}za~P$%kO}){O!P)|Ok$qa(t$qa(u$qa!Y$qa#]$qa~Og$qa#}$qa~P$&dO}){O!P)|Ok$sa(t$sa(u$sa!Y$sa#]$sa~Og$sa#}$sa~P$'VO#h0fO~Og%Ra!Y%Ra#]%Ra#}%Ra~P!0rO!d#vO~O#h0iO~O!Y+XOa)Pa'u)Pa~OR#zO}#yO!P#{O!i#xO([VOP!oi[!oio!oi!Y!oi!m!oi#O!oi#k!oi#l!oi#m!oi#n!oi#o!oi#p!oi#q!oi#r!oi#s!oi#u!oi#w!oi#y!oi#z!oi(m!oi(t!oi(u!oi~Oa!oi'u!oi's!oi!V!oi!h!ois!oi![!oi%f!oi!d!oi~P$(tOh%VOo%XOp$tOq$tOw%YOy%ZO{<OO!P${O![$|O!f=`O!i$xO#g<UO$V%_O$r<QO$t<SO$w%`O(QTO(TUO([$uO(t$}O(u%PO~Om0rO(O0qO~P$+[O!d+dOa(Wa![(Wa'u(Wa!Y(Wa~O#h0xO~O[]X!YfX!ZfX~O!Y0yO!Z)TX~O!Z0{O~O[0|O~Ob1OO(O+lO(QTO(TUO~O![%}O(O%eO`'qX!Y'qX~O!Y+qO`)Sa~O!h1RO~P!9tO[1UO~O`1VO~O#]1YO~Ok1]O![$|O~O(`(yO!Z)QP~Oh%VOk1fO![1cO%f1eO~O[1pO!Y1nO!Z)RX~O!Z1qO~O`1sOa%lO'u%lO~O(O#nO(QTO(TUO~O#P$dO#]$eO$P$eOP(bXR(bX[(bXo(bX}(bX!P(bX!Y(bX!i(bX!m(bX#O(bX#k(bX#l(bX#m(bX#n(bX#o(bX#p(bX#q(bX#r(bX#u(bX#w(bX#y(bX#z(bX([(bX(m(bX(t(bX(u(bX~O#s1vO&W1wOa(bX~P$0rO#]$eO#s1vO&W1wO~Oa1yO~P%[Oa1{O~O&a2OOP&_iQ&_iS&_iY&_ia&_id&_ie&_im&_io&_ip&_iq&_iw&_iy&_i{&_i!P&_i!T&_i!U&_i![&_i!f&_i!i&_i!l&_i!m&_i!n&_i!p&_i!r&_i!u&_i!y&_i#t&_i$V&_i%e&_i%g&_i%i&_i%j&_i%k&_i%n&_i%p&_i%s&_i%t&_i%v&_i&S&_i&Y&_i&[&_i&^&_i&`&_i&c&_i&i&_i&o&_i&q&_i&s&_i&u&_i&w&_i's&_i(O&_i(Q&_i(T&_i([&_i(j&_i(y&_i!Z&_ib&_i&f&_i~Ob2UO!Z2SO&f2TO~P`O![XO!i2WO~O&m,tOP&hiQ&hiS&hiY&hia&hid&hie&him&hio&hip&hiq&hiw&hiy&hi{&hi!P&hi!T&hi!U&hi![&hi!f&hi!i&hi!l&hi!m&hi!n&hi!p&hi!r&hi!u&hi!y&hi#t&hi$V&hi%e&hi%g&hi%i&hi%j&hi%k&hi%n&hi%p&hi%s&hi%t&hi%v&hi&S&hi&Y&hi&[&hi&^&hi&`&hi&c&hi&i&hi&o&hi&q&hi&s&hi&u&hi&w&hi's&hi(O&hi(Q&hi(T&hi([&hi(j&hi(y&hi!Z&hi&a&hib&hi&f&hi~O!V2^O~O!Y!^a!Z!^a~P#AiOp!nO!P!oO!X2dO(`!mO!Y'TX!Z'TX~P@YO!Y-UO!Z(da~O!Y'ZX!Z'ZX~P!8|O!Y-XO!Z(sa~O!Z2kO~P'_Oa%lO#]2tO'u%lO~Oa%lO!d#vO#]2tO'u%lO~Oa%lO!d#vO!m2xO#]2tO'u%lO(m'mO~Oa%lO'u%lO~P!9tO!Y$_Os$oa~O!V'Si!Y'Si~P!9tO!Y(SO!V(ci~O!Y(ZO!V(qi~O!V(ri!Y(ri~P!9tO!Y(oi!h(oia(oi'u(oi~P!9tO#]2zO!Y(oi!h(oia(oi'u(oi~O!Y(gO!h(ni~O!P%fO![%gO!y]O#f3PO#g3OO(O%eO~O!P%fO![%gO#g3OO(O%eO~Ok3WO![']O%f3VO~Oh%VOk3WO![']O%f3VO~O#h%^aP%^aR%^a[%^aa%^ao%^a!i%^a!m%^a#O%^a#k%^a#l%^a#m%^a#n%^a#o%^a#p%^a#q%^a#r%^a#s%^a#u%^a#w%^a#y%^a#z%^a'u%^a([%^a(m%^a!h%^a!V%^a's%^as%^a![%^a%f%^a!d%^a~P#KlO#h%`aP%`aR%`a[%`aa%`ao%`a!i%`a!m%`a#O%`a#k%`a#l%`a#m%`a#n%`a#o%`a#p%`a#q%`a#r%`a#s%`a#u%`a#w%`a#y%`a#z%`a'u%`a([%`a(m%`a!h%`a!V%`a's%`as%`a![%`a%f%`a!d%`a~P#L_O#h%^aP%^aR%^a[%^aa%^ao%^a!Y%^a!i%^a!m%^a#O%^a#k%^a#l%^a#m%^a#n%^a#o%^a#p%^a#q%^a#r%^a#s%^a#u%^a#w%^a#y%^a#z%^a'u%^a([%^a(m%^a!h%^a!V%^a's%^a#]%^as%^a![%^a%f%^a!d%^a~P#.hO#h%`aP%`aR%`a[%`aa%`ao%`a!Y%`a!i%`a!m%`a#O%`a#k%`a#l%`a#m%`a#n%`a#o%`a#p%`a#q%`a#r%`a#s%`a#u%`a#w%`a#y%`a#z%`a'u%`a([%`a(m%`a!h%`a!V%`a's%`a#]%`as%`a![%`a%f%`a!d%`a~P#.hO#hzaPza[zaazaoza!iza!mza#Oza#kza#lza#mza#nza#oza#pza#qza#rza#sza#uza#wza#yza#zza'uza([za(mza!hza!Vza'szasza![za%fza!dza~P$%kO#h$qaP$qaR$qa[$qaa$qao$qa!i$qa!m$qa#O$qa#k$qa#l$qa#m$qa#n$qa#o$qa#p$qa#q$qa#r$qa#s$qa#u$qa#w$qa#y$qa#z$qa'u$qa([$qa(m$qa!h$qa!V$qa's$qas$qa![$qa%f$qa!d$qa~P$&dO#h$saP$saR$sa[$saa$sao$sa!i$sa!m$sa#O$sa#k$sa#l$sa#m$sa#n$sa#o$sa#p$sa#q$sa#r$sa#s$sa#u$sa#w$sa#y$sa#z$sa'u$sa([$sa(m$sa!h$sa!V$sa's$sas$sa![$sa%f$sa!d$sa~P$'VO#h%RaP%RaR%Ra[%Raa%Rao%Ra!Y%Ra!i%Ra!m%Ra#O%Ra#k%Ra#l%Ra#m%Ra#n%Ra#o%Ra#p%Ra#q%Ra#r%Ra#s%Ra#u%Ra#w%Ra#y%Ra#z%Ra'u%Ra([%Ra(m%Ra!h%Ra!V%Ra's%Ra#]%Ras%Ra![%Ra%f%Ra!d%Ra~P#.hOa#`q!Y#`q'u#`q's#`q!V#`q!h#`qs#`q![#`q%f#`q!d#`q~P!9tO!X3`O!Y'UX!h'UX~P%[O!Y.mO!h(fa~O!Y.mO!h(fa~P!9tO!V3cO~O#}!ka!Z!ka~PKWO#}!ga!Y!ga!Z!ga~P#AiO#}!oa!Z!oa~P!<[O#}!qa!Z!qa~P!>rOg'XX!Y'XX~P!+oO!Y.xOg(ka~OSfO![3wO$c3xO~O!Z3|O~Os3}O~P#.hOa$lq!Y$lq'u$lq's$lq!V$lq!h$lqs$lq![$lq%f$lq!d$lq~P!9tO!V4OO~P#.hO}){O!P)|O(u%POk'ea(t'ea!Y'ea#]'ea~Og'ea#}'ea~P%)|O}){O!P)|Ok'ga(t'ga(u'ga!Y'ga#]'ga~Og'ga#}'ga~P%*oO(m$YO~P#.hO!VfX!V$xX!YfX!Y$xX!d%PX#]fX~P!/nO(O<bO~P!1aOmkO(O4QO~P.iO!P%fO!X4SO![%gO(O%eO!Y'aX!h'aX~O!Y/jO!h(za~O!Y/jO!d#vO!h(za~O!Y/jO!d#vO(m'mO!h(za~Og$zi!Y$zi#]$zi#}$zi~P!0rO!X4[O!V'cX!Y'cX~P!3`O!Y/rO!V({a~O!Y/rO!V({a~P#.hO!d#vO#s4dO~Oo4gO!d#vO(m'mO~O!P4jO(`!mO~O(t$}Ok%^i}%^i!P%^i(u%^i!Y%^i#]%^i~Og%^i#}%^i~P%/VO(u%POk%`i}%`i!P%`i(t%`i!Y%`i#]%`i~Og%`i#}%`i~P%/xOg(Yi!Y(Yi~P!0rO#]4oOg(Yi!Y(Yi~P!0rO!h4rO~Oa$mq!Y$mq'u$mq's$mq!V$mq!h$mqs$mq![$mq%f$mq!d$mq~P!9tO!V4vO~O!Y4wO![(|X~P#.hOa$xX![$xX%Z]X'u$xX!Y$xX~P!/nO%Z4zOalXklX}lX!PlX![lX'ulX(tlX(ulX!YlX~O%Z4zO~Ob5QO%g5RO(O+lO(QTO(TUO!Y'pX!Z'pX~O!Y0yO!Z)Ta~O[5VO~O`5WO~Oa%lO'u%lO~P#.hO![$|O~P#.hO!Y5`O#]5bO!Z)QX~O!Z5cO~Oo5jOp!nO!P5dO!_!yO!`!vO!a!vO!y;bO#Q!pO#R!pO#S!pO#T!pO#U!pO#X5iO#Y!zO(P!lO(QTO(TUO(`!mO(j!sO~O!Z5hO~P%5SOk5oO![1cO%f5nO~Oh%VOk5oO![1cO%f5nO~Ob5vO(O#nO(QTO(TUO!Y'oX!Z'oX~O!Y1nO!Z)Ra~O(QTO(TUO(`5xO~O`5|O~O#s6PO&W6QO~PMsO!h6RO~P%[Oa6TO~Oa6TO~P%[Ob2UO!Z6YO&f2TO~P`O!d6[O~O!d6^Oh(ei!Y(ei!Z(ei!d(ei!i(ei~O!Y#ei!Z#ei~P#AiO#]6_O!Y#ei!Z#ei~O!Y!^i!Z!^i~P#AiOa%lO#]6hO'u%lO~Oa%lO!d#vO#]6hO'u%lO~O!Y(oq!h(oqa(oq'u(oq~P!9tO!Y(gO!h(nq~O!P%fO![%gO#g6oO(O%eO~O![']O%f6rO~Ok6vO![']O%f6rO~O#h'eaP'eaR'ea['eaa'eao'ea!i'ea!m'ea#O'ea#k'ea#l'ea#m'ea#n'ea#o'ea#p'ea#q'ea#r'ea#s'ea#u'ea#w'ea#y'ea#z'ea'u'ea(['ea(m'ea!h'ea!V'ea's'eas'ea!['ea%f'ea!d'ea~P%)|O#h'gaP'gaR'ga['gaa'gao'ga!i'ga!m'ga#O'ga#k'ga#l'ga#m'ga#n'ga#o'ga#p'ga#q'ga#r'ga#s'ga#u'ga#w'ga#y'ga#z'ga'u'ga(['ga(m'ga!h'ga!V'ga's'gas'ga!['ga%f'ga!d'ga~P%*oO#h$ziP$ziR$zi[$zia$zio$zi!Y$zi!i$zi!m$zi#O$zi#k$zi#l$zi#m$zi#n$zi#o$zi#p$zi#q$zi#r$zi#s$zi#u$zi#w$zi#y$zi#z$zi'u$zi([$zi(m$zi!h$zi!V$zi's$zi#]$zis$zi![$zi%f$zi!d$zi~P#.hO#h%^iP%^iR%^i[%^ia%^io%^i!i%^i!m%^i#O%^i#k%^i#l%^i#m%^i#n%^i#o%^i#p%^i#q%^i#r%^i#s%^i#u%^i#w%^i#y%^i#z%^i'u%^i([%^i(m%^i!h%^i!V%^i's%^is%^i![%^i%f%^i!d%^i~P%/VO#h%`iP%`iR%`i[%`ia%`io%`i!i%`i!m%`i#O%`i#k%`i#l%`i#m%`i#n%`i#o%`i#p%`i#q%`i#r%`i#s%`i#u%`i#w%`i#y%`i#z%`i'u%`i([%`i(m%`i!h%`i!V%`i's%`is%`i![%`i%f%`i!d%`i~P%/xO!Y'Ua!h'Ua~P!9tO!Y.mO!h(fi~O#}#`i!Y#`i!Z#`i~P#AiOP$[OR#zO}#yO!P#{O!i#xO!m$[O([VO[#jio#ji#O#ji#l#ji#m#ji#n#ji#o#ji#p#ji#q#ji#r#ji#s#ji#u#ji#w#ji#y#ji#z#ji#}#ji(m#ji(t#ji(u#ji!Y#ji!Z#ji~O#k#ji~P%GlO#k;jO~P%GlOP$[OR#zOo;vO}#yO!P#{O!i#xO!m$[O#k;jO#l;kO#m;kO#n;kO([VO[#ji#O#ji#p#ji#q#ji#r#ji#s#ji#u#ji#w#ji#y#ji#z#ji#}#ji(m#ji(t#ji(u#ji!Y#ji!Z#ji~O#o#ji~P%ItO#o;lO~P%ItOP$[OR#zO[;xOo;vO}#yO!P#{O!i#xO!m$[O#O;mO#k;jO#l;kO#m;kO#n;kO#o;lO#p;mO#q;mO#r;wO#s;mO([VO#w#ji#y#ji#z#ji#}#ji(m#ji(t#ji(u#ji!Y#ji!Z#ji~O#u#ji~P%K|OP$[OR#zO[;xOo;vO}#yO!P#{O!i#xO!m$[O#O;mO#k;jO#l;kO#m;kO#n;kO#o;lO#p;mO#q;mO#r;wO#s;mO#u;nO([VO(u#}O#y#ji#z#ji#}#ji(m#ji(t#ji!Y#ji!Z#ji~O#w;pO~P%M}O#w#ji~P%M}O#u;nO~P%K|OP$[OR#zO[;xOo;vO}#yO!P#{O!i#xO!m$[O#O;mO#k;jO#l;kO#m;kO#n;kO#o;lO#p;mO#q;mO#r;wO#s;mO#u;nO#w;pO([VO(t#|O(u#}O#z#ji#}#ji(m#ji!Y#ji!Z#ji~O#y#ji~P&!^O#y;rO~P&!^Oa#{y!Y#{y'u#{y's#{y!V#{y!h#{ys#{y![#{y%f#{y!d#{y~P!9tO[#jio#ji#O#ji#o#ji#p#ji#q#ji#r#ji#s#ji#u#ji#w#ji#y#ji#z#ji#}#ji(m#ji!Y#ji!Z#ji~OP$[OR#zO}#yO!P#{O!i#xO!m$[O#k;jO#l;kO#m;kO#n;kO([VO(t#ji(u#ji~P&%YOk=gO}){O!P)|O(t$}O(u%POP#jiR#ji!i#ji!m#ji#k#ji#l#ji#m#ji#n#ji([#ji~P&%YO#P$dOP(ZXR(ZX[(ZXk(ZXo(ZX}(ZX!P(ZX!i(ZX!m(ZX#O(ZX#k(ZX#l(ZX#m(ZX#n(ZX#o(ZX#p(ZX#q(ZX#r(ZX#s(ZX#u(ZX#w(ZX#y(ZX#z(ZX#}(ZX([(ZX(m(ZX(t(ZX(u(ZX!Y(ZX!Z(ZX~O#}$Oi!Y$Oi!Z$Oi~P#AiO#}!oi!Z!oi~P$(tOg'Xa!Y'Xa~P!0rO!Z7YO~O!Y'`a!Z'`a~P#AiOP]XR]X[]Xo]X}]X!P]X!V]X!Y]X!i]X!m]X#O]X#P]X#]]X#hfX#k]X#l]X#m]X#n]X#o]X#p]X#q]X#r]X#s]X#u]X#w]X#y]X#z]X$P]X([]X(m]X(t]X(u]X~O!d%WX#s%WX~P&+`O!d#vO(m'mO!Y'aa!h'aa~O!Y/jO!h(zi~O!Y/jO!d#vO!h(zi~Og$zq!Y$zq#]$zq#}$zq~P!0rO!V'ca!Y'ca~P#.hO!d7aO~O!Y/rO!V({i~P#.hO!Y/rO!V({i~O!V7eO~O!d#vO#s7jO~Oo7kO!d#vO(m'mO~O}){O!P)|O(u%POk'fa(t'fa!Y'fa#]'fa~Og'fa#}'fa~P&0OO}){O!P)|Ok'ha(t'ha(u'ha!Y'ha#]'ha~Og'ha#}'ha~P&0qO!V7nO~Og$|q!Y$|q#]$|q#}$|q~P!0rOa$my!Y$my'u$my's$my!V$my!h$mys$my![$my%f$my!d$my~P!9tO!d6^O~O!Y4wO![(|a~O![']OP$SaR$Sa[$Sao$Sa}$Sa!P$Sa!Y$Sa!i$Sa!m$Sa#O$Sa#k$Sa#l$Sa#m$Sa#n$Sa#o$Sa#p$Sa#q$Sa#r$Sa#s$Sa#u$Sa#w$Sa#y$Sa#z$Sa([$Sa(m$Sa(t$Sa(u$Sa~O%f6rO~P&2zOa#`y!Y#`y'u#`y's#`y!V#`y!h#`ys#`y![#`y%f#`y!d#`y~P!9tO[7sO~Ob7uO(O+lO(QTO(TUO~O!Y0yO!Z)Ti~O`7yO~O(`(yO!Y'lX!Z'lX~O!Y5`O!Z)Qa~O!Z8SO~P%5SOp!nO!P8TO(QTO(TUO(`!mO(j!sO~O#X8UO~O![1cO~O![1cO%f8WO~Ok8ZO![1cO%f8WO~O[8`O!Y'oa!Z'oa~O!Y1nO!Z)Ri~O!h8dO~O!h8eO~O!h8hO~O!h8hO~P%[Oa8jO~O!d8kO~O!h8lO~O!Y(ri!Z(ri~P#AiOa%lO#]8tO'u%lO~O!Y(oy!h(oya(oy'u(oy~P!9tO!Y(gO!h(ny~O%f8wO~P&2zO![']O%f8wO~O#h$zqP$zqR$zq[$zqa$zqo$zq!Y$zq!i$zq!m$zq#O$zq#k$zq#l$zq#m$zq#n$zq#o$zq#p$zq#q$zq#r$zq#s$zq#u$zq#w$zq#y$zq#z$zq'u$zq([$zq(m$zq!h$zq!V$zq's$zq#]$zqs$zq![$zq%f$zq!d$zq~P#.hO#h'faP'faR'fa['faa'fao'fa!i'fa!m'fa#O'fa#k'fa#l'fa#m'fa#n'fa#o'fa#p'fa#q'fa#r'fa#s'fa#u'fa#w'fa#y'fa#z'fa'u'fa(['fa(m'fa!h'fa!V'fa's'fas'fa!['fa%f'fa!d'fa~P&0OO#h'haP'haR'ha['haa'hao'ha!i'ha!m'ha#O'ha#k'ha#l'ha#m'ha#n'ha#o'ha#p'ha#q'ha#r'ha#s'ha#u'ha#w'ha#y'ha#z'ha'u'ha(['ha(m'ha!h'ha!V'ha's'has'ha!['ha%f'ha!d'ha~P&0qO#h$|qP$|qR$|q[$|qa$|qo$|q!Y$|q!i$|q!m$|q#O$|q#k$|q#l$|q#m$|q#n$|q#o$|q#p$|q#q$|q#r$|q#s$|q#u$|q#w$|q#y$|q#z$|q'u$|q([$|q(m$|q!h$|q!V$|q's$|q#]$|qs$|q![$|q%f$|q!d$|q~P#.hO!Y'Ui!h'Ui~P!9tO#}#`q!Y#`q!Z#`q~P#AiO(t$}OP%^aR%^a[%^ao%^a!i%^a!m%^a#O%^a#k%^a#l%^a#m%^a#n%^a#o%^a#p%^a#q%^a#r%^a#s%^a#u%^a#w%^a#y%^a#z%^a#}%^a([%^a(m%^a!Y%^a!Z%^a~Ok%^a}%^a!P%^a(u%^a~P&C}O(u%POP%`aR%`a[%`ao%`a!i%`a!m%`a#O%`a#k%`a#l%`a#m%`a#n%`a#o%`a#p%`a#q%`a#r%`a#s%`a#u%`a#w%`a#y%`a#z%`a#}%`a([%`a(m%`a!Y%`a!Z%`a~Ok%`a}%`a!P%`a(t%`a~P&FROk=gO}){O!P)|O(u%PO~P&C}Ok=gO}){O!P)|O(t$}O~P&FROR0bO}0bO!P0cO#P$dOPza[zakzaoza!iza!mza#Oza#kza#lza#mza#nza#oza#pza#qza#rza#sza#uza#wza#yza#zza#}za([za(mza(tza(uza!Yza!Zza~O}){O!P)|OP$qaR$qa[$qak$qao$qa!i$qa!m$qa#O$qa#k$qa#l$qa#m$qa#n$qa#o$qa#p$qa#q$qa#r$qa#s$qa#u$qa#w$qa#y$qa#z$qa#}$qa([$qa(m$qa(t$qa(u$qa!Y$qa!Z$qa~O}){O!P)|OP$saR$sa[$sak$sao$sa!i$sa!m$sa#O$sa#k$sa#l$sa#m$sa#n$sa#o$sa#p$sa#q$sa#r$sa#s$sa#u$sa#w$sa#y$sa#z$sa#}$sa([$sa(m$sa(t$sa(u$sa!Y$sa!Z$sa~Ok=gO}){O!P)|O(t$}O(u%PO~OP%RaR%Ra[%Rao%Ra!i%Ra!m%Ra#O%Ra#k%Ra#l%Ra#m%Ra#n%Ra#o%Ra#p%Ra#q%Ra#r%Ra#s%Ra#u%Ra#w%Ra#y%Ra#z%Ra#}%Ra([%Ra(m%Ra!Y%Ra!Z%Ra~P&NzO#}$lq!Y$lq!Z$lq~P#AiO#}$mq!Y$mq!Z$mq~P#AiO!Z9UO~O#}9VO~P!0rO!d#vO!Y'ai!h'ai~O!d#vO(m'mO!Y'ai!h'ai~O!Y/jO!h(zq~O!V'ci!Y'ci~P#.hO!Y/rO!V({q~Oo9^O!d#vO(m'mO~O[9`O!V9_O~P#.hO!V9_O~O!d#vO#s9eO~Og(Yy!Y(Yy~P!0rO!Y'ja!['ja~P#.hOa%Yq![%Yq'u%Yq!Y%Yq~P#.hO[9gO~O!Y0yO!Z)Tq~O#]9kO!Y'la!Z'la~O!Y5`O!Z)Qi~P#AiO!P4jO~O![1cO%f9oO~O(QTO(TUO(`9tO~O!Y1nO!Z)Rq~O!h9wO~O!h9xO~O!h9yO~O!h9yO~P%[O#]9|O!Y#ey!Z#ey~O!Y#ey!Z#ey~P#AiO%f:RO~P&2zO![']O%f:RO~O#}#{y!Y#{y!Z#{y~P#AiOP$ziR$zi[$zio$zi!i$zi!m$zi#O$zi#k$zi#l$zi#m$zi#n$zi#o$zi#p$zi#q$zi#r$zi#s$zi#u$zi#w$zi#y$zi#z$zi#}$zi([$zi(m$zi!Y$zi!Z$zi~P&NzO}){O!P)|O(u%POP'eaR'ea['eak'eao'ea!i'ea!m'ea#O'ea#k'ea#l'ea#m'ea#n'ea#o'ea#p'ea#q'ea#r'ea#s'ea#u'ea#w'ea#y'ea#z'ea#}'ea(['ea(m'ea(t'ea!Y'ea!Z'ea~O}){O!P)|OP'gaR'ga['gak'gao'ga!i'ga!m'ga#O'ga#k'ga#l'ga#m'ga#n'ga#o'ga#p'ga#q'ga#r'ga#s'ga#u'ga#w'ga#y'ga#z'ga#}'ga(['ga(m'ga(t'ga(u'ga!Y'ga!Z'ga~O(t$}OP%^iR%^i[%^ik%^io%^i}%^i!P%^i!i%^i!m%^i#O%^i#k%^i#l%^i#m%^i#n%^i#o%^i#p%^i#q%^i#r%^i#s%^i#u%^i#w%^i#y%^i#z%^i#}%^i([%^i(m%^i(u%^i!Y%^i!Z%^i~O(u%POP%`iR%`i[%`ik%`io%`i}%`i!P%`i!i%`i!m%`i#O%`i#k%`i#l%`i#m%`i#n%`i#o%`i#p%`i#q%`i#r%`i#s%`i#u%`i#w%`i#y%`i#z%`i#}%`i([%`i(m%`i(t%`i!Y%`i!Z%`i~O#}$my!Y$my!Z$my~P#AiO#}#`y!Y#`y!Z#`y~P#AiO!d#vO!Y'aq!h'aq~O!Y/jO!h(zy~O!V'cq!Y'cq~P#.hOo:]O!d#vO(m'mO~O[:`O!V:_O~P#.hO!V:_O~O!Y0yO!Z)Ty~O!Y5`O!Z)Qq~O![1cO%f:hO~O!h:kO~O%f:pO~P&2zOP$zqR$zq[$zqo$zq!i$zq!m$zq#O$zq#k$zq#l$zq#m$zq#n$zq#o$zq#p$zq#q$zq#r$zq#s$zq#u$zq#w$zq#y$zq#z$zq#}$zq([$zq(m$zq!Y$zq!Z$zq~P&NzO}){O!P)|O(u%POP'faR'fa['fak'fao'fa!i'fa!m'fa#O'fa#k'fa#l'fa#m'fa#n'fa#o'fa#p'fa#q'fa#r'fa#s'fa#u'fa#w'fa#y'fa#z'fa#}'fa(['fa(m'fa(t'fa!Y'fa!Z'fa~O}){O!P)|OP'haR'ha['hak'hao'ha!i'ha!m'ha#O'ha#k'ha#l'ha#m'ha#n'ha#o'ha#p'ha#q'ha#r'ha#s'ha#u'ha#w'ha#y'ha#z'ha#}'ha(['ha(m'ha(t'ha(u'ha!Y'ha!Z'ha~OP$|qR$|q[$|qo$|q!i$|q!m$|q#O$|q#k$|q#l$|q#m$|q#n$|q#o$|q#p$|q#q$|q#r$|q#s$|q#u$|q#w$|q#y$|q#z$|q#}$|q([$|q(m$|q!Y$|q!Z$|q~P&NzOg%b!Z!Y%b!Z#]%b!Z#}%b!Z~P!0rO!V:tO~P#.hOo:uO!d#vO(m'mO~O[:wO!V:tO~P#.hO!Y'lq!Z'lq~P#AiO!Y#e!Z!Z#e!Z~P#AiO#h%b!ZP%b!ZR%b!Z[%b!Za%b!Zo%b!Z!Y%b!Z!i%b!Z!m%b!Z#O%b!Z#k%b!Z#l%b!Z#m%b!Z#n%b!Z#o%b!Z#p%b!Z#q%b!Z#r%b!Z#s%b!Z#u%b!Z#w%b!Z#y%b!Z#z%b!Z'u%b!Z([%b!Z(m%b!Z!h%b!Z!V%b!Z's%b!Z#]%b!Zs%b!Z![%b!Z%f%b!Z!d%b!Z~P#.hOo;PO!d#vO(m'mO~O!V;QO~P#.hOo;XO!d#vO(m'mO~O!V;YO~P#.hOP%b!ZR%b!Z[%b!Zo%b!Z!i%b!Z!m%b!Z#O%b!Z#k%b!Z#l%b!Z#m%b!Z#n%b!Z#o%b!Z#p%b!Z#q%b!Z#r%b!Z#s%b!Z#u%b!Z#w%b!Z#y%b!Z#z%b!Z#}%b!Z([%b!Z(m%b!Z!Y%b!Z!Z%b!Z~P&NzOo;]O!d#vO(m'mO~Os(aX~P1qO}%pO~P!(vO(P!lO~P!(vO!VfX!YfX#]fX~P&+`OP]XR]X[]Xo]X}]X!P]X!Y]X!YfX!i]X!m]X#O]X#P]X#]]X#]fX#hfX#k]X#l]X#m]X#n]X#o]X#p]X#q]X#r]X#s]X#u]X#w]X#y]X#z]X$P]X([]X(m]X(t]X(u]X~O!dfX!h]X!hfX(mfX~P'D^OP;aOQ;aOSfOd=[Oe!iOmkOo;aOpkOqkOwkOy;aO{;aO!PWO!TkO!UkO![XO!f;dO!iZO!l;aO!m;aO!n;aO!p;eO!r;hO!u!hO$V!kO(O)YO(QTO(TUO([VO(j[O(y=YO~O!Y;tO!Z$oa~Oh%VOm%WOo%XOp$tOq$tOw%YOy%ZO{<PO!P${O![$|O!f=aO!i$xO#g<VO$V%_O$r<RO$t<TO$w%`O(O(sO(QTO(TUO([$uO(t$}O(u%PO~O#t)aO~P'ISOo!bX(m!bX~P# bO!Z]X!ZfX~P'D^O!VfX!V$xX!YfX!Y$xX#]fX~P!/nO#h;iO~O!d#vO#h;iO~O#];yO~O#s;mO~O#]<YO!Y(rX!Z(rX~O#];yO!Y(pX!Z(pX~O#h<ZO~Og<]O~P!0rO#h<cO~O#h<dO~O!d#vO#h<eO~O!d#vO#h<ZO~O#}<fO~P#AiO#h<gO~O#h<hO~O#h<mO~O#h<nO~O#h<oO~O#h<pO~O#}<qO~P!0rO#}<rO~P!0rO#P#Q#R#T#U#X#f#g#r(y$r$t$w%Z%e%f%g%n%p%s%t%v%x~'yT#l!U'w(P#mp#k#no}'x$['x(O$^(`~",
  goto: "$5g)XPPPPPP)YPP)]P)nP+O/PPPPP5{PP6cPP<Y?sP@WP@WPPP@WPB[P@WP@WP@WPB`PBePCSPG{PPPHPPPPPHPKRPPPKXLTPHPPHPPPNcHPPPPHPPHPP!!jHPP!&P!'U!'_P!(R!(V!(R!+cPPPPPPP!,S!'UPP!,d!-xP!1THPHP!1Y!4e!8{!8{!<yPPP!=RHPPPPPPPPPPPP!@aP!AnPPHP!CPPHPPHPHPHPHPHPPHP!DcP!GlP!JqP!Ju!KP!KT!KTP!GiP!KX!KXP!N^P!NbHPHP!Nh##lB`@WP@WP@W@WP#$x@W@W#'W@W#)z@W#,S@W@W#,r#/S#/S#/X#/b#/S#/nP#/SP@W#0W@W#4P@W@W5{PPP#8OPPP#8i#8iP#8iP#9P#8iPP#9VP#8|P#8|#9j#8|#:U#:[5x)]#:_)]P#:f#:f#:fP)]P)]P)]P)]PP)]P#:l#:oP#:o)]P#:sP#:vP)]P)]P)]P)]P)]P)])]PP#:|#;S#;_#;e#;k#;q#;w#<V#<]#<g#<m#<w#<}#=_#=e#>V#>i#>o#>u#?T#?j#A]#Ak#Ar#C[#Cj#EY#Eh#En#Et#Ez#FU#F[#Fb#Fl#GO#GUPPPPPPPPPP#G[PPPPPPP#HP#KW#Lg#Ln#LvPPP$$YP$$c$'Z$-s$-v$-y$.f$.i$.p$.xP$/O$/RP$/o$/s$0k$1y$2O$2fPP$2k$2q$2uP$2x$2|$3Q$3v$4_$4v$4z$4}$5Q$5W$5Z$5_$5cR!|RoqOXst!Z#d%k&o&q&r&t,l,q2O2RY!vQ']-^1c5gQ%rvQ%zyQ&R|Q&g!VS'T!e-UQ'c!iS'i!r!yU*f$|*W*kQ+j%{Q+w&TQ,]&aQ-['[Q-f'dQ-n'jQ0T*mQ1m,^R<W;e%QdOPWXYZstuvw!Z!`!g!o#S#W#Z#d#o#u#x#{$O$P$Q$R$S$T$U$V$W$X$_$a$e%k%r&P&h&k&o&q&r&t&x'Q'_'o(Q(S(Y(a(u(w({)z+S+W,i,l,q-b-j-x.O.m.t/h0c0i0x1f1v1w1y1{2O2R2T2t2z3`5d5o6P6Q6T6h8T8Z8j8tS#q];b!r)[$Z$n'U)p,}-Q/O2d3w5b6_9k9|;a;d;e;h;i;j;k;l;m;n;o;p;q;r;s;t;v;y<W<Y<Z<]<e<f<o<p=]U*z%[<O<PQ+o%}Q,_&dQ,f&lQ0o+bQ0s+dQ1O+pQ1u,dQ3S.`Q5Q0yQ5v1nQ6t3WQ7u5RR8z6v'OkOPWXYZstuvw!Z!`!g!o#S#W#Z#d#o#u#x#{$O$P$Q$R$S$T$U$V$W$X$Z$_$a$e$n%k%r&P&h&k&l&o&q&r&t&x'Q'U'_'o(Q(S(Y(a(u(w({)p)z+S+W+b,i,l,q,}-Q-b-j-x.O.`.m.t/O/h0c0i0x1f1v1w1y1{2O2R2T2d2t2z3W3`3w5b5d5o6P6Q6T6_6h6v8T8Z8j8t9k9|;a;d;e;h;i;j;k;l;m;n;o;p;q;r;s;t;v;y<W<Y<Z<]<e<f<o<p=]t!nQ!r!v!y!z'T'[']'i'j'k-U-[-^-n1c5g5i%S$ti#v$b$c$d$x${%O%Q%]%^%b)v)|*O*Q*S*V*]*c*s*t+a+d+{,O._.x/_/g/q/r/t0X0Z0f1Y1]1e3V4P4[4d4o4w4z5n6r7a7j8W8w9V9`9e9o:R:`:h:p:w;w;x;z;{;|;}<Q<R<S<T<U<V<^<_<`<a<c<d<g<h<i<j<k<l<m<n<q<r=Y=b=c=f=gQ&U|Q'R!eU'X%g*W-XQ+o%}Q,_&dQ0e*}Q1O+pQ1T+vQ1t,cQ1u,dQ5Q0yQ5Z1VQ5v1nQ5y1pQ5z1sQ7u5RQ7x5WQ8c5|Q9j7yR9u8`rnOXst!V!Z#d%k&f&o&q&r&t,l,q2O2RR,a&h&x^OPXYstuvwz!Z!`!g!j!o#S#d#o#u#x#{$O$P$Q$R$S$T$U$V$W$X$Z$_$a$e$n%k%r&P&h&k&l&o&q&r&t&x'Q'_'o(S(Y(a(u(w({)p)z+S+W+b,i,l,q,}-Q-b-j-x.O.`.m.t/O/h0c0i0x1f1v1w1y1{2O2R2T2d2t2z3W3`3w5b5d5o6P6Q6T6_6h6v8T8Z8j8t9k9|;a;d;e;h;i;j;k;l;m;n;o;p;q;r;s;t;v;y<W<Y<Z<]<e<f<o<p=[=][#]WZ#W#Z'U(Q!b%hm#h#i#l$x%c%f(Z(e(f(g*V*Z*^+U+V+X,h-O-|.S.T.U.W/g/j2W3O3P4S6^6oQ%uxQ%yyS&O|&TQ&[!TQ'`!hQ'b!iQ(n#sS+i%z%{Q+m%}Q,W&_Q,[&aS-e'c'dQ.b(oQ0w+jQ0}+pQ1P+qQ1S+uQ1h,XS1l,],^Q2p-fQ5P0yQ5T0|Q5Y1UQ5u1mQ7t5RQ7w5VQ9f7sR:c9g!O$zi$d%O%Q%]%^%b*O*Q*]*s*t.x/q0X0Z0f4P4o9V=Y=b=c!S%wy!i!u%y%z%{'S'b'c'd'h'r*e+i+j-R-e-f-m/{0w2i2p2w4fQ+c%uQ+|&XQ,P&YQ,Z&aQ.a(nQ1g,WU1k,[,],^Q3X.bQ5p1hS5t1l1mQ8_5u#d=^#v$b$c$x${)v)|*S*V*c+a+d+{,O._/_/g/r/t1Y1]1e3V4[4d4w4z5n6r7a7j8W8w9`9e9o:R:`:h:p:w;z;|<Q<S<U<^<`<c<g<i<k<m<q=f=go=_;w;x;{;}<R<T<V<_<a<d<h<j<l<n<rW%Ti%V*u=YS&X!Q&fQ&Y!RQ&Z!SR+z&V%T%Si#v$b$c$d$x${%O%Q%]%^%b)v)|*O*Q*S*V*]*c*s*t+a+d+{,O._.x/_/g/q/r/t0X0Z0f1Y1]1e3V4P4[4d4o4w4z5n6r7a7j8W8w9V9`9e9o:R:`:h:p:w;w;x;z;{;|;}<Q<R<S<T<U<V<^<_<`<a<c<d<g<h<i<j<k<l<m<n<q<r=Y=b=c=f=gT)w$u)xV*z%[<O<PW'X!e%g*W-XS(z#y#zQ+^%pQ+t&QS.Z(j(kQ1^,QQ4p0bR7}5`'OkOPWXYZstuvw!Z!`!g!o#S#W#Z#d#o#u#x#{$O$P$Q$R$S$T$U$V$W$X$Z$_$a$e$n%k%r&P&h&k&l&o&q&r&t&x'Q'U'_'o(Q(S(Y(a(u(w({)p)z+S+W+b,i,l,q,}-Q-b-j-x.O.`.m.t/O/h0c0i0x1f1v1w1y1{2O2R2T2d2t2z3W3`3w5b5d5o6P6Q6T6_6h6v8T8Z8j8t9k9|;a;d;e;h;i;j;k;l;m;n;o;p;q;r;s;t;v;y<W<Y<Z<]<e<f<o<p=]$i$^c#Y#e%o%q%s(P(V(q(v)O)P)Q)R)S)T)U)V)W)X)Z)])_)d)n+_+s-S-q-v-{-}.l.o.s.u.v.w/Z0g2_2b2r2y3_3d3e3f3g3h3i3j3k3l3m3n3o3p3s3t3{4t4}6a6g6l6{6|7V7W8P8n8r8|9S9T:O:e:l;c=PT#TV#U'PkOPWXYZstuvw!Z!`!g!o#S#W#Z#d#o#u#x#{$O$P$Q$R$S$T$U$V$W$X$Z$_$a$e$n%k%r&P&h&k&l&o&q&r&t&x'Q'U'_'o(Q(S(Y(a(u(w({)p)z+S+W+b,i,l,q,}-Q-b-j-x.O.`.m.t/O/h0c0i0x1f1v1w1y1{2O2R2T2d2t2z3W3`3w5b5d5o6P6Q6T6_6h6v8T8Z8j8t9k9|;a;d;e;h;i;j;k;l;m;n;o;p;q;r;s;t;v;y<W<Y<Z<]<e<f<o<p=]Q'V!eR2e-Uv!nQ!e!r!v!y!z'T'[']'i'j'k-U-[-^-n1c5g5iU*e$|*W*kS/{*f*mQ0U*nQ1`,SQ4f0TR4i0WnqOXst!Z#d%k&o&q&r&t,l,q2O2RQ&v!^Q's!xS(p#u;iQ+g%xQ,U&[Q,V&^Q-c'aQ-p'lS.k(u<ZS0h+S<eQ0u+hQ1b,TQ2V,sQ2X,tQ2a-PQ2n-dQ2q-hS4u0i<oQ4{0vS5O0x<pQ6`2cQ6d2oQ6i2vQ7r4|Q8o6bQ8p6eQ8s6jR9{8l$d$]c#Y#e%q%s(P(V(q(v)O)P)Q)R)S)T)U)V)W)X)Z)])_)d)n+_+s-S-q-v-{-}.l.o.s.v.w/Z0g2_2b2r2y3_3d3e3f3g3h3i3j3k3l3m3n3o3p3s3t3{4t4}6a6g6l6{6|7V7W8P8n8r8|9S9T:O:e:l;c=PS(l#p'fQ(|#zS+]%o.uS.[(k(mR3Q.]'OkOPWXYZstuvw!Z!`!g!o#S#W#Z#d#o#u#x#{$O$P$Q$R$S$T$U$V$W$X$Z$_$a$e$n%k%r&P&h&k&l&o&q&r&t&x'Q'U'_'o(Q(S(Y(a(u(w({)p)z+S+W+b,i,l,q,}-Q-b-j-x.O.`.m.t/O/h0c0i0x1f1v1w1y1{2O2R2T2d2t2z3W3`3w5b5d5o6P6Q6T6_6h6v8T8Z8j8t9k9|;a;d;e;h;i;j;k;l;m;n;o;p;q;r;s;t;v;y<W<Y<Z<]<e<f<o<p=]S#q];bQ&q!XQ&r!YQ&t![Q&u!]R1},oQ'^!hQ+`%uQ-a'`S.^(n+cQ2l-`W3U.a.b0n0pQ6c2mW6p3R3T3X4yU8v6q6s6uU:Q8x8y8{S:n:P:SQ:{:oR;T:|U!wQ']-^T5e1c5g!Q_OXZ`st!V!Z#d#h%c%k&f&h&o&q&r&t(g,l,q.T2O2R]!pQ!r']-^1c5gT#q];b%[{OPWXYZstuvw!Z!`!g!o#S#W#Z#d#o#u#x#{$O$P$Q$R$S$T$U$V$W$X$_$a$e%k%r&P&h&k&l&o&q&r&t&x'Q'_'o(Q(S(Y(a(u(w({)z+S+W+b,i,l,q-b-j-x.O.`.m.t/h0c0i0x1f1v1w1y1{2O2R2T2t2z3W3`5d5o6P6Q6T6h6v8T8Z8j8tS(z#y#zS.Z(j(k!s<v$Z$n'U)p,}-Q/O2d3w5b6_9k9|;a;d;e;h;i;j;k;l;m;n;o;p;q;r;s;t;v;y<W<Y<Z<]<e<f<o<p=]U$fd)[,fS(m#p'fU*r%R(t3rU0d*y.g7RQ4y0oQ6q3SQ8y6tR:S8zm!tQ!r!v!y!z']'i'j'k-^-n1c5g5iQ'q!uS(c#g1xS-l'h'tQ/m*YQ/y*eQ2x-oQ4W/nS4a/z0UQ7]4RS7h4g4iQ9X7^Q9]7eQ9c7kS:[9^9_S:s:]:_S;O:t:uS;W;P;QS;[;X;YR;_;]Q#wbQ'p!uS(b#g1xS(d#m+RQ+T%dQ+e%vQ+k%|U-k'h'q'tQ.P(cQ/l*YQ/x*eQ0O*hQ0t+fQ1i,YS2u-l-oQ2}.XS4V/m/nS4`/y0UQ4c/}Q4e0PQ5r1jQ6k2xQ7[4RQ7`4WS7d4a4iQ7i4hQ8]5sS9W7]7^Q9[7eQ9a7hQ9d7lQ9r8^Q:Y9XS:Z9]9_Q:a9cQ:j9sS:r:[:_S:}:s:tS;V;O;QS;Z;W;YQ;^;[Q;`;_Q<y<tQ=U<}R=V=OV!wQ']-^%[aOPWXYZstuvw!Z!`!g!o#S#W#Z#d#o#u#x#{$O$P$Q$R$S$T$U$V$W$X$_$a$e%k%r&P&h&k&l&o&q&r&t&x'Q'_'o(Q(S(Y(a(u(w({)z+S+W+b,i,l,q-b-j-x.O.`.m.t/h0c0i0x1f1v1w1y1{2O2R2T2t2z3W3`5d5o6P6Q6T6h6v8T8Z8j8tS#wz!j!r<s$Z$n'U)p,}-Q/O2d3w5b6_9k9|;a;d;e;h;i;j;k;l;m;n;o;p;q;r;s;t;v;y<W<Y<Z<]<e<f<o<p=]R<y=[%[bOPWXYZstuvw!Z!`!g!o#S#W#Z#d#o#u#x#{$O$P$Q$R$S$T$U$V$W$X$_$a$e%k%r&P&h&k&l&o&q&r&t&x'Q'_'o(Q(S(Y(a(u(w({)z+S+W+b,i,l,q-b-j-x.O.`.m.t/h0c0i0x1f1v1w1y1{2O2R2T2t2z3W3`5d5o6P6Q6T6h6v8T8Z8j8tQ%dj!S%vy!i!u%y%z%{'S'b'c'd'h'r*e+i+j-R-e-f-m/{0w2i2p2w4fS%|z!jQ+f%wQ,Y&aW1j,Z,[,],^U5s1k1l1mS8^5t5uQ9s8_!r<t$Z$n'U)p,}-Q/O2d3w5b6_9k9|;a;d;e;h;i;j;k;l;m;n;o;p;q;r;s;t;v;y<W<Y<Z<]<e<f<o<p=]Q<}=ZR=O=[%OeOPXYstuvw!Z!`!g!o#S#d#o#u#x#{$O$P$Q$R$S$T$U$V$W$X$_$a$e%k%r&P&h&k&o&q&r&t&x'Q'_'o(S(Y(a(u(w({)z+S+W+b,i,l,q-b-j-x.O.`.m.t/h0c0i0x1f1v1w1y1{2O2R2T2t2z3W3`5d5o6P6Q6T6h6v8T8Z8j8tY#bWZ#W#Z(Q!b%hm#h#i#l$x%c%f(Z(e(f(g*V*Z*^+U+V+X,h-O-|.S.T.U.W/g/j2W3O3P4S6^6oQ,g&l!p<u$Z$n)p,}-Q/O2d3w5b6_9k9|;a;d;e;h;i;j;k;l;m;n;o;p;q;r;s;t;v;y<W<Y<Z<]<e<f<o<p=]R<x'UU'Y!e%g*WR2g-X%QdOPWXYZstuvw!Z!`!g!o#S#W#Z#d#o#u#x#{$O$P$Q$R$S$T$U$V$W$X$_$a$e%k%r&P&h&k&o&q&r&t&x'Q'_'o(Q(S(Y(a(u(w({)z+S+W,i,l,q-b-j-x.O.m.t/h0c0i0x1f1v1w1y1{2O2R2T2t2z3`5d5o6P6Q6T6h8T8Z8j8t!r)[$Z$n'U)p,}-Q/O2d3w5b6_9k9|;a;d;e;h;i;j;k;l;m;n;o;p;q;r;s;t;v;y<W<Y<Z<]<e<f<o<p=]Q,f&lQ0o+bQ3S.`Q6t3WR8z6v!b$Tc#Y%o(P(V(q(v)W)X)])d+s-q-v-{-}.l.o/Z0g2r2y3_3o4t4}6g6l6{8r:O;c!P;o)Z)n-S.u2_2b3d3m3n3s3{6a6|7V7W8P8n8|9S9T:e:l=P!f$Vc#Y%o(P(V(q(v)T)U)W)X)])d+s-q-v-{-}.l.o/Z0g2r2y3_3o4t4}6g6l6{8r:O;c!T;q)Z)n-S.u2_2b3d3j3k3m3n3s3{6a6|7V7W8P8n8|9S9T:e:l=P!^$Zc#Y%o(P(V(q(v)])d+s-q-v-{-}.l.o/Z0g2r2y3_3o4t4}6g6l6{8r:O;cQ4P/ez=])Z)n-S.u2_2b3d3s3{6a6|7V7W8P8n8|9S9T:e:l=PQ=b=dR=c=e'OkOPWXYZstuvw!Z!`!g!o#S#W#Z#d#o#u#x#{$O$P$Q$R$S$T$U$V$W$X$Z$_$a$e$n%k%r&P&h&k&l&o&q&r&t&x'Q'U'_'o(Q(S(Y(a(u(w({)p)z+S+W+b,i,l,q,}-Q-b-j-x.O.`.m.t/O/h0c0i0x1f1v1w1y1{2O2R2T2d2t2z3W3`3w5b5d5o6P6Q6T6_6h6v8T8Z8j8t9k9|;a;d;e;h;i;j;k;l;m;n;o;p;q;r;s;t;v;y<W<Y<Z<]<e<f<o<p=]S$oh$pR3x.}'VgOPWXYZhstuvw!Z!`!g!o#S#W#Z#d#o#u#x#{$O$P$Q$R$S$T$U$V$W$X$Z$_$a$e$n$p%k%r&P&h&k&l&o&q&r&t&x'Q'U'_'o(Q(S(Y(a(u(w({)p)z+S+W+b,i,l,q,}-Q-b-j-x.O.`.m.t.}/O/h0c0i0x1f1v1w1y1{2O2R2T2d2t2z3W3`3w5b5d5o6P6Q6T6_6h6v8T8Z8j8t9k9|;a;d;e;h;i;j;k;l;m;n;o;p;q;r;s;t;v;y<W<Y<Z<]<e<f<o<p=]T$kf$qQ$ifS)g$l)kR)s$qT$jf$qT)i$l)k'VhOPWXYZhstuvw!Z!`!g!o#S#W#Z#d#o#u#x#{$O$P$Q$R$S$T$U$V$W$X$Z$_$a$e$n$p%k%r&P&h&k&l&o&q&r&t&x'Q'U'_'o(Q(S(Y(a(u(w({)p)z+S+W+b,i,l,q,}-Q-b-j-x.O.`.m.t.}/O/h0c0i0x1f1v1w1y1{2O2R2T2d2t2z3W3`3w5b5d5o6P6Q6T6_6h6v8T8Z8j8t9k9|;a;d;e;h;i;j;k;l;m;n;o;p;q;r;s;t;v;y<W<Y<Z<]<e<f<o<p=]T$oh$pQ$rhR)r$p%[jOPWXYZstuvw!Z!`!g!o#S#W#Z#d#o#u#x#{$O$P$Q$R$S$T$U$V$W$X$_$a$e%k%r&P&h&k&l&o&q&r&t&x'Q'_'o(Q(S(Y(a(u(w({)z+S+W+b,i,l,q-b-j-x.O.`.m.t/h0c0i0x1f1v1w1y1{2O2R2T2t2z3W3`5d5o6P6Q6T6h6v8T8Z8j8t!s=Z$Z$n'U)p,}-Q/O2d3w5b6_9k9|;a;d;e;h;i;j;k;l;m;n;o;p;q;r;s;t;v;y<W<Y<Z<]<e<f<o<p=]#elOPXZst!Z!`!o#S#d#o#{$n%k&h&k&l&o&q&r&t&x'Q'_({)p+W+b,i,l,q-b.`/O/h0c1f1v1w1y1{2O2R2T3W3w5d5o6P6Q6T6v8T8Z8j!O%Ri$d%O%Q%]%^%b*O*Q*]*s*t.x/q0X0Z0f4P4o9V=Y=b=c#d(t#v$b$c$x${)v)|*S*V*c+a+d+{,O._/_/g/r/t1Y1]1e3V4[4d4w4z5n6r7a7j8W8w9`9e9o:R:`:h:p:w;z;|<Q<S<U<^<`<c<g<i<k<m<q=f=gQ+O%`Q/[){o3r;w;x;{;}<R<T<V<_<a<d<h<j<l<n<r!O$yi$d%O%Q%]%^%b*O*Q*]*s*t.x/q0X0Z0f4P4o9V=Y=b=cQ*_$zU*h$|*W*kQ+P%aQ0P*i#d<{#v$b$c$x${)v)|*S*V*c+a+d+{,O._/_/g/r/t1Y1]1e3V4[4d4w4z5n6r7a7j8W8w9`9e9o:R:`:h:p:w;z;|<Q<S<U<^<`<c<g<i<k<m<q=f=gn<|;w;x;{;}<R<T<V<_<a<d<h<j<l<n<rQ=Q=^Q=R=_Q=S=`R=T=a!O%Ri$d%O%Q%]%^%b*O*Q*]*s*t.x/q0X0Z0f4P4o9V=Y=b=c#d(t#v$b$c$x${)v)|*S*V*c+a+d+{,O._/_/g/r/t1Y1]1e3V4[4d4w4z5n6r7a7j8W8w9`9e9o:R:`:h:p:w;z;|<Q<S<U<^<`<c<g<i<k<m<q=f=go3r;w;x;{;}<R<T<V<_<a<d<h<j<l<n<rnoOXst!Z#d%k&o&q&r&t,l,q2O2RS*b${*VQ,z&{Q,{&}R4Z/r%S%Si#v$b$c$d$x${%O%Q%]%^%b)v)|*O*Q*S*V*]*c*s*t+a+d+{,O._.x/_/g/q/r/t0X0Z0f1Y1]1e3V4P4[4d4o4w4z5n6r7a7j8W8w9V9`9e9o:R:`:h:p:w;w;x;z;{;|;}<Q<R<S<T<U<V<^<_<`<a<c<d<g<h<i<j<k<l<m<n<q<r=Y=b=c=f=gQ+}&YQ1[,PQ5^1ZR7|5_V*j$|*W*kU*j$|*W*kT5f1c5gU/}*g/h5dS4h0V8TR7l4jQ+e%vQ0O*hQ0t+fQ1i,YQ5r1jQ8]5sQ9r8^R:j9s!O%Oi$d%O%Q%]%^%b*O*Q*]*s*t.x/q0X0Z0f4P4o9V=Y=b=cr*O$v)b*P*q+Q/p0]0^3u4X4s7Z7m:X<z=W=XS0X*p0Y#d;z#v$b$c$x${)v)|*S*V*c+a+d+{,O._/_/g/r/t1Y1]1e3V4[4d4w4z5n6r7a7j8W8w9`9e9o:R:`:h:p:w;z;|<Q<S<U<^<`<c<g<i<k<m<q=f=gn;{;w;x;{;}<R<T<V<_<a<d<h<j<l<n<r!f<^(r)`*X*a.c.f.j/W/]/e/u0m1X1Z3[4Y4^5]5_6w6z7b7f7o7q9Z9b:^:b:q:v;R=d=e`<_3q6}7Q7U8}:T:W;US<i.e3]T<j7P9Q!O%Qi$d%O%Q%]%^%b*O*Q*]*s*t.x/q0X0Z0f4P4o9V=Y=b=cv*Q$v)b*R*p+Q/a/p0]0^3u4X4k4s7Z7m:X<z=W=XS0Z*q0[#d;|#v$b$c$x${)v)|*S*V*c+a+d+{,O._/_/g/r/t1Y1]1e3V4[4d4w4z5n6r7a7j8W8w9`9e9o:R:`:h:p:w;z;|<Q<S<U<^<`<c<g<i<k<m<q=f=gn;};w;x;{;}<R<T<V<_<a<d<h<j<l<n<r!j<`(r)`*X*a.d.e.j/W/]/e/u0m1X1Z3Y3[4Y4^5]5_6w6x6z7b7f7o7q9Z9b:^:b:q:v;R=d=ed<a3q7O7P7U8}9O:T:U:W;US<k.f3^T<l7Q9RrnOXst!V!Z#d%k&f&o&q&r&t,l,q2O2RQ&c!UR,i&lrnOXst!V!Z#d%k&f&o&q&r&t,l,q2O2RR&c!UQ,R&ZR1W+zsnOXst!V!Z#d%k&f&o&q&r&t,l,q2O2RQ1d,WS5m1g1hU8V5k5l5pS9n8X8YS:f9m9pQ:x:gR;S:yQ&j!VR,b&fR5y1pS&O|&TR1P+qQ&o!WR,l&pR,r&uT2P,q2RR,v&vQ,u&vR2Y,vQ'v!{R-r'vSsOtQ#dXT%ns#dQ#OTR'x#OQ#RUR'z#RQ)x$uR/X)xQ#UVR'}#UQ#XWU(T#X(U-yQ(U#YR-y(VQ-V'VR2f-VQ.n(vS3a.n3bR3b.oQ-^']R2j-^Y!rQ']-^1c5gR'g!rQ.y)bR3v.yU#_W%f*VU([#_(]-zQ(]#`R-z(WQ-Y'YR2h-Yt`OXst!V!Z#d%k&f&h&o&q&r&t,l,q2O2RS#hZ%cU#r`#h.TR.T(gQ(h#jQ.Q(dW.Y(h.Q2{6mQ2{.RR6m2|Q)k$lR/P)kQ$phR)q$pQ$`cU)^$`-u;uQ-u;cR;u)nQ/k*YW4T/k4U7_9YU4U/l/m/nS7_4V4WR9Y7`$a)}$v(r)`)b*X*a*p*q*{*|+Q.e.f.h.i.j/W/]/a/c/e/p/u0]0^0m1X1Z3Y3Z3[3q3u4X4Y4^4k4m4s5]5_6w6x6y6z7P7Q7S7T7U7Z7b7f7m7o7q8}9O9P9Z9b:T:U:V:W:X:^:b:q:v;R;U<z=W=X=d=eQ/s*aU4]/s4_7cQ4_/uR7c4^S*k$|*WR0R*kr*P$v)b*p*q+Q/p0]0^3u4X4s7Z7m:X<z=W=X!f.c(r)`*X*a.e.f.j/W/]/e/u0m1X1Z3[4Y4^5]5_6w6z7b7f7o7q9Z9b:^:b:q:v;R=d=eU/b*P.c6}a6}3q7P7Q7U8}:T:W;UQ0Y*pQ3].eU4l0Y3]9QR9Q7Pv*R$v)b*p*q+Q/a/p0]0^3u4X4k4s7Z7m:X<z=W=X!j.d(r)`*X*a.e.f.j/W/]/e/u0m1X1Z3Y3[4Y4^5]5_6w6x6z7b7f7o7q9Z9b:^:b:q:v;R=d=eU/d*R.d7Oe7O3q7P7Q7U8}9O:T:U:W;UQ0[*qQ3^.fU4n0[3^9RR9R7QQ*v%UR0`*vQ4x0mR7p4xQ+Y%iR0l+YQ5a1^S8O5a9lR9l8PQ,T&[R1a,TQ5g1cR8R5gQ1o,_S5w1o8aR8a5yQ0z+mW5S0z5U7v9hQ5U0}Q7v5TR9h7wQ+r&OR1Q+rQ2R,qR6X2RYrOXst#dQ&s!ZQ+[%kQ,k&oQ,m&qQ,n&rQ,p&tQ1|,lS2P,q2RR6W2OQ%mpQ&w!_Q&z!aQ&|!bQ'O!cQ'n!uQ+Z%jQ+g%xQ+y&UQ,a&jQ,x&yW-i'h'p'q'tQ-p'lQ0Q*jQ0u+hS1r,b,eQ2Z,wQ2[,zQ2],{Q2q-hW2s-k-l-o-qQ4{0vQ5X1TQ5[1XQ5q1iQ5{1tQ6V1}U6f2r2u2xQ6i2vQ7r4|Q7z5ZQ7{5]Q8Q5fQ8[5rQ8b5zS8q6g6kQ8s6jQ9i7xQ9q8]Q9v8cQ9}8rQ:d9jQ:i9rQ:m:OR:z:jQ%xyQ'a!iQ'l!uU+h%y%z%{Q-P'SU-d'b'c'dS-h'h'rQ/w*eS0v+i+jQ2c-RS2o-e-fQ2v-mQ4b/{Q4|0wQ6b2iQ6e2pQ6j2wR7g4fS$wi=YR*w%VU%Ui%V=YR0_*uQ$viS(r#v+dS)`$b$cQ)b$dQ*X$xS*a${*VQ*p%OQ*q%QQ*{%]Q*|%^Q+Q%bQ.e;zQ.f;|Q.h<QQ.i<SQ.j<UQ/W)vS/])|/_Q/a*OQ/c*QQ/e*SQ/p*]S/u*c/gQ0]*sQ0^*th0m+a._1e3V5n6r8W8w9o:R:h:pQ1X+{Q1Z,OQ3Y<^Q3Z<`Q3[<cS3q;w;xQ3u.xQ4X/qQ4Y/rQ4^/tQ4k0XQ4m0ZQ4s0fQ5]1YQ5_1]Q6w<gQ6x<iQ6y<kQ6z<mQ7P;{Q7Q;}Q7S<RQ7T<TQ7U<VQ7Z4PQ7b4[Q7f4dQ7m4oQ7o4wQ7q4zQ8}<dQ9O<_Q9P<aQ9Z7aQ9b7jQ:T<hQ:U<jQ:V<lQ:W<nQ:X9VQ:^9`Q:b9eQ:q<qQ:v:`Q;R:wQ;U<rQ<z=YQ=W=bQ=X=cQ=d=fR=e=gQ*y%[Q.g<OR7R<PnpOXst!Z#d%k&o&q&r&t,l,q2O2RQ!fPS#fZ#oQ&y!`U'e!o5d8TQ'|#SQ(}#{Q)o$nS,e&h&kQ,j&lQ,w&xQ,|'QQ-`'_Q.q({Q/T)pS0j+W/hQ0p+bQ1z,iQ2m-bQ3T.`Q3z/OQ4q0cQ5l1fQ5}1vQ6O1wQ6S1yQ6U1{Q6Z2TQ6u3WQ7X3wQ8Y5oQ8f6PQ8g6QQ8i6TQ8{6vQ9p8ZR9z8j#YcOPXZst!Z!`!o#d#o#{%k&h&k&l&o&q&r&t&x'Q'_({+W+b,i,l,q-b.`/h0c1f1v1w1y1{2O2R2T3W5d5o6P6Q6T6v8T8Z8jQ#YWQ#eYQ%ouQ%qvS%sw!gS(P#W(SQ(V#ZQ(q#uQ(v#xQ)O$OQ)P$PQ)Q$QQ)R$RQ)S$SQ)T$TQ)U$UQ)V$VQ)W$WQ)X$XQ)Z$ZQ)]$_Q)_$aQ)d$eW)n$n)p/O3wQ+_%rQ+s&PS-S'U2dQ-q'oS-v(Q-xQ-{(YQ-}(aQ.l(uQ.o(wQ.s;aQ.u;dQ.v;eQ.w;hQ/Z)zQ0g+SQ2_,}Q2b-QQ2r-jQ2y.OQ3_.mQ3d;iQ3e;jQ3f;kQ3g;lQ3h;mQ3i;nQ3j;oQ3k;pQ3l;qQ3m;rQ3n;sQ3o.tQ3p;vQ3s;yQ3t<WQ3{;tQ4t0iQ4}0xQ6a<YQ6g2tQ6l2zQ6{3`Q6|<ZQ7V<]Q7W<eQ8P5bQ8n6_Q8r6hQ8|<fQ9S<oQ9T<pQ:O8tQ:e9kQ:l9|Q;c#SR=P=]R#[WR'W!el!tQ!r!v!y!z']'i'j'k-^-n1c5g5iS'S!e-US-R'T'[R2i-[R(x#xQ!fQT-]']-^]!qQ!r']-^1c5gQ#p]R'f;bR)c$dY!uQ']-^1c5gQ'h!rS'r!v!yS't!z5iS-m'i'jQ-o'kR2w-nT#kZ%cS#jZ%cS%im,hU(d#h#i#lS.R(e(fQ.V(gQ0k+XQ2|.SU2}.T.U.WS6n3O3PR8u6od#^W#W#Z%f(Q(Z*V+U-|/gr#gZm#h#i#l%c(e(f(g+X.S.T.U.W3O3P6oS*Y$x*^Q/n*ZQ1x,hQ2`-OQ4R/jQ6]2WQ7^4SQ8m6^T<w'U+VV#aW%f*VU#`W%f*VS(R#W(ZU(W#Z+U/gS-T'U+VT-w(Q-|V'Z!e%g*WQ$lfR)u$qT)j$l)kR3y.}T*[$x*^T*d${*VQ0n+aQ3R._Q5k1eQ6s3VQ8X5nQ8x6rQ9m8WQ:P8wQ:g9oQ:o:RQ:y:hR:|:pnqOXst!Z#d%k&o&q&r&t,l,q2O2RQ&i!VR,a&ftmOXst!U!V!Z#d%k&f&o&q&r&t,l,q2O2RR,h&lT%jm,hR1_,QR,`&dQ&S|R+x&TR+n%}T&m!W&pT&n!W&pT2Q,q2R",
  nodeNames: "⚠ ArithOp ArithOp ?. JSXStartTag LineComment BlockComment Script Hashbang ExportDeclaration export Star as VariableName String Escape from ; default FunctionDeclaration async function VariableDefinition > < TypeParamList TypeDefinition extends ThisType this LiteralType ArithOp Number BooleanLiteral TemplateType InterpolationEnd Interpolation InterpolationStart NullType null VoidType void TypeofType typeof MemberExpression . PropertyName [ TemplateString Escape Interpolation super RegExp ] ArrayExpression Spread , } { ObjectExpression Property async get set PropertyDefinition Block : NewTarget new NewExpression ) ( ArgList UnaryExpression delete LogicOp BitOp YieldExpression yield AwaitExpression await ParenthesizedExpression ClassExpression class ClassBody MethodDeclaration Decorator @ MemberExpression PrivatePropertyName CallExpression TypeArgList CompareOp < declare Privacy static abstract override PrivatePropertyDefinition PropertyDeclaration readonly accessor Optional TypeAnnotation Equals StaticBlock FunctionExpression ArrowFunction ParamList ParamList ArrayPattern ObjectPattern PatternProperty Privacy readonly Arrow MemberExpression BinaryExpression ArithOp ArithOp ArithOp ArithOp BitOp CompareOp instanceof satisfies in const CompareOp BitOp BitOp BitOp LogicOp LogicOp ConditionalExpression LogicOp LogicOp AssignmentExpression UpdateOp PostfixExpression CallExpression InstantiationExpression TaggedTemplateExpression DynamicImport import ImportMeta JSXElement JSXSelfCloseEndTag JSXSelfClosingTag JSXIdentifier JSXBuiltin JSXIdentifier JSXNamespacedName JSXMemberExpression JSXSpreadAttribute JSXAttribute JSXAttributeValue JSXEscape JSXEndTag JSXOpenTag JSXFragmentTag JSXText JSXEscape JSXStartCloseTag JSXCloseTag PrefixCast ArrowFunction TypeParamList SequenceExpression InstantiationExpression KeyofType keyof UniqueType unique ImportType InferredType infer TypeName ParenthesizedType FunctionSignature ParamList NewSignature IndexedType TupleType Label ArrayType ReadonlyType ObjectType MethodType PropertyType IndexSignature PropertyDefinition CallSignature TypePredicate is NewSignature new UnionType LogicOp IntersectionType LogicOp ConditionalType ParameterizedType ClassDeclaration abstract implements type VariableDeclaration let var using TypeAliasDeclaration InterfaceDeclaration interface EnumDeclaration enum EnumBody NamespaceDeclaration namespace module AmbientDeclaration declare GlobalDeclaration global ClassDeclaration ClassBody AmbientFunctionDeclaration ExportGroup VariableName VariableName ImportDeclaration ImportGroup ForStatement for ForSpec ForInSpec ForOfSpec of WhileStatement while WithStatement with DoStatement do IfStatement if else SwitchStatement switch SwitchBody CaseLabel case DefaultLabel TryStatement try CatchClause catch FinallyClause finally ReturnStatement return ThrowStatement throw BreakStatement break ContinueStatement continue DebuggerStatement debugger LabeledStatement ExpressionStatement SingleExpression SingleClassItem",
  maxTerm: 376,
  context: trackNewline,
  nodeProps: [
    ["isolate", -8,5,6,14,34,36,48,50,52,""],
    ["group", -26,9,17,19,65,204,208,212,213,215,218,221,231,233,239,241,243,245,248,254,260,262,264,266,268,270,271,"Statement",-34,13,14,29,32,33,39,48,51,52,54,59,67,69,73,77,79,81,82,107,108,117,118,135,138,140,141,142,143,144,146,147,166,167,169,"Expression",-23,28,30,34,38,40,42,171,173,175,176,178,179,180,182,183,184,186,187,188,198,200,202,203,"Type",-3,85,100,106,"ClassItem"],
    ["openedBy", 23,"<",35,"InterpolationStart",53,"[",57,"{",70,"(",159,"JSXStartCloseTag"],
    ["closedBy", 24,">",37,"InterpolationEnd",47,"]",58,"}",71,")",164,"JSXEndTag"]
  ],
  propSources: [jsHighlight],
  skippedNodes: [0,5,6,274],
  repeatNodeCount: 37,
  tokenData: "$Fq07[R!bOX%ZXY+gYZ-yZ[+g[]%Z]^.c^p%Zpq+gqr/mrs3cst:_tuEruvJSvwLkwx! Yxy!'iyz!(sz{!)}{|!,q|}!.O}!O!,q!O!P!/Y!P!Q!9j!Q!R#:O!R![#<_![!]#I_!]!^#Jk!^!_#Ku!_!`$![!`!a$$v!a!b$*T!b!c$,r!c!}Er!}#O$-|#O#P$/W#P#Q$4o#Q#R$5y#R#SEr#S#T$7W#T#o$8b#o#p$<r#p#q$=h#q#r$>x#r#s$@U#s$f%Z$f$g+g$g#BYEr#BY#BZ$A`#BZ$ISEr$IS$I_$A`$I_$I|Er$I|$I}$Dk$I}$JO$Dk$JO$JTEr$JT$JU$A`$JU$KVEr$KV$KW$A`$KW&FUEr&FU&FV$A`&FV;'SEr;'S;=`I|<%l?HTEr?HT?HU$A`?HUOEr(n%d_$h&j(Rp(U!bOY%ZYZ&cZr%Zrs&}sw%Zwx(rx!^%Z!^!_*g!_#O%Z#O#P&c#P#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z&j&hT$h&jO!^&c!_#o&c#p;'S&c;'S;=`&w<%lO&c&j&zP;=`<%l&c'|'U]$h&j(U!bOY&}YZ&cZw&}wx&cx!^&}!^!_'}!_#O&}#O#P&c#P#o&}#o#p'}#p;'S&};'S;=`(l<%lO&}!b(SU(U!bOY'}Zw'}x#O'}#P;'S'};'S;=`(f<%lO'}!b(iP;=`<%l'}'|(oP;=`<%l&}'[(y]$h&j(RpOY(rYZ&cZr(rrs&cs!^(r!^!_)r!_#O(r#O#P&c#P#o(r#o#p)r#p;'S(r;'S;=`*a<%lO(rp)wU(RpOY)rZr)rs#O)r#P;'S)r;'S;=`*Z<%lO)rp*^P;=`<%l)r'[*dP;=`<%l(r#S*nX(Rp(U!bOY*gZr*grs'}sw*gwx)rx#O*g#P;'S*g;'S;=`+Z<%lO*g#S+^P;=`<%l*g(n+dP;=`<%l%Z07[+rq$h&j(Rp(U!b'w0/lOX%ZXY+gYZ&cZ[+g[p%Zpq+gqr%Zrs&}sw%Zwx(rx!^%Z!^!_*g!_#O%Z#O#P&c#P#o%Z#o#p*g#p$f%Z$f$g+g$g#BY%Z#BY#BZ+g#BZ$IS%Z$IS$I_+g$I_$JT%Z$JT$JU+g$JU$KV%Z$KV$KW+g$KW&FU%Z&FU&FV+g&FV;'S%Z;'S;=`+a<%l?HT%Z?HT?HU+g?HUO%Z07[.ST(S#S$h&j'x0/lO!^&c!_#o&c#p;'S&c;'S;=`&w<%lO&c07[.n_$h&j(Rp(U!b'x0/lOY%ZYZ&cZr%Zrs&}sw%Zwx(rx!^%Z!^!_*g!_#O%Z#O#P&c#P#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z)3p/x`$h&j!m),Q(Rp(U!bOY%ZYZ&cZr%Zrs&}sw%Zwx(rx!^%Z!^!_*g!_!`0z!`#O%Z#O#P&c#P#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z(KW1V`#u(Ch$h&j(Rp(U!bOY%ZYZ&cZr%Zrs&}sw%Zwx(rx!^%Z!^!_*g!_!`2X!`#O%Z#O#P&c#P#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z(KW2d_#u(Ch$h&j(Rp(U!bOY%ZYZ&cZr%Zrs&}sw%Zwx(rx!^%Z!^!_*g!_#O%Z#O#P&c#P#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z'At3l_(Q':f$h&j(U!bOY4kYZ5qZr4krs7nsw4kwx5qx!^4k!^!_8p!_#O4k#O#P5q#P#o4k#o#p8p#p;'S4k;'S;=`:X<%lO4k(^4r_$h&j(U!bOY4kYZ5qZr4krs7nsw4kwx5qx!^4k!^!_8p!_#O4k#O#P5q#P#o4k#o#p8p#p;'S4k;'S;=`:X<%lO4k&z5vX$h&jOr5qrs6cs!^5q!^!_6y!_#o5q#o#p6y#p;'S5q;'S;=`7h<%lO5q&z6jT$c`$h&jO!^&c!_#o&c#p;'S&c;'S;=`&w<%lO&c`6|TOr6yrs7]s;'S6y;'S;=`7b<%lO6y`7bO$c``7eP;=`<%l6y&z7kP;=`<%l5q(^7w]$c`$h&j(U!bOY&}YZ&cZw&}wx&cx!^&}!^!_'}!_#O&}#O#P&c#P#o&}#o#p'}#p;'S&};'S;=`(l<%lO&}!r8uZ(U!bOY8pYZ6yZr8prs9hsw8pwx6yx#O8p#O#P6y#P;'S8p;'S;=`:R<%lO8p!r9oU$c`(U!bOY'}Zw'}x#O'}#P;'S'};'S;=`(f<%lO'}!r:UP;=`<%l8p(^:[P;=`<%l4k%9[:hh$h&j(Rp(U!bOY%ZYZ&cZq%Zqr<Srs&}st%ZtuCruw%Zwx(rx!^%Z!^!_*g!_!c%Z!c!}Cr!}#O%Z#O#P&c#P#R%Z#R#SCr#S#T%Z#T#oCr#o#p*g#p$g%Z$g;'SCr;'S;=`El<%lOCr(r<__WS$h&j(Rp(U!bOY<SYZ&cZr<Srs=^sw<Swx@nx!^<S!^!_Bm!_#O<S#O#P>`#P#o<S#o#pBm#p;'S<S;'S;=`Cl<%lO<S(Q=g]WS$h&j(U!bOY=^YZ&cZw=^wx>`x!^=^!^!_?q!_#O=^#O#P>`#P#o=^#o#p?q#p;'S=^;'S;=`@h<%lO=^&n>gXWS$h&jOY>`YZ&cZ!^>`!^!_?S!_#o>`#o#p?S#p;'S>`;'S;=`?k<%lO>`S?XSWSOY?SZ;'S?S;'S;=`?e<%lO?SS?hP;=`<%l?S&n?nP;=`<%l>`!f?xWWS(U!bOY?qZw?qwx?Sx#O?q#O#P?S#P;'S?q;'S;=`@b<%lO?q!f@eP;=`<%l?q(Q@kP;=`<%l=^'`@w]WS$h&j(RpOY@nYZ&cZr@nrs>`s!^@n!^!_Ap!_#O@n#O#P>`#P#o@n#o#pAp#p;'S@n;'S;=`Bg<%lO@ntAwWWS(RpOYApZrAprs?Ss#OAp#O#P?S#P;'SAp;'S;=`Ba<%lOAptBdP;=`<%lAp'`BjP;=`<%l@n#WBvYWS(Rp(U!bOYBmZrBmrs?qswBmwxApx#OBm#O#P?S#P;'SBm;'S;=`Cf<%lOBm#WCiP;=`<%lBm(rCoP;=`<%l<S%9[C}i$h&j(j%1l(Rp(U!bOY%ZYZ&cZr%Zrs&}st%ZtuCruw%Zwx(rx!Q%Z!Q![Cr![!^%Z!^!_*g!_!c%Z!c!}Cr!}#O%Z#O#P&c#P#R%Z#R#SCr#S#T%Z#T#oCr#o#p*g#p$g%Z$g;'SCr;'S;=`El<%lOCr%9[EoP;=`<%lCr07[FRk$h&j(Rp(U!b$[#t(O,2j(`$I[OY%ZYZ&cZr%Zrs&}st%ZtuEruw%Zwx(rx}%Z}!OGv!O!Q%Z!Q![Er![!^%Z!^!_*g!_!c%Z!c!}Er!}#O%Z#O#P&c#P#R%Z#R#SEr#S#T%Z#T#oEr#o#p*g#p$g%Z$g;'SEr;'S;=`I|<%lOEr+dHRk$h&j(Rp(U!b$[#tOY%ZYZ&cZr%Zrs&}st%ZtuGvuw%Zwx(rx}%Z}!OGv!O!Q%Z!Q![Gv![!^%Z!^!_*g!_!c%Z!c!}Gv!}#O%Z#O#P&c#P#R%Z#R#SGv#S#T%Z#T#oGv#o#p*g#p$g%Z$g;'SGv;'S;=`Iv<%lOGv+dIyP;=`<%lGv07[JPP;=`<%lEr(KWJ_`$h&j(Rp(U!b#m(ChOY%ZYZ&cZr%Zrs&}sw%Zwx(rx!^%Z!^!_*g!_!`Ka!`#O%Z#O#P&c#P#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z(KWKl_$h&j$P(Ch(Rp(U!bOY%ZYZ&cZr%Zrs&}sw%Zwx(rx!^%Z!^!_*g!_#O%Z#O#P&c#P#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z,#xLva(u+JY$h&j(Rp(U!bOY%ZYZ&cZr%Zrs&}sv%ZvwM{wx(rx!^%Z!^!_*g!_!`Ka!`#O%Z#O#P&c#P#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z(KWNW`$h&j#y(Ch(Rp(U!bOY%ZYZ&cZr%Zrs&}sw%Zwx(rx!^%Z!^!_*g!_!`Ka!`#O%Z#O#P&c#P#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z'At! c_(T';W$h&j(RpOY!!bYZ!#hZr!!brs!#hsw!!bwx!$xx!^!!b!^!_!%z!_#O!!b#O#P!#h#P#o!!b#o#p!%z#p;'S!!b;'S;=`!'c<%lO!!b'l!!i_$h&j(RpOY!!bYZ!#hZr!!brs!#hsw!!bwx!$xx!^!!b!^!_!%z!_#O!!b#O#P!#h#P#o!!b#o#p!%z#p;'S!!b;'S;=`!'c<%lO!!b&z!#mX$h&jOw!#hwx6cx!^!#h!^!_!$Y!_#o!#h#o#p!$Y#p;'S!#h;'S;=`!$r<%lO!#h`!$]TOw!$Ywx7]x;'S!$Y;'S;=`!$l<%lO!$Y`!$oP;=`<%l!$Y&z!$uP;=`<%l!#h'l!%R]$c`$h&j(RpOY(rYZ&cZr(rrs&cs!^(r!^!_)r!_#O(r#O#P&c#P#o(r#o#p)r#p;'S(r;'S;=`*a<%lO(r!Q!&PZ(RpOY!%zYZ!$YZr!%zrs!$Ysw!%zwx!&rx#O!%z#O#P!$Y#P;'S!%z;'S;=`!']<%lO!%z!Q!&yU$c`(RpOY)rZr)rs#O)r#P;'S)r;'S;=`*Z<%lO)r!Q!'`P;=`<%l!%z'l!'fP;=`<%l!!b/5|!'t_!i/.^$h&j(Rp(U!bOY%ZYZ&cZr%Zrs&}sw%Zwx(rx!^%Z!^!_*g!_#O%Z#O#P&c#P#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z#&U!)O_!h!Lf$h&j(Rp(U!bOY%ZYZ&cZr%Zrs&}sw%Zwx(rx!^%Z!^!_*g!_#O%Z#O#P&c#P#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z-!n!*[b$h&j(Rp(U!b(P%&f#n(ChOY%ZYZ&cZr%Zrs&}sw%Zwx(rxz%Zz{!+d{!^%Z!^!_*g!_!`Ka!`#O%Z#O#P&c#P#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z(KW!+o`$h&j(Rp(U!b#k(ChOY%ZYZ&cZr%Zrs&}sw%Zwx(rx!^%Z!^!_*g!_!`Ka!`#O%Z#O#P&c#P#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z+;x!,|`$h&j(Rp(U!bo+4YOY%ZYZ&cZr%Zrs&}sw%Zwx(rx!^%Z!^!_*g!_!`Ka!`#O%Z#O#P&c#P#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z,$U!.Z_!Y+Jf$h&j(Rp(U!bOY%ZYZ&cZr%Zrs&}sw%Zwx(rx!^%Z!^!_*g!_#O%Z#O#P&c#P#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z07[!/ec$h&j(Rp(U!b}.2^OY%ZYZ&cZr%Zrs&}sw%Zwx(rx!O%Z!O!P!0p!P!Q%Z!Q![!3Y![!^%Z!^!_*g!_#O%Z#O#P&c#P#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z#%|!0ya$h&j(Rp(U!bOY%ZYZ&cZr%Zrs&}sw%Zwx(rx!O%Z!O!P!2O!P!^%Z!^!_*g!_#O%Z#O#P&c#P#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z#%|!2Z_!X!L^$h&j(Rp(U!bOY%ZYZ&cZr%Zrs&}sw%Zwx(rx!^%Z!^!_*g!_#O%Z#O#P&c#P#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z'Ad!3eg$h&j(Rp(U!bp'9tOY%ZYZ&cZr%Zrs&}sw%Zwx(rx!Q%Z!Q![!3Y![!^%Z!^!_*g!_!g%Z!g!h!4|!h#O%Z#O#P&c#P#R%Z#R#S!3Y#S#X%Z#X#Y!4|#Y#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z'Ad!5Vg$h&j(Rp(U!bOY%ZYZ&cZr%Zrs&}sw%Zwx(rx{%Z{|!6n|}%Z}!O!6n!O!Q%Z!Q![!8S![!^%Z!^!_*g!_#O%Z#O#P&c#P#R%Z#R#S!8S#S#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z'Ad!6wc$h&j(Rp(U!bOY%ZYZ&cZr%Zrs&}sw%Zwx(rx!Q%Z!Q![!8S![!^%Z!^!_*g!_#O%Z#O#P&c#P#R%Z#R#S!8S#S#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z'Ad!8_c$h&j(Rp(U!bp'9tOY%ZYZ&cZr%Zrs&}sw%Zwx(rx!Q%Z!Q![!8S![!^%Z!^!_*g!_#O%Z#O#P&c#P#R%Z#R#S!8S#S#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z07[!9uf$h&j(Rp(U!b#l(ChOY!;ZYZ&cZr!;Zrs!<nsw!;Zwx!Lcxz!;Zz{#-}{!P!;Z!P!Q#/d!Q!^!;Z!^!_#(i!_!`#7S!`!a#8i!a!}!;Z!}#O#,f#O#P!Dy#P#o!;Z#o#p#(i#p;'S!;Z;'S;=`#-w<%lO!;Z?O!;fb$h&j(Rp(U!b!U7`OY!;ZYZ&cZr!;Zrs!<nsw!;Zwx!Lcx!P!;Z!P!Q#&`!Q!^!;Z!^!_#(i!_!}!;Z!}#O#,f#O#P!Dy#P#o!;Z#o#p#(i#p;'S!;Z;'S;=`#-w<%lO!;Z>^!<w`$h&j(U!b!U7`OY!<nYZ&cZw!<nwx!=yx!P!<n!P!Q!Eq!Q!^!<n!^!_!Gr!_!}!<n!}#O!KS#O#P!Dy#P#o!<n#o#p!Gr#p;'S!<n;'S;=`!L]<%lO!<n<z!>Q^$h&j!U7`OY!=yYZ&cZ!P!=y!P!Q!>|!Q!^!=y!^!_!@c!_!}!=y!}#O!CW#O#P!Dy#P#o!=y#o#p!@c#p;'S!=y;'S;=`!Ek<%lO!=y<z!?Td$h&j!U7`O!^&c!_#W&c#W#X!>|#X#Z&c#Z#[!>|#[#]&c#]#^!>|#^#a&c#a#b!>|#b#g&c#g#h!>|#h#i&c#i#j!>|#j#k!>|#k#m&c#m#n!>|#n#o&c#p;'S&c;'S;=`&w<%lO&c7`!@hX!U7`OY!@cZ!P!@c!P!Q!AT!Q!}!@c!}#O!Ar#O#P!Bq#P;'S!@c;'S;=`!CQ<%lO!@c7`!AYW!U7`#W#X!AT#Z#[!AT#]#^!AT#a#b!AT#g#h!AT#i#j!AT#j#k!AT#m#n!AT7`!AuVOY!ArZ#O!Ar#O#P!B[#P#Q!@c#Q;'S!Ar;'S;=`!Bk<%lO!Ar7`!B_SOY!ArZ;'S!Ar;'S;=`!Bk<%lO!Ar7`!BnP;=`<%l!Ar7`!BtSOY!@cZ;'S!@c;'S;=`!CQ<%lO!@c7`!CTP;=`<%l!@c<z!C][$h&jOY!CWYZ&cZ!^!CW!^!_!Ar!_#O!CW#O#P!DR#P#Q!=y#Q#o!CW#o#p!Ar#p;'S!CW;'S;=`!Ds<%lO!CW<z!DWX$h&jOY!CWYZ&cZ!^!CW!^!_!Ar!_#o!CW#o#p!Ar#p;'S!CW;'S;=`!Ds<%lO!CW<z!DvP;=`<%l!CW<z!EOX$h&jOY!=yYZ&cZ!^!=y!^!_!@c!_#o!=y#o#p!@c#p;'S!=y;'S;=`!Ek<%lO!=y<z!EnP;=`<%l!=y>^!Ezl$h&j(U!b!U7`OY&}YZ&cZw&}wx&cx!^&}!^!_'}!_#O&}#O#P&c#P#W&}#W#X!Eq#X#Z&}#Z#[!Eq#[#]&}#]#^!Eq#^#a&}#a#b!Eq#b#g&}#g#h!Eq#h#i&}#i#j!Eq#j#k!Eq#k#m&}#m#n!Eq#n#o&}#o#p'}#p;'S&};'S;=`(l<%lO&}8r!GyZ(U!b!U7`OY!GrZw!Grwx!@cx!P!Gr!P!Q!Hl!Q!}!Gr!}#O!JU#O#P!Bq#P;'S!Gr;'S;=`!J|<%lO!Gr8r!Hse(U!b!U7`OY'}Zw'}x#O'}#P#W'}#W#X!Hl#X#Z'}#Z#[!Hl#[#]'}#]#^!Hl#^#a'}#a#b!Hl#b#g'}#g#h!Hl#h#i'}#i#j!Hl#j#k!Hl#k#m'}#m#n!Hl#n;'S'};'S;=`(f<%lO'}8r!JZX(U!bOY!JUZw!JUwx!Arx#O!JU#O#P!B[#P#Q!Gr#Q;'S!JU;'S;=`!Jv<%lO!JU8r!JyP;=`<%l!JU8r!KPP;=`<%l!Gr>^!KZ^$h&j(U!bOY!KSYZ&cZw!KSwx!CWx!^!KS!^!_!JU!_#O!KS#O#P!DR#P#Q!<n#Q#o!KS#o#p!JU#p;'S!KS;'S;=`!LV<%lO!KS>^!LYP;=`<%l!KS>^!L`P;=`<%l!<n=l!Ll`$h&j(Rp!U7`OY!LcYZ&cZr!Lcrs!=ys!P!Lc!P!Q!Mn!Q!^!Lc!^!_# o!_!}!Lc!}#O#%P#O#P!Dy#P#o!Lc#o#p# o#p;'S!Lc;'S;=`#&Y<%lO!Lc=l!Mwl$h&j(Rp!U7`OY(rYZ&cZr(rrs&cs!^(r!^!_)r!_#O(r#O#P&c#P#W(r#W#X!Mn#X#Z(r#Z#[!Mn#[#](r#]#^!Mn#^#a(r#a#b!Mn#b#g(r#g#h!Mn#h#i(r#i#j!Mn#j#k!Mn#k#m(r#m#n!Mn#n#o(r#o#p)r#p;'S(r;'S;=`*a<%lO(r8Q# vZ(Rp!U7`OY# oZr# ors!@cs!P# o!P!Q#!i!Q!}# o!}#O#$R#O#P!Bq#P;'S# o;'S;=`#$y<%lO# o8Q#!pe(Rp!U7`OY)rZr)rs#O)r#P#W)r#W#X#!i#X#Z)r#Z#[#!i#[#])r#]#^#!i#^#a)r#a#b#!i#b#g)r#g#h#!i#h#i)r#i#j#!i#j#k#!i#k#m)r#m#n#!i#n;'S)r;'S;=`*Z<%lO)r8Q#$WX(RpOY#$RZr#$Rrs!Ars#O#$R#O#P!B[#P#Q# o#Q;'S#$R;'S;=`#$s<%lO#$R8Q#$vP;=`<%l#$R8Q#$|P;=`<%l# o=l#%W^$h&j(RpOY#%PYZ&cZr#%Prs!CWs!^#%P!^!_#$R!_#O#%P#O#P!DR#P#Q!Lc#Q#o#%P#o#p#$R#p;'S#%P;'S;=`#&S<%lO#%P=l#&VP;=`<%l#%P=l#&]P;=`<%l!Lc?O#&kn$h&j(Rp(U!b!U7`OY%ZYZ&cZr%Zrs&}sw%Zwx(rx!^%Z!^!_*g!_#O%Z#O#P&c#P#W%Z#W#X#&`#X#Z%Z#Z#[#&`#[#]%Z#]#^#&`#^#a%Z#a#b#&`#b#g%Z#g#h#&`#h#i%Z#i#j#&`#j#k#&`#k#m%Z#m#n#&`#n#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z9d#(r](Rp(U!b!U7`OY#(iZr#(irs!Grsw#(iwx# ox!P#(i!P!Q#)k!Q!}#(i!}#O#+`#O#P!Bq#P;'S#(i;'S;=`#,`<%lO#(i9d#)th(Rp(U!b!U7`OY*gZr*grs'}sw*gwx)rx#O*g#P#W*g#W#X#)k#X#Z*g#Z#[#)k#[#]*g#]#^#)k#^#a*g#a#b#)k#b#g*g#g#h#)k#h#i*g#i#j#)k#j#k#)k#k#m*g#m#n#)k#n;'S*g;'S;=`+Z<%lO*g9d#+gZ(Rp(U!bOY#+`Zr#+`rs!JUsw#+`wx#$Rx#O#+`#O#P!B[#P#Q#(i#Q;'S#+`;'S;=`#,Y<%lO#+`9d#,]P;=`<%l#+`9d#,cP;=`<%l#(i?O#,o`$h&j(Rp(U!bOY#,fYZ&cZr#,frs!KSsw#,fwx#%Px!^#,f!^!_#+`!_#O#,f#O#P!DR#P#Q!;Z#Q#o#,f#o#p#+`#p;'S#,f;'S;=`#-q<%lO#,f?O#-tP;=`<%l#,f?O#-zP;=`<%l!;Z07[#.[b$h&j(Rp(U!b'y0/l!U7`OY!;ZYZ&cZr!;Zrs!<nsw!;Zwx!Lcx!P!;Z!P!Q#&`!Q!^!;Z!^!_#(i!_!}!;Z!}#O#,f#O#P!Dy#P#o!;Z#o#p#(i#p;'S!;Z;'S;=`#-w<%lO!;Z07[#/o_$h&j(Rp(U!bT0/lOY#/dYZ&cZr#/drs#0nsw#/dwx#4Ox!^#/d!^!_#5}!_#O#/d#O#P#1p#P#o#/d#o#p#5}#p;'S#/d;'S;=`#6|<%lO#/d06j#0w]$h&j(U!bT0/lOY#0nYZ&cZw#0nwx#1px!^#0n!^!_#3R!_#O#0n#O#P#1p#P#o#0n#o#p#3R#p;'S#0n;'S;=`#3x<%lO#0n05W#1wX$h&jT0/lOY#1pYZ&cZ!^#1p!^!_#2d!_#o#1p#o#p#2d#p;'S#1p;'S;=`#2{<%lO#1p0/l#2iST0/lOY#2dZ;'S#2d;'S;=`#2u<%lO#2d0/l#2xP;=`<%l#2d05W#3OP;=`<%l#1p01O#3YW(U!bT0/lOY#3RZw#3Rwx#2dx#O#3R#O#P#2d#P;'S#3R;'S;=`#3r<%lO#3R01O#3uP;=`<%l#3R06j#3{P;=`<%l#0n05x#4X]$h&j(RpT0/lOY#4OYZ&cZr#4Ors#1ps!^#4O!^!_#5Q!_#O#4O#O#P#1p#P#o#4O#o#p#5Q#p;'S#4O;'S;=`#5w<%lO#4O00^#5XW(RpT0/lOY#5QZr#5Qrs#2ds#O#5Q#O#P#2d#P;'S#5Q;'S;=`#5q<%lO#5Q00^#5tP;=`<%l#5Q05x#5zP;=`<%l#4O01p#6WY(Rp(U!bT0/lOY#5}Zr#5}rs#3Rsw#5}wx#5Qx#O#5}#O#P#2d#P;'S#5};'S;=`#6v<%lO#5}01p#6yP;=`<%l#5}07[#7PP;=`<%l#/d)3h#7ab$h&j$P(Ch(Rp(U!b!U7`OY!;ZYZ&cZr!;Zrs!<nsw!;Zwx!Lcx!P!;Z!P!Q#&`!Q!^!;Z!^!_#(i!_!}!;Z!}#O#,f#O#P!Dy#P#o!;Z#o#p#(i#p;'S!;Z;'S;=`#-w<%lO!;ZAt#8vb$Y#t$h&j(Rp(U!b!U7`OY!;ZYZ&cZr!;Zrs!<nsw!;Zwx!Lcx!P!;Z!P!Q#&`!Q!^!;Z!^!_#(i!_!}!;Z!}#O#,f#O#P!Dy#P#o!;Z#o#p#(i#p;'S!;Z;'S;=`#-w<%lO!;Z'Ad#:Zp$h&j(Rp(U!bp'9tOY%ZYZ&cZr%Zrs&}sw%Zwx(rx!O%Z!O!P!3Y!P!Q%Z!Q![#<_![!^%Z!^!_*g!_!g%Z!g!h!4|!h#O%Z#O#P&c#P#R%Z#R#S#<_#S#U%Z#U#V#?i#V#X%Z#X#Y!4|#Y#b%Z#b#c#>_#c#d#Bq#d#l%Z#l#m#Es#m#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z'Ad#<jk$h&j(Rp(U!bp'9tOY%ZYZ&cZr%Zrs&}sw%Zwx(rx!O%Z!O!P!3Y!P!Q%Z!Q![#<_![!^%Z!^!_*g!_!g%Z!g!h!4|!h#O%Z#O#P&c#P#R%Z#R#S#<_#S#X%Z#X#Y!4|#Y#b%Z#b#c#>_#c#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z'Ad#>j_$h&j(Rp(U!bp'9tOY%ZYZ&cZr%Zrs&}sw%Zwx(rx!^%Z!^!_*g!_#O%Z#O#P&c#P#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z'Ad#?rd$h&j(Rp(U!bOY%ZYZ&cZr%Zrs&}sw%Zwx(rx!Q%Z!Q!R#AQ!R!S#AQ!S!^%Z!^!_*g!_#O%Z#O#P&c#P#R%Z#R#S#AQ#S#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z'Ad#A]f$h&j(Rp(U!bp'9tOY%ZYZ&cZr%Zrs&}sw%Zwx(rx!Q%Z!Q!R#AQ!R!S#AQ!S!^%Z!^!_*g!_#O%Z#O#P&c#P#R%Z#R#S#AQ#S#b%Z#b#c#>_#c#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z'Ad#Bzc$h&j(Rp(U!bOY%ZYZ&cZr%Zrs&}sw%Zwx(rx!Q%Z!Q!Y#DV!Y!^%Z!^!_*g!_#O%Z#O#P&c#P#R%Z#R#S#DV#S#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z'Ad#Dbe$h&j(Rp(U!bp'9tOY%ZYZ&cZr%Zrs&}sw%Zwx(rx!Q%Z!Q!Y#DV!Y!^%Z!^!_*g!_#O%Z#O#P&c#P#R%Z#R#S#DV#S#b%Z#b#c#>_#c#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z'Ad#E|g$h&j(Rp(U!bOY%ZYZ&cZr%Zrs&}sw%Zwx(rx!Q%Z!Q![#Ge![!^%Z!^!_*g!_!c%Z!c!i#Ge!i#O%Z#O#P&c#P#R%Z#R#S#Ge#S#T%Z#T#Z#Ge#Z#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z'Ad#Gpi$h&j(Rp(U!bp'9tOY%ZYZ&cZr%Zrs&}sw%Zwx(rx!Q%Z!Q![#Ge![!^%Z!^!_*g!_!c%Z!c!i#Ge!i#O%Z#O#P&c#P#R%Z#R#S#Ge#S#T%Z#T#Z#Ge#Z#b%Z#b#c#>_#c#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z*)x#Il_!d$b$h&j#})Lv(Rp(U!bOY%ZYZ&cZr%Zrs&}sw%Zwx(rx!^%Z!^!_*g!_#O%Z#O#P&c#P#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z)[#Jv_al$h&j(Rp(U!bOY%ZYZ&cZr%Zrs&}sw%Zwx(rx!^%Z!^!_*g!_#O%Z#O#P&c#P#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z04f#LS^h#)`#O-<U(Rp(U!b(y7`OY*gZr*grs'}sw*gwx)rx!P*g!P!Q#MO!Q!^*g!^!_#Mt!_!`$ f!`#O*g#P;'S*g;'S;=`+Z<%lO*g(n#MXX$j&j(Rp(U!bOY*gZr*grs'}sw*gwx)rx#O*g#P;'S*g;'S;=`+Z<%lO*g(El#M}Z#o(Ch(Rp(U!bOY*gZr*grs'}sw*gwx)rx!_*g!_!`#Np!`#O*g#P;'S*g;'S;=`+Z<%lO*g(El#NyX$P(Ch(Rp(U!bOY*gZr*grs'}sw*gwx)rx#O*g#P;'S*g;'S;=`+Z<%lO*g(El$ oX#p(Ch(Rp(U!bOY*gZr*grs'}sw*gwx)rx#O*g#P;'S*g;'S;=`+Z<%lO*g*)x$!ga#]*!Y$h&j(Rp(U!bOY%ZYZ&cZr%Zrs&}sw%Zwx(rx!^%Z!^!_*g!_!`0z!`!a$#l!a#O%Z#O#P&c#P#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z(K[$#w_#h(Cl$h&j(Rp(U!bOY%ZYZ&cZr%Zrs&}sw%Zwx(rx!^%Z!^!_*g!_#O%Z#O#P&c#P#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z*)x$%Vag!*r#p(Ch$e#|$h&j(Rp(U!bOY%ZYZ&cZr%Zrs&}sw%Zwx(rx!^%Z!^!_*g!_!`$&[!`!a$'f!a#O%Z#O#P&c#P#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z(KW$&g_#p(Ch$h&j(Rp(U!bOY%ZYZ&cZr%Zrs&}sw%Zwx(rx!^%Z!^!_*g!_#O%Z#O#P&c#P#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z(KW$'qa#o(Ch$h&j(Rp(U!bOY%ZYZ&cZr%Zrs&}sw%Zwx(rx!^%Z!^!_*g!_!`Ka!`!a$(v!a#O%Z#O#P&c#P#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z(KW$)R`#o(Ch$h&j(Rp(U!bOY%ZYZ&cZr%Zrs&}sw%Zwx(rx!^%Z!^!_*g!_!`Ka!`#O%Z#O#P&c#P#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z(Kd$*`a(m(Ct$h&j(Rp(U!bOY%ZYZ&cZr%Zrs&}sw%Zwx(rx!^%Z!^!_*g!_!a%Z!a!b$+e!b#O%Z#O#P&c#P#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z(KW$+p`$h&j#z(Ch(Rp(U!bOY%ZYZ&cZr%Zrs&}sw%Zwx(rx!^%Z!^!_*g!_!`Ka!`#O%Z#O#P&c#P#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z%#`$,}_!y$Ip$h&j(Rp(U!bOY%ZYZ&cZr%Zrs&}sw%Zwx(rx!^%Z!^!_*g!_#O%Z#O#P&c#P#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z04f$.X_!P0,v$h&j(Rp(U!bOY%ZYZ&cZr%Zrs&}sw%Zwx(rx!^%Z!^!_*g!_#O%Z#O#P&c#P#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z(n$/]Z$h&jO!^$0O!^!_$0f!_#i$0O#i#j$0k#j#l$0O#l#m$2^#m#o$0O#o#p$0f#p;'S$0O;'S;=`$4i<%lO$0O(n$0VT_#S$h&jO!^&c!_#o&c#p;'S&c;'S;=`&w<%lO&c#S$0kO_#S(n$0p[$h&jO!Q&c!Q![$1f![!^&c!_!c&c!c!i$1f!i#T&c#T#Z$1f#Z#o&c#o#p$3|#p;'S&c;'S;=`&w<%lO&c(n$1kZ$h&jO!Q&c!Q![$2^![!^&c!_!c&c!c!i$2^!i#T&c#T#Z$2^#Z#o&c#p;'S&c;'S;=`&w<%lO&c(n$2cZ$h&jO!Q&c!Q![$3U![!^&c!_!c&c!c!i$3U!i#T&c#T#Z$3U#Z#o&c#p;'S&c;'S;=`&w<%lO&c(n$3ZZ$h&jO!Q&c!Q![$0O![!^&c!_!c&c!c!i$0O!i#T&c#T#Z$0O#Z#o&c#p;'S&c;'S;=`&w<%lO&c#S$4PR!Q![$4Y!c!i$4Y#T#Z$4Y#S$4]S!Q![$4Y!c!i$4Y#T#Z$4Y#q#r$0f(n$4lP;=`<%l$0O#1[$4z_!V#)l$h&j(Rp(U!bOY%ZYZ&cZr%Zrs&}sw%Zwx(rx!^%Z!^!_*g!_#O%Z#O#P&c#P#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z(KW$6U`#w(Ch$h&j(Rp(U!bOY%ZYZ&cZr%Zrs&}sw%Zwx(rx!^%Z!^!_*g!_!`Ka!`#O%Z#O#P&c#P#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z+;p$7c_$h&j(Rp(U!b([+4QOY%ZYZ&cZr%Zrs&}sw%Zwx(rx!^%Z!^!_*g!_#O%Z#O#P&c#P#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z07[$8qk$h&j(Rp(U!b(O,2j$^#t(`$I[OY%ZYZ&cZr%Zrs&}st%Ztu$8buw%Zwx(rx}%Z}!O$:f!O!Q%Z!Q![$8b![!^%Z!^!_*g!_!c%Z!c!}$8b!}#O%Z#O#P&c#P#R%Z#R#S$8b#S#T%Z#T#o$8b#o#p*g#p$g%Z$g;'S$8b;'S;=`$<l<%lO$8b+d$:qk$h&j(Rp(U!b$^#tOY%ZYZ&cZr%Zrs&}st%Ztu$:fuw%Zwx(rx}%Z}!O$:f!O!Q%Z!Q![$:f![!^%Z!^!_*g!_!c%Z!c!}$:f!}#O%Z#O#P&c#P#R%Z#R#S$:f#S#T%Z#T#o$:f#o#p*g#p$g%Z$g;'S$:f;'S;=`$<f<%lO$:f+d$<iP;=`<%l$:f07[$<oP;=`<%l$8b#Jf$<{X![#Hb(Rp(U!bOY*gZr*grs'}sw*gwx)rx#O*g#P;'S*g;'S;=`+Z<%lO*g,#x$=sa(t+JY$h&j(Rp(U!bOY%ZYZ&cZr%Zrs&}sw%Zwx(rx!^%Z!^!_*g!_!`Ka!`#O%Z#O#P&c#P#o%Z#o#p*g#p#q$+e#q;'S%Z;'S;=`+a<%lO%Z)>v$?V_!Z(CdsBr$h&j(Rp(U!bOY%ZYZ&cZr%Zrs&}sw%Zwx(rx!^%Z!^!_*g!_#O%Z#O#P&c#P#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z?O$@a_!n7`$h&j(Rp(U!bOY%ZYZ&cZr%Zrs&}sw%Zwx(rx!^%Z!^!_*g!_#O%Z#O#P&c#P#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z07[$Aq|$h&j(Rp(U!b'w0/l$[#t(O,2j(`$I[OX%ZXY+gYZ&cZ[+g[p%Zpq+gqr%Zrs&}st%ZtuEruw%Zwx(rx}%Z}!OGv!O!Q%Z!Q![Er![!^%Z!^!_*g!_!c%Z!c!}Er!}#O%Z#O#P&c#P#R%Z#R#SEr#S#T%Z#T#oEr#o#p*g#p$f%Z$f$g+g$g#BYEr#BY#BZ$A`#BZ$ISEr$IS$I_$A`$I_$JTEr$JT$JU$A`$JU$KVEr$KV$KW$A`$KW&FUEr&FU&FV$A`&FV;'SEr;'S;=`I|<%l?HTEr?HT?HU$A`?HUOEr07[$D|k$h&j(Rp(U!b'x0/l$[#t(O,2j(`$I[OY%ZYZ&cZr%Zrs&}st%ZtuEruw%Zwx(rx}%Z}!OGv!O!Q%Z!Q![Er![!^%Z!^!_*g!_!c%Z!c!}Er!}#O%Z#O#P&c#P#R%Z#R#SEr#S#T%Z#T#oEr#o#p*g#p$g%Z$g;'SEr;'S;=`I|<%lOEr",
  tokenizers: [noSemicolon, operatorToken, jsx, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, insertSemicolon, new LocalTokenGroup("$S~RRtu[#O#Pg#S#T#|~_P#o#pb~gOu~~jVO#i!P#i#j!U#j#l!P#l#m!q#m;'S!P;'S;=`#v<%lO!P~!UO!R~~!XS!Q![!e!c!i!e#T#Z!e#o#p#Z~!hR!Q![!q!c!i!q#T#Z!q~!tR!Q![!}!c!i!}#T#Z!}~#QR!Q![!P!c!i!P#T#Z!P~#^R!Q![#g!c!i#g#T#Z#g~#jS!Q![#g!c!i#g#T#Z#g#q#r!P~#yP;=`<%l!P~$RO(^~~", 141, 335), new LocalTokenGroup("j~RQYZXz{^~^O'{~~aP!P!Qd~iO'|~~", 25, 318)],
  topRules: {"Script":[0,7],"SingleExpression":[1,272],"SingleClassItem":[2,273]},
  dialects: {jsx: 0, ts: 14791},
  dynamicPrecedences: {"77":1,"79":1,"91":1,"167":1,"196":1},
  specialized: [{term: 322, get: (value) => spec_identifier[value] || -1},{term: 338, get: (value) => spec_word[value] || -1},{term: 92, get: (value) => spec_LessThan[value] || -1}],
  tokenPrec: 14815
});/**
An instance of this is passed to completion source functions.
*/
var CompletionContext = function CompletionContext(
/**
The editor state that the completion happens in.
*/
state, 
/**
The position at which the completion is happening.
*/
pos, 
/**
Indicates whether completion was activated explicitly, or
implicitly by typing. The usual way to respond to this is to
only return completions when either there is part of a
completable entity before the cursor, or `explicit` is true.
*/
explicit, 
/**
The editor view. May be undefined if the context was created
in a situation where there is no such view available, such as
in synchronous updates via
[`CompletionResult.update`](https://codemirror.net/6/docs/ref/#autocomplete.CompletionResult.update)
or when called by test code.
*/
view) {
    this.state = state;
    this.pos = pos;
    this.explicit = explicit;
    this.view = view;
    /**
    @internal
    */
    this.abortListeners = [];
    /**
    @internal
    */
    this.abortOnDocChange = false;
};

var prototypeAccessors = { aborted: { configurable: true } };
/**
Get the extent, content, and (if there is a token) type of the
token before `this.pos`.
*/
CompletionContext.prototype.tokenBefore = function tokenBefore (types) {
    var token = syntaxTree(this.state).resolveInner(this.pos, -1);
    while (token && types.indexOf(token.name) < 0)
        { token = token.parent; }
    return token ? { from: token.from, to: this.pos,
        text: this.state.sliceDoc(token.from, this.pos),
        type: token.type } : null;
};
/**
Get the match of the given expression directly before the
cursor.
*/
CompletionContext.prototype.matchBefore = function matchBefore (expr) {
    var line = this.state.doc.lineAt(this.pos);
    var start = Math.max(line.from, this.pos - 250);
    var str = line.text.slice(start - line.from, this.pos - line.from);
    var found = str.search(ensureAnchor(expr, false));
    return found < 0 ? null : { from: start + found, to: this.pos, text: str.slice(found) };
};
/**
Yields true when the query has been aborted. Can be useful in
asynchronous queries to avoid doing work that will be ignored.
*/
prototypeAccessors.aborted.get = function () { return this.abortListeners == null; };
/**
Allows you to register abort handlers, which will be called when
the query is
[aborted](https://codemirror.net/6/docs/ref/#autocomplete.CompletionContext.aborted).
    
By default, running queries will not be aborted for regular
typing or backspacing, on the assumption that they are likely to
return a result with a
[`validFor`](https://codemirror.net/6/docs/ref/#autocomplete.CompletionResult.validFor) field that
allows the result to be used after all. Passing `onDocChange:
true` will cause this query to be aborted for any document
change.
*/
CompletionContext.prototype.addEventListener = function addEventListener (type, listener, options) {
    if (type == "abort" && this.abortListeners) {
        this.abortListeners.push(listener);
        if (options && options.onDocChange)
            { this.abortOnDocChange = true; }
    }
};

Object.defineProperties( CompletionContext.prototype, prototypeAccessors );
function toSet(chars) {
    var flat = Object.keys(chars).join("");
    var words = /\w/.test(flat);
    if (words)
        { flat = flat.replace(/\w/g, ""); }
    return ("[" + (words ? "\\w" : "") + (flat.replace(/[^\w\s]/g, "\\$&")) + "]");
}
function prefixMatch(options) {
    var first = Object.create(null), rest = Object.create(null);
    for (var { label } of options) {
        first[label[0]] = true;
        for (var i = 1; i < label.length; i++)
            { rest[label[i]] = true; }
    }
    var source = toSet(first) + toSet(rest) + "*$";
    return [new RegExp("^" + source), new RegExp(source)];
}
/**
Given a a fixed array of options, return an autocompleter that
completes them.
*/
function completeFromList(list) {
    var options = list.map(function (o) { return typeof o == "string" ? { label: o } : o; });
    var ref = options.every(function (o) { return /^\w+$/.test(o.label); }) ? [/\w*$/, /\w+$/] : prefixMatch(options);
    var validFor = ref[0];
    var match = ref[1];
    return function (context) {
        var token = context.matchBefore(match);
        return token || context.explicit ? { from: token ? token.from : context.pos, options: options, validFor: validFor } : null;
    };
}
/**
Wrap the given completion source so that it will not fire when the
cursor is in a syntax node with one of the given names.
*/
function ifNotIn(nodes, source) {
    return function (context) {
        for (var pos = syntaxTree(context.state).resolveInner(context.pos, -1); pos; pos = pos.parent) {
            if (nodes.indexOf(pos.name) > -1)
                { return null; }
            if (pos.type.isTop)
                { break; }
        }
        return source(context);
    };
}
var Option = function Option(completion, source, match, score) {
    this.completion = completion;
    this.source = source;
    this.match = match;
    this.score = score;
};
function cur(state) { return state.selection.main.from; }
// Make sure the given regexp has a $ at its end and, if `start` is
// true, a ^ at its start.
function ensureAnchor(expr, start) {
    var _a;
    var source = expr.source;
    var addStart = start && source[0] != "^", addEnd = source[source.length - 1] != "$";
    if (!addStart && !addEnd)
        { return expr; }
    return new RegExp(((addStart ? "^" : "") + "(?:" + source + ")" + (addEnd ? "$" : "")), (_a = expr.flags) !== null && _a !== void 0 ? _a : (expr.ignoreCase ? "i" : ""));
}
/**
This annotation is added to transactions that are produced by
picking a completion.
*/
var pickedCompletion = /*@__PURE__*/Annotation.define();
/**
Helper function that returns a transaction spec which inserts a
completion's text in the main selection range, and any other
selection range that has the same text in front of it.
*/
function insertCompletionText(state, text, from, to) {
    var ref = state.selection;
    var main = ref.main;
    var fromOff = from - main.from, toOff = to - main.from;
    return Object.assign(Object.assign({}, state.changeByRange(function (range) {
        if (range != main && from != to &&
            state.sliceDoc(range.from + fromOff, range.from + toOff) != state.sliceDoc(from, to))
            { return { range: range }; }
        var lines = state.toText(text);
        return {
            changes: { from: range.from + fromOff, to: to == main.from ? range.to : range.from + toOff, insert: lines },
            range: EditorSelection.cursor(range.from + fromOff + lines.length)
        };
    })), { scrollIntoView: true, userEvent: "input.complete" });
}
var SourceCache = /*@__PURE__*/new WeakMap();
function asSource(source) {
    if (!Array.isArray(source))
        { return source; }
    var known = SourceCache.get(source);
    if (!known)
        { SourceCache.set(source, known = completeFromList(source)); }
    return known;
}
var startCompletionEffect = /*@__PURE__*/StateEffect.define();
var closeCompletionEffect = /*@__PURE__*/StateEffect.define();

// A pattern matcher for fuzzy completion matching. Create an instance
// once for a pattern, and then use that to match any number of
// completions.
var FuzzyMatcher = function FuzzyMatcher(pattern) {
    this.pattern = pattern;
    this.chars = [];
    this.folded = [];
    // Buffers reused by calls to `match` to track matched character
    // positions.
    this.any = [];
    this.precise = [];
    this.byWord = [];
    this.score = 0;
    this.matched = [];
    for (var p = 0; p < pattern.length;) {
        var char = codePointAt(pattern, p), size = codePointSize(char);
        this.chars.push(char);
        var part = pattern.slice(p, p + size), upper = part.toUpperCase();
        this.folded.push(codePointAt(upper == part ? part.toLowerCase() : upper, 0));
        p += size;
    }
    this.astral = pattern.length != this.chars.length;
};
FuzzyMatcher.prototype.ret = function ret (score, matched) {
    this.score = score;
    this.matched = matched;
    return this;
};
// Matches a given word (completion) against the pattern (input).
// Will return a boolean indicating whether there was a match and,
// on success, set `this.score` to the score, `this.matched` to an
// array of `from, to` pairs indicating the matched parts of `word`.
//
// The score is a number that is more negative the worse the match
// is. See `Penalty` above.
FuzzyMatcher.prototype.match = function match (word) {
    if (this.pattern.length == 0)
        { return this.ret(-100 /* Penalty.NotFull */, []); }
    if (word.length < this.pattern.length)
        { return null; }
    var ref = this;
        var chars = ref.chars;
        var folded = ref.folded;
        var any = ref.any;
        var precise = ref.precise;
        var byWord = ref.byWord;
    // For single-character queries, only match when they occur right
    // at the start
    if (chars.length == 1) {
        var first = codePointAt(word, 0), firstSize = codePointSize(first);
        var score = firstSize == word.length ? 0 : -100 /* Penalty.NotFull */;
        if (first == chars[0]) ;
        else if (first == folded[0])
            { score += -200 /* Penalty.CaseFold */; }
        else
            { return null; }
        return this.ret(score, [0, firstSize]);
    }
    var direct = word.indexOf(this.pattern);
    if (direct == 0)
        { return this.ret(word.length == this.pattern.length ? 0 : -100 /* Penalty.NotFull */, [0, this.pattern.length]); }
    var len = chars.length, anyTo = 0;
    if (direct < 0) {
        for (var i = 0, e = Math.min(word.length, 200); i < e && anyTo < len;) {
            var next = codePointAt(word, i);
            if (next == chars[anyTo] || next == folded[anyTo])
                { any[anyTo++] = i; }
            i += codePointSize(next);
        }
        // No match, exit immediately
        if (anyTo < len)
            { return null; }
    }
    // This tracks the extent of the precise (non-folded, not
    // necessarily adjacent) match
    var preciseTo = 0;
    // Tracks whether there is a match that hits only characters that
    // appear to be starting words. `byWordFolded` is set to true when
    // a case folded character is encountered in such a match
    var byWordTo = 0, byWordFolded = false;
    // If we've found a partial adjacent match, these track its state
    var adjacentTo = 0, adjacentStart = -1, adjacentEnd = -1;
    var hasLower = /[a-z]/.test(word), wordAdjacent = true;
    // Go over the option's text, scanning for the various kinds of matches
    for (var i$1 = 0, e$1 = Math.min(word.length, 200), prevType = 0 /* Tp.NonWord */; i$1 < e$1 && byWordTo < len;) {
        var next$1 = codePointAt(word, i$1);
        if (direct < 0) {
            if (preciseTo < len && next$1 == chars[preciseTo])
                { precise[preciseTo++] = i$1; }
            if (adjacentTo < len) {
                if (next$1 == chars[adjacentTo] || next$1 == folded[adjacentTo]) {
                    if (adjacentTo == 0)
                        { adjacentStart = i$1; }
                    adjacentEnd = i$1 + 1;
                    adjacentTo++;
                }
                else {
                    adjacentTo = 0;
                }
            }
        }
        var ch = (void 0), type = next$1 < 0xff
            ? (next$1 >= 48 && next$1 <= 57 || next$1 >= 97 && next$1 <= 122 ? 2 /* Tp.Lower */ : next$1 >= 65 && next$1 <= 90 ? 1 /* Tp.Upper */ : 0 /* Tp.NonWord */)
            : ((ch = fromCodePoint$1(next$1)) != ch.toLowerCase() ? 1 /* Tp.Upper */ : ch != ch.toUpperCase() ? 2 /* Tp.Lower */ : 0 /* Tp.NonWord */);
        if (!i$1 || type == 1 /* Tp.Upper */ && hasLower || prevType == 0 /* Tp.NonWord */ && type != 0 /* Tp.NonWord */) {
            if (chars[byWordTo] == next$1 || (folded[byWordTo] == next$1 && (byWordFolded = true)))
                { byWord[byWordTo++] = i$1; }
            else if (byWord.length)
                { wordAdjacent = false; }
        }
        prevType = type;
        i$1 += codePointSize(next$1);
    }
    if (byWordTo == len && byWord[0] == 0 && wordAdjacent)
        { return this.result(-100 /* Penalty.ByWord */ + (byWordFolded ? -200 /* Penalty.CaseFold */ : 0), byWord, word); }
    if (adjacentTo == len && adjacentStart == 0)
        { return this.ret(-200 /* Penalty.CaseFold */ - word.length + (adjacentEnd == word.length ? 0 : -100 /* Penalty.NotFull */), [0, adjacentEnd]); }
    if (direct > -1)
        { return this.ret(-700 /* Penalty.NotStart */ - word.length, [direct, direct + this.pattern.length]); }
    if (adjacentTo == len)
        { return this.ret(-200 /* Penalty.CaseFold */ + -700 /* Penalty.NotStart */ - word.length, [adjacentStart, adjacentEnd]); }
    if (byWordTo == len)
        { return this.result(-100 /* Penalty.ByWord */ + (byWordFolded ? -200 /* Penalty.CaseFold */ : 0) + -700 /* Penalty.NotStart */ +
            (wordAdjacent ? 0 : -1100 /* Penalty.Gap */), byWord, word); }
    return chars.length == 2 ? null
        : this.result((any[0] ? -700 /* Penalty.NotStart */ : 0) + -200 /* Penalty.CaseFold */ + -1100 /* Penalty.Gap */, any, word);
};
FuzzyMatcher.prototype.result = function result (score, positions, word) {
    var result = [], i = 0;
    for (var pos of positions) {
        var to = pos + (this.astral ? codePointSize(codePointAt(word, pos)) : 1);
        if (i && result[i - 1] == pos)
            { result[i - 1] = to; }
        else {
            result[i++] = pos;
            result[i++] = to;
        }
    }
    return this.ret(score - word.length, result);
};
var StrictMatcher = function StrictMatcher(pattern) {
    this.pattern = pattern;
    this.matched = [];
    this.score = 0;
    this.folded = pattern.toLowerCase();
};
StrictMatcher.prototype.match = function match (word) {
    if (word.length < this.pattern.length)
        { return null; }
    var start = word.slice(0, this.pattern.length);
    var match = start == this.pattern ? 0 : start.toLowerCase() == this.folded ? -200 /* Penalty.CaseFold */ : null;
    if (match == null)
        { return null; }
    this.matched = [0, start.length];
    this.score = match + (word.length == this.pattern.length ? 0 : -100 /* Penalty.NotFull */);
    return this;
};

var completionConfig = /*@__PURE__*/Facet.define({
    combine: function combine(configs) {
        return combineConfig(configs, {
            activateOnTyping: true,
            activateOnCompletion: function () { return false; },
            activateOnTypingDelay: 100,
            selectOnOpen: true,
            override: null,
            closeOnBlur: true,
            maxRenderedOptions: 100,
            defaultKeymap: true,
            tooltipClass: function () { return ""; },
            optionClass: function () { return ""; },
            aboveCursor: false,
            icons: true,
            addToOptions: [],
            positionInfo: defaultPositionInfo,
            filterStrict: false,
            compareCompletions: function (a, b) { return a.label.localeCompare(b.label); },
            interactionDelay: 75,
            updateSyncTime: 100
        }, {
            defaultKeymap: function (a, b) { return a && b; },
            closeOnBlur: function (a, b) { return a && b; },
            icons: function (a, b) { return a && b; },
            tooltipClass: function (a, b) { return function (c) { return joinClass(a(c), b(c)); }; },
            optionClass: function (a, b) { return function (c) { return joinClass(a(c), b(c)); }; },
            addToOptions: function (a, b) { return a.concat(b); },
            filterStrict: function (a, b) { return a || b; },
        });
    }
});
function joinClass(a, b) {
    return a ? b ? a + " " + b : a : b;
}
function defaultPositionInfo(view, list, option, info, space, tooltip) {
    var rtl = view.textDirection == Direction.RTL, left = rtl, narrow = false;
    var side = "top", offset, maxWidth;
    var spaceLeft = list.left - space.left, spaceRight = space.right - list.right;
    var infoWidth = info.right - info.left, infoHeight = info.bottom - info.top;
    if (left && spaceLeft < Math.min(infoWidth, spaceRight))
        { left = false; }
    else if (!left && spaceRight < Math.min(infoWidth, spaceLeft))
        { left = true; }
    if (infoWidth <= (left ? spaceLeft : spaceRight)) {
        offset = Math.max(space.top, Math.min(option.top, space.bottom - infoHeight)) - list.top;
        maxWidth = Math.min(400 /* Info.Width */, left ? spaceLeft : spaceRight);
    }
    else {
        narrow = true;
        maxWidth = Math.min(400 /* Info.Width */, (rtl ? list.right : space.right - list.left) - 30 /* Info.Margin */);
        var spaceBelow = space.bottom - list.bottom;
        if (spaceBelow >= infoHeight || spaceBelow > list.top) { // Below the completion
            offset = option.bottom - list.top;
        }
        else { // Above it
            side = "bottom";
            offset = list.bottom - option.top;
        }
    }
    var scaleY = (list.bottom - list.top) / tooltip.offsetHeight;
    var scaleX = (list.right - list.left) / tooltip.offsetWidth;
    return {
        style: (side + ": " + (offset / scaleY) + "px; max-width: " + (maxWidth / scaleX) + "px"),
        class: "cm-completionInfo-" + (narrow ? (rtl ? "left-narrow" : "right-narrow") : left ? "left" : "right")
    };
}

function optionContent(config) {
    var content = config.addToOptions.slice();
    if (config.icons)
        { content.push({
            render: function render(completion) {
                var ref;

                var icon = document.createElement("div");
                icon.classList.add("cm-completionIcon");
                if (completion.type)
                    { (ref = icon.classList).add.apply(ref, completion.type.split(/\s+/g).map(function (cls) { return "cm-completionIcon-" + cls; })); }
                icon.setAttribute("aria-hidden", "true");
                return icon;
            },
            position: 20
        }); }
    content.push({
        render: function render(completion, _s, _v, match) {
            var labelElt = document.createElement("span");
            labelElt.className = "cm-completionLabel";
            var label = completion.displayLabel || completion.label, off = 0;
            for (var j = 0; j < match.length;) {
                var from = match[j++], to = match[j++];
                if (from > off)
                    { labelElt.appendChild(document.createTextNode(label.slice(off, from))); }
                var span = labelElt.appendChild(document.createElement("span"));
                span.appendChild(document.createTextNode(label.slice(from, to)));
                span.className = "cm-completionMatchedText";
                off = to;
            }
            if (off < label.length)
                { labelElt.appendChild(document.createTextNode(label.slice(off))); }
            return labelElt;
        },
        position: 50
    }, {
        render: function render(completion) {
            if (!completion.detail)
                { return null; }
            var detailElt = document.createElement("span");
            detailElt.className = "cm-completionDetail";
            detailElt.textContent = completion.detail;
            return detailElt;
        },
        position: 80
    });
    return content.sort(function (a, b) { return a.position - b.position; }).map(function (a) { return a.render; });
}
function rangeAroundSelected(total, selected, max) {
    if (total <= max)
        { return { from: 0, to: total }; }
    if (selected < 0)
        { selected = 0; }
    if (selected <= (total >> 1)) {
        var off$1 = Math.floor(selected / max);
        return { from: off$1 * max, to: (off$1 + 1) * max };
    }
    var off = Math.floor((total - selected) / max);
    return { from: total - (off + 1) * max, to: total - off * max };
}
var CompletionTooltip = function CompletionTooltip(view, stateField, applyCompletion) {
    var this$1$1 = this;

    this.view = view;
    this.stateField = stateField;
    this.applyCompletion = applyCompletion;
    this.info = null;
    this.infoDestroy = null;
    this.placeInfoReq = {
        read: function () { return this$1$1.measureInfo(); },
        write: function (pos) { return this$1$1.placeInfo(pos); },
        key: this
    };
    this.space = null;
    this.currentClass = "";
    var cState = view.state.field(stateField);
    var ref = cState.open;
    var options = ref.options;
    var selected = ref.selected;
    var config = view.state.facet(completionConfig);
    this.optionContent = optionContent(config);
    this.optionClass = config.optionClass;
    this.tooltipClass = config.tooltipClass;
    this.range = rangeAroundSelected(options.length, selected, config.maxRenderedOptions);
    this.dom = document.createElement("div");
    this.dom.className = "cm-tooltip-autocomplete";
    this.updateTooltipClass(view.state);
    this.dom.addEventListener("mousedown", function (e) {
        var ref = view.state.field(stateField).open;
        var options = ref.options;
        for (var dom = e.target, match = (void 0); dom && dom != this$1$1.dom; dom = dom.parentNode) {
            if (dom.nodeName == "LI" && (match = /-(\d+)$/.exec(dom.id)) && +match[1] < options.length) {
                this$1$1.applyCompletion(view, options[+match[1]]);
                e.preventDefault();
                return;
            }
        }
    });
    this.dom.addEventListener("focusout", function (e) {
        var state = view.state.field(this$1$1.stateField, false);
        if (state && state.tooltip && view.state.facet(completionConfig).closeOnBlur &&
            e.relatedTarget != view.contentDOM)
            { view.dispatch({ effects: closeCompletionEffect.of(null) }); }
    });
    this.showOptions(options, cState.id);
};
CompletionTooltip.prototype.mount = function mount () { this.updateSel(); };
CompletionTooltip.prototype.showOptions = function showOptions (options, id) {
        var this$1$1 = this;

    if (this.list)
        { this.list.remove(); }
    this.list = this.dom.appendChild(this.createListBox(options, id, this.range));
    this.list.addEventListener("scroll", function () {
        if (this$1$1.info)
            { this$1$1.view.requestMeasure(this$1$1.placeInfoReq); }
    });
};
CompletionTooltip.prototype.update = function update (update$1) {
    var _a;
    var cState = update$1.state.field(this.stateField);
    var prevState = update$1.startState.field(this.stateField);
    this.updateTooltipClass(update$1.state);
    if (cState != prevState) {
        var ref = cState.open;
            var options = ref.options;
            var selected = ref.selected;
            var disabled = ref.disabled;
        if (!prevState.open || prevState.open.options != options) {
            this.range = rangeAroundSelected(options.length, selected, update$1.state.facet(completionConfig).maxRenderedOptions);
            this.showOptions(options, cState.id);
        }
        this.updateSel();
        if (disabled != ((_a = prevState.open) === null || _a === void 0 ? void 0 : _a.disabled))
            { this.dom.classList.toggle("cm-tooltip-autocomplete-disabled", !!disabled); }
    }
};
CompletionTooltip.prototype.updateTooltipClass = function updateTooltipClass (state) {
    var cls = this.tooltipClass(state);
    if (cls != this.currentClass) {
        for (var c of this.currentClass.split(" "))
            if (c)
                { this.dom.classList.remove(c); }
        for (var c$1 of cls.split(" "))
            if (c$1)
                { this.dom.classList.add(c$1); }
        this.currentClass = cls;
    }
};
CompletionTooltip.prototype.positioned = function positioned (space) {
    this.space = space;
    if (this.info)
        { this.view.requestMeasure(this.placeInfoReq); }
};
CompletionTooltip.prototype.updateSel = function updateSel () {
        var this$1$1 = this;

    var cState = this.view.state.field(this.stateField), open = cState.open;
    if (open.selected > -1 && open.selected < this.range.from || open.selected >= this.range.to) {
        this.range = rangeAroundSelected(open.options.length, open.selected, this.view.state.facet(completionConfig).maxRenderedOptions);
        this.showOptions(open.options, cState.id);
    }
    if (this.updateSelectedOption(open.selected)) {
        this.destroyInfo();
        var ref = open.options[open.selected];
            var completion = ref.completion;
        var info = completion.info;
        if (!info)
            { return; }
        var infoResult = typeof info === "string" ? document.createTextNode(info) : info(completion);
        if (!infoResult)
            { return; }
        if ("then" in infoResult) {
            infoResult.then(function (obj) {
                if (obj && this$1$1.view.state.field(this$1$1.stateField, false) == cState)
                    { this$1$1.addInfoPane(obj, completion); }
            }).catch(function (e) { return logException(this$1$1.view.state, e, "completion info"); });
        }
        else {
            this.addInfoPane(infoResult, completion);
        }
    }
};
CompletionTooltip.prototype.addInfoPane = function addInfoPane (content, completion) {
    this.destroyInfo();
    var wrap = this.info = document.createElement("div");
    wrap.className = "cm-tooltip cm-completionInfo";
    if (content.nodeType != null) {
        wrap.appendChild(content);
        this.infoDestroy = null;
    }
    else {
        var dom = content.dom;
            var destroy = content.destroy;
        wrap.appendChild(dom);
        this.infoDestroy = destroy || null;
    }
    this.dom.appendChild(wrap);
    this.view.requestMeasure(this.placeInfoReq);
};
CompletionTooltip.prototype.updateSelectedOption = function updateSelectedOption (selected) {
    var set = null;
    for (var opt = this.list.firstChild, i = this.range.from; opt; opt = opt.nextSibling, i++) {
        if (opt.nodeName != "LI" || !opt.id) {
            i--; // A section header
        }
        else if (i == selected) {
            if (!opt.hasAttribute("aria-selected")) {
                opt.setAttribute("aria-selected", "true");
                set = opt;
            }
        }
        else {
            if (opt.hasAttribute("aria-selected"))
                { opt.removeAttribute("aria-selected"); }
        }
    }
    if (set)
        { scrollIntoView(this.list, set); }
    return set;
};
CompletionTooltip.prototype.measureInfo = function measureInfo () {
    var sel = this.dom.querySelector("[aria-selected]");
    if (!sel || !this.info)
        { return null; }
    var listRect = this.dom.getBoundingClientRect();
    var infoRect = this.info.getBoundingClientRect();
    var selRect = sel.getBoundingClientRect();
    var space = this.space;
    if (!space) {
        var win = this.dom.ownerDocument.defaultView || window;
        space = { left: 0, top: 0, right: win.innerWidth, bottom: win.innerHeight };
    }
    if (selRect.top > Math.min(space.bottom, listRect.bottom) - 10 ||
        selRect.bottom < Math.max(space.top, listRect.top) + 10)
        { return null; }
    return this.view.state.facet(completionConfig).positionInfo(this.view, listRect, selRect, infoRect, space, this.dom);
};
CompletionTooltip.prototype.placeInfo = function placeInfo (pos) {
    if (this.info) {
        if (pos) {
            if (pos.style)
                { this.info.style.cssText = pos.style; }
            this.info.className = "cm-tooltip cm-completionInfo " + (pos.class || "");
        }
        else {
            this.info.style.cssText = "top: -1e6px";
        }
    }
};
CompletionTooltip.prototype.createListBox = function createListBox (options, id, range) {
    var ul = document.createElement("ul");
    ul.id = id;
    ul.setAttribute("role", "listbox");
    ul.setAttribute("aria-expanded", "true");
    ul.setAttribute("aria-label", this.view.state.phrase("Completions"));
    var curSection = null;
    for (var i = range.from; i < range.to; i++) {
        var ref = options[i];
            var completion = ref.completion;
            var match = ref.match;
            var section = completion.section;
        if (section) {
            var name = typeof section == "string" ? section : section.name;
            if (name != curSection && (i > range.from || range.from == 0)) {
                curSection = name;
                if (typeof section != "string" && section.header) {
                    ul.appendChild(section.header(section));
                }
                else {
                    var header = ul.appendChild(document.createElement("completion-section"));
                    header.textContent = name;
                }
            }
        }
        var li = ul.appendChild(document.createElement("li"));
        li.id = id + "-" + i;
        li.setAttribute("role", "option");
        var cls = this.optionClass(completion);
        if (cls)
            { li.className = cls; }
        for (var source of this.optionContent) {
            var node = source(completion, this.view.state, this.view, match);
            if (node)
                { li.appendChild(node); }
        }
    }
    if (range.from)
        { ul.classList.add("cm-completionListIncompleteTop"); }
    if (range.to < options.length)
        { ul.classList.add("cm-completionListIncompleteBottom"); }
    return ul;
};
CompletionTooltip.prototype.destroyInfo = function destroyInfo () {
    if (this.info) {
        if (this.infoDestroy)
            { this.infoDestroy(); }
        this.info.remove();
        this.info = null;
    }
};
CompletionTooltip.prototype.destroy = function destroy () {
    this.destroyInfo();
};
function completionTooltip(stateField, applyCompletion) {
    return function (view) { return new CompletionTooltip(view, stateField, applyCompletion); };
}
function scrollIntoView(container, element) {
    var parent = container.getBoundingClientRect();
    var self = element.getBoundingClientRect();
    var scaleY = parent.height / container.offsetHeight;
    if (self.top < parent.top)
        { container.scrollTop -= (parent.top - self.top) / scaleY; }
    else if (self.bottom > parent.bottom)
        { container.scrollTop += (self.bottom - parent.bottom) / scaleY; }
}

// Used to pick a preferred option when two options with the same
// label occur in the result.
function score(option) {
    return (option.boost || 0) * 100 + (option.apply ? 10 : 0) + (option.info ? 5 : 0) +
        (option.type ? 1 : 0);
}
function sortOptions(active, state) {
    var options = [];
    var sections = null;
    var addOption = function (option) {
        options.push(option);
        var ref = option.completion;
        var section = ref.section;
        if (section) {
            if (!sections)
                { sections = []; }
            var name = typeof section == "string" ? section : section.name;
            if (!sections.some(function (s) { return s.name == name; }))
                { sections.push(typeof section == "string" ? { name: name } : section); }
        }
    };
    var conf = state.facet(completionConfig);
    for (var a of active)
        if (a.hasResult()) {
            var getMatch = a.result.getMatch;
            if (a.result.filter === false) {
                for (var option of a.result.options) {
                    addOption(new Option(option, a.source, getMatch ? getMatch(option) : [], 1e9 - options.length));
                }
            }
            else {
                var pattern = state.sliceDoc(a.from, a.to), match = (void 0);
                var matcher = conf.filterStrict ? new StrictMatcher(pattern) : new FuzzyMatcher(pattern);
                for (var option$1 of a.result.options)
                    if (match = matcher.match(option$1.label)) {
                        var matched = !option$1.displayLabel ? match.matched : getMatch ? getMatch(option$1, match.matched) : [];
                        addOption(new Option(option$1, a.source, matched, match.score + (option$1.boost || 0)));
                    }
            }
        }
    if (sections) {
        var sectionOrder = Object.create(null), pos = 0;
        var cmp = function (a, b) { var _a, _b; return ((_a = a.rank) !== null && _a !== void 0 ? _a : 1e9) - ((_b = b.rank) !== null && _b !== void 0 ? _b : 1e9) || (a.name < b.name ? -1 : 1); };
        for (var s of sections.sort(cmp)) {
            pos -= 1e5;
            sectionOrder[s.name] = pos;
        }
        for (var option$2 of options) {
            var ref = option$2.completion;
            var section = ref.section;
            if (section)
                { option$2.score += sectionOrder[typeof section == "string" ? section : section.name]; }
        }
    }
    var result = [], prev = null;
    var compare = conf.compareCompletions;
    for (var opt of options.sort(function (a, b) { return (b.score - a.score) || compare(a.completion, b.completion); })) {
        var cur = opt.completion;
        if (!prev || prev.label != cur.label || prev.detail != cur.detail ||
            (prev.type != null && cur.type != null && prev.type != cur.type) ||
            prev.apply != cur.apply || prev.boost != cur.boost)
            { result.push(opt); }
        else if (score(opt.completion) > score(prev))
            { result[result.length - 1] = opt; }
        prev = opt.completion;
    }
    return result;
}
var CompletionDialog = function CompletionDialog(options, attrs, tooltip, timestamp, selected, disabled) {
    this.options = options;
    this.attrs = attrs;
    this.tooltip = tooltip;
    this.timestamp = timestamp;
    this.selected = selected;
    this.disabled = disabled;
};
CompletionDialog.prototype.setSelected = function setSelected (selected, id) {
    return selected == this.selected || selected >= this.options.length ? this
        : new CompletionDialog(this.options, makeAttrs(id, selected), this.tooltip, this.timestamp, selected, this.disabled);
};
CompletionDialog.build = function build (active, state, id, prev, conf) {
    var options = sortOptions(active, state);
    if (!options.length) {
        return prev && active.some(function (a) { return a.state == 1; } /* State.Pending */) ?
            new CompletionDialog(prev.options, prev.attrs, prev.tooltip, prev.timestamp, prev.selected, true) : null;
    }
    var selected = state.facet(completionConfig).selectOnOpen ? 0 : -1;
    if (prev && prev.selected != selected && prev.selected != -1) {
        var selectedValue = prev.options[prev.selected].completion;
        for (var i = 0; i < options.length; i++)
            { if (options[i].completion == selectedValue) {
                selected = i;
                break;
            } }
    }
    return new CompletionDialog(options, makeAttrs(id, selected), {
        pos: active.reduce(function (a, b) { return b.hasResult() ? Math.min(a, b.from) : a; }, 1e8),
        create: createTooltip,
        above: conf.aboveCursor,
    }, prev ? prev.timestamp : Date.now(), selected, false);
};
CompletionDialog.prototype.map = function map (changes) {
    return new CompletionDialog(this.options, this.attrs, Object.assign(Object.assign({}, this.tooltip), { pos: changes.mapPos(this.tooltip.pos) }), this.timestamp, this.selected, this.disabled);
};
var CompletionState = function CompletionState(active, id, open) {
    this.active = active;
    this.id = id;
    this.open = open;
};

var prototypeAccessors$1 = { tooltip: { configurable: true },attrs: { configurable: true } };
CompletionState.start = function start () {
    return new CompletionState(none, "cm-ac-" + Math.floor(Math.random() * 2e6).toString(36), null);
};
CompletionState.prototype.update = function update (tr) {
        var this$1$1 = this;

    var state = tr.state;
        var conf = state.facet(completionConfig);
    var sources = conf.override ||
        state.languageDataAt("autocomplete", cur(state)).map(asSource);
    var active = sources.map(function (source) {
        var value = this$1$1.active.find(function (s) { return s.source == source; }) ||
            new ActiveSource(source, this$1$1.active.some(function (a) { return a.state != 0; } /* State.Inactive */) ? 1 /* State.Pending */ : 0 /* State.Inactive */);
        return value.update(tr, conf);
    });
    if (active.length == this.active.length && active.every(function (a, i) { return a == this$1$1.active[i]; }))
        { active = this.active; }
    var open = this.open;
    if (open && tr.docChanged)
        { open = open.map(tr.changes); }
    if (tr.selection || active.some(function (a) { return a.hasResult() && tr.changes.touchesRange(a.from, a.to); }) ||
        !sameResults(active, this.active))
        { open = CompletionDialog.build(active, state, this.id, open, conf); }
    else if (open && open.disabled && !active.some(function (a) { return a.state == 1; } /* State.Pending */))
        { open = null; }
    if (!open && active.every(function (a) { return a.state != 1; } /* State.Pending */) && active.some(function (a) { return a.hasResult(); }))
        { active = active.map(function (a) { return a.hasResult() ? new ActiveSource(a.source, 0 /* State.Inactive */) : a; }); }
    for (var effect of tr.effects)
        if (effect.is(setSelectedEffect))
            { open = open && open.setSelected(effect.value, this.id); }
    return active == this.active && open == this.open ? this : new CompletionState(active, this.id, open);
};
prototypeAccessors$1.tooltip.get = function () { return this.open ? this.open.tooltip : null; };
prototypeAccessors$1.attrs.get = function () { return this.open ? this.open.attrs : this.active.length ? baseAttrs : noAttrs; };

Object.defineProperties( CompletionState.prototype, prototypeAccessors$1 );
function sameResults(a, b) {
    if (a == b)
        { return true; }
    for (var iA = 0, iB = 0;;) {
        while (iA < a.length && !a[iA].hasResult)
            { iA++; }
        while (iB < b.length && !b[iB].hasResult)
            { iB++; }
        var endA = iA == a.length, endB = iB == b.length;
        if (endA || endB)
            { return endA == endB; }
        if (a[iA++].result != b[iB++].result)
            { return false; }
    }
}
var baseAttrs = {
    "aria-autocomplete": "list"
};
var noAttrs = {};
function makeAttrs(id, selected) {
    var result = {
        "aria-autocomplete": "list",
        "aria-haspopup": "listbox",
        "aria-controls": id
    };
    if (selected > -1)
        { result["aria-activedescendant"] = id + "-" + selected; }
    return result;
}
var none = [];
function getUpdateType(tr, conf) {
    if (tr.isUserEvent("input.complete")) {
        var completion = tr.annotation(pickedCompletion);
        if (completion && conf.activateOnCompletion(completion))
            { return 4 /* UpdateType.Activate */ | 8 /* UpdateType.Reset */; }
    }
    var typing = tr.isUserEvent("input.type");
    return typing && conf.activateOnTyping ? 4 /* UpdateType.Activate */ | 1 /* UpdateType.Typing */
        : typing ? 1 /* UpdateType.Typing */
            : tr.isUserEvent("delete.backward") ? 2 /* UpdateType.Backspacing */
                : tr.selection ? 8 /* UpdateType.Reset */
                    : tr.docChanged ? 16 /* UpdateType.ResetIfTouching */ : 0 /* UpdateType.None */;
}
var ActiveSource = function ActiveSource(source, state, explicitPos) {
    if ( explicitPos === void 0 ) explicitPos = -1;

    this.source = source;
    this.state = state;
    this.explicitPos = explicitPos;
};
ActiveSource.prototype.hasResult = function hasResult () { return false; };
ActiveSource.prototype.update = function update (tr, conf) {
    var type = getUpdateType(tr, conf), value = this;
    if ((type & 8 /* UpdateType.Reset */) || (type & 16 /* UpdateType.ResetIfTouching */) && this.touches(tr))
        { value = new ActiveSource(value.source, 0 /* State.Inactive */); }
    if ((type & 4 /* UpdateType.Activate */) && value.state == 0 /* State.Inactive */)
        { value = new ActiveSource(this.source, 1 /* State.Pending */); }
    value = value.updateFor(tr, type);
    for (var effect of tr.effects) {
        if (effect.is(startCompletionEffect))
            { value = new ActiveSource(value.source, 1 /* State.Pending */, effect.value ? cur(tr.state) : -1); }
        else if (effect.is(closeCompletionEffect))
            { value = new ActiveSource(value.source, 0 /* State.Inactive */); }
        else if (effect.is(setActiveEffect))
            { for (var active of effect.value)
                if (active.source == value.source)
                    { value = active; } }
    }
    return value;
};
ActiveSource.prototype.updateFor = function updateFor (tr, type) { return this.map(tr.changes); };
ActiveSource.prototype.map = function map (changes) {
    return changes.empty || this.explicitPos < 0 ? this : new ActiveSource(this.source, this.state, changes.mapPos(this.explicitPos));
};
ActiveSource.prototype.touches = function touches (tr) {
    return tr.changes.touchesRange(cur(tr.state));
};
var ActiveResult = /*@__PURE__*/(function (ActiveSource) {
    function ActiveResult(source, explicitPos, result, from, to) {
        ActiveSource.call(this, source, 2 /* State.Result */, explicitPos);
        this.result = result;
        this.from = from;
        this.to = to;
    }

    if ( ActiveSource ) ActiveResult.__proto__ = ActiveSource;
    ActiveResult.prototype = Object.create( ActiveSource && ActiveSource.prototype );
    ActiveResult.prototype.constructor = ActiveResult;
    ActiveResult.prototype.hasResult = function hasResult () { return true; };
    ActiveResult.prototype.updateFor = function updateFor (tr, type) {
        var _a;
        if (!(type & 3 /* UpdateType.SimpleInteraction */))
            { return this.map(tr.changes); }
        var result = this.result;
        if (result.map && !tr.changes.empty)
            { result = result.map(result, tr.changes); }
        var from = tr.changes.mapPos(this.from), to = tr.changes.mapPos(this.to, 1);
        var pos = cur(tr.state);
        if ((this.explicitPos < 0 ? pos <= from : pos < this.from) ||
            pos > to || !result ||
            (type & 2 /* UpdateType.Backspacing */) && cur(tr.startState) == this.from)
            { return new ActiveSource(this.source, type & 4 /* UpdateType.Activate */ ? 1 /* State.Pending */ : 0 /* State.Inactive */); }
        var explicitPos = this.explicitPos < 0 ? -1 : tr.changes.mapPos(this.explicitPos);
        if (checkValid(result.validFor, tr.state, from, to))
            { return new ActiveResult(this.source, explicitPos, result, from, to); }
        if (result.update &&
            (result = result.update(result, from, to, new CompletionContext(tr.state, pos, explicitPos >= 0))))
            { return new ActiveResult(this.source, explicitPos, result, result.from, (_a = result.to) !== null && _a !== void 0 ? _a : cur(tr.state)); }
        return new ActiveSource(this.source, 1 /* State.Pending */, explicitPos);
    };
    ActiveResult.prototype.map = function map (mapping) {
        if (mapping.empty)
            { return this; }
        var result = this.result.map ? this.result.map(this.result, mapping) : this.result;
        if (!result)
            { return new ActiveSource(this.source, 0 /* State.Inactive */); }
        return new ActiveResult(this.source, this.explicitPos < 0 ? -1 : mapping.mapPos(this.explicitPos), this.result, mapping.mapPos(this.from), mapping.mapPos(this.to, 1));
    };
    ActiveResult.prototype.touches = function touches (tr) {
        return tr.changes.touchesRange(this.from, this.to);
    };

    return ActiveResult;
}(ActiveSource));
function checkValid(validFor, state, from, to) {
    if (!validFor)
        { return false; }
    var text = state.sliceDoc(from, to);
    return typeof validFor == "function" ? validFor(text, from, to, state) : ensureAnchor(validFor, true).test(text);
}
var setActiveEffect = /*@__PURE__*/StateEffect.define({
    map: function map(sources, mapping) { return sources.map(function (s) { return s.map(mapping); }); }
});
var setSelectedEffect = /*@__PURE__*/StateEffect.define();
var completionState = /*@__PURE__*/StateField.define({
    create: function create() { return CompletionState.start(); },
    update: function update(value, tr) { return value.update(tr); },
    provide: function (f) { return [
        showTooltip.from(f, function (val) { return val.tooltip; }),
        EditorView.contentAttributes.from(f, function (state) { return state.attrs; })
    ]; }
});
function applyCompletion(view, option) {
    var apply = option.completion.apply || option.completion.label;
    var result = view.state.field(completionState).active.find(function (a) { return a.source == option.source; });
    if (!(result instanceof ActiveResult))
        { return false; }
    if (typeof apply == "string")
        { view.dispatch(Object.assign(Object.assign({}, insertCompletionText(view.state, apply, result.from, result.to)), { annotations: pickedCompletion.of(option.completion) })); }
    else
        { apply(view, option.completion, result.from, result.to); }
    return true;
}
var createTooltip = /*@__PURE__*/completionTooltip(completionState, applyCompletion);

var baseTheme = /*@__PURE__*/EditorView.baseTheme({
    ".cm-tooltip.cm-tooltip-autocomplete": {
        "& > ul": {
            fontFamily: "monospace",
            whiteSpace: "nowrap",
            overflow: "hidden auto",
            maxWidth_fallback: "700px",
            maxWidth: "min(700px, 95vw)",
            minWidth: "250px",
            maxHeight: "10em",
            height: "100%",
            listStyle: "none",
            margin: 0,
            padding: 0,
            "& > li, & > completion-section": {
                padding: "1px 3px",
                lineHeight: 1.2
            },
            "& > li": {
                overflowX: "hidden",
                textOverflow: "ellipsis",
                cursor: "pointer"
            },
            "& > completion-section": {
                display: "list-item",
                borderBottom: "1px solid silver",
                paddingLeft: "0.5em",
                opacity: 0.7
            }
        }
    },
    "&light .cm-tooltip-autocomplete ul li[aria-selected]": {
        background: "#17c",
        color: "white",
    },
    "&light .cm-tooltip-autocomplete-disabled ul li[aria-selected]": {
        background: "#777",
    },
    "&dark .cm-tooltip-autocomplete ul li[aria-selected]": {
        background: "#347",
        color: "white",
    },
    "&dark .cm-tooltip-autocomplete-disabled ul li[aria-selected]": {
        background: "#444",
    },
    ".cm-completionListIncompleteTop:before, .cm-completionListIncompleteBottom:after": {
        content: '"···"',
        opacity: 0.5,
        display: "block",
        textAlign: "center"
    },
    ".cm-tooltip.cm-completionInfo": {
        position: "absolute",
        padding: "3px 9px",
        width: "max-content",
        maxWidth: ((400) + "px"),
        boxSizing: "border-box",
        whiteSpace: "pre-line"
    },
    ".cm-completionInfo.cm-completionInfo-left": { right: "100%" },
    ".cm-completionInfo.cm-completionInfo-right": { left: "100%" },
    ".cm-completionInfo.cm-completionInfo-left-narrow": { right: ((30) + "px") },
    ".cm-completionInfo.cm-completionInfo-right-narrow": { left: ((30) + "px") },
    "&light .cm-snippetField": { backgroundColor: "#00000022" },
    "&dark .cm-snippetField": { backgroundColor: "#ffffff22" },
    ".cm-snippetFieldPosition": {
        verticalAlign: "text-top",
        width: 0,
        height: "1.15em",
        display: "inline-block",
        margin: "0 -0.7px -.7em",
        borderLeft: "1.4px dotted #888"
    },
    ".cm-completionMatchedText": {
        textDecoration: "underline"
    },
    ".cm-completionDetail": {
        marginLeft: "0.5em",
        fontStyle: "italic"
    },
    ".cm-completionIcon": {
        fontSize: "90%",
        width: ".8em",
        display: "inline-block",
        textAlign: "center",
        paddingRight: ".6em",
        opacity: "0.6",
        boxSizing: "content-box"
    },
    ".cm-completionIcon-function, .cm-completionIcon-method": {
        "&:after": { content: "'ƒ'" }
    },
    ".cm-completionIcon-class": {
        "&:after": { content: "'○'" }
    },
    ".cm-completionIcon-interface": {
        "&:after": { content: "'◌'" }
    },
    ".cm-completionIcon-variable": {
        "&:after": { content: "'𝑥'" }
    },
    ".cm-completionIcon-constant": {
        "&:after": { content: "'𝐶'" }
    },
    ".cm-completionIcon-type": {
        "&:after": { content: "'𝑡'" }
    },
    ".cm-completionIcon-enum": {
        "&:after": { content: "'∪'" }
    },
    ".cm-completionIcon-property": {
        "&:after": { content: "'□'" }
    },
    ".cm-completionIcon-keyword": {
        "&:after": { content: "'🔑\uFE0E'" } // Disable emoji rendering
    },
    ".cm-completionIcon-namespace": {
        "&:after": { content: "'▢'" }
    },
    ".cm-completionIcon-text": {
        "&:after": { content: "'abc'", fontSize: "50%", verticalAlign: "middle" }
    }
});

var FieldPos = function FieldPos(field, line, from, to) {
    this.field = field;
    this.line = line;
    this.from = from;
    this.to = to;
};
var FieldRange = function FieldRange(field, from, to) {
    this.field = field;
    this.from = from;
    this.to = to;
};
FieldRange.prototype.map = function map (changes) {
    var from = changes.mapPos(this.from, -1, MapMode.TrackDel);
    var to = changes.mapPos(this.to, 1, MapMode.TrackDel);
    return from == null || to == null ? null : new FieldRange(this.field, from, to);
};
var Snippet = function Snippet(lines, fieldPositions) {
    this.lines = lines;
    this.fieldPositions = fieldPositions;
};
Snippet.prototype.instantiate = function instantiate (state, pos) {
    var text = [], lineStart = [pos];
    var lineObj = state.doc.lineAt(pos), baseIndent = /^\s*/.exec(lineObj.text)[0];
    for (var line of this.lines) {
        if (text.length) {
            var indent = baseIndent, tabs = /^\t*/.exec(line)[0].length;
            for (var i = 0; i < tabs; i++)
                { indent += state.facet(indentUnit); }
            lineStart.push(pos + indent.length - tabs);
            line = indent + line.slice(tabs);
        }
        text.push(line);
        pos += line.length + 1;
    }
    var ranges = this.fieldPositions.map(function (pos) { return new FieldRange(pos.field, lineStart[pos.line] + pos.from, lineStart[pos.line] + pos.to); });
    return { text: text, ranges: ranges };
};
Snippet.parse = function parse (template) {
    var fields = [];
    var lines = [], positions = [], m;
    for (var line of template.split(/\r\n?|\n/)) {
        while (m = /[#$]\{(?:(\d+)(?::([^}]*))?|((?:\\[{}]|[^}])*))\}/.exec(line)) {
            var seq = m[1] ? +m[1] : null, rawName = m[2] || m[3] || "", found = -1;
            var name = rawName.replace(/\\[{}]/g, function (m) { return m[1]; });
            for (var i = 0; i < fields.length; i++) {
                if (seq != null ? fields[i].seq == seq : name ? fields[i].name == name : false)
                    { found = i; }
            }
            if (found < 0) {
                var i$1 = 0;
                while (i$1 < fields.length && (seq == null || (fields[i$1].seq != null && fields[i$1].seq < seq)))
                    { i$1++; }
                fields.splice(i$1, 0, { seq: seq, name: name });
                found = i$1;
                for (var pos of positions)
                    if (pos.field >= found)
                        { pos.field++; }
            }
            positions.push(new FieldPos(found, lines.length, m.index, m.index + name.length));
            line = line.slice(0, m.index) + rawName + line.slice(m.index + m[0].length);
        }
        line = line.replace(/\\([{}])/g, function (_, brace, index) {
            for (var pos of positions)
                if (pos.line == lines.length && pos.from > index) {
                    pos.from--;
                    pos.to--;
                }
            return brace;
        });
        lines.push(line);
    }
    return new Snippet(lines, positions);
};
var fieldMarker = /*@__PURE__*/Decoration.widget({ widget: /*@__PURE__*/new /*@__PURE__*/(function (WidgetType) {
    function anonymous$1 () {
        WidgetType.apply(this, arguments);
    }

    if ( WidgetType ) anonymous$1.__proto__ = WidgetType;
    anonymous$1.prototype = Object.create( WidgetType && WidgetType.prototype );
    anonymous$1.prototype.constructor = anonymous$1;

    anonymous$1.prototype.toDOM = function toDOM () {
            var span = document.createElement("span");
            span.className = "cm-snippetFieldPosition";
            return span;
        };
        anonymous$1.prototype.ignoreEvent = function ignoreEvent () { return false; };

    return anonymous$1;
}(WidgetType)) });
var fieldRange = /*@__PURE__*/Decoration.mark({ class: "cm-snippetField" });
var ActiveSnippet = function ActiveSnippet(ranges, active) {
    this.ranges = ranges;
    this.active = active;
    this.deco = Decoration.set(ranges.map(function (r) { return (r.from == r.to ? fieldMarker : fieldRange).range(r.from, r.to); }));
};
ActiveSnippet.prototype.map = function map (changes) {
    var ranges = [];
    for (var r of this.ranges) {
        var mapped = r.map(changes);
        if (!mapped)
            { return null; }
        ranges.push(mapped);
    }
    return new ActiveSnippet(ranges, this.active);
};
ActiveSnippet.prototype.selectionInsideField = function selectionInsideField (sel) {
        var this$1$1 = this;

    return sel.ranges.every(function (range) { return this$1$1.ranges.some(function (r) { return r.field == this$1$1.active && r.from <= range.from && r.to >= range.to; }); });
};
var setActive = /*@__PURE__*/StateEffect.define({
    map: function map(value, changes) { return value && value.map(changes); }
});
var moveToField = /*@__PURE__*/StateEffect.define();
var snippetState = /*@__PURE__*/StateField.define({
    create: function create() { return null; },
    update: function update(value, tr) {
        for (var effect of tr.effects) {
            if (effect.is(setActive))
                { return effect.value; }
            if (effect.is(moveToField) && value)
                { return new ActiveSnippet(value.ranges, effect.value); }
        }
        if (value && tr.docChanged)
            { value = value.map(tr.changes); }
        if (value && tr.selection && !value.selectionInsideField(tr.selection))
            { value = null; }
        return value;
    },
    provide: function (f) { return EditorView.decorations.from(f, function (val) { return val ? val.deco : Decoration.none; }); }
});
function fieldSelection(ranges, field) {
    return EditorSelection.create(ranges.filter(function (r) { return r.field == field; }).map(function (r) { return EditorSelection.range(r.from, r.to); }));
}
/**
Convert a snippet template to a function that can
[apply](https://codemirror.net/6/docs/ref/#autocomplete.Completion.apply) it. Snippets are written
using syntax like this:

    "for (let ${index} = 0; ${index} < ${end}; ${index}++) {\n\t${}\n}"

Each `${}` placeholder (you may also use `#{}`) indicates a field
that the user can fill in. Its name, if any, will be the default
content for the field.

When the snippet is activated by calling the returned function,
the code is inserted at the given position. Newlines in the
template are indented by the indentation of the start line, plus
one [indent unit](https://codemirror.net/6/docs/ref/#language.indentUnit) per tab character after
the newline.

On activation, (all instances of) the first field are selected.
The user can move between fields with Tab and Shift-Tab as long as
the fields are active. Moving to the last field or moving the
cursor out of the current field deactivates the fields.

The order of fields defaults to textual order, but you can add
numbers to placeholders (`${1}` or `${1:defaultText}`) to provide
a custom order.

To include a literal `{` or `}` in your template, put a backslash
in front of it. This will be removed and the brace will not be
interpreted as indicating a placeholder.
*/
function snippet(template) {
    var snippet = Snippet.parse(template);
    return function (editor, completion, from, to) {
        var ref = snippet.instantiate(editor.state, from);
        var text = ref.text;
        var ranges = ref.ranges;
        var spec = {
            changes: { from: from, to: to, insert: Text.of(text) },
            scrollIntoView: true,
            annotations: completion ? [pickedCompletion.of(completion), Transaction.userEvent.of("input.complete")] : undefined
        };
        if (ranges.length)
            { spec.selection = fieldSelection(ranges, 0); }
        if (ranges.some(function (r) { return r.field > 0; })) {
            var active = new ActiveSnippet(ranges, 0);
            var effects = spec.effects = [setActive.of(active)];
            if (editor.state.field(snippetState, false) === undefined)
                { effects.push(StateEffect.appendConfig.of([snippetState, addSnippetKeymap, snippetPointerHandler, baseTheme])); }
        }
        editor.dispatch(editor.state.update(spec));
    };
}
function moveField(dir) {
    return function (ref) {
        var state = ref.state;
        var dispatch = ref.dispatch;

        var active = state.field(snippetState, false);
        if (!active || dir < 0 && active.active == 0)
            { return false; }
        var next = active.active + dir, last = dir > 0 && !active.ranges.some(function (r) { return r.field == next + dir; });
        dispatch(state.update({
            selection: fieldSelection(active.ranges, next),
            effects: setActive.of(last ? null : new ActiveSnippet(active.ranges, next)),
            scrollIntoView: true
        }));
        return true;
    };
}
/**
A command that clears the active snippet, if any.
*/
var clearSnippet = function (ref) {
    var state = ref.state;
    var dispatch = ref.dispatch;

    var active = state.field(snippetState, false);
    if (!active)
        { return false; }
    dispatch(state.update({ effects: setActive.of(null) }));
    return true;
};
/**
Move to the next snippet field, if available.
*/
var nextSnippetField = /*@__PURE__*/moveField(1);
/**
Move to the previous snippet field, if available.
*/
var prevSnippetField = /*@__PURE__*/moveField(-1);
var defaultSnippetKeymap = [
    { key: "Tab", run: nextSnippetField, shift: prevSnippetField },
    { key: "Escape", run: clearSnippet }
];
/**
A facet that can be used to configure the key bindings used by
snippets. The default binds Tab to
[`nextSnippetField`](https://codemirror.net/6/docs/ref/#autocomplete.nextSnippetField), Shift-Tab to
[`prevSnippetField`](https://codemirror.net/6/docs/ref/#autocomplete.prevSnippetField), and Escape
to [`clearSnippet`](https://codemirror.net/6/docs/ref/#autocomplete.clearSnippet).
*/
var snippetKeymap = /*@__PURE__*/Facet.define({
    combine: function combine(maps) { return maps.length ? maps[0] : defaultSnippetKeymap; }
});
var addSnippetKeymap = /*@__PURE__*/Prec.highest(/*@__PURE__*/keymap$3.compute([snippetKeymap], function (state) { return state.facet(snippetKeymap); }));
/**
Create a completion from a snippet. Returns an object with the
properties from `completion`, plus an `apply` function that
applies the snippet.
*/
function snippetCompletion(template, completion) {
    return Object.assign(Object.assign({}, completion), { apply: snippet(template) });
}
var snippetPointerHandler = /*@__PURE__*/EditorView.domEventHandlers({
    mousedown: function mousedown(event, view) {
        var active = view.state.field(snippetState, false), pos;
        if (!active || (pos = view.posAtCoords({ x: event.clientX, y: event.clientY })) == null)
            { return false; }
        var match = active.ranges.find(function (r) { return r.from <= pos && r.to >= pos; });
        if (!match || match.field == active.active)
            { return false; }
        view.dispatch({
            selection: fieldSelection(active.ranges, match.field),
            effects: setActive.of(active.ranges.some(function (r) { return r.field > match.field; })
                ? new ActiveSnippet(active.ranges, match.field) : null),
            scrollIntoView: true
        });
        return true;
    }
});
var closedBracket = /*@__PURE__*/new /*@__PURE__*/(function (RangeValue) {
    function anonymous$2 () {
        RangeValue.apply(this, arguments);
    }if ( RangeValue ) anonymous$2.__proto__ = RangeValue;
    anonymous$2.prototype = Object.create( RangeValue && RangeValue.prototype );
    anonymous$2.prototype.constructor = anonymous$2;

    

    return anonymous$2;
}(RangeValue));
closedBracket.startSide = 1;
closedBracket.endSide = -1;/**
A collection of JavaScript-related
[snippets](https://codemirror.net/6/docs/ref/#autocomplete.snippet).
*/
var snippets = [
    /*@__PURE__*/snippetCompletion("function ${name}(${params}) {\n\t${}\n}", {
        label: "function",
        detail: "definition",
        type: "keyword"
    }),
    /*@__PURE__*/snippetCompletion("for (let ${index} = 0; ${index} < ${bound}; ${index}++) {\n\t${}\n}", {
        label: "for",
        detail: "loop",
        type: "keyword"
    }),
    /*@__PURE__*/snippetCompletion("for (let ${name} of ${collection}) {\n\t${}\n}", {
        label: "for",
        detail: "of loop",
        type: "keyword"
    }),
    /*@__PURE__*/snippetCompletion("do {\n\t${}\n} while (${})", {
        label: "do",
        detail: "loop",
        type: "keyword"
    }),
    /*@__PURE__*/snippetCompletion("while (${}) {\n\t${}\n}", {
        label: "while",
        detail: "loop",
        type: "keyword"
    }),
    /*@__PURE__*/snippetCompletion("try {\n\t${}\n} catch (${error}) {\n\t${}\n}", {
        label: "try",
        detail: "/ catch block",
        type: "keyword"
    }),
    /*@__PURE__*/snippetCompletion("if (${}) {\n\t${}\n}", {
        label: "if",
        detail: "block",
        type: "keyword"
    }),
    /*@__PURE__*/snippetCompletion("if (${}) {\n\t${}\n} else {\n\t${}\n}", {
        label: "if",
        detail: "/ else block",
        type: "keyword"
    }),
    /*@__PURE__*/snippetCompletion("class ${name} {\n\tconstructor(${params}) {\n\t\t${}\n\t}\n}", {
        label: "class",
        detail: "definition",
        type: "keyword"
    }),
    /*@__PURE__*/snippetCompletion("import {${names}} from \"${module}\"\n${}", {
        label: "import",
        detail: "named",
        type: "keyword"
    }),
    /*@__PURE__*/snippetCompletion("import ${name} from \"${module}\"\n${}", {
        label: "import",
        detail: "default",
        type: "keyword"
    })
];
/**
A collection of snippet completions for TypeScript. Includes the
JavaScript [snippets](https://codemirror.net/6/docs/ref/#lang-javascript.snippets).
*/
var typescriptSnippets = /*@__PURE__*/snippets.concat([
    /*@__PURE__*/snippetCompletion("interface ${name} {\n\t${}\n}", {
        label: "interface",
        detail: "definition",
        type: "keyword"
    }),
    /*@__PURE__*/snippetCompletion("type ${name} = ${type}", {
        label: "type",
        detail: "definition",
        type: "keyword"
    }),
    /*@__PURE__*/snippetCompletion("enum ${name} {\n\t${}\n}", {
        label: "enum",
        detail: "definition",
        type: "keyword"
    })
]);

var cache = /*@__PURE__*/new NodeWeakMap();
var ScopeNodes = /*@__PURE__*/new Set([
    "Script", "Block",
    "FunctionExpression", "FunctionDeclaration", "ArrowFunction", "MethodDeclaration",
    "ForStatement"
]);
function defID(type) {
    return function (node, def) {
        var id = node.node.getChild("VariableDefinition");
        if (id)
            { def(id, type); }
        return true;
    };
}
var functionContext = ["FunctionDeclaration"];
var gatherCompletions = {
    FunctionDeclaration: /*@__PURE__*/defID("function"),
    ClassDeclaration: /*@__PURE__*/defID("class"),
    ClassExpression: function () { return true; },
    EnumDeclaration: /*@__PURE__*/defID("constant"),
    TypeAliasDeclaration: /*@__PURE__*/defID("type"),
    NamespaceDeclaration: /*@__PURE__*/defID("namespace"),
    VariableDefinition: function VariableDefinition(node, def) { if (!node.matchContext(functionContext))
        { def(node, "variable"); } },
    TypeDefinition: function TypeDefinition(node, def) { def(node, "type"); },
    __proto__: null
};
function getScope(doc, node) {
    var cached = cache.get(node);
    if (cached)
        { return cached; }
    var completions = [], top = true;
    function def(node, type) {
        var name = doc.sliceString(node.from, node.to);
        completions.push({ label: name, type: type });
    }
    node.cursor(IterMode.IncludeAnonymous).iterate(function (node) {
        if (top) {
            top = false;
        }
        else if (node.name) {
            var gather = gatherCompletions[node.name];
            if (gather && gather(node, def) || ScopeNodes.has(node.name))
                { return false; }
        }
        else if (node.to - node.from > 8192) {
            // Allow caching for bigger internal nodes
            for (var c of getScope(doc, node.node))
                completions.push(c);
            return false;
        }
    });
    cache.set(node, completions);
    return completions;
}
var Identifier = /^[\w$\xa1-\uffff][\w$\d\xa1-\uffff]*$/;
var dontComplete = [
    "TemplateString", "String", "RegExp",
    "LineComment", "BlockComment",
    "VariableDefinition", "TypeDefinition", "Label",
    "PropertyDefinition", "PropertyName",
    "PrivatePropertyDefinition", "PrivatePropertyName",
    ".", "?."
];
/**
Completion source that looks up locally defined names in
JavaScript code.
*/
function localCompletionSource(context) {
    var inner = syntaxTree(context.state).resolveInner(context.pos, -1);
    if (dontComplete.indexOf(inner.name) > -1)
        { return null; }
    var isWord = inner.name == "VariableName" ||
        inner.to - inner.from < 20 && Identifier.test(context.state.sliceDoc(inner.from, inner.to));
    if (!isWord && !context.explicit)
        { return null; }
    var options = [];
    for (var pos = inner; pos; pos = pos.parent) {
        if (ScopeNodes.has(pos.name))
            { options = options.concat(getScope(context.state.doc, pos)); }
    }
    return {
        options: options,
        from: isWord ? inner.from : context.pos,
        validFor: Identifier
    };
}

/**
A language provider based on the [Lezer JavaScript
parser](https://github.com/lezer-parser/javascript), extended with
highlighting and indentation information.
*/
var javascriptLanguage = /*@__PURE__*/LRLanguage.define({
    name: "javascript",
    parser: /*@__PURE__*/parser.configure({
        props: [
            /*@__PURE__*/indentNodeProp.add({
                IfStatement: /*@__PURE__*/continuedIndent({ except: /^\s*({|else\b)/ }),
                TryStatement: /*@__PURE__*/continuedIndent({ except: /^\s*({|catch\b|finally\b)/ }),
                LabeledStatement: flatIndent,
                SwitchBody: function (context) {
                    var after = context.textAfter, closed = /^\s*\}/.test(after), isCase = /^\s*(case|default)\b/.test(after);
                    return context.baseIndent + (closed ? 0 : isCase ? 1 : 2) * context.unit;
                },
                Block: /*@__PURE__*/delimitedIndent({ closing: "}" }),
                ArrowFunction: function (cx) { return cx.baseIndent + cx.unit; },
                "TemplateString BlockComment": function () { return null; },
                "Statement Property": /*@__PURE__*/continuedIndent({ except: /^{/ }),
                JSXElement: function JSXElement(context) {
                    var closed = /^\s*<\//.test(context.textAfter);
                    return context.lineIndent(context.node.from) + (closed ? 0 : context.unit);
                },
                JSXEscape: function JSXEscape(context) {
                    var closed = /\s*\}/.test(context.textAfter);
                    return context.lineIndent(context.node.from) + (closed ? 0 : context.unit);
                },
                "JSXOpenTag JSXSelfClosingTag": function JSXOpenTagJSXSelfClosingTag(context) {
                    return context.column(context.node.from) + context.unit;
                }
            }),
            /*@__PURE__*/foldNodeProp.add({
                "Block ClassBody SwitchBody EnumBody ObjectExpression ArrayExpression ObjectType": foldInside,
                BlockComment: function BlockComment(tree) { return { from: tree.from + 2, to: tree.to - 2 }; }
            })
        ]
    }),
    languageData: {
        closeBrackets: { brackets: ["(", "[", "{", "'", '"', "`"] },
        commentTokens: { line: "//", block: { open: "/*", close: "*/" } },
        indentOnInput: /^\s*(?:case |default:|\{|\}|<\/)$/,
        wordChars: "$"
    }
});
var jsxSublanguage = {
    test: function (node) { return /^JSX/.test(node.name); },
    facet: /*@__PURE__*/defineLanguageFacet({ commentTokens: { block: { open: "{/*", close: "*/}" } } })
};
/**
A language provider for TypeScript.
*/
var typescriptLanguage = /*@__PURE__*/javascriptLanguage.configure({ dialect: "ts" }, "typescript");
/**
Language provider for JSX.
*/
var jsxLanguage = /*@__PURE__*/javascriptLanguage.configure({
    dialect: "jsx",
    props: [/*@__PURE__*/sublanguageProp.add(function (n) { return n.isTop ? [jsxSublanguage] : undefined; })]
});
/**
Language provider for JSX + TypeScript.
*/
var tsxLanguage = /*@__PURE__*/javascriptLanguage.configure({
    dialect: "jsx ts",
    props: [/*@__PURE__*/sublanguageProp.add(function (n) { return n.isTop ? [jsxSublanguage] : undefined; })]
}, "typescript");
var kwCompletion = function (name) { return ({ label: name, type: "keyword" }); };
var keywords = /*@__PURE__*/"break case const continue default delete export extends false finally in instanceof let new return static super switch this throw true typeof var yield".split(" ").map(kwCompletion);
var typescriptKeywords = /*@__PURE__*/keywords.concat(/*@__PURE__*/["declare", "implements", "private", "protected", "public"].map(kwCompletion));
/**
JavaScript support. Includes [snippet](https://codemirror.net/6/docs/ref/#lang-javascript.snippets)
and local variable completion.
*/
function javascript(config) {
    if ( config === void 0 ) config = {};

    var lang = config.jsx ? (config.typescript ? tsxLanguage : jsxLanguage)
        : config.typescript ? typescriptLanguage : javascriptLanguage;
    var completions = config.typescript ? typescriptSnippets.concat(typescriptKeywords) : snippets.concat(keywords);
    return new LanguageSupport(lang, [
        javascriptLanguage.data.of({
            autocomplete: ifNotIn(dontComplete, completeFromList(completions))
        }),
        javascriptLanguage.data.of({
            autocomplete: localCompletionSource
        }),
        config.jsx ? autoCloseTags : [] ]);
}
function findOpenTag(node) {
    for (;;) {
        if (node.name == "JSXOpenTag" || node.name == "JSXSelfClosingTag" || node.name == "JSXFragmentTag")
            { return node; }
        if (node.name == "JSXEscape" || !node.parent)
            { return null; }
        node = node.parent;
    }
}
function elementName(doc, tree, max) {
    if ( max === void 0 ) max = doc.length;

    for (var ch = tree === null || tree === void 0 ? void 0 : tree.firstChild; ch; ch = ch.nextSibling) {
        if (ch.name == "JSXIdentifier" || ch.name == "JSXBuiltin" || ch.name == "JSXNamespacedName" ||
            ch.name == "JSXMemberExpression")
            { return doc.sliceString(ch.from, Math.min(ch.to, max)); }
    }
    return "";
}
var android = typeof navigator == "object" && /*@__PURE__*//Android\b/.test(navigator.userAgent);
/**
Extension that will automatically insert JSX close tags when a `>` or
`/` is typed.
*/
var autoCloseTags = /*@__PURE__*/EditorView.inputHandler.of(function (view, from, to, text, defaultInsert) {
    if ((android ? view.composing : view.compositionStarted) || view.state.readOnly ||
        from != to || (text != ">" && text != "/") ||
        !javascriptLanguage.isActiveAt(view.state, from, -1))
        { return false; }
    var base = defaultInsert();
    var state = base.state;
    var closeTags = state.changeByRange(function (range) {
        var _a;
        var head = range.head;
        var around = syntaxTree(state).resolveInner(head - 1, -1), name;
        if (around.name == "JSXStartTag")
            { around = around.parent; }
        if (state.doc.sliceString(head - 1, head) != text || around.name == "JSXAttributeValue" && around.to > head) ;
        else if (text == ">" && around.name == "JSXFragmentTag") {
            return { range: range, changes: { from: head, insert: "</>" } };
        }
        else if (text == "/" && around.name == "JSXStartCloseTag") {
            var empty = around.parent, base = empty.parent;
            if (base && empty.from == head - 2 &&
                ((name = elementName(state.doc, base.firstChild, head)) || ((_a = base.firstChild) === null || _a === void 0 ? void 0 : _a.name) == "JSXFragmentTag")) {
                var insert = name + ">";
                return { range: EditorSelection.cursor(head + insert.length, -1), changes: { from: head, insert: insert } };
            }
        }
        else if (text == ">") {
            var openTag = findOpenTag(around);
            if (openTag && openTag.name == "JSXOpenTag" &&
                !/^\/?>|^<\//.test(state.doc.sliceString(head, head + 2)) &&
                (name = elementName(state.doc, openTag, head)))
                { return { range: range, changes: { from: head, insert: ("</" + name + ">") } }; }
        }
        return { range: range };
    });
    if (closeTags.changes.empty)
        { return false; }
    view.dispatch([
        base,
        state.update(closeTags, { userEvent: "input.complete", scrollIntoView: true })
    ]);
    return true;
});var CodeBlockView = function CodeBlockView(node, view, getPos) {
    var this$1$1 = this;

    // Store for later
    this.node = node;
    this.view = view;
    this.getPos = getPos;

    // Create a CodeMirror instance
    this.cm = new EditorView({
        doc: this.node.textContent,
        extensions: [
            keymap$3.of(this.codeMirrorKeymap().concat( indentWithTab,
                defaultKeymap
            )),
            drawSelection(),
            lineNumbers(),
            javascript(),
            syntaxHighlighting(defaultHighlightStyle),
            EditorView.updateListener.of(function (update) { return this$1$1.forwardUpdate(update); })
        ]
    });

    // The editor's outer node is our DOM representation
    this.dom = this.cm.dom;

    // This flag is used to avoid an update loop between the outer and inner editor
    this.updating = false;
};

CodeBlockView.prototype.forwardUpdate = function forwardUpdate (update) {
        var this$1$1 = this;

    if (this.updating || !this.cm.hasFocus) { return; }

    var codePos = this.getPos();
        var ref = update.state.selection;
        var main = ref.main;
    var offset = codePos + 1;
    var selFrom = offset + main.from, selTo = offset + main.to;
    var pmSel = this.view.state.selection;

    if (update.docChanged || pmSel.from !== selFrom || pmSel.to !== selTo) {
        var tr = this.view.state.tr;

        update.changes.iterChanges(function (fromA, toA, fromB, toB, text) {
            var from_A = offset + fromA;
            var to_A = offset + toA;

            if (text.length)
                { tr.replaceWith(from_A, to_A, this$1$1.view.state.schema.text(text.toString())); }
            else
                { tr.delete(from_A, to_A); }
            offset += (toB - fromB) - (toA - fromA);
        });

        tr.setSelection(TextSelection.create(tr.doc, selFrom, selTo));
        this.view.dispatch(tr);
    }
};

CodeBlockView.prototype.setSelection = function setSelection (anchor, head) {
    this.cm.focus();
    this.updating = true;
    this.cm.dispatch({selection: {anchor: anchor, head: head}});
    this.updating = false;
};

CodeBlockView.prototype.codeMirrorKeymap = function codeMirrorKeymap () {
        var this$1$1 = this;

    var view = this.view;
    return [
        {key: "ArrowUp", run: function () { return this$1$1.maybeEscape("line", -1); }},
        {key: "ArrowLeft", run: function () { return this$1$1.maybeEscape("char", -1); }},
        {key: "ArrowDown", run: function () { return this$1$1.maybeEscape("line", 1); }},
        {key: "ArrowRight", run: function () { return this$1$1.maybeEscape("char", 1); }},
        {key: "Ctrl-Enter", run: function () { return this$1$1.escapeBlock(); }},
        {key: "Ctrl-z", mac: "Cmd-z",
            run: function () { return undo(view.state, view.dispatch); }},
        {key: "Shift-Ctrl-z", mac: "Shift-Cmd-z",
            run: function () { return redo(view.state, view.dispatch); }},
        {key: "Ctrl-y", mac: "Cmd-y",
            run: function () { return redo(view.state, view.dispatch); }}
    ];
};

CodeBlockView.prototype.escapeBlock = function escapeBlock () {
    if (!exitCode(this.view.state, this.view.dispatch)) { return false; }
    this.view.focus();
    return true;
};

CodeBlockView.prototype.maybeEscape = function maybeEscape (unit, dir) {
    var ref = this.cm;
        var state = ref.state;
        var ref$1 = state.selection;
        var main = ref$1.main;
    if (!main.empty) { return false; }
    if (unit === "line") { main = state.doc.lineAt(main.head); }
    if (dir < 0 ? main.from > 0 : main.to < state.doc.length) { return false; }
    var targetPos = this.getPos() + (dir < 0 ? 0 : this.node.nodeSize);
    if (dir > 0 && main.to === state.doc.length && targetPos === this.view.state.doc.content.size) {
        this.escapeBlock();
    }
    var selection = Selection.near(this.view.state.doc.resolve(targetPos), dir);
    var tr = this.view.state.tr.setSelection(selection).scrollIntoView();
    this.view.dispatch(tr);
    this.view.focus();
};

CodeBlockView.prototype.update = function update (node) {
    if (node.type !== this.node.type) { return false; }
    this.node = node;
    if (this.updating) { return true; }
    var newText = node.textContent, curText = this.cm.state.doc.toString();

    if (newText !== curText) {
        var start = 0, curEnd = curText.length, newEnd = newText.length;
        while (start < curEnd && curText.charCodeAt(start) === newText.charCodeAt(start)) {
            ++start;
        }
        while (curEnd > start && newEnd > start && curText.charCodeAt(curEnd - 1) === newText.charCodeAt(newEnd - 1)) {
            curEnd--;
            newEnd--;
        }
        this.updating = true;
        this.cm.dispatch({
            changes: {
                from: start, to: curEnd,
                insert: newText.slice(start, newEnd)
            }
        });
        this.updating = false;
    }

    return true;
};

CodeBlockView.prototype.selectNode = function selectNode () {
    this.cm.focus();
};

CodeBlockView.prototype.stopEvent = function stopEvent () {
    return true;
};

var codeBlockPlugin = function (context) {
    return new Plugin({
        props: {
            nodeViews: {
                code_block: function (node, view, getPos) { return new CodeBlockView(node, view, getPos); }
            }
        }
    });
};/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 */


// : (NodeType) → InputRule
// Given a blockquote node type, returns an input rule that turns `"> "`
// at the start of a textblock into a blockquote.
var codeBlockRule = function (schema) {
    return textblockTypeInputRule(/^```$/, schema.nodes.code_block);
};/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 */


var code_block = {
    id: 'code_block',
    schema: schema$j,
    menu: function (context) { return menu$g(context); },
    inputRules: function (schema) {return [codeBlockRule(schema)]},
    keymap: function () { return keymap$4(); },
    plugins: function (context) {
        return [codeBlockPlugin()];
    }
};/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 */

var schema$i = {
    marks: {
        em: {
            sortOrder: 100,
            parseDOM: [{tag: "i"}, {tag: "em"},
                {
                    style: "font-style", getAttrs: function (value) {
                    return value === "italic" && null;
                }
                }],
            toDOM: function () {
                return ["em"]
            },
            parseMarkdown: {mark: "em"},
            toMarkdown: {open: "_", close: "_", mixable: true, expelEnclosingWhitespace: true}
        }
    }
};/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 *
 */



function markEm(context) {
    return markItem(context.schema.marks.em, {
        title: context.translate("Toggle emphasis"),
        icon: icons.em,
        sortOrder: 200
    }, context);
}

function menu$f(context) {
    return [
        {
            id: 'markEm',
            mark: 'em',
            group: 'marks',
            item: markEm(context)
        }
    ]
}/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 *
 */

var em = {
    id: 'em',
    schema: schema$i,
    menu: function (context) { return menu$f(context); }
};/*! Copyright Twitter Inc. and other contributors. Licensed under MIT */
var twemoji=function(){var twemoji={base:"https://twemoji.maxcdn.com/v/14.0.2/",ext:".png",size:"72x72",className:"emoji",convert:{fromCodePoint:fromCodePoint,toCodePoint:toCodePoint},onerror:function onerror(){if(this.parentNode){this.parentNode.replaceChild(createText(this.alt,false),this);}},parse:parse,replace:replace,test:test},escaper={"&":"&amp;","<":"&lt;",">":"&gt;","'":"&#39;",'"':"&quot;"},re=/(?:\ud83d\udc68\ud83c\udffb\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc68\ud83c\udffc\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc68\ud83c\udffd\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc68\ud83c\udffe\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc68\ud83c\udfff\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffb\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffb\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc69\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffc\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffc\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc69\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffd\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffd\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc69\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffe\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffe\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc69\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udfff\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udfff\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc69\ud83c[\udffb-\udfff]|\ud83e\uddd1\ud83c\udffb\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83e\uddd1\ud83c[\udffc-\udfff]|\ud83e\uddd1\ud83c\udffc\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83e\uddd1\ud83c[\udffb\udffd-\udfff]|\ud83e\uddd1\ud83c\udffd\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83e\uddd1\ud83c[\udffb\udffc\udffe\udfff]|\ud83e\uddd1\ud83c\udffe\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83e\uddd1\ud83c[\udffb-\udffd\udfff]|\ud83e\uddd1\ud83c\udfff\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83e\uddd1\ud83c[\udffb-\udffe]|\ud83d\udc68\ud83c\udffb\u200d\u2764\ufe0f\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc68\ud83c\udffb\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffc-\udfff]|\ud83d\udc68\ud83c\udffc\u200d\u2764\ufe0f\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc68\ud83c\udffc\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffb\udffd-\udfff]|\ud83d\udc68\ud83c\udffd\u200d\u2764\ufe0f\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc68\ud83c\udffd\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffb\udffc\udffe\udfff]|\ud83d\udc68\ud83c\udffe\u200d\u2764\ufe0f\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc68\ud83c\udffe\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffb-\udffd\udfff]|\ud83d\udc68\ud83c\udfff\u200d\u2764\ufe0f\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc68\ud83c\udfff\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffb-\udffe]|\ud83d\udc69\ud83c\udffb\u200d\u2764\ufe0f\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffb\u200d\u2764\ufe0f\u200d\ud83d\udc69\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffb\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffc-\udfff]|\ud83d\udc69\ud83c\udffb\u200d\ud83e\udd1d\u200d\ud83d\udc69\ud83c[\udffc-\udfff]|\ud83d\udc69\ud83c\udffc\u200d\u2764\ufe0f\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffc\u200d\u2764\ufe0f\u200d\ud83d\udc69\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffc\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffb\udffd-\udfff]|\ud83d\udc69\ud83c\udffc\u200d\ud83e\udd1d\u200d\ud83d\udc69\ud83c[\udffb\udffd-\udfff]|\ud83d\udc69\ud83c\udffd\u200d\u2764\ufe0f\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffd\u200d\u2764\ufe0f\u200d\ud83d\udc69\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffd\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffb\udffc\udffe\udfff]|\ud83d\udc69\ud83c\udffd\u200d\ud83e\udd1d\u200d\ud83d\udc69\ud83c[\udffb\udffc\udffe\udfff]|\ud83d\udc69\ud83c\udffe\u200d\u2764\ufe0f\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffe\u200d\u2764\ufe0f\u200d\ud83d\udc69\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffe\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffb-\udffd\udfff]|\ud83d\udc69\ud83c\udffe\u200d\ud83e\udd1d\u200d\ud83d\udc69\ud83c[\udffb-\udffd\udfff]|\ud83d\udc69\ud83c\udfff\u200d\u2764\ufe0f\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udfff\u200d\u2764\ufe0f\u200d\ud83d\udc69\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udfff\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffb-\udffe]|\ud83d\udc69\ud83c\udfff\u200d\ud83e\udd1d\u200d\ud83d\udc69\ud83c[\udffb-\udffe]|\ud83e\uddd1\ud83c\udffb\u200d\u2764\ufe0f\u200d\ud83e\uddd1\ud83c[\udffc-\udfff]|\ud83e\uddd1\ud83c\udffb\u200d\ud83e\udd1d\u200d\ud83e\uddd1\ud83c[\udffb-\udfff]|\ud83e\uddd1\ud83c\udffc\u200d\u2764\ufe0f\u200d\ud83e\uddd1\ud83c[\udffb\udffd-\udfff]|\ud83e\uddd1\ud83c\udffc\u200d\ud83e\udd1d\u200d\ud83e\uddd1\ud83c[\udffb-\udfff]|\ud83e\uddd1\ud83c\udffd\u200d\u2764\ufe0f\u200d\ud83e\uddd1\ud83c[\udffb\udffc\udffe\udfff]|\ud83e\uddd1\ud83c\udffd\u200d\ud83e\udd1d\u200d\ud83e\uddd1\ud83c[\udffb-\udfff]|\ud83e\uddd1\ud83c\udffe\u200d\u2764\ufe0f\u200d\ud83e\uddd1\ud83c[\udffb-\udffd\udfff]|\ud83e\uddd1\ud83c\udffe\u200d\ud83e\udd1d\u200d\ud83e\uddd1\ud83c[\udffb-\udfff]|\ud83e\uddd1\ud83c\udfff\u200d\u2764\ufe0f\u200d\ud83e\uddd1\ud83c[\udffb-\udffe]|\ud83e\uddd1\ud83c\udfff\u200d\ud83e\udd1d\u200d\ud83e\uddd1\ud83c[\udffb-\udfff]|\ud83d\udc68\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68|\ud83d\udc69\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d[\udc68\udc69]|\ud83e\udef1\ud83c\udffb\u200d\ud83e\udef2\ud83c[\udffc-\udfff]|\ud83e\udef1\ud83c\udffc\u200d\ud83e\udef2\ud83c[\udffb\udffd-\udfff]|\ud83e\udef1\ud83c\udffd\u200d\ud83e\udef2\ud83c[\udffb\udffc\udffe\udfff]|\ud83e\udef1\ud83c\udffe\u200d\ud83e\udef2\ud83c[\udffb-\udffd\udfff]|\ud83e\udef1\ud83c\udfff\u200d\ud83e\udef2\ud83c[\udffb-\udffe]|\ud83d\udc68\u200d\u2764\ufe0f\u200d\ud83d\udc68|\ud83d\udc69\u200d\u2764\ufe0f\u200d\ud83d[\udc68\udc69]|\ud83e\uddd1\u200d\ud83e\udd1d\u200d\ud83e\uddd1|\ud83d\udc6b\ud83c[\udffb-\udfff]|\ud83d\udc6c\ud83c[\udffb-\udfff]|\ud83d\udc6d\ud83c[\udffb-\udfff]|\ud83d\udc8f\ud83c[\udffb-\udfff]|\ud83d\udc91\ud83c[\udffb-\udfff]|\ud83e\udd1d\ud83c[\udffb-\udfff]|\ud83d[\udc6b-\udc6d\udc8f\udc91]|\ud83e\udd1d)|(?:\ud83d[\udc68\udc69]|\ud83e\uddd1)(?:\ud83c[\udffb-\udfff])?\u200d(?:\u2695\ufe0f|\u2696\ufe0f|\u2708\ufe0f|\ud83c[\udf3e\udf73\udf7c\udf84\udf93\udfa4\udfa8\udfeb\udfed]|\ud83d[\udcbb\udcbc\udd27\udd2c\ude80\ude92]|\ud83e[\uddaf-\uddb3\uddbc\uddbd])|(?:\ud83c[\udfcb\udfcc]|\ud83d[\udd74\udd75]|\u26f9)((?:\ud83c[\udffb-\udfff]|\ufe0f)\u200d[\u2640\u2642]\ufe0f)|(?:\ud83c[\udfc3\udfc4\udfca]|\ud83d[\udc6e\udc70\udc71\udc73\udc77\udc81\udc82\udc86\udc87\ude45-\ude47\ude4b\ude4d\ude4e\udea3\udeb4-\udeb6]|\ud83e[\udd26\udd35\udd37-\udd39\udd3d\udd3e\uddb8\uddb9\uddcd-\uddcf\uddd4\uddd6-\udddd])(?:\ud83c[\udffb-\udfff])?\u200d[\u2640\u2642]\ufe0f|(?:\ud83d\udc68\u200d\ud83d\udc68\u200d\ud83d\udc66\u200d\ud83d\udc66|\ud83d\udc68\u200d\ud83d\udc68\u200d\ud83d\udc67\u200d\ud83d[\udc66\udc67]|\ud83d\udc68\u200d\ud83d\udc69\u200d\ud83d\udc66\u200d\ud83d\udc66|\ud83d\udc68\u200d\ud83d\udc69\u200d\ud83d\udc67\u200d\ud83d[\udc66\udc67]|\ud83d\udc69\u200d\ud83d\udc69\u200d\ud83d\udc66\u200d\ud83d\udc66|\ud83d\udc69\u200d\ud83d\udc69\u200d\ud83d\udc67\u200d\ud83d[\udc66\udc67]|\ud83d\udc68\u200d\ud83d\udc66\u200d\ud83d\udc66|\ud83d\udc68\u200d\ud83d\udc67\u200d\ud83d[\udc66\udc67]|\ud83d\udc68\u200d\ud83d\udc68\u200d\ud83d[\udc66\udc67]|\ud83d\udc68\u200d\ud83d\udc69\u200d\ud83d[\udc66\udc67]|\ud83d\udc69\u200d\ud83d\udc66\u200d\ud83d\udc66|\ud83d\udc69\u200d\ud83d\udc67\u200d\ud83d[\udc66\udc67]|\ud83d\udc69\u200d\ud83d\udc69\u200d\ud83d[\udc66\udc67]|\ud83c\udff3\ufe0f\u200d\u26a7\ufe0f|\ud83c\udff3\ufe0f\u200d\ud83c\udf08|\ud83d\ude36\u200d\ud83c\udf2b\ufe0f|\u2764\ufe0f\u200d\ud83d\udd25|\u2764\ufe0f\u200d\ud83e\ude79|\ud83c\udff4\u200d\u2620\ufe0f|\ud83d\udc15\u200d\ud83e\uddba|\ud83d\udc3b\u200d\u2744\ufe0f|\ud83d\udc41\u200d\ud83d\udde8|\ud83d\udc68\u200d\ud83d[\udc66\udc67]|\ud83d\udc69\u200d\ud83d[\udc66\udc67]|\ud83d\udc6f\u200d\u2640\ufe0f|\ud83d\udc6f\u200d\u2642\ufe0f|\ud83d\ude2e\u200d\ud83d\udca8|\ud83d\ude35\u200d\ud83d\udcab|\ud83e\udd3c\u200d\u2640\ufe0f|\ud83e\udd3c\u200d\u2642\ufe0f|\ud83e\uddde\u200d\u2640\ufe0f|\ud83e\uddde\u200d\u2642\ufe0f|\ud83e\udddf\u200d\u2640\ufe0f|\ud83e\udddf\u200d\u2642\ufe0f|\ud83d\udc08\u200d\u2b1b)|[#*0-9]\ufe0f?\u20e3|(?:[©®\u2122\u265f]\ufe0f)|(?:\ud83c[\udc04\udd70\udd71\udd7e\udd7f\ude02\ude1a\ude2f\ude37\udf21\udf24-\udf2c\udf36\udf7d\udf96\udf97\udf99-\udf9b\udf9e\udf9f\udfcd\udfce\udfd4-\udfdf\udff3\udff5\udff7]|\ud83d[\udc3f\udc41\udcfd\udd49\udd4a\udd6f\udd70\udd73\udd76-\udd79\udd87\udd8a-\udd8d\udda5\udda8\uddb1\uddb2\uddbc\uddc2-\uddc4\uddd1-\uddd3\udddc-\uddde\udde1\udde3\udde8\uddef\uddf3\uddfa\udecb\udecd-\udecf\udee0-\udee5\udee9\udef0\udef3]|[\u203c\u2049\u2139\u2194-\u2199\u21a9\u21aa\u231a\u231b\u2328\u23cf\u23ed-\u23ef\u23f1\u23f2\u23f8-\u23fa\u24c2\u25aa\u25ab\u25b6\u25c0\u25fb-\u25fe\u2600-\u2604\u260e\u2611\u2614\u2615\u2618\u2620\u2622\u2623\u2626\u262a\u262e\u262f\u2638-\u263a\u2640\u2642\u2648-\u2653\u2660\u2663\u2665\u2666\u2668\u267b\u267f\u2692-\u2697\u2699\u269b\u269c\u26a0\u26a1\u26a7\u26aa\u26ab\u26b0\u26b1\u26bd\u26be\u26c4\u26c5\u26c8\u26cf\u26d1\u26d3\u26d4\u26e9\u26ea\u26f0-\u26f5\u26f8\u26fa\u26fd\u2702\u2708\u2709\u270f\u2712\u2714\u2716\u271d\u2721\u2733\u2734\u2744\u2747\u2757\u2763\u2764\u27a1\u2934\u2935\u2b05-\u2b07\u2b1b\u2b1c\u2b50\u2b55\u3030\u303d\u3297\u3299])(?:\ufe0f|(?!\ufe0e))|(?:(?:\ud83c[\udfcb\udfcc]|\ud83d[\udd74\udd75\udd90]|[\u261d\u26f7\u26f9\u270c\u270d])(?:\ufe0f|(?!\ufe0e))|(?:\ud83c[\udf85\udfc2-\udfc4\udfc7\udfca]|\ud83d[\udc42\udc43\udc46-\udc50\udc66-\udc69\udc6e\udc70-\udc78\udc7c\udc81-\udc83\udc85-\udc87\udcaa\udd7a\udd95\udd96\ude45-\ude47\ude4b-\ude4f\udea3\udeb4-\udeb6\udec0\udecc]|\ud83e[\udd0c\udd0f\udd18-\udd1c\udd1e\udd1f\udd26\udd30-\udd39\udd3d\udd3e\udd77\uddb5\uddb6\uddb8\uddb9\uddbb\uddcd-\uddcf\uddd1-\udddd\udec3-\udec5\udef0-\udef6]|[\u270a\u270b]))(?:\ud83c[\udffb-\udfff])?|(?:\ud83c\udff4\udb40\udc67\udb40\udc62\udb40\udc65\udb40\udc6e\udb40\udc67\udb40\udc7f|\ud83c\udff4\udb40\udc67\udb40\udc62\udb40\udc73\udb40\udc63\udb40\udc74\udb40\udc7f|\ud83c\udff4\udb40\udc67\udb40\udc62\udb40\udc77\udb40\udc6c\udb40\udc73\udb40\udc7f|\ud83c\udde6\ud83c[\udde8-\uddec\uddee\uddf1\uddf2\uddf4\uddf6-\uddfa\uddfc\uddfd\uddff]|\ud83c\udde7\ud83c[\udde6\udde7\udde9-\uddef\uddf1-\uddf4\uddf6-\uddf9\uddfb\uddfc\uddfe\uddff]|\ud83c\udde8\ud83c[\udde6\udde8\udde9\uddeb-\uddee\uddf0-\uddf5\uddf7\uddfa-\uddff]|\ud83c\udde9\ud83c[\uddea\uddec\uddef\uddf0\uddf2\uddf4\uddff]|\ud83c\uddea\ud83c[\udde6\udde8\uddea\uddec\udded\uddf7-\uddfa]|\ud83c\uddeb\ud83c[\uddee-\uddf0\uddf2\uddf4\uddf7]|\ud83c\uddec\ud83c[\udde6\udde7\udde9-\uddee\uddf1-\uddf3\uddf5-\uddfa\uddfc\uddfe]|\ud83c\udded\ud83c[\uddf0\uddf2\uddf3\uddf7\uddf9\uddfa]|\ud83c\uddee\ud83c[\udde8-\uddea\uddf1-\uddf4\uddf6-\uddf9]|\ud83c\uddef\ud83c[\uddea\uddf2\uddf4\uddf5]|\ud83c\uddf0\ud83c[\uddea\uddec-\uddee\uddf2\uddf3\uddf5\uddf7\uddfc\uddfe\uddff]|\ud83c\uddf1\ud83c[\udde6-\udde8\uddee\uddf0\uddf7-\uddfb\uddfe]|\ud83c\uddf2\ud83c[\udde6\udde8-\udded\uddf0-\uddff]|\ud83c\uddf3\ud83c[\udde6\udde8\uddea-\uddec\uddee\uddf1\uddf4\uddf5\uddf7\uddfa\uddff]|\ud83c\uddf4\ud83c\uddf2|\ud83c\uddf5\ud83c[\udde6\uddea-\udded\uddf0-\uddf3\uddf7-\uddf9\uddfc\uddfe]|\ud83c\uddf6\ud83c\udde6|\ud83c\uddf7\ud83c[\uddea\uddf4\uddf8\uddfa\uddfc]|\ud83c\uddf8\ud83c[\udde6-\uddea\uddec-\uddf4\uddf7-\uddf9\uddfb\uddfd-\uddff]|\ud83c\uddf9\ud83c[\udde6\udde8\udde9\uddeb-\udded\uddef-\uddf4\uddf7\uddf9\uddfb\uddfc\uddff]|\ud83c\uddfa\ud83c[\udde6\uddec\uddf2\uddf3\uddf8\uddfe\uddff]|\ud83c\uddfb\ud83c[\udde6\udde8\uddea\uddec\uddee\uddf3\uddfa]|\ud83c\uddfc\ud83c[\uddeb\uddf8]|\ud83c\uddfd\ud83c\uddf0|\ud83c\uddfe\ud83c[\uddea\uddf9]|\ud83c\uddff\ud83c[\udde6\uddf2\uddfc]|\ud83c[\udccf\udd8e\udd91-\udd9a\udde6-\uddff\ude01\ude32-\ude36\ude38-\ude3a\ude50\ude51\udf00-\udf20\udf2d-\udf35\udf37-\udf7c\udf7e-\udf84\udf86-\udf93\udfa0-\udfc1\udfc5\udfc6\udfc8\udfc9\udfcf-\udfd3\udfe0-\udff0\udff4\udff8-\udfff]|\ud83d[\udc00-\udc3e\udc40\udc44\udc45\udc51-\udc65\udc6a\udc6f\udc79-\udc7b\udc7d-\udc80\udc84\udc88-\udc8e\udc90\udc92-\udca9\udcab-\udcfc\udcff-\udd3d\udd4b-\udd4e\udd50-\udd67\udda4\uddfb-\ude44\ude48-\ude4a\ude80-\udea2\udea4-\udeb3\udeb7-\udebf\udec1-\udec5\uded0-\uded2\uded5-\uded7\udedd-\udedf\udeeb\udeec\udef4-\udefc\udfe0-\udfeb\udff0]|\ud83e[\udd0d\udd0e\udd10-\udd17\udd20-\udd25\udd27-\udd2f\udd3a\udd3c\udd3f-\udd45\udd47-\udd76\udd78-\uddb4\uddb7\uddba\uddbc-\uddcc\uddd0\uddde-\uddff\ude70-\ude74\ude78-\ude7c\ude80-\ude86\ude90-\udeac\udeb0-\udeba\udec0-\udec2\uded0-\uded9\udee0-\udee7]|[\u23e9-\u23ec\u23f0\u23f3\u267e\u26ce\u2705\u2728\u274c\u274e\u2753-\u2755\u2795-\u2797\u27b0\u27bf\ue50a])|\ufe0f/g,UFE0Fg=/\uFE0F/g,U200D=String.fromCharCode(8205),rescaper=/[&<>'"]/g,shouldntBeParsed=/^(?:iframe|noframes|noscript|script|select|style|textarea)$/,fromCharCode=String.fromCharCode;return twemoji;function createText(text,clean){return document.createTextNode(clean?text.replace(UFE0Fg,""):text)}function escapeHTML(s){return s.replace(rescaper,replacer)}function defaultImageSrcGenerator(icon,options){return "".concat(options.base,options.size,"/",icon,options.ext)}function grabAllTextNodes(node,allText){var childNodes=node.childNodes,length=childNodes.length,subnode,nodeType;while(length--){subnode=childNodes[length];nodeType=subnode.nodeType;if(nodeType===3){allText.push(subnode);}else if(nodeType===1&&!("ownerSVGElement"in subnode)&&!shouldntBeParsed.test(subnode.nodeName.toLowerCase())){grabAllTextNodes(subnode,allText);}}return allText}function grabTheRightIcon(rawText){return toCodePoint(rawText.indexOf(U200D)<0?rawText.replace(UFE0Fg,""):rawText)}function parseNode(node,options){var allText=grabAllTextNodes(node,[]),length=allText.length,attrib,attrname,modified,fragment,subnode,text,match,i,index,img,rawText,iconId,src;while(length--){modified=false;fragment=document.createDocumentFragment();subnode=allText[length];text=subnode.nodeValue;i=0;while(match=re.exec(text)){index=match.index;if(index!==i){fragment.appendChild(createText(text.slice(i,index),true));}rawText=match[0];iconId=grabTheRightIcon(rawText);i=index+rawText.length;src=options.callback(iconId,options);if(iconId&&src){img=new Image;img.onerror=options.onerror;img.setAttribute("draggable","false");attrib=options.attributes(rawText,iconId);for(attrname in attrib){if(attrib.hasOwnProperty(attrname)&&attrname.indexOf("on")!==0&&!img.hasAttribute(attrname)){img.setAttribute(attrname,attrib[attrname]);}}img.className=options.className;img.alt=rawText;img.src=src;modified=true;fragment.appendChild(img);}if(!img){ fragment.appendChild(createText(rawText,false)); }img=null;}if(modified){if(i<text.length){fragment.appendChild(createText(text.slice(i),true));}subnode.parentNode.replaceChild(fragment,subnode);}}return node}function parseString(str,options){return replace(str,function(rawText){var ret=rawText,iconId=grabTheRightIcon(rawText),src=options.callback(iconId,options),attrib,attrname;if(iconId&&src){ret="<img ".concat('class="',options.className,'" ','draggable="false" ','alt="',rawText,'"',' src="',src,'"');attrib=options.attributes(rawText,iconId);for(attrname in attrib){if(attrib.hasOwnProperty(attrname)&&attrname.indexOf("on")!==0&&ret.indexOf(" "+attrname+"=")===-1){ret=ret.concat(" ",attrname,'="',escapeHTML(attrib[attrname]),'"');}}ret=ret.concat("/>");}return ret})}function replacer(m){return escaper[m]}function returnNull(){return null}function toSizeSquaredAsset(value){return typeof value==="number"?value+"x"+value:value}function fromCodePoint(codepoint){var code=typeof codepoint==="string"?parseInt(codepoint,16):codepoint;if(code<65536){return fromCharCode(code)}code-=65536;return fromCharCode(55296+(code>>10),56320+(code&1023))}function parse(what,how){if(!how||typeof how==="function"){how={callback:how};}return (typeof what==="string"?parseString:parseNode)(what,{callback:how.callback||defaultImageSrcGenerator,attributes:typeof how.attributes==="function"?how.attributes:returnNull,base:typeof how.base==="string"?how.base:twemoji.base,ext:how.ext||twemoji.ext,size:how.folder||toSizeSquaredAsset(how.size||twemoji.size),className:how.className||twemoji.className,onerror:how.onerror||twemoji.onerror})}function replace(text,callback){return String(text).replace(re,callback)}function test(text){re.lastIndex=0;var result=re.test(text);re.lastIndex=0;return result}function toCodePoint(unicodeSurrogates,sep){var r=[],c=0,p=0,i=0;while(i<unicodeSurrogates.length){c=unicodeSurrogates.charCodeAt(i++);if(p){r.push((65536+(p-55296<<10)+(c-56320)).toString(16));p=0;}else if(55296<=c&&c<=56319){p=c;}else {r.push(c.toString(16));}}return r.join(sep||"-")}}();
var schema$h = {
    nodes: {
        emoji: {
            attrs: {
                class: {default: 'emoji'},
                draggable: {default: 'false'},
                width: {default: '16'},
                height: {default: '16'},
                'data-name': {default: null},
                alt: {default: null},
                src: {default: null},
            },
            inline: true,
            group: "inline",
            parseDOM: [{
                tag: "img.emoji",
                getAttrs: function (dom) {
                    return {
                        src: dom.getAttribute("src"),
                        alt: dom.getAttribute("alt"),
                        'data-name': String(dom.getAttribute('data-name'))
                    };
                }
            }],
            toDOM: function (node) {
                return ['img', node.attrs];
            },
            parseMarkdown: {
                node: "emoji",
                getAttrs: function (tok) {
                    // Workaround, since the context is not available here,
                    // so we can't use context.getPluginOption('emoji', 'twemoji');
                    var options = getEmojiConfig()['twemoji'];

                    var $dom = $(twemoji.parse(tok.content, options));
                    return ({
                        'data-name': String(tok.markup),
                        alt: $dom.attr('alt'),
                        src: $dom.attr('src')
                    });
                }
            },
            toMarkdown: function (state, node) {
                var result;

                if (!node.attrs['data-name']) {
                    result = (state.alt) ? state.esc(state.alt) : '';
                } else {
                    result = ':' + state.esc(node.attrs['data-name']) + ':';
                }

                state.write(result);
            }
        }
    },
    marks: {
        emojiQuery: {
            excludes: "_",
            inclusive: true,
            parseDOM: [
                {tag: 'span[data-emoji-query]'}
            ],
            toDOM: function toDOM(node) {
                return ['span', {
                    'data-emoji-query': true,
                }];
            }
        }
    }
};function getDefaultExportFromCjs (x) {
	return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
}

function getAugmentedNamespace(n) {
  if (n.__esModule) return n;
  var f = n.default;
	if (typeof f == "function") {
		var a = function a () {
			if (this instanceof a) {
        return Reflect.construct(f, arguments, this.constructor);
			}
			return f.apply(this, arguments);
		};
		a.prototype = f.prototype;
  } else a = {};
  Object.defineProperty(a, '__esModule', {value: true});
	Object.keys(n).forEach(function (k) {
		var d = Object.getOwnPropertyDescriptor(n, k);
		Object.defineProperty(a, k, d.get ? d : {
			enumerable: true,
			get: function () {
				return n[k];
			}
		});
	});
	return a;
}var grinning$2 = "😀";
var smiley$2 = "😃";
var smile$3 = "😄";
var grin$2 = "😁";
var laughing$2 = "😆";
var satisfied = "😆";
var sweat_smile$2 = "😅";
var rofl$2 = "🤣";
var joy$2 = "😂";
var slightly_smiling_face$2 = "🙂";
var upside_down_face$2 = "🙃";
var wink$2 = "😉";
var blush$2 = "😊";
var innocent$2 = "😇";
var smiling_face_with_three_hearts$2 = "🥰";
var heart_eyes$2 = "😍";
var star_struck$2 = "🤩";
var kissing_heart$2 = "😘";
var kissing$2 = "😗";
var relaxed$2 = "☺️";
var kissing_closed_eyes$2 = "😚";
var kissing_smiling_eyes$2 = "😙";
var smiling_face_with_tear = "🥲";
var yum$2 = "😋";
var stuck_out_tongue$2 = "😛";
var stuck_out_tongue_winking_eye$2 = "😜";
var zany_face = "🤪";
var stuck_out_tongue_closed_eyes$2 = "😝";
var money_mouth_face$2 = "🤑";
var hugs$2 = "🤗";
var hand_over_mouth$2 = "🤭";
var shushing_face = "🤫";
var thinking$2 = "🤔";
var zipper_mouth_face$2 = "🤐";
var raised_eyebrow$2 = "🤨";
var neutral_face$2 = "😐";
var expressionless$2 = "😑";
var no_mouth$2 = "😶";
var smirk$2 = "😏";
var unamused$2 = "😒";
var roll_eyes$2 = "🙄";
var grimacing$2 = "😬";
var lying_face$2 = "🤥";
var relieved$2 = "😌";
var pensive$2 = "😔";
var sleepy$2 = "😪";
var drooling_face$2 = "🤤";
var sleeping$2 = "😴";
var mask$2 = "😷";
var face_with_thermometer$2 = "🤒";
var face_with_head_bandage$2 = "🤕";
var nauseated_face$2 = "🤢";
var vomiting_face = "🤮";
var sneezing_face$2 = "🤧";
var hot_face = "🥵";
var cold_face = "🥶";
var woozy_face = "🥴";
var dizzy_face$2 = "😵";
var exploding_head$2 = "🤯";
var cowboy_hat_face$2 = "🤠";
var partying_face = "🥳";
var disguised_face = "🥸";
var sunglasses$2 = "😎";
var nerd_face$2 = "🤓";
var monocle_face = "🧐";
var confused$2 = "😕";
var worried$2 = "😟";
var slightly_frowning_face$2 = "🙁";
var frowning_face$2 = "☹️";
var open_mouth$2 = "😮";
var hushed$2 = "😯";
var astonished$2 = "😲";
var flushed$2 = "😳";
var pleading_face = "🥺";
var frowning$2 = "😦";
var anguished$2 = "😧";
var fearful$2 = "😨";
var cold_sweat$2 = "😰";
var disappointed_relieved$2 = "😥";
var cry$2 = "😢";
var sob$2 = "😭";
var scream$2 = "😱";
var confounded$2 = "😖";
var persevere$2 = "😣";
var disappointed$2 = "😞";
var sweat$2 = "😓";
var weary$2 = "😩";
var tired_face$2 = "😫";
var yawning_face = "🥱";
var triumph$2 = "😤";
var rage$2 = "😡";
var pout = "😡";
var angry$2 = "😠";
var cursing_face = "🤬";
var smiling_imp$2 = "😈";
var imp$2 = "👿";
var skull$2 = "💀";
var skull_and_crossbones$2 = "☠️";
var hankey = "💩";
var poop$2 = "💩";
var shit = "💩";
var clown_face$2 = "🤡";
var japanese_ogre$2 = "👹";
var japanese_goblin$2 = "👺";
var ghost$2 = "👻";
var alien$2 = "👽";
var space_invader$2 = "👾";
var robot$2 = "🤖";
var smiley_cat$2 = "😺";
var smile_cat$2 = "😸";
var joy_cat$2 = "😹";
var heart_eyes_cat$2 = "😻";
var smirk_cat$2 = "😼";
var kissing_cat$2 = "😽";
var scream_cat$2 = "🙀";
var crying_cat_face$2 = "😿";
var pouting_cat$2 = "😾";
var see_no_evil$2 = "🙈";
var hear_no_evil$2 = "🙉";
var speak_no_evil$2 = "🙊";
var kiss$2 = "💋";
var love_letter$2 = "💌";
var cupid$2 = "💘";
var gift_heart$2 = "💝";
var sparkling_heart$2 = "💖";
var heartpulse$2 = "💗";
var heartbeat$2 = "💓";
var revolving_hearts$2 = "💞";
var two_hearts$2 = "💕";
var heart_decoration$2 = "💟";
var heavy_heart_exclamation$2 = "❣️";
var broken_heart$2 = "💔";
var heart$2 = "❤️";
var orange_heart$2 = "🧡";
var yellow_heart$2 = "💛";
var green_heart$2 = "💚";
var blue_heart$2 = "💙";
var purple_heart$2 = "💜";
var brown_heart = "🤎";
var black_heart$2 = "🖤";
var white_heart = "🤍";
var anger$2 = "💢";
var boom$2 = "💥";
var collision = "💥";
var dizzy$2 = "💫";
var sweat_drops$2 = "💦";
var dash$3 = "💨";
var hole$2 = "🕳️";
var bomb$2 = "💣";
var speech_balloon$2 = "💬";
var eye_speech_bubble = "👁️‍🗨️";
var left_speech_bubble$2 = "🗨️";
var right_anger_bubble$2 = "🗯️";
var thought_balloon$2 = "💭";
var zzz$2 = "💤";
var wave$2 = "👋";
var raised_back_of_hand$2 = "🤚";
var raised_hand_with_fingers_splayed$2 = "🖐️";
var hand = "✋";
var raised_hand$2 = "✋";
var vulcan_salute$2 = "🖖";
var ok_hand$2 = "👌";
var pinched_fingers = "🤌";
var pinching_hand = "🤏";
var v$2 = "✌️";
var crossed_fingers$2 = "🤞";
var love_you_gesture = "🤟";
var metal$2 = "🤘";
var call_me_hand$2 = "🤙";
var point_left$2 = "👈";
var point_right$2 = "👉";
var point_up_2$2 = "👆";
var middle_finger = "🖕";
var fu$2 = "🖕";
var point_down$2 = "👇";
var point_up$2 = "☝️";
var thumbsup = "👍";
var thumbsdown = "👎";
var fist_raised = "✊";
var fist$2 = "✊";
var fist_oncoming = "👊";
var facepunch$2 = "👊";
var punch = "👊";
var fist_left$2 = "🤛";
var fist_right$2 = "🤜";
var clap$2 = "👏";
var raised_hands$2 = "🙌";
var open_hands$2 = "👐";
var palms_up_together = "🤲";
var handshake$2 = "🤝";
var pray$2 = "🙏";
var writing_hand$2 = "✍️";
var nail_care$2 = "💅";
var selfie$2 = "🤳";
var muscle$2 = "💪";
var mechanical_arm = "🦾";
var mechanical_leg = "🦿";
var leg$3 = "🦵";
var foot$2 = "🦶";
var ear$2 = "👂";
var ear_with_hearing_aid = "🦻";
var nose$2 = "👃";
var brain$2 = "🧠";
var anatomical_heart = "🫀";
var lungs = "🫁";
var tooth$2 = "🦷";
var bone$2 = "🦴";
var eyes$2 = "👀";
var eye$2 = "👁️";
var tongue$2 = "👅";
var lips$2 = "👄";
var baby$2 = "👶";
var child$2 = "🧒";
var boy$2 = "👦";
var girl$2 = "👧";
var adult$2 = "🧑";
var blond_haired_person = "👱";
var man$2 = "👨";
var bearded_person$2 = "🧔";
var red_haired_man = "👨‍🦰";
var curly_haired_man = "👨‍🦱";
var white_haired_man = "👨‍🦳";
var bald_man = "👨‍🦲";
var woman$2 = "👩";
var red_haired_woman = "👩‍🦰";
var person_red_hair = "🧑‍🦰";
var curly_haired_woman = "👩‍🦱";
var person_curly_hair = "🧑‍🦱";
var white_haired_woman = "👩‍🦳";
var person_white_hair = "🧑‍🦳";
var bald_woman = "👩‍🦲";
var person_bald = "🧑‍🦲";
var blond_haired_woman = "👱‍♀️";
var blonde_woman$2 = "👱‍♀️";
var blond_haired_man = "👱‍♂️";
var older_adult$2 = "🧓";
var older_man$2 = "👴";
var older_woman$2 = "👵";
var frowning_person = "🙍";
var frowning_man$2 = "🙍‍♂️";
var frowning_woman$2 = "🙍‍♀️";
var pouting_face = "🙎";
var pouting_man$2 = "🙎‍♂️";
var pouting_woman$2 = "🙎‍♀️";
var no_good = "🙅";
var no_good_man$2 = "🙅‍♂️";
var ng_man = "🙅‍♂️";
var no_good_woman$2 = "🙅‍♀️";
var ng_woman = "🙅‍♀️";
var ok_person = "🙆";
var ok_man$2 = "🙆‍♂️";
var ok_woman$2 = "🙆‍♀️";
var tipping_hand_person = "💁";
var information_desk_person = "💁";
var tipping_hand_man$2 = "💁‍♂️";
var sassy_man = "💁‍♂️";
var tipping_hand_woman$2 = "💁‍♀️";
var sassy_woman = "💁‍♀️";
var raising_hand = "🙋";
var raising_hand_man$2 = "🙋‍♂️";
var raising_hand_woman$2 = "🙋‍♀️";
var deaf_person = "🧏";
var deaf_man = "🧏‍♂️";
var deaf_woman = "🧏‍♀️";
var bow = "🙇";
var bowing_man$2 = "🙇‍♂️";
var bowing_woman$2 = "🙇‍♀️";
var facepalm = "🤦";
var man_facepalming$2 = "🤦‍♂️";
var woman_facepalming$2 = "🤦‍♀️";
var shrug = "🤷";
var man_shrugging$2 = "🤷‍♂️";
var woman_shrugging$2 = "🤷‍♀️";
var health_worker = "🧑‍⚕️";
var man_health_worker$2 = "👨‍⚕️";
var woman_health_worker$2 = "👩‍⚕️";
var student = "🧑‍🎓";
var man_student$2 = "👨‍🎓";
var woman_student$2 = "👩‍🎓";
var teacher = "🧑‍🏫";
var man_teacher$2 = "👨‍🏫";
var woman_teacher$2 = "👩‍🏫";
var judge = "🧑‍⚖️";
var man_judge$2 = "👨‍⚖️";
var woman_judge$2 = "👩‍⚖️";
var farmer = "🧑‍🌾";
var man_farmer$2 = "👨‍🌾";
var woman_farmer$2 = "👩‍🌾";
var cook = "🧑‍🍳";
var man_cook$2 = "👨‍🍳";
var woman_cook$2 = "👩‍🍳";
var mechanic = "🧑‍🔧";
var man_mechanic$2 = "👨‍🔧";
var woman_mechanic$2 = "👩‍🔧";
var factory_worker = "🧑‍🏭";
var man_factory_worker$2 = "👨‍🏭";
var woman_factory_worker$2 = "👩‍🏭";
var office_worker = "🧑‍💼";
var man_office_worker$2 = "👨‍💼";
var woman_office_worker$2 = "👩‍💼";
var scientist = "🧑‍🔬";
var man_scientist$2 = "👨‍🔬";
var woman_scientist$2 = "👩‍🔬";
var technologist = "🧑‍💻";
var man_technologist$2 = "👨‍💻";
var woman_technologist$2 = "👩‍💻";
var singer = "🧑‍🎤";
var man_singer$2 = "👨‍🎤";
var woman_singer$2 = "👩‍🎤";
var artist = "🧑‍🎨";
var man_artist$2 = "👨‍🎨";
var woman_artist$2 = "👩‍🎨";
var pilot = "🧑‍✈️";
var man_pilot$2 = "👨‍✈️";
var woman_pilot$2 = "👩‍✈️";
var astronaut = "🧑‍🚀";
var man_astronaut$2 = "👨‍🚀";
var woman_astronaut$2 = "👩‍🚀";
var firefighter = "🧑‍🚒";
var man_firefighter$2 = "👨‍🚒";
var woman_firefighter$2 = "👩‍🚒";
var police_officer = "👮";
var cop = "👮";
var policeman$2 = "👮‍♂️";
var policewoman$2 = "👮‍♀️";
var detective = "🕵️";
var male_detective$2 = "🕵️‍♂️";
var female_detective$2 = "🕵️‍♀️";
var guard = "💂";
var guardsman$2 = "💂‍♂️";
var guardswoman$2 = "💂‍♀️";
var ninja = "🥷";
var construction_worker = "👷";
var construction_worker_man$2 = "👷‍♂️";
var construction_worker_woman$2 = "👷‍♀️";
var prince$2 = "🤴";
var princess$2 = "👸";
var person_with_turban = "👳";
var man_with_turban$2 = "👳‍♂️";
var woman_with_turban$2 = "👳‍♀️";
var man_with_gua_pi_mao$2 = "👲";
var woman_with_headscarf$2 = "🧕";
var person_in_tuxedo = "🤵";
var man_in_tuxedo$2 = "🤵‍♂️";
var woman_in_tuxedo = "🤵‍♀️";
var person_with_veil = "👰";
var man_with_veil = "👰‍♂️";
var woman_with_veil = "👰‍♀️";
var bride_with_veil$2 = "👰‍♀️";
var pregnant_woman$2 = "🤰";
var breast_feeding = "🤱";
var woman_feeding_baby = "👩‍🍼";
var man_feeding_baby = "👨‍🍼";
var person_feeding_baby = "🧑‍🍼";
var angel$2 = "👼";
var santa$2 = "🎅";
var mrs_claus$2 = "🤶";
var mx_claus = "🧑‍🎄";
var superhero = "🦸";
var superhero_man = "🦸‍♂️";
var superhero_woman = "🦸‍♀️";
var supervillain = "🦹";
var supervillain_man = "🦹‍♂️";
var supervillain_woman = "🦹‍♀️";
var mage = "🧙";
var mage_man = "🧙‍♂️";
var mage_woman = "🧙‍♀️";
var fairy = "🧚";
var fairy_man = "🧚‍♂️";
var fairy_woman = "🧚‍♀️";
var vampire = "🧛";
var vampire_man = "🧛‍♂️";
var vampire_woman = "🧛‍♀️";
var merperson = "🧜";
var merman$2 = "🧜‍♂️";
var mermaid$2 = "🧜‍♀️";
var elf = "🧝";
var elf_man = "🧝‍♂️";
var elf_woman = "🧝‍♀️";
var genie = "🧞";
var genie_man = "🧞‍♂️";
var genie_woman = "🧞‍♀️";
var zombie = "🧟";
var zombie_man = "🧟‍♂️";
var zombie_woman = "🧟‍♀️";
var massage = "💆";
var massage_man$2 = "💆‍♂️";
var massage_woman$2 = "💆‍♀️";
var haircut = "💇";
var haircut_man$2 = "💇‍♂️";
var haircut_woman$2 = "💇‍♀️";
var walking = "🚶";
var walking_man$2 = "🚶‍♂️";
var walking_woman$2 = "🚶‍♀️";
var standing_person = "🧍";
var standing_man = "🧍‍♂️";
var standing_woman = "🧍‍♀️";
var kneeling_person = "🧎";
var kneeling_man = "🧎‍♂️";
var kneeling_woman = "🧎‍♀️";
var person_with_probing_cane = "🧑‍🦯";
var man_with_probing_cane = "👨‍🦯";
var woman_with_probing_cane = "👩‍🦯";
var person_in_motorized_wheelchair = "🧑‍🦼";
var man_in_motorized_wheelchair = "👨‍🦼";
var woman_in_motorized_wheelchair = "👩‍🦼";
var person_in_manual_wheelchair = "🧑‍🦽";
var man_in_manual_wheelchair = "👨‍🦽";
var woman_in_manual_wheelchair = "👩‍🦽";
var runner = "🏃";
var running = "🏃";
var running_man$2 = "🏃‍♂️";
var running_woman$2 = "🏃‍♀️";
var woman_dancing = "💃";
var dancer$2 = "💃";
var man_dancing$2 = "🕺";
var business_suit_levitating$2 = "🕴️";
var dancers = "👯";
var dancing_men$2 = "👯‍♂️";
var dancing_women$2 = "👯‍♀️";
var sauna_person = "🧖";
var sauna_man = "🧖‍♂️";
var sauna_woman = "🧖‍♀️";
var climbing = "🧗";
var climbing_man$2 = "🧗‍♂️";
var climbing_woman$2 = "🧗‍♀️";
var person_fencing$2 = "🤺";
var horse_racing$2 = "🏇";
var skier$2 = "⛷️";
var snowboarder$2 = "🏂";
var golfing = "🏌️";
var golfing_man$2 = "🏌️‍♂️";
var golfing_woman$2 = "🏌️‍♀️";
var surfer = "🏄";
var surfing_man$2 = "🏄‍♂️";
var surfing_woman$2 = "🏄‍♀️";
var rowboat = "🚣";
var rowing_man$2 = "🚣‍♂️";
var rowing_woman$2 = "🚣‍♀️";
var swimmer = "🏊";
var swimming_man$2 = "🏊‍♂️";
var swimming_woman$2 = "🏊‍♀️";
var bouncing_ball_person = "⛹️";
var bouncing_ball_man = "⛹️‍♂️";
var basketball_man$2 = "⛹️‍♂️";
var bouncing_ball_woman = "⛹️‍♀️";
var basketball_woman$2 = "⛹️‍♀️";
var weight_lifting = "🏋️";
var weight_lifting_man$2 = "🏋️‍♂️";
var weight_lifting_woman$2 = "🏋️‍♀️";
var bicyclist = "🚴";
var biking_man$2 = "🚴‍♂️";
var biking_woman$2 = "🚴‍♀️";
var mountain_bicyclist = "🚵";
var mountain_biking_man$2 = "🚵‍♂️";
var mountain_biking_woman$2 = "🚵‍♀️";
var cartwheeling = "🤸";
var man_cartwheeling$2 = "🤸‍♂️";
var woman_cartwheeling$2 = "🤸‍♀️";
var wrestling = "🤼";
var men_wrestling$2 = "🤼‍♂️";
var women_wrestling$2 = "🤼‍♀️";
var water_polo = "🤽";
var man_playing_water_polo$2 = "🤽‍♂️";
var woman_playing_water_polo$2 = "🤽‍♀️";
var handball_person = "🤾";
var man_playing_handball$2 = "🤾‍♂️";
var woman_playing_handball$2 = "🤾‍♀️";
var juggling_person = "🤹";
var man_juggling$2 = "🤹‍♂️";
var woman_juggling$2 = "🤹‍♀️";
var lotus_position = "🧘";
var lotus_position_man = "🧘‍♂️";
var lotus_position_woman = "🧘‍♀️";
var bath$2 = "🛀";
var sleeping_bed$2 = "🛌";
var people_holding_hands = "🧑‍🤝‍🧑";
var two_women_holding_hands$2 = "👭";
var couple$2 = "👫";
var two_men_holding_hands$2 = "👬";
var couplekiss = "💏";
var couplekiss_man_woman$2 = "👩‍❤️‍💋‍👨";
var couplekiss_man_man$2 = "👨‍❤️‍💋‍👨";
var couplekiss_woman_woman$2 = "👩‍❤️‍💋‍👩";
var couple_with_heart = "💑";
var couple_with_heart_woman_man$2 = "👩‍❤️‍👨";
var couple_with_heart_man_man$2 = "👨‍❤️‍👨";
var couple_with_heart_woman_woman$2 = "👩‍❤️‍👩";
var family = "👪";
var family_man_woman_boy$2 = "👨‍👩‍👦";
var family_man_woman_girl$2 = "👨‍👩‍👧";
var family_man_woman_girl_boy$2 = "👨‍👩‍👧‍👦";
var family_man_woman_boy_boy$2 = "👨‍👩‍👦‍👦";
var family_man_woman_girl_girl$2 = "👨‍👩‍👧‍👧";
var family_man_man_boy$2 = "👨‍👨‍👦";
var family_man_man_girl$2 = "👨‍👨‍👧";
var family_man_man_girl_boy$2 = "👨‍👨‍👧‍👦";
var family_man_man_boy_boy$2 = "👨‍👨‍👦‍👦";
var family_man_man_girl_girl$2 = "👨‍👨‍👧‍👧";
var family_woman_woman_boy$2 = "👩‍👩‍👦";
var family_woman_woman_girl$2 = "👩‍👩‍👧";
var family_woman_woman_girl_boy$2 = "👩‍👩‍👧‍👦";
var family_woman_woman_boy_boy$2 = "👩‍👩‍👦‍👦";
var family_woman_woman_girl_girl$2 = "👩‍👩‍👧‍👧";
var family_man_boy$2 = "👨‍👦";
var family_man_boy_boy$2 = "👨‍👦‍👦";
var family_man_girl$2 = "👨‍👧";
var family_man_girl_boy$2 = "👨‍👧‍👦";
var family_man_girl_girl$2 = "👨‍👧‍👧";
var family_woman_boy$2 = "👩‍👦";
var family_woman_boy_boy$2 = "👩‍👦‍👦";
var family_woman_girl$2 = "👩‍👧";
var family_woman_girl_boy$2 = "👩‍👧‍👦";
var family_woman_girl_girl$2 = "👩‍👧‍👧";
var speaking_head$2 = "🗣️";
var bust_in_silhouette$2 = "👤";
var busts_in_silhouette$2 = "👥";
var people_hugging = "🫂";
var footprints$2 = "👣";
var monkey_face$2 = "🐵";
var monkey$2 = "🐒";
var gorilla$2 = "🦍";
var orangutan = "🦧";
var dog$2 = "🐶";
var dog2$2 = "🐕";
var guide_dog = "🦮";
var service_dog = "🐕‍🦺";
var poodle$2 = "🐩";
var wolf$2 = "🐺";
var fox_face$2 = "🦊";
var raccoon$2 = "🦝";
var cat$2 = "🐱";
var cat2$2 = "🐈";
var black_cat = "🐈‍⬛";
var lion$2 = "🦁";
var tiger$2 = "🐯";
var tiger2$2 = "🐅";
var leopard$2 = "🐆";
var horse$2 = "🐴";
var racehorse$2 = "🐎";
var unicorn$2 = "🦄";
var zebra$2 = "🦓";
var deer$2 = "🦌";
var bison = "🦬";
var cow$2 = "🐮";
var ox$2 = "🐂";
var water_buffalo$2 = "🐃";
var cow2$2 = "🐄";
var pig$2 = "🐷";
var pig2$2 = "🐖";
var boar$2 = "🐗";
var pig_nose$2 = "🐽";
var ram$2 = "🐏";
var sheep$2 = "🐑";
var goat$2 = "🐐";
var dromedary_camel$2 = "🐪";
var camel$2 = "🐫";
var llama$2 = "🦙";
var giraffe$2 = "🦒";
var elephant$2 = "🐘";
var mammoth = "🦣";
var rhinoceros$2 = "🦏";
var hippopotamus$2 = "🦛";
var mouse$2 = "🐭";
var mouse2$2 = "🐁";
var rat$2 = "🐀";
var hamster$2 = "🐹";
var rabbit$2 = "🐰";
var rabbit2$2 = "🐇";
var chipmunk$2 = "🐿️";
var beaver = "🦫";
var hedgehog$2 = "🦔";
var bat$2 = "🦇";
var bear$2 = "🐻";
var polar_bear = "🐻‍❄️";
var koala$2 = "🐨";
var panda_face$2 = "🐼";
var sloth = "🦥";
var otter = "🦦";
var skunk = "🦨";
var kangaroo$2 = "🦘";
var badger$2 = "🦡";
var feet = "🐾";
var paw_prints$2 = "🐾";
var turkey$2 = "🦃";
var chicken$2 = "🐔";
var rooster$2 = "🐓";
var hatching_chick$2 = "🐣";
var baby_chick$2 = "🐤";
var hatched_chick$2 = "🐥";
var bird$2 = "🐦";
var penguin$2 = "🐧";
var dove$2 = "🕊️";
var eagle$2 = "🦅";
var duck$2 = "🦆";
var swan$2 = "🦢";
var owl$2 = "🦉";
var dodo = "🦤";
var feather = "🪶";
var flamingo = "🦩";
var peacock$2 = "🦚";
var parrot$2 = "🦜";
var frog$2 = "🐸";
var crocodile$2 = "🐊";
var turtle$2 = "🐢";
var lizard$2 = "🦎";
var snake$2 = "🐍";
var dragon_face$2 = "🐲";
var dragon$2 = "🐉";
var sauropod$2 = "🦕";
var whale$2 = "🐳";
var whale2$2 = "🐋";
var dolphin$2 = "🐬";
var flipper = "🐬";
var seal = "🦭";
var fish$2 = "🐟";
var tropical_fish$2 = "🐠";
var blowfish$2 = "🐡";
var shark$2 = "🦈";
var octopus$2 = "🐙";
var shell$2 = "🐚";
var snail$2 = "🐌";
var butterfly$2 = "🦋";
var bug$2 = "🐛";
var ant$2 = "🐜";
var bee = "🐝";
var honeybee$2 = "🐝";
var beetle$2 = "🪲";
var lady_beetle = "🐞";
var cricket$2 = "🦗";
var cockroach = "🪳";
var spider$2 = "🕷️";
var spider_web$2 = "🕸️";
var scorpion$2 = "🦂";
var mosquito$2 = "🦟";
var fly = "🪰";
var worm = "🪱";
var microbe$2 = "🦠";
var bouquet$2 = "💐";
var cherry_blossom$2 = "🌸";
var white_flower$2 = "💮";
var rosette$2 = "🏵️";
var rose$2 = "🌹";
var wilted_flower$2 = "🥀";
var hibiscus$2 = "🌺";
var sunflower$2 = "🌻";
var blossom$2 = "🌼";
var tulip$2 = "🌷";
var seedling$2 = "🌱";
var potted_plant = "🪴";
var evergreen_tree$2 = "🌲";
var deciduous_tree$2 = "🌳";
var palm_tree$2 = "🌴";
var cactus$2 = "🌵";
var ear_of_rice$2 = "🌾";
var herb$2 = "🌿";
var shamrock$2 = "☘️";
var four_leaf_clover$2 = "🍀";
var maple_leaf$2 = "🍁";
var fallen_leaf$2 = "🍂";
var leaves$2 = "🍃";
var grapes$2 = "🍇";
var melon$2 = "🍈";
var watermelon$2 = "🍉";
var tangerine$2 = "🍊";
var orange = "🍊";
var mandarin = "🍊";
var lemon$2 = "🍋";
var banana$2 = "🍌";
var pineapple$2 = "🍍";
var mango$2 = "🥭";
var apple$2 = "🍎";
var green_apple$2 = "🍏";
var pear$2 = "🍐";
var peach$2 = "🍑";
var cherries$2 = "🍒";
var strawberry$2 = "🍓";
var blueberries = "🫐";
var kiwi_fruit$2 = "🥝";
var tomato$2 = "🍅";
var olive = "🫒";
var coconut$2 = "🥥";
var avocado$2 = "🥑";
var eggplant$2 = "🍆";
var potato$2 = "🥔";
var carrot$2 = "🥕";
var corn$2 = "🌽";
var hot_pepper$2 = "🌶️";
var bell_pepper = "🫑";
var cucumber$2 = "🥒";
var leafy_green = "🥬";
var broccoli$2 = "🥦";
var garlic = "🧄";
var onion = "🧅";
var mushroom$2 = "🍄";
var peanuts$2 = "🥜";
var chestnut$2 = "🌰";
var bread$2 = "🍞";
var croissant$2 = "🥐";
var baguette_bread$2 = "🥖";
var flatbread = "🫓";
var pretzel$2 = "🥨";
var bagel$2 = "🥯";
var pancakes$2 = "🥞";
var waffle = "🧇";
var cheese$2 = "🧀";
var meat_on_bone$2 = "🍖";
var poultry_leg$2 = "🍗";
var cut_of_meat = "🥩";
var bacon$2 = "🥓";
var hamburger$2 = "🍔";
var fries$2 = "🍟";
var pizza$2 = "🍕";
var hotdog$2 = "🌭";
var sandwich$2 = "🥪";
var taco$2 = "🌮";
var burrito$2 = "🌯";
var tamale = "🫔";
var stuffed_flatbread$2 = "🥙";
var falafel = "🧆";
var egg$2 = "🥚";
var fried_egg$2 = "🍳";
var shallow_pan_of_food$2 = "🥘";
var stew$2 = "🍲";
var fondue = "🫕";
var bowl_with_spoon$2 = "🥣";
var green_salad$2 = "🥗";
var popcorn$2 = "🍿";
var butter = "🧈";
var salt$2 = "🧂";
var canned_food$2 = "🥫";
var bento$2 = "🍱";
var rice_cracker$2 = "🍘";
var rice_ball$2 = "🍙";
var rice$2 = "🍚";
var curry$2 = "🍛";
var ramen$2 = "🍜";
var spaghetti$2 = "🍝";
var sweet_potato$2 = "🍠";
var oden$2 = "🍢";
var sushi$2 = "🍣";
var fried_shrimp$2 = "🍤";
var fish_cake$2 = "🍥";
var moon_cake$2 = "🥮";
var dango$2 = "🍡";
var dumpling$2 = "🥟";
var fortune_cookie$2 = "🥠";
var takeout_box$2 = "🥡";
var crab$2 = "🦀";
var lobster$2 = "🦞";
var shrimp$2 = "🦐";
var squid$2 = "🦑";
var oyster = "🦪";
var icecream$2 = "🍦";
var shaved_ice$2 = "🍧";
var ice_cream$2 = "🍨";
var doughnut$2 = "🍩";
var cookie$2 = "🍪";
var birthday$2 = "🎂";
var cake$2 = "🍰";
var cupcake$2 = "🧁";
var pie$2 = "🥧";
var chocolate_bar$2 = "🍫";
var candy$2 = "🍬";
var lollipop$2 = "🍭";
var custard$2 = "🍮";
var honey_pot$2 = "🍯";
var baby_bottle$2 = "🍼";
var milk_glass$2 = "🥛";
var coffee$2 = "☕";
var teapot = "🫖";
var tea$2 = "🍵";
var sake$2 = "🍶";
var champagne$2 = "🍾";
var wine_glass$2 = "🍷";
var cocktail$2 = "🍸";
var tropical_drink$2 = "🍹";
var beer$2 = "🍺";
var beers$2 = "🍻";
var clinking_glasses$2 = "🥂";
var tumbler_glass$2 = "🥃";
var cup_with_straw$2 = "🥤";
var bubble_tea = "🧋";
var beverage_box = "🧃";
var mate = "🧉";
var ice_cube = "🧊";
var chopsticks$2 = "🥢";
var plate_with_cutlery$2 = "🍽️";
var fork_and_knife$2 = "🍴";
var spoon$2 = "🥄";
var hocho$2 = "🔪";
var knife = "🔪";
var amphora$2 = "🏺";
var earth_africa$2 = "🌍";
var earth_americas$2 = "🌎";
var earth_asia$2 = "🌏";
var globe_with_meridians$2 = "🌐";
var world_map$2 = "🗺️";
var japan$2 = "🗾";
var compass$2 = "🧭";
var mountain_snow$2 = "🏔️";
var mountain$2 = "⛰️";
var volcano$2 = "🌋";
var mount_fuji$2 = "🗻";
var camping$2 = "🏕️";
var beach_umbrella$2 = "🏖️";
var desert$2 = "🏜️";
var desert_island$2 = "🏝️";
var national_park$2 = "🏞️";
var stadium$2 = "🏟️";
var classical_building$2 = "🏛️";
var building_construction$2 = "🏗️";
var bricks = "🧱";
var rock = "🪨";
var wood = "🪵";
var hut = "🛖";
var houses$2 = "🏘️";
var derelict_house$2 = "🏚️";
var house$2 = "🏠";
var house_with_garden$2 = "🏡";
var office$2 = "🏢";
var post_office$2 = "🏣";
var european_post_office$2 = "🏤";
var hospital$2 = "🏥";
var bank$2 = "🏦";
var hotel$2 = "🏨";
var love_hotel$2 = "🏩";
var convenience_store$2 = "🏪";
var school$2 = "🏫";
var department_store$2 = "🏬";
var factory$2 = "🏭";
var japanese_castle$2 = "🏯";
var european_castle$2 = "🏰";
var wedding$2 = "💒";
var tokyo_tower$2 = "🗼";
var statue_of_liberty$2 = "🗽";
var church$2 = "⛪";
var mosque$2 = "🕌";
var hindu_temple = "🛕";
var synagogue$2 = "🕍";
var shinto_shrine$2 = "⛩️";
var kaaba$2 = "🕋";
var fountain$2 = "⛲";
var tent$2 = "⛺";
var foggy$2 = "🌁";
var night_with_stars$2 = "🌃";
var cityscape$2 = "🏙️";
var sunrise_over_mountains$2 = "🌄";
var sunrise$2 = "🌅";
var city_sunset$2 = "🌆";
var city_sunrise$2 = "🌇";
var bridge_at_night$2 = "🌉";
var hotsprings$2 = "♨️";
var carousel_horse$2 = "🎠";
var ferris_wheel$2 = "🎡";
var roller_coaster$2 = "🎢";
var barber$2 = "💈";
var circus_tent$2 = "🎪";
var steam_locomotive$2 = "🚂";
var railway_car$2 = "🚃";
var bullettrain_side$2 = "🚄";
var bullettrain_front$2 = "🚅";
var train2$2 = "🚆";
var metro$2 = "🚇";
var light_rail$2 = "🚈";
var station$2 = "🚉";
var tram$2 = "🚊";
var monorail$2 = "🚝";
var mountain_railway$2 = "🚞";
var train$2 = "🚋";
var bus$2 = "🚌";
var oncoming_bus$2 = "🚍";
var trolleybus$2 = "🚎";
var minibus$2 = "🚐";
var ambulance$2 = "🚑";
var fire_engine$2 = "🚒";
var police_car$2 = "🚓";
var oncoming_police_car$2 = "🚔";
var taxi$2 = "🚕";
var oncoming_taxi$2 = "🚖";
var car = "🚗";
var red_car$2 = "🚗";
var oncoming_automobile$2 = "🚘";
var blue_car$2 = "🚙";
var pickup_truck = "🛻";
var truck$2 = "🚚";
var articulated_lorry$2 = "🚛";
var tractor$2 = "🚜";
var racing_car$2 = "🏎️";
var motorcycle$2 = "🏍️";
var motor_scooter$2 = "🛵";
var manual_wheelchair = "🦽";
var motorized_wheelchair = "🦼";
var auto_rickshaw = "🛺";
var bike$2 = "🚲";
var kick_scooter$2 = "🛴";
var skateboard$2 = "🛹";
var roller_skate = "🛼";
var busstop$2 = "🚏";
var motorway$2 = "🛣️";
var railway_track$2 = "🛤️";
var oil_drum$2 = "🛢️";
var fuelpump$2 = "⛽";
var rotating_light$2 = "🚨";
var traffic_light$2 = "🚥";
var vertical_traffic_light$2 = "🚦";
var stop_sign$2 = "🛑";
var construction$2 = "🚧";
var anchor$2 = "⚓";
var boat = "⛵";
var sailboat$2 = "⛵";
var canoe$2 = "🛶";
var speedboat$2 = "🚤";
var passenger_ship$2 = "🛳️";
var ferry$2 = "⛴️";
var motor_boat$2 = "🛥️";
var ship$2 = "🚢";
var airplane$2 = "✈️";
var small_airplane$2 = "🛩️";
var flight_departure$2 = "🛫";
var flight_arrival$2 = "🛬";
var parachute = "🪂";
var seat$2 = "💺";
var helicopter$2 = "🚁";
var suspension_railway$2 = "🚟";
var mountain_cableway$2 = "🚠";
var aerial_tramway$2 = "🚡";
var artificial_satellite$2 = "🛰️";
var rocket$2 = "🚀";
var flying_saucer$2 = "🛸";
var bellhop_bell$2 = "🛎️";
var luggage$2 = "🧳";
var hourglass$2 = "⌛";
var hourglass_flowing_sand$2 = "⏳";
var watch$2 = "⌚";
var alarm_clock$2 = "⏰";
var stopwatch$2 = "⏱️";
var timer_clock$2 = "⏲️";
var mantelpiece_clock$2 = "🕰️";
var clock12$2 = "🕛";
var clock1230$2 = "🕧";
var clock1$2 = "🕐";
var clock130$2 = "🕜";
var clock2$2 = "🕑";
var clock230$2 = "🕝";
var clock3$2 = "🕒";
var clock330$2 = "🕞";
var clock4$2 = "🕓";
var clock430$2 = "🕟";
var clock5$2 = "🕔";
var clock530$2 = "🕠";
var clock6$2 = "🕕";
var clock630$2 = "🕡";
var clock7$2 = "🕖";
var clock730$2 = "🕢";
var clock8$2 = "🕗";
var clock830$2 = "🕣";
var clock9$2 = "🕘";
var clock930$2 = "🕤";
var clock10$2 = "🕙";
var clock1030$2 = "🕥";
var clock11$2 = "🕚";
var clock1130$2 = "🕦";
var new_moon$2 = "🌑";
var waxing_crescent_moon$2 = "🌒";
var first_quarter_moon$2 = "🌓";
var moon = "🌔";
var waxing_gibbous_moon$2 = "🌔";
var full_moon$2 = "🌕";
var waning_gibbous_moon$2 = "🌖";
var last_quarter_moon$2 = "🌗";
var waning_crescent_moon$2 = "🌘";
var crescent_moon$2 = "🌙";
var new_moon_with_face$2 = "🌚";
var first_quarter_moon_with_face$2 = "🌛";
var last_quarter_moon_with_face$2 = "🌜";
var thermometer$2 = "🌡️";
var sunny$2 = "☀️";
var full_moon_with_face$2 = "🌝";
var sun_with_face$2 = "🌞";
var ringed_planet = "🪐";
var star$3 = "⭐";
var star2$2 = "🌟";
var stars$2 = "🌠";
var milky_way$2 = "🌌";
var cloud$2 = "☁️";
var partly_sunny$2 = "⛅";
var cloud_with_lightning_and_rain$2 = "⛈️";
var sun_behind_small_cloud$2 = "🌤️";
var sun_behind_large_cloud$2 = "🌥️";
var sun_behind_rain_cloud$2 = "🌦️";
var cloud_with_rain$2 = "🌧️";
var cloud_with_snow$2 = "🌨️";
var cloud_with_lightning$2 = "🌩️";
var tornado$2 = "🌪️";
var fog$2 = "🌫️";
var wind_face$2 = "🌬️";
var cyclone$2 = "🌀";
var rainbow$2 = "🌈";
var closed_umbrella$2 = "🌂";
var open_umbrella$2 = "☂️";
var umbrella$2 = "☔";
var parasol_on_ground$2 = "⛱️";
var zap$2 = "⚡";
var snowflake$2 = "❄️";
var snowman_with_snow$2 = "☃️";
var snowman$2 = "⛄";
var comet$2 = "☄️";
var fire$2 = "🔥";
var droplet$2 = "💧";
var ocean$2 = "🌊";
var jack_o_lantern$2 = "🎃";
var christmas_tree$2 = "🎄";
var fireworks$2 = "🎆";
var sparkler$2 = "🎇";
var firecracker$2 = "🧨";
var sparkles$2 = "✨";
var balloon$2 = "🎈";
var tada$2 = "🎉";
var confetti_ball$2 = "🎊";
var tanabata_tree$2 = "🎋";
var bamboo$2 = "🎍";
var dolls$2 = "🎎";
var flags$2 = "🎏";
var wind_chime$2 = "🎐";
var rice_scene$2 = "🎑";
var red_envelope$2 = "🧧";
var ribbon$2 = "🎀";
var gift$2 = "🎁";
var reminder_ribbon$2 = "🎗️";
var tickets$2 = "🎟️";
var ticket$2 = "🎫";
var medal_military$2 = "🎖️";
var trophy$2 = "🏆";
var medal_sports$2 = "🏅";
var soccer$2 = "⚽";
var baseball$2 = "⚾";
var softball$2 = "🥎";
var basketball$2 = "🏀";
var volleyball$2 = "🏐";
var football$2 = "🏈";
var rugby_football$2 = "🏉";
var tennis$2 = "🎾";
var flying_disc$2 = "🥏";
var bowling$2 = "🎳";
var cricket_game = "🏏";
var field_hockey$2 = "🏑";
var ice_hockey$2 = "🏒";
var lacrosse$2 = "🥍";
var ping_pong$2 = "🏓";
var badminton$2 = "🏸";
var boxing_glove$2 = "🥊";
var martial_arts_uniform$2 = "🥋";
var goal_net$2 = "🥅";
var golf$2 = "⛳";
var ice_skate$2 = "⛸️";
var fishing_pole_and_fish$2 = "🎣";
var diving_mask = "🤿";
var running_shirt_with_sash$2 = "🎽";
var ski$2 = "🎿";
var sled$2 = "🛷";
var curling_stone$2 = "🥌";
var dart$2 = "🎯";
var yo_yo = "🪀";
var kite = "🪁";
var crystal_ball$2 = "🔮";
var magic_wand = "🪄";
var nazar_amulet$2 = "🧿";
var video_game$2 = "🎮";
var joystick$2 = "🕹️";
var slot_machine$2 = "🎰";
var game_die$2 = "🎲";
var jigsaw$2 = "🧩";
var teddy_bear$2 = "🧸";
var pinata = "🪅";
var nesting_dolls = "🪆";
var spades$3 = "♠️";
var hearts$3 = "♥️";
var diamonds$2 = "♦️";
var clubs$3 = "♣️";
var chess_pawn$2 = "♟️";
var black_joker$2 = "🃏";
var mahjong$2 = "🀄";
var flower_playing_cards$2 = "🎴";
var performing_arts$2 = "🎭";
var framed_picture$2 = "🖼️";
var art$2 = "🎨";
var thread$2 = "🧵";
var sewing_needle = "🪡";
var yarn$2 = "🧶";
var knot = "🪢";
var eyeglasses$2 = "👓";
var dark_sunglasses$2 = "🕶️";
var goggles$2 = "🥽";
var lab_coat = "🥼";
var safety_vest = "🦺";
var necktie$2 = "👔";
var shirt = "👕";
var tshirt$2 = "👕";
var jeans$2 = "👖";
var scarf$2 = "🧣";
var gloves$2 = "🧤";
var coat$2 = "🧥";
var socks$2 = "🧦";
var dress$2 = "👗";
var kimono$2 = "👘";
var sari = "🥻";
var one_piece_swimsuit = "🩱";
var swim_brief = "🩲";
var shorts = "🩳";
var bikini$2 = "👙";
var womans_clothes$2 = "👚";
var purse$2 = "👛";
var handbag$2 = "👜";
var pouch$2 = "👝";
var shopping$2 = "🛍️";
var school_satchel$2 = "🎒";
var thong_sandal = "🩴";
var mans_shoe$2 = "👞";
var shoe = "👞";
var athletic_shoe$2 = "👟";
var hiking_boot$2 = "🥾";
var flat_shoe$2 = "🥿";
var high_heel$2 = "👠";
var sandal$2 = "👡";
var ballet_shoes = "🩰";
var boot$2 = "👢";
var crown$2 = "👑";
var womans_hat$2 = "👒";
var tophat$2 = "🎩";
var mortar_board$2 = "🎓";
var billed_cap = "🧢";
var military_helmet = "🪖";
var rescue_worker_helmet$2 = "⛑️";
var prayer_beads$2 = "📿";
var lipstick$2 = "💄";
var ring$3 = "💍";
var gem$2 = "💎";
var mute$2 = "🔇";
var speaker$2 = "🔈";
var sound$2 = "🔉";
var loud_sound$2 = "🔊";
var loudspeaker$2 = "📢";
var mega$2 = "📣";
var postal_horn$2 = "📯";
var bell$2 = "🔔";
var no_bell$2 = "🔕";
var musical_score$2 = "🎼";
var musical_note$2 = "🎵";
var notes$2 = "🎶";
var studio_microphone$2 = "🎙️";
var level_slider$2 = "🎚️";
var control_knobs$2 = "🎛️";
var microphone$2 = "🎤";
var headphones$2 = "🎧";
var radio$2 = "📻";
var saxophone$2 = "🎷";
var accordion = "🪗";
var guitar$2 = "🎸";
var musical_keyboard$2 = "🎹";
var trumpet$2 = "🎺";
var violin$2 = "🎻";
var banjo = "🪕";
var drum$2 = "🥁";
var long_drum = "🪘";
var iphone$2 = "📱";
var calling$2 = "📲";
var phone$3 = "☎️";
var telephone = "☎️";
var telephone_receiver$2 = "📞";
var pager$2 = "📟";
var fax$2 = "📠";
var battery$2 = "🔋";
var electric_plug$2 = "🔌";
var computer$2 = "💻";
var desktop_computer$2 = "🖥️";
var printer$2 = "🖨️";
var keyboard$2 = "⌨️";
var computer_mouse$2 = "🖱️";
var trackball$2 = "🖲️";
var minidisc$2 = "💽";
var floppy_disk$2 = "💾";
var cd$2 = "💿";
var dvd$2 = "📀";
var abacus$2 = "🧮";
var movie_camera$2 = "🎥";
var film_strip$2 = "🎞️";
var film_projector$2 = "📽️";
var clapper$2 = "🎬";
var tv$2 = "📺";
var camera$2 = "📷";
var camera_flash$2 = "📸";
var video_camera$2 = "📹";
var vhs$2 = "📼";
var mag$2 = "🔍";
var mag_right$2 = "🔎";
var candle$2 = "🕯️";
var bulb$2 = "💡";
var flashlight$2 = "🔦";
var izakaya_lantern$2 = "🏮";
var lantern = "🏮";
var diya_lamp = "🪔";
var notebook_with_decorative_cover$2 = "📔";
var closed_book$2 = "📕";
var book = "📖";
var open_book$2 = "📖";
var green_book$2 = "📗";
var blue_book$2 = "📘";
var orange_book$2 = "📙";
var books$2 = "📚";
var notebook$2 = "📓";
var ledger$2 = "📒";
var page_with_curl$2 = "📃";
var scroll$2 = "📜";
var page_facing_up$2 = "📄";
var newspaper$2 = "📰";
var newspaper_roll$2 = "🗞️";
var bookmark_tabs$2 = "📑";
var bookmark$2 = "🔖";
var label$2 = "🏷️";
var moneybag$2 = "💰";
var coin = "🪙";
var yen$3 = "💴";
var dollar$3 = "💵";
var euro$3 = "💶";
var pound$3 = "💷";
var money_with_wings$2 = "💸";
var credit_card$2 = "💳";
var receipt$2 = "🧾";
var chart$2 = "💹";
var envelope = "✉️";
var email$2 = "📧";
var incoming_envelope$2 = "📨";
var envelope_with_arrow$2 = "📩";
var outbox_tray$2 = "📤";
var inbox_tray$2 = "📥";
var mailbox$2 = "📫";
var mailbox_closed$2 = "📪";
var mailbox_with_mail$2 = "📬";
var mailbox_with_no_mail$2 = "📭";
var postbox$2 = "📮";
var ballot_box$2 = "🗳️";
var pencil2$2 = "✏️";
var black_nib$2 = "✒️";
var fountain_pen$2 = "🖋️";
var pen$2 = "🖊️";
var paintbrush$2 = "🖌️";
var crayon$2 = "🖍️";
var memo$2 = "📝";
var pencil = "📝";
var briefcase$2 = "💼";
var file_folder$2 = "📁";
var open_file_folder$2 = "📂";
var card_index_dividers$2 = "🗂️";
var date$2 = "📅";
var calendar$2 = "📆";
var spiral_notepad$2 = "🗒️";
var spiral_calendar$2 = "🗓️";
var card_index$2 = "📇";
var chart_with_upwards_trend$2 = "📈";
var chart_with_downwards_trend$2 = "📉";
var bar_chart$2 = "📊";
var clipboard$3 = "📋";
var pushpin$2 = "📌";
var round_pushpin$2 = "📍";
var paperclip$2 = "📎";
var paperclips$2 = "🖇️";
var straight_ruler$2 = "📏";
var triangular_ruler$2 = "📐";
var scissors$2 = "✂️";
var card_file_box$2 = "🗃️";
var file_cabinet$2 = "🗄️";
var wastebasket$2 = "🗑️";
var lock$2 = "🔒";
var unlock$2 = "🔓";
var lock_with_ink_pen$2 = "🔏";
var closed_lock_with_key$2 = "🔐";
var key$2 = "🔑";
var old_key$2 = "🗝️";
var hammer$2 = "🔨";
var axe = "🪓";
var pick$2 = "⛏️";
var hammer_and_pick$2 = "⚒️";
var hammer_and_wrench$2 = "🛠️";
var dagger$3 = "🗡️";
var crossed_swords$2 = "⚔️";
var gun$2 = "🔫";
var boomerang = "🪃";
var bow_and_arrow$2 = "🏹";
var shield$2 = "🛡️";
var carpentry_saw = "🪚";
var wrench$2 = "🔧";
var screwdriver = "🪛";
var nut_and_bolt$2 = "🔩";
var gear$2 = "⚙️";
var clamp$2 = "🗜️";
var balance_scale$2 = "⚖️";
var probing_cane = "🦯";
var link$4 = "🔗";
var chains$2 = "⛓️";
var hook = "🪝";
var toolbox$2 = "🧰";
var magnet$2 = "🧲";
var ladder = "🪜";
var alembic$2 = "⚗️";
var test_tube$2 = "🧪";
var petri_dish$2 = "🧫";
var dna$2 = "🧬";
var microscope$2 = "🔬";
var telescope$2 = "🔭";
var satellite$2 = "📡";
var syringe$2 = "💉";
var drop_of_blood = "🩸";
var pill$2 = "💊";
var adhesive_bandage = "🩹";
var stethoscope = "🩺";
var door$2 = "🚪";
var elevator = "🛗";
var mirror = "🪞";
var window$1 = "🪟";
var bed$2 = "🛏️";
var couch_and_lamp$2 = "🛋️";
var chair = "🪑";
var toilet$2 = "🚽";
var plunger = "🪠";
var shower$2 = "🚿";
var bathtub$2 = "🛁";
var mouse_trap = "🪤";
var razor = "🪒";
var lotion_bottle$2 = "🧴";
var safety_pin$2 = "🧷";
var broom$2 = "🧹";
var basket$2 = "🧺";
var roll_of_paper = "🧻";
var bucket = "🪣";
var soap$2 = "🧼";
var toothbrush = "🪥";
var sponge$2 = "🧽";
var fire_extinguisher$2 = "🧯";
var shopping_cart$2 = "🛒";
var smoking$2 = "🚬";
var coffin$2 = "⚰️";
var headstone = "🪦";
var funeral_urn$2 = "⚱️";
var moyai$2 = "🗿";
var placard = "🪧";
var atm$2 = "🏧";
var put_litter_in_its_place$2 = "🚮";
var potable_water$2 = "🚰";
var wheelchair$2 = "♿";
var mens$2 = "🚹";
var womens$2 = "🚺";
var restroom$2 = "🚻";
var baby_symbol$2 = "🚼";
var wc$2 = "🚾";
var passport_control$2 = "🛂";
var customs$2 = "🛃";
var baggage_claim$2 = "🛄";
var left_luggage$2 = "🛅";
var warning$2 = "⚠️";
var children_crossing$2 = "🚸";
var no_entry$2 = "⛔";
var no_entry_sign$2 = "🚫";
var no_bicycles$2 = "🚳";
var no_smoking$2 = "🚭";
var do_not_litter$2 = "🚯";
var no_pedestrians$2 = "🚷";
var no_mobile_phones$2 = "📵";
var underage$2 = "🔞";
var radioactive$2 = "☢️";
var biohazard$2 = "☣️";
var arrow_up$2 = "⬆️";
var arrow_upper_right$2 = "↗️";
var arrow_right$2 = "➡️";
var arrow_lower_right$2 = "↘️";
var arrow_down$2 = "⬇️";
var arrow_lower_left$2 = "↙️";
var arrow_left$2 = "⬅️";
var arrow_upper_left$2 = "↖️";
var arrow_up_down$2 = "↕️";
var left_right_arrow$2 = "↔️";
var leftwards_arrow_with_hook$2 = "↩️";
var arrow_right_hook$2 = "↪️";
var arrow_heading_up$2 = "⤴️";
var arrow_heading_down$2 = "⤵️";
var arrows_clockwise$2 = "🔃";
var arrows_counterclockwise$2 = "🔄";
var back$2 = "🔙";
var end$2 = "🔚";
var on$2 = "🔛";
var soon$2 = "🔜";
var top$3 = "🔝";
var place_of_worship$2 = "🛐";
var atom_symbol$2 = "⚛️";
var om$2 = "🕉️";
var star_of_david$2 = "✡️";
var wheel_of_dharma$2 = "☸️";
var yin_yang$2 = "☯️";
var latin_cross$2 = "✝️";
var orthodox_cross$2 = "☦️";
var star_and_crescent$2 = "☪️";
var peace_symbol$2 = "☮️";
var menorah$2 = "🕎";
var six_pointed_star$2 = "🔯";
var aries$2 = "♈";
var taurus$2 = "♉";
var gemini$2 = "♊";
var cancer$2 = "♋";
var leo$2 = "♌";
var virgo$2 = "♍";
var libra$2 = "♎";
var scorpius$2 = "♏";
var sagittarius$2 = "♐";
var capricorn$2 = "♑";
var aquarius$2 = "♒";
var pisces$2 = "♓";
var ophiuchus$2 = "⛎";
var twisted_rightwards_arrows$2 = "🔀";
var repeat$2 = "🔁";
var repeat_one$2 = "🔂";
var arrow_forward$2 = "▶️";
var fast_forward$2 = "⏩";
var next_track_button$2 = "⏭️";
var play_or_pause_button$2 = "⏯️";
var arrow_backward$2 = "◀️";
var rewind$2 = "⏪";
var previous_track_button$2 = "⏮️";
var arrow_up_small$2 = "🔼";
var arrow_double_up$2 = "⏫";
var arrow_down_small$2 = "🔽";
var arrow_double_down$2 = "⏬";
var pause_button$2 = "⏸️";
var stop_button$2 = "⏹️";
var record_button$2 = "⏺️";
var eject_button$2 = "⏏️";
var cinema$2 = "🎦";
var low_brightness$2 = "🔅";
var high_brightness$2 = "🔆";
var signal_strength$2 = "📶";
var vibration_mode$2 = "📳";
var mobile_phone_off$2 = "📴";
var female_sign = "♀️";
var male_sign = "♂️";
var transgender_symbol = "⚧️";
var heavy_multiplication_x$2 = "✖️";
var heavy_plus_sign$2 = "➕";
var heavy_minus_sign$2 = "➖";
var heavy_division_sign$2 = "➗";
var infinity$2 = "♾️";
var bangbang$2 = "‼️";
var interrobang$2 = "⁉️";
var question$2 = "❓";
var grey_question$2 = "❔";
var grey_exclamation$2 = "❕";
var exclamation$2 = "❗";
var heavy_exclamation_mark = "❗";
var wavy_dash$2 = "〰️";
var currency_exchange$2 = "💱";
var heavy_dollar_sign$2 = "💲";
var medical_symbol = "⚕️";
var recycle$2 = "♻️";
var fleur_de_lis$2 = "⚜️";
var trident$2 = "🔱";
var name_badge$2 = "📛";
var beginner$2 = "🔰";
var o$3 = "⭕";
var white_check_mark$2 = "✅";
var ballot_box_with_check$2 = "☑️";
var heavy_check_mark$2 = "✔️";
var x$2 = "❌";
var negative_squared_cross_mark$2 = "❎";
var curly_loop$2 = "➰";
var loop$2 = "➿";
var part_alternation_mark$2 = "〽️";
var eight_spoked_asterisk$2 = "✳️";
var eight_pointed_black_star$2 = "✴️";
var sparkle$2 = "❇️";
var copyright$2 = "©️";
var registered$2 = "®️";
var tm$2 = "™️";
var hash$2 = "#️⃣";
var asterisk$2 = "*️⃣";
var zero$3 = "0️⃣";
var one$2 = "1️⃣";
var two$2 = "2️⃣";
var three$2 = "3️⃣";
var four$2 = "4️⃣";
var five$2 = "5️⃣";
var six$2 = "6️⃣";
var seven$2 = "7️⃣";
var eight$2 = "8️⃣";
var nine$2 = "9️⃣";
var keycap_ten$2 = "🔟";
var capital_abcd$2 = "🔠";
var abcd$2 = "🔡";
var symbols$2 = "🔣";
var abc$2 = "🔤";
var a$3 = "🅰️";
var ab$2 = "🆎";
var b$2 = "🅱️";
var cl$2 = "🆑";
var cool$2 = "🆒";
var free$2 = "🆓";
var information_source$2 = "ℹ️";
var id$2 = "🆔";
var m$2 = "Ⓜ️";
var ng$2 = "🆖";
var o2$2 = "🅾️";
var ok$2 = "🆗";
var parking$2 = "🅿️";
var sos$2 = "🆘";
var up$2 = "🆙";
var vs$2 = "🆚";
var koko$2 = "🈁";
var sa$2 = "🈂️";
var ideograph_advantage$2 = "🉐";
var accept$2 = "🉑";
var congratulations$2 = "㊗️";
var secret$2 = "㊙️";
var u6e80$2 = "🈵";
var red_circle$2 = "🔴";
var orange_circle = "🟠";
var yellow_circle = "🟡";
var green_circle = "🟢";
var large_blue_circle$2 = "🔵";
var purple_circle = "🟣";
var brown_circle = "🟤";
var black_circle$2 = "⚫";
var white_circle$2 = "⚪";
var red_square = "🟥";
var orange_square = "🟧";
var yellow_square = "🟨";
var green_square = "🟩";
var blue_square = "🟦";
var purple_square = "🟪";
var brown_square = "🟫";
var black_large_square$2 = "⬛";
var white_large_square$2 = "⬜";
var black_medium_square$2 = "◼️";
var white_medium_square$2 = "◻️";
var black_medium_small_square$2 = "◾";
var white_medium_small_square$2 = "◽";
var black_small_square$2 = "▪️";
var white_small_square$2 = "▫️";
var large_orange_diamond$2 = "🔶";
var large_blue_diamond$2 = "🔷";
var small_orange_diamond$2 = "🔸";
var small_blue_diamond$2 = "🔹";
var small_red_triangle$2 = "🔺";
var small_red_triangle_down$2 = "🔻";
var diamond_shape_with_a_dot_inside$2 = "💠";
var radio_button$2 = "🔘";
var white_square_button$2 = "🔳";
var black_square_button$2 = "🔲";
var checkered_flag$2 = "🏁";
var triangular_flag_on_post$2 = "🚩";
var crossed_flags$2 = "🎌";
var black_flag$2 = "🏴";
var white_flag$2 = "🏳️";
var rainbow_flag$2 = "🏳️‍🌈";
var transgender_flag = "🏳️‍⚧️";
var pirate_flag$2 = "🏴‍☠️";
var ascension_island = "🇦🇨";
var andorra$2 = "🇦🇩";
var united_arab_emirates$2 = "🇦🇪";
var afghanistan$2 = "🇦🇫";
var antigua_barbuda$2 = "🇦🇬";
var anguilla$2 = "🇦🇮";
var albania$2 = "🇦🇱";
var armenia$2 = "🇦🇲";
var angola$2 = "🇦🇴";
var antarctica$2 = "🇦🇶";
var argentina$2 = "🇦🇷";
var american_samoa$2 = "🇦🇸";
var austria$2 = "🇦🇹";
var australia$2 = "🇦🇺";
var aruba$2 = "🇦🇼";
var aland_islands$2 = "🇦🇽";
var azerbaijan$2 = "🇦🇿";
var bosnia_herzegovina$2 = "🇧🇦";
var barbados$2 = "🇧🇧";
var bangladesh$2 = "🇧🇩";
var belgium$2 = "🇧🇪";
var burkina_faso$2 = "🇧🇫";
var bulgaria$2 = "🇧🇬";
var bahrain$2 = "🇧🇭";
var burundi$2 = "🇧🇮";
var benin$2 = "🇧🇯";
var st_barthelemy$2 = "🇧🇱";
var bermuda$2 = "🇧🇲";
var brunei$2 = "🇧🇳";
var bolivia$2 = "🇧🇴";
var caribbean_netherlands$2 = "🇧🇶";
var brazil$2 = "🇧🇷";
var bahamas$2 = "🇧🇸";
var bhutan$2 = "🇧🇹";
var bouvet_island = "🇧🇻";
var botswana$2 = "🇧🇼";
var belarus$2 = "🇧🇾";
var belize$2 = "🇧🇿";
var canada$2 = "🇨🇦";
var cocos_islands$2 = "🇨🇨";
var congo_kinshasa$2 = "🇨🇩";
var central_african_republic$2 = "🇨🇫";
var congo_brazzaville$2 = "🇨🇬";
var switzerland$2 = "🇨🇭";
var cote_divoire$2 = "🇨🇮";
var cook_islands$2 = "🇨🇰";
var chile$2 = "🇨🇱";
var cameroon$2 = "🇨🇲";
var cn$2 = "🇨🇳";
var colombia$2 = "🇨🇴";
var clipperton_island = "🇨🇵";
var costa_rica$2 = "🇨🇷";
var cuba$2 = "🇨🇺";
var cape_verde$2 = "🇨🇻";
var curacao$2 = "🇨🇼";
var christmas_island$2 = "🇨🇽";
var cyprus$2 = "🇨🇾";
var czech_republic$2 = "🇨🇿";
var de$2 = "🇩🇪";
var diego_garcia = "🇩🇬";
var djibouti$2 = "🇩🇯";
var denmark$2 = "🇩🇰";
var dominica$2 = "🇩🇲";
var dominican_republic$2 = "🇩🇴";
var algeria$2 = "🇩🇿";
var ceuta_melilla = "🇪🇦";
var ecuador$2 = "🇪🇨";
var estonia$2 = "🇪🇪";
var egypt$2 = "🇪🇬";
var western_sahara$2 = "🇪🇭";
var eritrea$2 = "🇪🇷";
var es$2 = "🇪🇸";
var ethiopia$2 = "🇪🇹";
var eu$2 = "🇪🇺";
var european_union = "🇪🇺";
var finland$2 = "🇫🇮";
var fiji$2 = "🇫🇯";
var falkland_islands$2 = "🇫🇰";
var micronesia$2 = "🇫🇲";
var faroe_islands$2 = "🇫🇴";
var fr$2 = "🇫🇷";
var gabon$2 = "🇬🇦";
var gb = "🇬🇧";
var uk$2 = "🇬🇧";
var grenada$2 = "🇬🇩";
var georgia$2 = "🇬🇪";
var french_guiana$2 = "🇬🇫";
var guernsey$2 = "🇬🇬";
var ghana$2 = "🇬🇭";
var gibraltar$2 = "🇬🇮";
var greenland$2 = "🇬🇱";
var gambia$2 = "🇬🇲";
var guinea$2 = "🇬🇳";
var guadeloupe$2 = "🇬🇵";
var equatorial_guinea$2 = "🇬🇶";
var greece$2 = "🇬🇷";
var south_georgia_south_sandwich_islands$2 = "🇬🇸";
var guatemala$2 = "🇬🇹";
var guam$2 = "🇬🇺";
var guinea_bissau$2 = "🇬🇼";
var guyana$2 = "🇬🇾";
var hong_kong$2 = "🇭🇰";
var heard_mcdonald_islands = "🇭🇲";
var honduras$2 = "🇭🇳";
var croatia$2 = "🇭🇷";
var haiti$2 = "🇭🇹";
var hungary$2 = "🇭🇺";
var canary_islands$2 = "🇮🇨";
var indonesia$2 = "🇮🇩";
var ireland$2 = "🇮🇪";
var israel$2 = "🇮🇱";
var isle_of_man$2 = "🇮🇲";
var india$2 = "🇮🇳";
var british_indian_ocean_territory$2 = "🇮🇴";
var iraq$2 = "🇮🇶";
var iran$2 = "🇮🇷";
var iceland$2 = "🇮🇸";
var it$3 = "🇮🇹";
var jersey$2 = "🇯🇪";
var jamaica$2 = "🇯🇲";
var jordan$2 = "🇯🇴";
var jp$2 = "🇯🇵";
var kenya$2 = "🇰🇪";
var kyrgyzstan$2 = "🇰🇬";
var cambodia$2 = "🇰🇭";
var kiribati$2 = "🇰🇮";
var comoros$2 = "🇰🇲";
var st_kitts_nevis$2 = "🇰🇳";
var north_korea$2 = "🇰🇵";
var kr$2 = "🇰🇷";
var kuwait$2 = "🇰🇼";
var cayman_islands$2 = "🇰🇾";
var kazakhstan$2 = "🇰🇿";
var laos$2 = "🇱🇦";
var lebanon$2 = "🇱🇧";
var st_lucia$2 = "🇱🇨";
var liechtenstein$2 = "🇱🇮";
var sri_lanka$2 = "🇱🇰";
var liberia$2 = "🇱🇷";
var lesotho$2 = "🇱🇸";
var lithuania$2 = "🇱🇹";
var luxembourg$2 = "🇱🇺";
var latvia$2 = "🇱🇻";
var libya$2 = "🇱🇾";
var morocco$2 = "🇲🇦";
var monaco$2 = "🇲🇨";
var moldova$2 = "🇲🇩";
var montenegro$2 = "🇲🇪";
var st_martin = "🇲🇫";
var madagascar$2 = "🇲🇬";
var marshall_islands$2 = "🇲🇭";
var macedonia$2 = "🇲🇰";
var mali$2 = "🇲🇱";
var myanmar$2 = "🇲🇲";
var mongolia$2 = "🇲🇳";
var macau$2 = "🇲🇴";
var northern_mariana_islands$2 = "🇲🇵";
var martinique$2 = "🇲🇶";
var mauritania$2 = "🇲🇷";
var montserrat$2 = "🇲🇸";
var malta$2 = "🇲🇹";
var mauritius$2 = "🇲🇺";
var maldives$2 = "🇲🇻";
var malawi$2 = "🇲🇼";
var mexico$2 = "🇲🇽";
var malaysia$2 = "🇲🇾";
var mozambique$2 = "🇲🇿";
var namibia$2 = "🇳🇦";
var new_caledonia$2 = "🇳🇨";
var niger$2 = "🇳🇪";
var norfolk_island$2 = "🇳🇫";
var nigeria$2 = "🇳🇬";
var nicaragua$2 = "🇳🇮";
var netherlands$2 = "🇳🇱";
var norway$2 = "🇳🇴";
var nepal$2 = "🇳🇵";
var nauru$2 = "🇳🇷";
var niue$2 = "🇳🇺";
var new_zealand$2 = "🇳🇿";
var oman$2 = "🇴🇲";
var panama$2 = "🇵🇦";
var peru$2 = "🇵🇪";
var french_polynesia$2 = "🇵🇫";
var papua_new_guinea$2 = "🇵🇬";
var philippines$2 = "🇵🇭";
var pakistan$2 = "🇵🇰";
var poland$2 = "🇵🇱";
var st_pierre_miquelon$2 = "🇵🇲";
var pitcairn_islands$2 = "🇵🇳";
var puerto_rico$2 = "🇵🇷";
var palestinian_territories$2 = "🇵🇸";
var portugal$2 = "🇵🇹";
var palau$2 = "🇵🇼";
var paraguay$2 = "🇵🇾";
var qatar$2 = "🇶🇦";
var reunion$2 = "🇷🇪";
var romania$2 = "🇷🇴";
var serbia$2 = "🇷🇸";
var ru$2 = "🇷🇺";
var rwanda$2 = "🇷🇼";
var saudi_arabia$2 = "🇸🇦";
var solomon_islands$2 = "🇸🇧";
var seychelles$2 = "🇸🇨";
var sudan$2 = "🇸🇩";
var sweden$2 = "🇸🇪";
var singapore$2 = "🇸🇬";
var st_helena$2 = "🇸🇭";
var slovenia$2 = "🇸🇮";
var svalbard_jan_mayen = "🇸🇯";
var slovakia$2 = "🇸🇰";
var sierra_leone$2 = "🇸🇱";
var san_marino$2 = "🇸🇲";
var senegal$2 = "🇸🇳";
var somalia$2 = "🇸🇴";
var suriname$2 = "🇸🇷";
var south_sudan$2 = "🇸🇸";
var sao_tome_principe$2 = "🇸🇹";
var el_salvador$2 = "🇸🇻";
var sint_maarten$2 = "🇸🇽";
var syria$2 = "🇸🇾";
var swaziland$2 = "🇸🇿";
var tristan_da_cunha = "🇹🇦";
var turks_caicos_islands$2 = "🇹🇨";
var chad$2 = "🇹🇩";
var french_southern_territories$2 = "🇹🇫";
var togo$2 = "🇹🇬";
var thailand$2 = "🇹🇭";
var tajikistan$2 = "🇹🇯";
var tokelau$2 = "🇹🇰";
var timor_leste$2 = "🇹🇱";
var turkmenistan$2 = "🇹🇲";
var tunisia$2 = "🇹🇳";
var tonga$2 = "🇹🇴";
var tr$2 = "🇹🇷";
var trinidad_tobago$2 = "🇹🇹";
var tuvalu$2 = "🇹🇻";
var taiwan$2 = "🇹🇼";
var tanzania$2 = "🇹🇿";
var ukraine$2 = "🇺🇦";
var uganda$2 = "🇺🇬";
var us_outlying_islands = "🇺🇲";
var united_nations$2 = "🇺🇳";
var us$2 = "🇺🇸";
var uruguay$2 = "🇺🇾";
var uzbekistan$2 = "🇺🇿";
var vatican_city$2 = "🇻🇦";
var st_vincent_grenadines$2 = "🇻🇨";
var venezuela$2 = "🇻🇪";
var british_virgin_islands$2 = "🇻🇬";
var us_virgin_islands$2 = "🇻🇮";
var vietnam$2 = "🇻🇳";
var vanuatu$2 = "🇻🇺";
var wallis_futuna$2 = "🇼🇫";
var samoa$2 = "🇼🇸";
var kosovo$2 = "🇽🇰";
var yemen$2 = "🇾🇪";
var mayotte$2 = "🇾🇹";
var south_africa$2 = "🇿🇦";
var zambia$2 = "🇿🇲";
var zimbabwe$2 = "🇿🇼";
var england$2 = "🏴󠁧󠁢󠁥󠁮󠁧󠁿";
var scotland$2 = "🏴󠁧󠁢󠁳󠁣󠁴󠁿";
var wales$2 = "🏴󠁧󠁢󠁷󠁬󠁳󠁿";
var require$$0$3 = {
	"100": "💯",
	"1234": "🔢",
	grinning: grinning$2,
	smiley: smiley$2,
	smile: smile$3,
	grin: grin$2,
	laughing: laughing$2,
	satisfied: satisfied,
	sweat_smile: sweat_smile$2,
	rofl: rofl$2,
	joy: joy$2,
	slightly_smiling_face: slightly_smiling_face$2,
	upside_down_face: upside_down_face$2,
	wink: wink$2,
	blush: blush$2,
	innocent: innocent$2,
	smiling_face_with_three_hearts: smiling_face_with_three_hearts$2,
	heart_eyes: heart_eyes$2,
	star_struck: star_struck$2,
	kissing_heart: kissing_heart$2,
	kissing: kissing$2,
	relaxed: relaxed$2,
	kissing_closed_eyes: kissing_closed_eyes$2,
	kissing_smiling_eyes: kissing_smiling_eyes$2,
	smiling_face_with_tear: smiling_face_with_tear,
	yum: yum$2,
	stuck_out_tongue: stuck_out_tongue$2,
	stuck_out_tongue_winking_eye: stuck_out_tongue_winking_eye$2,
	zany_face: zany_face,
	stuck_out_tongue_closed_eyes: stuck_out_tongue_closed_eyes$2,
	money_mouth_face: money_mouth_face$2,
	hugs: hugs$2,
	hand_over_mouth: hand_over_mouth$2,
	shushing_face: shushing_face,
	thinking: thinking$2,
	zipper_mouth_face: zipper_mouth_face$2,
	raised_eyebrow: raised_eyebrow$2,
	neutral_face: neutral_face$2,
	expressionless: expressionless$2,
	no_mouth: no_mouth$2,
	smirk: smirk$2,
	unamused: unamused$2,
	roll_eyes: roll_eyes$2,
	grimacing: grimacing$2,
	lying_face: lying_face$2,
	relieved: relieved$2,
	pensive: pensive$2,
	sleepy: sleepy$2,
	drooling_face: drooling_face$2,
	sleeping: sleeping$2,
	mask: mask$2,
	face_with_thermometer: face_with_thermometer$2,
	face_with_head_bandage: face_with_head_bandage$2,
	nauseated_face: nauseated_face$2,
	vomiting_face: vomiting_face,
	sneezing_face: sneezing_face$2,
	hot_face: hot_face,
	cold_face: cold_face,
	woozy_face: woozy_face,
	dizzy_face: dizzy_face$2,
	exploding_head: exploding_head$2,
	cowboy_hat_face: cowboy_hat_face$2,
	partying_face: partying_face,
	disguised_face: disguised_face,
	sunglasses: sunglasses$2,
	nerd_face: nerd_face$2,
	monocle_face: monocle_face,
	confused: confused$2,
	worried: worried$2,
	slightly_frowning_face: slightly_frowning_face$2,
	frowning_face: frowning_face$2,
	open_mouth: open_mouth$2,
	hushed: hushed$2,
	astonished: astonished$2,
	flushed: flushed$2,
	pleading_face: pleading_face,
	frowning: frowning$2,
	anguished: anguished$2,
	fearful: fearful$2,
	cold_sweat: cold_sweat$2,
	disappointed_relieved: disappointed_relieved$2,
	cry: cry$2,
	sob: sob$2,
	scream: scream$2,
	confounded: confounded$2,
	persevere: persevere$2,
	disappointed: disappointed$2,
	sweat: sweat$2,
	weary: weary$2,
	tired_face: tired_face$2,
	yawning_face: yawning_face,
	triumph: triumph$2,
	rage: rage$2,
	pout: pout,
	angry: angry$2,
	cursing_face: cursing_face,
	smiling_imp: smiling_imp$2,
	imp: imp$2,
	skull: skull$2,
	skull_and_crossbones: skull_and_crossbones$2,
	hankey: hankey,
	poop: poop$2,
	shit: shit,
	clown_face: clown_face$2,
	japanese_ogre: japanese_ogre$2,
	japanese_goblin: japanese_goblin$2,
	ghost: ghost$2,
	alien: alien$2,
	space_invader: space_invader$2,
	robot: robot$2,
	smiley_cat: smiley_cat$2,
	smile_cat: smile_cat$2,
	joy_cat: joy_cat$2,
	heart_eyes_cat: heart_eyes_cat$2,
	smirk_cat: smirk_cat$2,
	kissing_cat: kissing_cat$2,
	scream_cat: scream_cat$2,
	crying_cat_face: crying_cat_face$2,
	pouting_cat: pouting_cat$2,
	see_no_evil: see_no_evil$2,
	hear_no_evil: hear_no_evil$2,
	speak_no_evil: speak_no_evil$2,
	kiss: kiss$2,
	love_letter: love_letter$2,
	cupid: cupid$2,
	gift_heart: gift_heart$2,
	sparkling_heart: sparkling_heart$2,
	heartpulse: heartpulse$2,
	heartbeat: heartbeat$2,
	revolving_hearts: revolving_hearts$2,
	two_hearts: two_hearts$2,
	heart_decoration: heart_decoration$2,
	heavy_heart_exclamation: heavy_heart_exclamation$2,
	broken_heart: broken_heart$2,
	heart: heart$2,
	orange_heart: orange_heart$2,
	yellow_heart: yellow_heart$2,
	green_heart: green_heart$2,
	blue_heart: blue_heart$2,
	purple_heart: purple_heart$2,
	brown_heart: brown_heart,
	black_heart: black_heart$2,
	white_heart: white_heart,
	anger: anger$2,
	boom: boom$2,
	collision: collision,
	dizzy: dizzy$2,
	sweat_drops: sweat_drops$2,
	dash: dash$3,
	hole: hole$2,
	bomb: bomb$2,
	speech_balloon: speech_balloon$2,
	eye_speech_bubble: eye_speech_bubble,
	left_speech_bubble: left_speech_bubble$2,
	right_anger_bubble: right_anger_bubble$2,
	thought_balloon: thought_balloon$2,
	zzz: zzz$2,
	wave: wave$2,
	raised_back_of_hand: raised_back_of_hand$2,
	raised_hand_with_fingers_splayed: raised_hand_with_fingers_splayed$2,
	hand: hand,
	raised_hand: raised_hand$2,
	vulcan_salute: vulcan_salute$2,
	ok_hand: ok_hand$2,
	pinched_fingers: pinched_fingers,
	pinching_hand: pinching_hand,
	v: v$2,
	crossed_fingers: crossed_fingers$2,
	love_you_gesture: love_you_gesture,
	metal: metal$2,
	call_me_hand: call_me_hand$2,
	point_left: point_left$2,
	point_right: point_right$2,
	point_up_2: point_up_2$2,
	middle_finger: middle_finger,
	fu: fu$2,
	point_down: point_down$2,
	point_up: point_up$2,
	"+1": "👍",
	thumbsup: thumbsup,
	"-1": "👎",
	thumbsdown: thumbsdown,
	fist_raised: fist_raised,
	fist: fist$2,
	fist_oncoming: fist_oncoming,
	facepunch: facepunch$2,
	punch: punch,
	fist_left: fist_left$2,
	fist_right: fist_right$2,
	clap: clap$2,
	raised_hands: raised_hands$2,
	open_hands: open_hands$2,
	palms_up_together: palms_up_together,
	handshake: handshake$2,
	pray: pray$2,
	writing_hand: writing_hand$2,
	nail_care: nail_care$2,
	selfie: selfie$2,
	muscle: muscle$2,
	mechanical_arm: mechanical_arm,
	mechanical_leg: mechanical_leg,
	leg: leg$3,
	foot: foot$2,
	ear: ear$2,
	ear_with_hearing_aid: ear_with_hearing_aid,
	nose: nose$2,
	brain: brain$2,
	anatomical_heart: anatomical_heart,
	lungs: lungs,
	tooth: tooth$2,
	bone: bone$2,
	eyes: eyes$2,
	eye: eye$2,
	tongue: tongue$2,
	lips: lips$2,
	baby: baby$2,
	child: child$2,
	boy: boy$2,
	girl: girl$2,
	adult: adult$2,
	blond_haired_person: blond_haired_person,
	man: man$2,
	bearded_person: bearded_person$2,
	red_haired_man: red_haired_man,
	curly_haired_man: curly_haired_man,
	white_haired_man: white_haired_man,
	bald_man: bald_man,
	woman: woman$2,
	red_haired_woman: red_haired_woman,
	person_red_hair: person_red_hair,
	curly_haired_woman: curly_haired_woman,
	person_curly_hair: person_curly_hair,
	white_haired_woman: white_haired_woman,
	person_white_hair: person_white_hair,
	bald_woman: bald_woman,
	person_bald: person_bald,
	blond_haired_woman: blond_haired_woman,
	blonde_woman: blonde_woman$2,
	blond_haired_man: blond_haired_man,
	older_adult: older_adult$2,
	older_man: older_man$2,
	older_woman: older_woman$2,
	frowning_person: frowning_person,
	frowning_man: frowning_man$2,
	frowning_woman: frowning_woman$2,
	pouting_face: pouting_face,
	pouting_man: pouting_man$2,
	pouting_woman: pouting_woman$2,
	no_good: no_good,
	no_good_man: no_good_man$2,
	ng_man: ng_man,
	no_good_woman: no_good_woman$2,
	ng_woman: ng_woman,
	ok_person: ok_person,
	ok_man: ok_man$2,
	ok_woman: ok_woman$2,
	tipping_hand_person: tipping_hand_person,
	information_desk_person: information_desk_person,
	tipping_hand_man: tipping_hand_man$2,
	sassy_man: sassy_man,
	tipping_hand_woman: tipping_hand_woman$2,
	sassy_woman: sassy_woman,
	raising_hand: raising_hand,
	raising_hand_man: raising_hand_man$2,
	raising_hand_woman: raising_hand_woman$2,
	deaf_person: deaf_person,
	deaf_man: deaf_man,
	deaf_woman: deaf_woman,
	bow: bow,
	bowing_man: bowing_man$2,
	bowing_woman: bowing_woman$2,
	facepalm: facepalm,
	man_facepalming: man_facepalming$2,
	woman_facepalming: woman_facepalming$2,
	shrug: shrug,
	man_shrugging: man_shrugging$2,
	woman_shrugging: woman_shrugging$2,
	health_worker: health_worker,
	man_health_worker: man_health_worker$2,
	woman_health_worker: woman_health_worker$2,
	student: student,
	man_student: man_student$2,
	woman_student: woman_student$2,
	teacher: teacher,
	man_teacher: man_teacher$2,
	woman_teacher: woman_teacher$2,
	judge: judge,
	man_judge: man_judge$2,
	woman_judge: woman_judge$2,
	farmer: farmer,
	man_farmer: man_farmer$2,
	woman_farmer: woman_farmer$2,
	cook: cook,
	man_cook: man_cook$2,
	woman_cook: woman_cook$2,
	mechanic: mechanic,
	man_mechanic: man_mechanic$2,
	woman_mechanic: woman_mechanic$2,
	factory_worker: factory_worker,
	man_factory_worker: man_factory_worker$2,
	woman_factory_worker: woman_factory_worker$2,
	office_worker: office_worker,
	man_office_worker: man_office_worker$2,
	woman_office_worker: woman_office_worker$2,
	scientist: scientist,
	man_scientist: man_scientist$2,
	woman_scientist: woman_scientist$2,
	technologist: technologist,
	man_technologist: man_technologist$2,
	woman_technologist: woman_technologist$2,
	singer: singer,
	man_singer: man_singer$2,
	woman_singer: woman_singer$2,
	artist: artist,
	man_artist: man_artist$2,
	woman_artist: woman_artist$2,
	pilot: pilot,
	man_pilot: man_pilot$2,
	woman_pilot: woman_pilot$2,
	astronaut: astronaut,
	man_astronaut: man_astronaut$2,
	woman_astronaut: woman_astronaut$2,
	firefighter: firefighter,
	man_firefighter: man_firefighter$2,
	woman_firefighter: woman_firefighter$2,
	police_officer: police_officer,
	cop: cop,
	policeman: policeman$2,
	policewoman: policewoman$2,
	detective: detective,
	male_detective: male_detective$2,
	female_detective: female_detective$2,
	guard: guard,
	guardsman: guardsman$2,
	guardswoman: guardswoman$2,
	ninja: ninja,
	construction_worker: construction_worker,
	construction_worker_man: construction_worker_man$2,
	construction_worker_woman: construction_worker_woman$2,
	prince: prince$2,
	princess: princess$2,
	person_with_turban: person_with_turban,
	man_with_turban: man_with_turban$2,
	woman_with_turban: woman_with_turban$2,
	man_with_gua_pi_mao: man_with_gua_pi_mao$2,
	woman_with_headscarf: woman_with_headscarf$2,
	person_in_tuxedo: person_in_tuxedo,
	man_in_tuxedo: man_in_tuxedo$2,
	woman_in_tuxedo: woman_in_tuxedo,
	person_with_veil: person_with_veil,
	man_with_veil: man_with_veil,
	woman_with_veil: woman_with_veil,
	bride_with_veil: bride_with_veil$2,
	pregnant_woman: pregnant_woman$2,
	breast_feeding: breast_feeding,
	woman_feeding_baby: woman_feeding_baby,
	man_feeding_baby: man_feeding_baby,
	person_feeding_baby: person_feeding_baby,
	angel: angel$2,
	santa: santa$2,
	mrs_claus: mrs_claus$2,
	mx_claus: mx_claus,
	superhero: superhero,
	superhero_man: superhero_man,
	superhero_woman: superhero_woman,
	supervillain: supervillain,
	supervillain_man: supervillain_man,
	supervillain_woman: supervillain_woman,
	mage: mage,
	mage_man: mage_man,
	mage_woman: mage_woman,
	fairy: fairy,
	fairy_man: fairy_man,
	fairy_woman: fairy_woman,
	vampire: vampire,
	vampire_man: vampire_man,
	vampire_woman: vampire_woman,
	merperson: merperson,
	merman: merman$2,
	mermaid: mermaid$2,
	elf: elf,
	elf_man: elf_man,
	elf_woman: elf_woman,
	genie: genie,
	genie_man: genie_man,
	genie_woman: genie_woman,
	zombie: zombie,
	zombie_man: zombie_man,
	zombie_woman: zombie_woman,
	massage: massage,
	massage_man: massage_man$2,
	massage_woman: massage_woman$2,
	haircut: haircut,
	haircut_man: haircut_man$2,
	haircut_woman: haircut_woman$2,
	walking: walking,
	walking_man: walking_man$2,
	walking_woman: walking_woman$2,
	standing_person: standing_person,
	standing_man: standing_man,
	standing_woman: standing_woman,
	kneeling_person: kneeling_person,
	kneeling_man: kneeling_man,
	kneeling_woman: kneeling_woman,
	person_with_probing_cane: person_with_probing_cane,
	man_with_probing_cane: man_with_probing_cane,
	woman_with_probing_cane: woman_with_probing_cane,
	person_in_motorized_wheelchair: person_in_motorized_wheelchair,
	man_in_motorized_wheelchair: man_in_motorized_wheelchair,
	woman_in_motorized_wheelchair: woman_in_motorized_wheelchair,
	person_in_manual_wheelchair: person_in_manual_wheelchair,
	man_in_manual_wheelchair: man_in_manual_wheelchair,
	woman_in_manual_wheelchair: woman_in_manual_wheelchair,
	runner: runner,
	running: running,
	running_man: running_man$2,
	running_woman: running_woman$2,
	woman_dancing: woman_dancing,
	dancer: dancer$2,
	man_dancing: man_dancing$2,
	business_suit_levitating: business_suit_levitating$2,
	dancers: dancers,
	dancing_men: dancing_men$2,
	dancing_women: dancing_women$2,
	sauna_person: sauna_person,
	sauna_man: sauna_man,
	sauna_woman: sauna_woman,
	climbing: climbing,
	climbing_man: climbing_man$2,
	climbing_woman: climbing_woman$2,
	person_fencing: person_fencing$2,
	horse_racing: horse_racing$2,
	skier: skier$2,
	snowboarder: snowboarder$2,
	golfing: golfing,
	golfing_man: golfing_man$2,
	golfing_woman: golfing_woman$2,
	surfer: surfer,
	surfing_man: surfing_man$2,
	surfing_woman: surfing_woman$2,
	rowboat: rowboat,
	rowing_man: rowing_man$2,
	rowing_woman: rowing_woman$2,
	swimmer: swimmer,
	swimming_man: swimming_man$2,
	swimming_woman: swimming_woman$2,
	bouncing_ball_person: bouncing_ball_person,
	bouncing_ball_man: bouncing_ball_man,
	basketball_man: basketball_man$2,
	bouncing_ball_woman: bouncing_ball_woman,
	basketball_woman: basketball_woman$2,
	weight_lifting: weight_lifting,
	weight_lifting_man: weight_lifting_man$2,
	weight_lifting_woman: weight_lifting_woman$2,
	bicyclist: bicyclist,
	biking_man: biking_man$2,
	biking_woman: biking_woman$2,
	mountain_bicyclist: mountain_bicyclist,
	mountain_biking_man: mountain_biking_man$2,
	mountain_biking_woman: mountain_biking_woman$2,
	cartwheeling: cartwheeling,
	man_cartwheeling: man_cartwheeling$2,
	woman_cartwheeling: woman_cartwheeling$2,
	wrestling: wrestling,
	men_wrestling: men_wrestling$2,
	women_wrestling: women_wrestling$2,
	water_polo: water_polo,
	man_playing_water_polo: man_playing_water_polo$2,
	woman_playing_water_polo: woman_playing_water_polo$2,
	handball_person: handball_person,
	man_playing_handball: man_playing_handball$2,
	woman_playing_handball: woman_playing_handball$2,
	juggling_person: juggling_person,
	man_juggling: man_juggling$2,
	woman_juggling: woman_juggling$2,
	lotus_position: lotus_position,
	lotus_position_man: lotus_position_man,
	lotus_position_woman: lotus_position_woman,
	bath: bath$2,
	sleeping_bed: sleeping_bed$2,
	people_holding_hands: people_holding_hands,
	two_women_holding_hands: two_women_holding_hands$2,
	couple: couple$2,
	two_men_holding_hands: two_men_holding_hands$2,
	couplekiss: couplekiss,
	couplekiss_man_woman: couplekiss_man_woman$2,
	couplekiss_man_man: couplekiss_man_man$2,
	couplekiss_woman_woman: couplekiss_woman_woman$2,
	couple_with_heart: couple_with_heart,
	couple_with_heart_woman_man: couple_with_heart_woman_man$2,
	couple_with_heart_man_man: couple_with_heart_man_man$2,
	couple_with_heart_woman_woman: couple_with_heart_woman_woman$2,
	family: family,
	family_man_woman_boy: family_man_woman_boy$2,
	family_man_woman_girl: family_man_woman_girl$2,
	family_man_woman_girl_boy: family_man_woman_girl_boy$2,
	family_man_woman_boy_boy: family_man_woman_boy_boy$2,
	family_man_woman_girl_girl: family_man_woman_girl_girl$2,
	family_man_man_boy: family_man_man_boy$2,
	family_man_man_girl: family_man_man_girl$2,
	family_man_man_girl_boy: family_man_man_girl_boy$2,
	family_man_man_boy_boy: family_man_man_boy_boy$2,
	family_man_man_girl_girl: family_man_man_girl_girl$2,
	family_woman_woman_boy: family_woman_woman_boy$2,
	family_woman_woman_girl: family_woman_woman_girl$2,
	family_woman_woman_girl_boy: family_woman_woman_girl_boy$2,
	family_woman_woman_boy_boy: family_woman_woman_boy_boy$2,
	family_woman_woman_girl_girl: family_woman_woman_girl_girl$2,
	family_man_boy: family_man_boy$2,
	family_man_boy_boy: family_man_boy_boy$2,
	family_man_girl: family_man_girl$2,
	family_man_girl_boy: family_man_girl_boy$2,
	family_man_girl_girl: family_man_girl_girl$2,
	family_woman_boy: family_woman_boy$2,
	family_woman_boy_boy: family_woman_boy_boy$2,
	family_woman_girl: family_woman_girl$2,
	family_woman_girl_boy: family_woman_girl_boy$2,
	family_woman_girl_girl: family_woman_girl_girl$2,
	speaking_head: speaking_head$2,
	bust_in_silhouette: bust_in_silhouette$2,
	busts_in_silhouette: busts_in_silhouette$2,
	people_hugging: people_hugging,
	footprints: footprints$2,
	monkey_face: monkey_face$2,
	monkey: monkey$2,
	gorilla: gorilla$2,
	orangutan: orangutan,
	dog: dog$2,
	dog2: dog2$2,
	guide_dog: guide_dog,
	service_dog: service_dog,
	poodle: poodle$2,
	wolf: wolf$2,
	fox_face: fox_face$2,
	raccoon: raccoon$2,
	cat: cat$2,
	cat2: cat2$2,
	black_cat: black_cat,
	lion: lion$2,
	tiger: tiger$2,
	tiger2: tiger2$2,
	leopard: leopard$2,
	horse: horse$2,
	racehorse: racehorse$2,
	unicorn: unicorn$2,
	zebra: zebra$2,
	deer: deer$2,
	bison: bison,
	cow: cow$2,
	ox: ox$2,
	water_buffalo: water_buffalo$2,
	cow2: cow2$2,
	pig: pig$2,
	pig2: pig2$2,
	boar: boar$2,
	pig_nose: pig_nose$2,
	ram: ram$2,
	sheep: sheep$2,
	goat: goat$2,
	dromedary_camel: dromedary_camel$2,
	camel: camel$2,
	llama: llama$2,
	giraffe: giraffe$2,
	elephant: elephant$2,
	mammoth: mammoth,
	rhinoceros: rhinoceros$2,
	hippopotamus: hippopotamus$2,
	mouse: mouse$2,
	mouse2: mouse2$2,
	rat: rat$2,
	hamster: hamster$2,
	rabbit: rabbit$2,
	rabbit2: rabbit2$2,
	chipmunk: chipmunk$2,
	beaver: beaver,
	hedgehog: hedgehog$2,
	bat: bat$2,
	bear: bear$2,
	polar_bear: polar_bear,
	koala: koala$2,
	panda_face: panda_face$2,
	sloth: sloth,
	otter: otter,
	skunk: skunk,
	kangaroo: kangaroo$2,
	badger: badger$2,
	feet: feet,
	paw_prints: paw_prints$2,
	turkey: turkey$2,
	chicken: chicken$2,
	rooster: rooster$2,
	hatching_chick: hatching_chick$2,
	baby_chick: baby_chick$2,
	hatched_chick: hatched_chick$2,
	bird: bird$2,
	penguin: penguin$2,
	dove: dove$2,
	eagle: eagle$2,
	duck: duck$2,
	swan: swan$2,
	owl: owl$2,
	dodo: dodo,
	feather: feather,
	flamingo: flamingo,
	peacock: peacock$2,
	parrot: parrot$2,
	frog: frog$2,
	crocodile: crocodile$2,
	turtle: turtle$2,
	lizard: lizard$2,
	snake: snake$2,
	dragon_face: dragon_face$2,
	dragon: dragon$2,
	sauropod: sauropod$2,
	"t-rex": "🦖",
	whale: whale$2,
	whale2: whale2$2,
	dolphin: dolphin$2,
	flipper: flipper,
	seal: seal,
	fish: fish$2,
	tropical_fish: tropical_fish$2,
	blowfish: blowfish$2,
	shark: shark$2,
	octopus: octopus$2,
	shell: shell$2,
	snail: snail$2,
	butterfly: butterfly$2,
	bug: bug$2,
	ant: ant$2,
	bee: bee,
	honeybee: honeybee$2,
	beetle: beetle$2,
	lady_beetle: lady_beetle,
	cricket: cricket$2,
	cockroach: cockroach,
	spider: spider$2,
	spider_web: spider_web$2,
	scorpion: scorpion$2,
	mosquito: mosquito$2,
	fly: fly,
	worm: worm,
	microbe: microbe$2,
	bouquet: bouquet$2,
	cherry_blossom: cherry_blossom$2,
	white_flower: white_flower$2,
	rosette: rosette$2,
	rose: rose$2,
	wilted_flower: wilted_flower$2,
	hibiscus: hibiscus$2,
	sunflower: sunflower$2,
	blossom: blossom$2,
	tulip: tulip$2,
	seedling: seedling$2,
	potted_plant: potted_plant,
	evergreen_tree: evergreen_tree$2,
	deciduous_tree: deciduous_tree$2,
	palm_tree: palm_tree$2,
	cactus: cactus$2,
	ear_of_rice: ear_of_rice$2,
	herb: herb$2,
	shamrock: shamrock$2,
	four_leaf_clover: four_leaf_clover$2,
	maple_leaf: maple_leaf$2,
	fallen_leaf: fallen_leaf$2,
	leaves: leaves$2,
	grapes: grapes$2,
	melon: melon$2,
	watermelon: watermelon$2,
	tangerine: tangerine$2,
	orange: orange,
	mandarin: mandarin,
	lemon: lemon$2,
	banana: banana$2,
	pineapple: pineapple$2,
	mango: mango$2,
	apple: apple$2,
	green_apple: green_apple$2,
	pear: pear$2,
	peach: peach$2,
	cherries: cherries$2,
	strawberry: strawberry$2,
	blueberries: blueberries,
	kiwi_fruit: kiwi_fruit$2,
	tomato: tomato$2,
	olive: olive,
	coconut: coconut$2,
	avocado: avocado$2,
	eggplant: eggplant$2,
	potato: potato$2,
	carrot: carrot$2,
	corn: corn$2,
	hot_pepper: hot_pepper$2,
	bell_pepper: bell_pepper,
	cucumber: cucumber$2,
	leafy_green: leafy_green,
	broccoli: broccoli$2,
	garlic: garlic,
	onion: onion,
	mushroom: mushroom$2,
	peanuts: peanuts$2,
	chestnut: chestnut$2,
	bread: bread$2,
	croissant: croissant$2,
	baguette_bread: baguette_bread$2,
	flatbread: flatbread,
	pretzel: pretzel$2,
	bagel: bagel$2,
	pancakes: pancakes$2,
	waffle: waffle,
	cheese: cheese$2,
	meat_on_bone: meat_on_bone$2,
	poultry_leg: poultry_leg$2,
	cut_of_meat: cut_of_meat,
	bacon: bacon$2,
	hamburger: hamburger$2,
	fries: fries$2,
	pizza: pizza$2,
	hotdog: hotdog$2,
	sandwich: sandwich$2,
	taco: taco$2,
	burrito: burrito$2,
	tamale: tamale,
	stuffed_flatbread: stuffed_flatbread$2,
	falafel: falafel,
	egg: egg$2,
	fried_egg: fried_egg$2,
	shallow_pan_of_food: shallow_pan_of_food$2,
	stew: stew$2,
	fondue: fondue,
	bowl_with_spoon: bowl_with_spoon$2,
	green_salad: green_salad$2,
	popcorn: popcorn$2,
	butter: butter,
	salt: salt$2,
	canned_food: canned_food$2,
	bento: bento$2,
	rice_cracker: rice_cracker$2,
	rice_ball: rice_ball$2,
	rice: rice$2,
	curry: curry$2,
	ramen: ramen$2,
	spaghetti: spaghetti$2,
	sweet_potato: sweet_potato$2,
	oden: oden$2,
	sushi: sushi$2,
	fried_shrimp: fried_shrimp$2,
	fish_cake: fish_cake$2,
	moon_cake: moon_cake$2,
	dango: dango$2,
	dumpling: dumpling$2,
	fortune_cookie: fortune_cookie$2,
	takeout_box: takeout_box$2,
	crab: crab$2,
	lobster: lobster$2,
	shrimp: shrimp$2,
	squid: squid$2,
	oyster: oyster,
	icecream: icecream$2,
	shaved_ice: shaved_ice$2,
	ice_cream: ice_cream$2,
	doughnut: doughnut$2,
	cookie: cookie$2,
	birthday: birthday$2,
	cake: cake$2,
	cupcake: cupcake$2,
	pie: pie$2,
	chocolate_bar: chocolate_bar$2,
	candy: candy$2,
	lollipop: lollipop$2,
	custard: custard$2,
	honey_pot: honey_pot$2,
	baby_bottle: baby_bottle$2,
	milk_glass: milk_glass$2,
	coffee: coffee$2,
	teapot: teapot,
	tea: tea$2,
	sake: sake$2,
	champagne: champagne$2,
	wine_glass: wine_glass$2,
	cocktail: cocktail$2,
	tropical_drink: tropical_drink$2,
	beer: beer$2,
	beers: beers$2,
	clinking_glasses: clinking_glasses$2,
	tumbler_glass: tumbler_glass$2,
	cup_with_straw: cup_with_straw$2,
	bubble_tea: bubble_tea,
	beverage_box: beverage_box,
	mate: mate,
	ice_cube: ice_cube,
	chopsticks: chopsticks$2,
	plate_with_cutlery: plate_with_cutlery$2,
	fork_and_knife: fork_and_knife$2,
	spoon: spoon$2,
	hocho: hocho$2,
	knife: knife,
	amphora: amphora$2,
	earth_africa: earth_africa$2,
	earth_americas: earth_americas$2,
	earth_asia: earth_asia$2,
	globe_with_meridians: globe_with_meridians$2,
	world_map: world_map$2,
	japan: japan$2,
	compass: compass$2,
	mountain_snow: mountain_snow$2,
	mountain: mountain$2,
	volcano: volcano$2,
	mount_fuji: mount_fuji$2,
	camping: camping$2,
	beach_umbrella: beach_umbrella$2,
	desert: desert$2,
	desert_island: desert_island$2,
	national_park: national_park$2,
	stadium: stadium$2,
	classical_building: classical_building$2,
	building_construction: building_construction$2,
	bricks: bricks,
	rock: rock,
	wood: wood,
	hut: hut,
	houses: houses$2,
	derelict_house: derelict_house$2,
	house: house$2,
	house_with_garden: house_with_garden$2,
	office: office$2,
	post_office: post_office$2,
	european_post_office: european_post_office$2,
	hospital: hospital$2,
	bank: bank$2,
	hotel: hotel$2,
	love_hotel: love_hotel$2,
	convenience_store: convenience_store$2,
	school: school$2,
	department_store: department_store$2,
	factory: factory$2,
	japanese_castle: japanese_castle$2,
	european_castle: european_castle$2,
	wedding: wedding$2,
	tokyo_tower: tokyo_tower$2,
	statue_of_liberty: statue_of_liberty$2,
	church: church$2,
	mosque: mosque$2,
	hindu_temple: hindu_temple,
	synagogue: synagogue$2,
	shinto_shrine: shinto_shrine$2,
	kaaba: kaaba$2,
	fountain: fountain$2,
	tent: tent$2,
	foggy: foggy$2,
	night_with_stars: night_with_stars$2,
	cityscape: cityscape$2,
	sunrise_over_mountains: sunrise_over_mountains$2,
	sunrise: sunrise$2,
	city_sunset: city_sunset$2,
	city_sunrise: city_sunrise$2,
	bridge_at_night: bridge_at_night$2,
	hotsprings: hotsprings$2,
	carousel_horse: carousel_horse$2,
	ferris_wheel: ferris_wheel$2,
	roller_coaster: roller_coaster$2,
	barber: barber$2,
	circus_tent: circus_tent$2,
	steam_locomotive: steam_locomotive$2,
	railway_car: railway_car$2,
	bullettrain_side: bullettrain_side$2,
	bullettrain_front: bullettrain_front$2,
	train2: train2$2,
	metro: metro$2,
	light_rail: light_rail$2,
	station: station$2,
	tram: tram$2,
	monorail: monorail$2,
	mountain_railway: mountain_railway$2,
	train: train$2,
	bus: bus$2,
	oncoming_bus: oncoming_bus$2,
	trolleybus: trolleybus$2,
	minibus: minibus$2,
	ambulance: ambulance$2,
	fire_engine: fire_engine$2,
	police_car: police_car$2,
	oncoming_police_car: oncoming_police_car$2,
	taxi: taxi$2,
	oncoming_taxi: oncoming_taxi$2,
	car: car,
	red_car: red_car$2,
	oncoming_automobile: oncoming_automobile$2,
	blue_car: blue_car$2,
	pickup_truck: pickup_truck,
	truck: truck$2,
	articulated_lorry: articulated_lorry$2,
	tractor: tractor$2,
	racing_car: racing_car$2,
	motorcycle: motorcycle$2,
	motor_scooter: motor_scooter$2,
	manual_wheelchair: manual_wheelchair,
	motorized_wheelchair: motorized_wheelchair,
	auto_rickshaw: auto_rickshaw,
	bike: bike$2,
	kick_scooter: kick_scooter$2,
	skateboard: skateboard$2,
	roller_skate: roller_skate,
	busstop: busstop$2,
	motorway: motorway$2,
	railway_track: railway_track$2,
	oil_drum: oil_drum$2,
	fuelpump: fuelpump$2,
	rotating_light: rotating_light$2,
	traffic_light: traffic_light$2,
	vertical_traffic_light: vertical_traffic_light$2,
	stop_sign: stop_sign$2,
	construction: construction$2,
	anchor: anchor$2,
	boat: boat,
	sailboat: sailboat$2,
	canoe: canoe$2,
	speedboat: speedboat$2,
	passenger_ship: passenger_ship$2,
	ferry: ferry$2,
	motor_boat: motor_boat$2,
	ship: ship$2,
	airplane: airplane$2,
	small_airplane: small_airplane$2,
	flight_departure: flight_departure$2,
	flight_arrival: flight_arrival$2,
	parachute: parachute,
	seat: seat$2,
	helicopter: helicopter$2,
	suspension_railway: suspension_railway$2,
	mountain_cableway: mountain_cableway$2,
	aerial_tramway: aerial_tramway$2,
	artificial_satellite: artificial_satellite$2,
	rocket: rocket$2,
	flying_saucer: flying_saucer$2,
	bellhop_bell: bellhop_bell$2,
	luggage: luggage$2,
	hourglass: hourglass$2,
	hourglass_flowing_sand: hourglass_flowing_sand$2,
	watch: watch$2,
	alarm_clock: alarm_clock$2,
	stopwatch: stopwatch$2,
	timer_clock: timer_clock$2,
	mantelpiece_clock: mantelpiece_clock$2,
	clock12: clock12$2,
	clock1230: clock1230$2,
	clock1: clock1$2,
	clock130: clock130$2,
	clock2: clock2$2,
	clock230: clock230$2,
	clock3: clock3$2,
	clock330: clock330$2,
	clock4: clock4$2,
	clock430: clock430$2,
	clock5: clock5$2,
	clock530: clock530$2,
	clock6: clock6$2,
	clock630: clock630$2,
	clock7: clock7$2,
	clock730: clock730$2,
	clock8: clock8$2,
	clock830: clock830$2,
	clock9: clock9$2,
	clock930: clock930$2,
	clock10: clock10$2,
	clock1030: clock1030$2,
	clock11: clock11$2,
	clock1130: clock1130$2,
	new_moon: new_moon$2,
	waxing_crescent_moon: waxing_crescent_moon$2,
	first_quarter_moon: first_quarter_moon$2,
	moon: moon,
	waxing_gibbous_moon: waxing_gibbous_moon$2,
	full_moon: full_moon$2,
	waning_gibbous_moon: waning_gibbous_moon$2,
	last_quarter_moon: last_quarter_moon$2,
	waning_crescent_moon: waning_crescent_moon$2,
	crescent_moon: crescent_moon$2,
	new_moon_with_face: new_moon_with_face$2,
	first_quarter_moon_with_face: first_quarter_moon_with_face$2,
	last_quarter_moon_with_face: last_quarter_moon_with_face$2,
	thermometer: thermometer$2,
	sunny: sunny$2,
	full_moon_with_face: full_moon_with_face$2,
	sun_with_face: sun_with_face$2,
	ringed_planet: ringed_planet,
	star: star$3,
	star2: star2$2,
	stars: stars$2,
	milky_way: milky_way$2,
	cloud: cloud$2,
	partly_sunny: partly_sunny$2,
	cloud_with_lightning_and_rain: cloud_with_lightning_and_rain$2,
	sun_behind_small_cloud: sun_behind_small_cloud$2,
	sun_behind_large_cloud: sun_behind_large_cloud$2,
	sun_behind_rain_cloud: sun_behind_rain_cloud$2,
	cloud_with_rain: cloud_with_rain$2,
	cloud_with_snow: cloud_with_snow$2,
	cloud_with_lightning: cloud_with_lightning$2,
	tornado: tornado$2,
	fog: fog$2,
	wind_face: wind_face$2,
	cyclone: cyclone$2,
	rainbow: rainbow$2,
	closed_umbrella: closed_umbrella$2,
	open_umbrella: open_umbrella$2,
	umbrella: umbrella$2,
	parasol_on_ground: parasol_on_ground$2,
	zap: zap$2,
	snowflake: snowflake$2,
	snowman_with_snow: snowman_with_snow$2,
	snowman: snowman$2,
	comet: comet$2,
	fire: fire$2,
	droplet: droplet$2,
	ocean: ocean$2,
	jack_o_lantern: jack_o_lantern$2,
	christmas_tree: christmas_tree$2,
	fireworks: fireworks$2,
	sparkler: sparkler$2,
	firecracker: firecracker$2,
	sparkles: sparkles$2,
	balloon: balloon$2,
	tada: tada$2,
	confetti_ball: confetti_ball$2,
	tanabata_tree: tanabata_tree$2,
	bamboo: bamboo$2,
	dolls: dolls$2,
	flags: flags$2,
	wind_chime: wind_chime$2,
	rice_scene: rice_scene$2,
	red_envelope: red_envelope$2,
	ribbon: ribbon$2,
	gift: gift$2,
	reminder_ribbon: reminder_ribbon$2,
	tickets: tickets$2,
	ticket: ticket$2,
	medal_military: medal_military$2,
	trophy: trophy$2,
	medal_sports: medal_sports$2,
	"1st_place_medal": "🥇",
	"2nd_place_medal": "🥈",
	"3rd_place_medal": "🥉",
	soccer: soccer$2,
	baseball: baseball$2,
	softball: softball$2,
	basketball: basketball$2,
	volleyball: volleyball$2,
	football: football$2,
	rugby_football: rugby_football$2,
	tennis: tennis$2,
	flying_disc: flying_disc$2,
	bowling: bowling$2,
	cricket_game: cricket_game,
	field_hockey: field_hockey$2,
	ice_hockey: ice_hockey$2,
	lacrosse: lacrosse$2,
	ping_pong: ping_pong$2,
	badminton: badminton$2,
	boxing_glove: boxing_glove$2,
	martial_arts_uniform: martial_arts_uniform$2,
	goal_net: goal_net$2,
	golf: golf$2,
	ice_skate: ice_skate$2,
	fishing_pole_and_fish: fishing_pole_and_fish$2,
	diving_mask: diving_mask,
	running_shirt_with_sash: running_shirt_with_sash$2,
	ski: ski$2,
	sled: sled$2,
	curling_stone: curling_stone$2,
	dart: dart$2,
	yo_yo: yo_yo,
	kite: kite,
	"8ball": "🎱",
	crystal_ball: crystal_ball$2,
	magic_wand: magic_wand,
	nazar_amulet: nazar_amulet$2,
	video_game: video_game$2,
	joystick: joystick$2,
	slot_machine: slot_machine$2,
	game_die: game_die$2,
	jigsaw: jigsaw$2,
	teddy_bear: teddy_bear$2,
	pinata: pinata,
	nesting_dolls: nesting_dolls,
	spades: spades$3,
	hearts: hearts$3,
	diamonds: diamonds$2,
	clubs: clubs$3,
	chess_pawn: chess_pawn$2,
	black_joker: black_joker$2,
	mahjong: mahjong$2,
	flower_playing_cards: flower_playing_cards$2,
	performing_arts: performing_arts$2,
	framed_picture: framed_picture$2,
	art: art$2,
	thread: thread$2,
	sewing_needle: sewing_needle,
	yarn: yarn$2,
	knot: knot,
	eyeglasses: eyeglasses$2,
	dark_sunglasses: dark_sunglasses$2,
	goggles: goggles$2,
	lab_coat: lab_coat,
	safety_vest: safety_vest,
	necktie: necktie$2,
	shirt: shirt,
	tshirt: tshirt$2,
	jeans: jeans$2,
	scarf: scarf$2,
	gloves: gloves$2,
	coat: coat$2,
	socks: socks$2,
	dress: dress$2,
	kimono: kimono$2,
	sari: sari,
	one_piece_swimsuit: one_piece_swimsuit,
	swim_brief: swim_brief,
	shorts: shorts,
	bikini: bikini$2,
	womans_clothes: womans_clothes$2,
	purse: purse$2,
	handbag: handbag$2,
	pouch: pouch$2,
	shopping: shopping$2,
	school_satchel: school_satchel$2,
	thong_sandal: thong_sandal,
	mans_shoe: mans_shoe$2,
	shoe: shoe,
	athletic_shoe: athletic_shoe$2,
	hiking_boot: hiking_boot$2,
	flat_shoe: flat_shoe$2,
	high_heel: high_heel$2,
	sandal: sandal$2,
	ballet_shoes: ballet_shoes,
	boot: boot$2,
	crown: crown$2,
	womans_hat: womans_hat$2,
	tophat: tophat$2,
	mortar_board: mortar_board$2,
	billed_cap: billed_cap,
	military_helmet: military_helmet,
	rescue_worker_helmet: rescue_worker_helmet$2,
	prayer_beads: prayer_beads$2,
	lipstick: lipstick$2,
	ring: ring$3,
	gem: gem$2,
	mute: mute$2,
	speaker: speaker$2,
	sound: sound$2,
	loud_sound: loud_sound$2,
	loudspeaker: loudspeaker$2,
	mega: mega$2,
	postal_horn: postal_horn$2,
	bell: bell$2,
	no_bell: no_bell$2,
	musical_score: musical_score$2,
	musical_note: musical_note$2,
	notes: notes$2,
	studio_microphone: studio_microphone$2,
	level_slider: level_slider$2,
	control_knobs: control_knobs$2,
	microphone: microphone$2,
	headphones: headphones$2,
	radio: radio$2,
	saxophone: saxophone$2,
	accordion: accordion,
	guitar: guitar$2,
	musical_keyboard: musical_keyboard$2,
	trumpet: trumpet$2,
	violin: violin$2,
	banjo: banjo,
	drum: drum$2,
	long_drum: long_drum,
	iphone: iphone$2,
	calling: calling$2,
	phone: phone$3,
	telephone: telephone,
	telephone_receiver: telephone_receiver$2,
	pager: pager$2,
	fax: fax$2,
	battery: battery$2,
	electric_plug: electric_plug$2,
	computer: computer$2,
	desktop_computer: desktop_computer$2,
	printer: printer$2,
	keyboard: keyboard$2,
	computer_mouse: computer_mouse$2,
	trackball: trackball$2,
	minidisc: minidisc$2,
	floppy_disk: floppy_disk$2,
	cd: cd$2,
	dvd: dvd$2,
	abacus: abacus$2,
	movie_camera: movie_camera$2,
	film_strip: film_strip$2,
	film_projector: film_projector$2,
	clapper: clapper$2,
	tv: tv$2,
	camera: camera$2,
	camera_flash: camera_flash$2,
	video_camera: video_camera$2,
	vhs: vhs$2,
	mag: mag$2,
	mag_right: mag_right$2,
	candle: candle$2,
	bulb: bulb$2,
	flashlight: flashlight$2,
	izakaya_lantern: izakaya_lantern$2,
	lantern: lantern,
	diya_lamp: diya_lamp,
	notebook_with_decorative_cover: notebook_with_decorative_cover$2,
	closed_book: closed_book$2,
	book: book,
	open_book: open_book$2,
	green_book: green_book$2,
	blue_book: blue_book$2,
	orange_book: orange_book$2,
	books: books$2,
	notebook: notebook$2,
	ledger: ledger$2,
	page_with_curl: page_with_curl$2,
	scroll: scroll$2,
	page_facing_up: page_facing_up$2,
	newspaper: newspaper$2,
	newspaper_roll: newspaper_roll$2,
	bookmark_tabs: bookmark_tabs$2,
	bookmark: bookmark$2,
	label: label$2,
	moneybag: moneybag$2,
	coin: coin,
	yen: yen$3,
	dollar: dollar$3,
	euro: euro$3,
	pound: pound$3,
	money_with_wings: money_with_wings$2,
	credit_card: credit_card$2,
	receipt: receipt$2,
	chart: chart$2,
	envelope: envelope,
	email: email$2,
	"e-mail": "📧",
	incoming_envelope: incoming_envelope$2,
	envelope_with_arrow: envelope_with_arrow$2,
	outbox_tray: outbox_tray$2,
	inbox_tray: inbox_tray$2,
	"package": "📦",
	mailbox: mailbox$2,
	mailbox_closed: mailbox_closed$2,
	mailbox_with_mail: mailbox_with_mail$2,
	mailbox_with_no_mail: mailbox_with_no_mail$2,
	postbox: postbox$2,
	ballot_box: ballot_box$2,
	pencil2: pencil2$2,
	black_nib: black_nib$2,
	fountain_pen: fountain_pen$2,
	pen: pen$2,
	paintbrush: paintbrush$2,
	crayon: crayon$2,
	memo: memo$2,
	pencil: pencil,
	briefcase: briefcase$2,
	file_folder: file_folder$2,
	open_file_folder: open_file_folder$2,
	card_index_dividers: card_index_dividers$2,
	date: date$2,
	calendar: calendar$2,
	spiral_notepad: spiral_notepad$2,
	spiral_calendar: spiral_calendar$2,
	card_index: card_index$2,
	chart_with_upwards_trend: chart_with_upwards_trend$2,
	chart_with_downwards_trend: chart_with_downwards_trend$2,
	bar_chart: bar_chart$2,
	clipboard: clipboard$3,
	pushpin: pushpin$2,
	round_pushpin: round_pushpin$2,
	paperclip: paperclip$2,
	paperclips: paperclips$2,
	straight_ruler: straight_ruler$2,
	triangular_ruler: triangular_ruler$2,
	scissors: scissors$2,
	card_file_box: card_file_box$2,
	file_cabinet: file_cabinet$2,
	wastebasket: wastebasket$2,
	lock: lock$2,
	unlock: unlock$2,
	lock_with_ink_pen: lock_with_ink_pen$2,
	closed_lock_with_key: closed_lock_with_key$2,
	key: key$2,
	old_key: old_key$2,
	hammer: hammer$2,
	axe: axe,
	pick: pick$2,
	hammer_and_pick: hammer_and_pick$2,
	hammer_and_wrench: hammer_and_wrench$2,
	dagger: dagger$3,
	crossed_swords: crossed_swords$2,
	gun: gun$2,
	boomerang: boomerang,
	bow_and_arrow: bow_and_arrow$2,
	shield: shield$2,
	carpentry_saw: carpentry_saw,
	wrench: wrench$2,
	screwdriver: screwdriver,
	nut_and_bolt: nut_and_bolt$2,
	gear: gear$2,
	clamp: clamp$2,
	balance_scale: balance_scale$2,
	probing_cane: probing_cane,
	link: link$4,
	chains: chains$2,
	hook: hook,
	toolbox: toolbox$2,
	magnet: magnet$2,
	ladder: ladder,
	alembic: alembic$2,
	test_tube: test_tube$2,
	petri_dish: petri_dish$2,
	dna: dna$2,
	microscope: microscope$2,
	telescope: telescope$2,
	satellite: satellite$2,
	syringe: syringe$2,
	drop_of_blood: drop_of_blood,
	pill: pill$2,
	adhesive_bandage: adhesive_bandage,
	stethoscope: stethoscope,
	door: door$2,
	elevator: elevator,
	mirror: mirror,
	window: window$1,
	bed: bed$2,
	couch_and_lamp: couch_and_lamp$2,
	chair: chair,
	toilet: toilet$2,
	plunger: plunger,
	shower: shower$2,
	bathtub: bathtub$2,
	mouse_trap: mouse_trap,
	razor: razor,
	lotion_bottle: lotion_bottle$2,
	safety_pin: safety_pin$2,
	broom: broom$2,
	basket: basket$2,
	roll_of_paper: roll_of_paper,
	bucket: bucket,
	soap: soap$2,
	toothbrush: toothbrush,
	sponge: sponge$2,
	fire_extinguisher: fire_extinguisher$2,
	shopping_cart: shopping_cart$2,
	smoking: smoking$2,
	coffin: coffin$2,
	headstone: headstone,
	funeral_urn: funeral_urn$2,
	moyai: moyai$2,
	placard: placard,
	atm: atm$2,
	put_litter_in_its_place: put_litter_in_its_place$2,
	potable_water: potable_water$2,
	wheelchair: wheelchair$2,
	mens: mens$2,
	womens: womens$2,
	restroom: restroom$2,
	baby_symbol: baby_symbol$2,
	wc: wc$2,
	passport_control: passport_control$2,
	customs: customs$2,
	baggage_claim: baggage_claim$2,
	left_luggage: left_luggage$2,
	warning: warning$2,
	children_crossing: children_crossing$2,
	no_entry: no_entry$2,
	no_entry_sign: no_entry_sign$2,
	no_bicycles: no_bicycles$2,
	no_smoking: no_smoking$2,
	do_not_litter: do_not_litter$2,
	"non-potable_water": "🚱",
	no_pedestrians: no_pedestrians$2,
	no_mobile_phones: no_mobile_phones$2,
	underage: underage$2,
	radioactive: radioactive$2,
	biohazard: biohazard$2,
	arrow_up: arrow_up$2,
	arrow_upper_right: arrow_upper_right$2,
	arrow_right: arrow_right$2,
	arrow_lower_right: arrow_lower_right$2,
	arrow_down: arrow_down$2,
	arrow_lower_left: arrow_lower_left$2,
	arrow_left: arrow_left$2,
	arrow_upper_left: arrow_upper_left$2,
	arrow_up_down: arrow_up_down$2,
	left_right_arrow: left_right_arrow$2,
	leftwards_arrow_with_hook: leftwards_arrow_with_hook$2,
	arrow_right_hook: arrow_right_hook$2,
	arrow_heading_up: arrow_heading_up$2,
	arrow_heading_down: arrow_heading_down$2,
	arrows_clockwise: arrows_clockwise$2,
	arrows_counterclockwise: arrows_counterclockwise$2,
	back: back$2,
	end: end$2,
	on: on$2,
	soon: soon$2,
	top: top$3,
	place_of_worship: place_of_worship$2,
	atom_symbol: atom_symbol$2,
	om: om$2,
	star_of_david: star_of_david$2,
	wheel_of_dharma: wheel_of_dharma$2,
	yin_yang: yin_yang$2,
	latin_cross: latin_cross$2,
	orthodox_cross: orthodox_cross$2,
	star_and_crescent: star_and_crescent$2,
	peace_symbol: peace_symbol$2,
	menorah: menorah$2,
	six_pointed_star: six_pointed_star$2,
	aries: aries$2,
	taurus: taurus$2,
	gemini: gemini$2,
	cancer: cancer$2,
	leo: leo$2,
	virgo: virgo$2,
	libra: libra$2,
	scorpius: scorpius$2,
	sagittarius: sagittarius$2,
	capricorn: capricorn$2,
	aquarius: aquarius$2,
	pisces: pisces$2,
	ophiuchus: ophiuchus$2,
	twisted_rightwards_arrows: twisted_rightwards_arrows$2,
	repeat: repeat$2,
	repeat_one: repeat_one$2,
	arrow_forward: arrow_forward$2,
	fast_forward: fast_forward$2,
	next_track_button: next_track_button$2,
	play_or_pause_button: play_or_pause_button$2,
	arrow_backward: arrow_backward$2,
	rewind: rewind$2,
	previous_track_button: previous_track_button$2,
	arrow_up_small: arrow_up_small$2,
	arrow_double_up: arrow_double_up$2,
	arrow_down_small: arrow_down_small$2,
	arrow_double_down: arrow_double_down$2,
	pause_button: pause_button$2,
	stop_button: stop_button$2,
	record_button: record_button$2,
	eject_button: eject_button$2,
	cinema: cinema$2,
	low_brightness: low_brightness$2,
	high_brightness: high_brightness$2,
	signal_strength: signal_strength$2,
	vibration_mode: vibration_mode$2,
	mobile_phone_off: mobile_phone_off$2,
	female_sign: female_sign,
	male_sign: male_sign,
	transgender_symbol: transgender_symbol,
	heavy_multiplication_x: heavy_multiplication_x$2,
	heavy_plus_sign: heavy_plus_sign$2,
	heavy_minus_sign: heavy_minus_sign$2,
	heavy_division_sign: heavy_division_sign$2,
	infinity: infinity$2,
	bangbang: bangbang$2,
	interrobang: interrobang$2,
	question: question$2,
	grey_question: grey_question$2,
	grey_exclamation: grey_exclamation$2,
	exclamation: exclamation$2,
	heavy_exclamation_mark: heavy_exclamation_mark,
	wavy_dash: wavy_dash$2,
	currency_exchange: currency_exchange$2,
	heavy_dollar_sign: heavy_dollar_sign$2,
	medical_symbol: medical_symbol,
	recycle: recycle$2,
	fleur_de_lis: fleur_de_lis$2,
	trident: trident$2,
	name_badge: name_badge$2,
	beginner: beginner$2,
	o: o$3,
	white_check_mark: white_check_mark$2,
	ballot_box_with_check: ballot_box_with_check$2,
	heavy_check_mark: heavy_check_mark$2,
	x: x$2,
	negative_squared_cross_mark: negative_squared_cross_mark$2,
	curly_loop: curly_loop$2,
	loop: loop$2,
	part_alternation_mark: part_alternation_mark$2,
	eight_spoked_asterisk: eight_spoked_asterisk$2,
	eight_pointed_black_star: eight_pointed_black_star$2,
	sparkle: sparkle$2,
	copyright: copyright$2,
	registered: registered$2,
	tm: tm$2,
	hash: hash$2,
	asterisk: asterisk$2,
	zero: zero$3,
	one: one$2,
	two: two$2,
	three: three$2,
	four: four$2,
	five: five$2,
	six: six$2,
	seven: seven$2,
	eight: eight$2,
	nine: nine$2,
	keycap_ten: keycap_ten$2,
	capital_abcd: capital_abcd$2,
	abcd: abcd$2,
	symbols: symbols$2,
	abc: abc$2,
	a: a$3,
	ab: ab$2,
	b: b$2,
	cl: cl$2,
	cool: cool$2,
	free: free$2,
	information_source: information_source$2,
	id: id$2,
	m: m$2,
	"new": "🆕",
	ng: ng$2,
	o2: o2$2,
	ok: ok$2,
	parking: parking$2,
	sos: sos$2,
	up: up$2,
	vs: vs$2,
	koko: koko$2,
	sa: sa$2,
	ideograph_advantage: ideograph_advantage$2,
	accept: accept$2,
	congratulations: congratulations$2,
	secret: secret$2,
	u6e80: u6e80$2,
	red_circle: red_circle$2,
	orange_circle: orange_circle,
	yellow_circle: yellow_circle,
	green_circle: green_circle,
	large_blue_circle: large_blue_circle$2,
	purple_circle: purple_circle,
	brown_circle: brown_circle,
	black_circle: black_circle$2,
	white_circle: white_circle$2,
	red_square: red_square,
	orange_square: orange_square,
	yellow_square: yellow_square,
	green_square: green_square,
	blue_square: blue_square,
	purple_square: purple_square,
	brown_square: brown_square,
	black_large_square: black_large_square$2,
	white_large_square: white_large_square$2,
	black_medium_square: black_medium_square$2,
	white_medium_square: white_medium_square$2,
	black_medium_small_square: black_medium_small_square$2,
	white_medium_small_square: white_medium_small_square$2,
	black_small_square: black_small_square$2,
	white_small_square: white_small_square$2,
	large_orange_diamond: large_orange_diamond$2,
	large_blue_diamond: large_blue_diamond$2,
	small_orange_diamond: small_orange_diamond$2,
	small_blue_diamond: small_blue_diamond$2,
	small_red_triangle: small_red_triangle$2,
	small_red_triangle_down: small_red_triangle_down$2,
	diamond_shape_with_a_dot_inside: diamond_shape_with_a_dot_inside$2,
	radio_button: radio_button$2,
	white_square_button: white_square_button$2,
	black_square_button: black_square_button$2,
	checkered_flag: checkered_flag$2,
	triangular_flag_on_post: triangular_flag_on_post$2,
	crossed_flags: crossed_flags$2,
	black_flag: black_flag$2,
	white_flag: white_flag$2,
	rainbow_flag: rainbow_flag$2,
	transgender_flag: transgender_flag,
	pirate_flag: pirate_flag$2,
	ascension_island: ascension_island,
	andorra: andorra$2,
	united_arab_emirates: united_arab_emirates$2,
	afghanistan: afghanistan$2,
	antigua_barbuda: antigua_barbuda$2,
	anguilla: anguilla$2,
	albania: albania$2,
	armenia: armenia$2,
	angola: angola$2,
	antarctica: antarctica$2,
	argentina: argentina$2,
	american_samoa: american_samoa$2,
	austria: austria$2,
	australia: australia$2,
	aruba: aruba$2,
	aland_islands: aland_islands$2,
	azerbaijan: azerbaijan$2,
	bosnia_herzegovina: bosnia_herzegovina$2,
	barbados: barbados$2,
	bangladesh: bangladesh$2,
	belgium: belgium$2,
	burkina_faso: burkina_faso$2,
	bulgaria: bulgaria$2,
	bahrain: bahrain$2,
	burundi: burundi$2,
	benin: benin$2,
	st_barthelemy: st_barthelemy$2,
	bermuda: bermuda$2,
	brunei: brunei$2,
	bolivia: bolivia$2,
	caribbean_netherlands: caribbean_netherlands$2,
	brazil: brazil$2,
	bahamas: bahamas$2,
	bhutan: bhutan$2,
	bouvet_island: bouvet_island,
	botswana: botswana$2,
	belarus: belarus$2,
	belize: belize$2,
	canada: canada$2,
	cocos_islands: cocos_islands$2,
	congo_kinshasa: congo_kinshasa$2,
	central_african_republic: central_african_republic$2,
	congo_brazzaville: congo_brazzaville$2,
	switzerland: switzerland$2,
	cote_divoire: cote_divoire$2,
	cook_islands: cook_islands$2,
	chile: chile$2,
	cameroon: cameroon$2,
	cn: cn$2,
	colombia: colombia$2,
	clipperton_island: clipperton_island,
	costa_rica: costa_rica$2,
	cuba: cuba$2,
	cape_verde: cape_verde$2,
	curacao: curacao$2,
	christmas_island: christmas_island$2,
	cyprus: cyprus$2,
	czech_republic: czech_republic$2,
	de: de$2,
	diego_garcia: diego_garcia,
	djibouti: djibouti$2,
	denmark: denmark$2,
	dominica: dominica$2,
	dominican_republic: dominican_republic$2,
	algeria: algeria$2,
	ceuta_melilla: ceuta_melilla,
	ecuador: ecuador$2,
	estonia: estonia$2,
	egypt: egypt$2,
	western_sahara: western_sahara$2,
	eritrea: eritrea$2,
	es: es$2,
	ethiopia: ethiopia$2,
	eu: eu$2,
	european_union: european_union,
	finland: finland$2,
	fiji: fiji$2,
	falkland_islands: falkland_islands$2,
	micronesia: micronesia$2,
	faroe_islands: faroe_islands$2,
	fr: fr$2,
	gabon: gabon$2,
	gb: gb,
	uk: uk$2,
	grenada: grenada$2,
	georgia: georgia$2,
	french_guiana: french_guiana$2,
	guernsey: guernsey$2,
	ghana: ghana$2,
	gibraltar: gibraltar$2,
	greenland: greenland$2,
	gambia: gambia$2,
	guinea: guinea$2,
	guadeloupe: guadeloupe$2,
	equatorial_guinea: equatorial_guinea$2,
	greece: greece$2,
	south_georgia_south_sandwich_islands: south_georgia_south_sandwich_islands$2,
	guatemala: guatemala$2,
	guam: guam$2,
	guinea_bissau: guinea_bissau$2,
	guyana: guyana$2,
	hong_kong: hong_kong$2,
	heard_mcdonald_islands: heard_mcdonald_islands,
	honduras: honduras$2,
	croatia: croatia$2,
	haiti: haiti$2,
	hungary: hungary$2,
	canary_islands: canary_islands$2,
	indonesia: indonesia$2,
	ireland: ireland$2,
	israel: israel$2,
	isle_of_man: isle_of_man$2,
	india: india$2,
	british_indian_ocean_territory: british_indian_ocean_territory$2,
	iraq: iraq$2,
	iran: iran$2,
	iceland: iceland$2,
	it: it$3,
	jersey: jersey$2,
	jamaica: jamaica$2,
	jordan: jordan$2,
	jp: jp$2,
	kenya: kenya$2,
	kyrgyzstan: kyrgyzstan$2,
	cambodia: cambodia$2,
	kiribati: kiribati$2,
	comoros: comoros$2,
	st_kitts_nevis: st_kitts_nevis$2,
	north_korea: north_korea$2,
	kr: kr$2,
	kuwait: kuwait$2,
	cayman_islands: cayman_islands$2,
	kazakhstan: kazakhstan$2,
	laos: laos$2,
	lebanon: lebanon$2,
	st_lucia: st_lucia$2,
	liechtenstein: liechtenstein$2,
	sri_lanka: sri_lanka$2,
	liberia: liberia$2,
	lesotho: lesotho$2,
	lithuania: lithuania$2,
	luxembourg: luxembourg$2,
	latvia: latvia$2,
	libya: libya$2,
	morocco: morocco$2,
	monaco: monaco$2,
	moldova: moldova$2,
	montenegro: montenegro$2,
	st_martin: st_martin,
	madagascar: madagascar$2,
	marshall_islands: marshall_islands$2,
	macedonia: macedonia$2,
	mali: mali$2,
	myanmar: myanmar$2,
	mongolia: mongolia$2,
	macau: macau$2,
	northern_mariana_islands: northern_mariana_islands$2,
	martinique: martinique$2,
	mauritania: mauritania$2,
	montserrat: montserrat$2,
	malta: malta$2,
	mauritius: mauritius$2,
	maldives: maldives$2,
	malawi: malawi$2,
	mexico: mexico$2,
	malaysia: malaysia$2,
	mozambique: mozambique$2,
	namibia: namibia$2,
	new_caledonia: new_caledonia$2,
	niger: niger$2,
	norfolk_island: norfolk_island$2,
	nigeria: nigeria$2,
	nicaragua: nicaragua$2,
	netherlands: netherlands$2,
	norway: norway$2,
	nepal: nepal$2,
	nauru: nauru$2,
	niue: niue$2,
	new_zealand: new_zealand$2,
	oman: oman$2,
	panama: panama$2,
	peru: peru$2,
	french_polynesia: french_polynesia$2,
	papua_new_guinea: papua_new_guinea$2,
	philippines: philippines$2,
	pakistan: pakistan$2,
	poland: poland$2,
	st_pierre_miquelon: st_pierre_miquelon$2,
	pitcairn_islands: pitcairn_islands$2,
	puerto_rico: puerto_rico$2,
	palestinian_territories: palestinian_territories$2,
	portugal: portugal$2,
	palau: palau$2,
	paraguay: paraguay$2,
	qatar: qatar$2,
	reunion: reunion$2,
	romania: romania$2,
	serbia: serbia$2,
	ru: ru$2,
	rwanda: rwanda$2,
	saudi_arabia: saudi_arabia$2,
	solomon_islands: solomon_islands$2,
	seychelles: seychelles$2,
	sudan: sudan$2,
	sweden: sweden$2,
	singapore: singapore$2,
	st_helena: st_helena$2,
	slovenia: slovenia$2,
	svalbard_jan_mayen: svalbard_jan_mayen,
	slovakia: slovakia$2,
	sierra_leone: sierra_leone$2,
	san_marino: san_marino$2,
	senegal: senegal$2,
	somalia: somalia$2,
	suriname: suriname$2,
	south_sudan: south_sudan$2,
	sao_tome_principe: sao_tome_principe$2,
	el_salvador: el_salvador$2,
	sint_maarten: sint_maarten$2,
	syria: syria$2,
	swaziland: swaziland$2,
	tristan_da_cunha: tristan_da_cunha,
	turks_caicos_islands: turks_caicos_islands$2,
	chad: chad$2,
	french_southern_territories: french_southern_territories$2,
	togo: togo$2,
	thailand: thailand$2,
	tajikistan: tajikistan$2,
	tokelau: tokelau$2,
	timor_leste: timor_leste$2,
	turkmenistan: turkmenistan$2,
	tunisia: tunisia$2,
	tonga: tonga$2,
	tr: tr$2,
	trinidad_tobago: trinidad_tobago$2,
	tuvalu: tuvalu$2,
	taiwan: taiwan$2,
	tanzania: tanzania$2,
	ukraine: ukraine$2,
	uganda: uganda$2,
	us_outlying_islands: us_outlying_islands,
	united_nations: united_nations$2,
	us: us$2,
	uruguay: uruguay$2,
	uzbekistan: uzbekistan$2,
	vatican_city: vatican_city$2,
	st_vincent_grenadines: st_vincent_grenadines$2,
	venezuela: venezuela$2,
	british_virgin_islands: british_virgin_islands$2,
	us_virgin_islands: us_virgin_islands$2,
	vietnam: vietnam$2,
	vanuatu: vanuatu$2,
	wallis_futuna: wallis_futuna$2,
	samoa: samoa$2,
	kosovo: kosovo$2,
	yemen: yemen$2,
	mayotte: mayotte$2,
	south_africa: south_africa$2,
	zambia: zambia$2,
	zimbabwe: zimbabwe$2,
	england: england$2,
	scotland: scotland$2,
	wales: wales$2
};var shortcuts$1 = {
  angry:            [ '>:(', '>:-(' ],
  blush:            [ ':")', ':-")' ],
  broken_heart:     [ '</3', '<\\3' ],
  // :\ and :-\ not used because of conflict with markdown escaping
  confused:         [ ':/', ':-/' ], // twemoji shows question
  cry:              [ ":'(", ":'-(", ':,(', ':,-(' ],
  frowning:         [ ':(', ':-(' ],
  heart:            [ '<3' ],
  imp:              [ ']:(', ']:-(' ],
  innocent:         [ 'o:)', 'O:)', 'o:-)', 'O:-)', '0:)', '0:-)' ],
  joy:              [ ":')", ":'-)", ':,)', ':,-)', ":'D", ":'-D", ':,D', ':,-D' ],
  kissing:          [ ':*', ':-*' ],
  laughing:         [ 'x-)', 'X-)' ],
  neutral_face:     [ ':|', ':-|' ],
  open_mouth:       [ ':o', ':-o', ':O', ':-O' ],
  rage:             [ ':@', ':-@' ],
  smile:            [ ':D', ':-D' ],
  smiley:           [ ':)', ':-)' ],
  smiling_imp:      [ ']:)', ']:-)' ],
  sob:              [ ":,'(", ":,'-(", ';(', ';-(' ],
  stuck_out_tongue: [ ':P', ':-P' ],
  sunglasses:       [ '8-)', 'B-)' ],
  sweat:            [ ',:(', ',:-(' ],
  sweat_smile:      [ ',:)', ',:-)' ],
  unamused:         [ ':s', ':-S', ':z', ':-Z', ':$', ':-$' ],
  wink:             [ ';)', ';-)' ]
};

var emoji_shortcuts = /*@__PURE__*/getDefaultExportFromCjs(shortcuts$1);var render = function emoji_html(tokens, idx /*, options, env */) {
  return tokens[idx].content;
};var replace = function create_rule(md, emojies, shortcuts, scanRE, replaceRE) {
  var arrayReplaceAt = md.utils.arrayReplaceAt,
      ucm = md.utils.lib.ucmicro,
      ZPCc = new RegExp([ ucm.Z.source, ucm.P.source, ucm.Cc.source ].join('|'));

  function splitTextToken(text, level, Token) {
    var token, last_pos = 0, nodes = [];

    text.replace(replaceRE, function (match, offset, src) {
      var emoji_name;
      // Validate emoji name
      if (shortcuts.hasOwnProperty(match)) {
        // replace shortcut with full name
        emoji_name = shortcuts[match];

        // Don't allow letters before any shortcut (as in no ":/" in http://)
        if (offset > 0 && !ZPCc.test(src[offset - 1])) {
          return;
        }

        // Don't allow letters after any shortcut
        if (offset + match.length < src.length && !ZPCc.test(src[offset + match.length])) {
          return;
        }
      } else {
        emoji_name = match.slice(1, -1);
      }

      // Add new tokens to pending list
      if (offset > last_pos) {
        token         = new Token('text', '', 0);
        token.content = text.slice(last_pos, offset);
        nodes.push(token);
      }

      token         = new Token('emoji', '', 0);
      token.markup  = emoji_name;
      token.content = emojies[emoji_name];
      nodes.push(token);

      last_pos = offset + match.length;
    });

    if (last_pos < text.length) {
      token         = new Token('text', '', 0);
      token.content = text.slice(last_pos);
      nodes.push(token);
    }

    return nodes;
  }

  return function emoji_replace(state) {
    var i, j, l, tokens, token,
        blockTokens = state.tokens,
        autolinkLevel = 0;

    for (j = 0, l = blockTokens.length; j < l; j++) {
      if (blockTokens[j].type !== 'inline') { continue; }
      tokens = blockTokens[j].children;

      // We scan from the end, to keep position when new tags added.
      // Use reversed logic in links start/end match
      for (i = tokens.length - 1; i >= 0; i--) {
        token = tokens[i];

        if (token.type === 'link_open' || token.type === 'link_close') {
          if (token.info === 'auto') { autolinkLevel -= token.nesting; }
        }

        if (token.type === 'text' && autolinkLevel === 0 && scanRE.test(token.content)) {
          // replace current node
          blockTokens[j].children = tokens = arrayReplaceAt(
            tokens, i, splitTextToken(token.content, token.level, state.Token)
          );
        }
      }
    }
  };
};function quoteRE$1(str) {
  return str.replace(/[.?*+^$[\]\\(){}|-]/g, '\\$&');
}


var normalize_opts$1 = function normalize_opts(options) {
  var emojies = options.defs,
      shortcuts;

  // Filter emojies by whitelist, if needed
  if (options.enabled.length) {
    emojies = Object.keys(emojies).reduce(function (acc, key) {
      if (options.enabled.indexOf(key) >= 0) {
        acc[key] = emojies[key];
      }
      return acc;
    }, {});
  }

  // Flatten shortcuts to simple object: { alias: emoji_name }
  shortcuts = Object.keys(options.shortcuts).reduce(function (acc, key) {
    // Skip aliases for filtered emojies, to reduce regexp
    if (!emojies[key]) { return acc; }

    if (Array.isArray(options.shortcuts[key])) {
      options.shortcuts[key].forEach(function (alias) {
        acc[alias] = key;
      });
      return acc;
    }

    acc[options.shortcuts[key]] = key;
    return acc;
  }, {});

  var keys = Object.keys(emojies),
      names;

  // If no definitions are given, return empty regex to avoid replacements with 'undefined'.
  if (keys.length === 0) {
    names = '^$';
  } else {
    // Compile regexp
    names = keys
      .map(function (name) { return ':' + name + ':'; })
      .concat(Object.keys(shortcuts))
      .sort()
      .reverse()
      .map(function (name) { return quoteRE$1(name); })
      .join('|');
  }
  var scanRE = RegExp(names);
  var replaceRE = RegExp(names, 'g');

  return {
    defs: emojies,
    shortcuts: shortcuts,
    scanRE: scanRE,
    replaceRE: replaceRE
  };
};var emoji_html        = render;
var emoji_replace     = replace;
var normalize_opts    = normalize_opts$1;


var bare = function emoji_plugin(md, options) {
  var defaults = {
    defs: {},
    shortcuts: {},
    enabled: []
  };

  var opts = normalize_opts(md.utils.assign({}, defaults, options || {}));

  md.renderer.rules.emoji = emoji_html;

  md.core.ruler.after(
    'linkify',
    'emoji',
    emoji_replace(md, opts.defs, opts.shortcuts, opts.scanRE, opts.replaceRE)
  );
};var emojies_defs      = require$$0$3;
var emojies_shortcuts = shortcuts$1;
var bare_emoji_plugin = bare;


var markdownItEmoji = function emoji_plugin(md, options) {
  var defaults = {
    defs: emojies_defs,
    shortcuts: emojies_shortcuts,
    enabled: []
  };

  var opts = md.utils.assign({}, defaults, options || {});

  bare_emoji_plugin(md, opts);
};

var emoji_plugin = /*@__PURE__*/getDefaultExportFromCjs(markdownItEmoji);var grinning$1 = {
	keywords: [
		"face",
		"smile",
		"happy",
		"joy",
		":D",
		"grin"
	],
	char: "😀",
	fitzpatrick_scale: false,
	category: "people"
};
var grimacing$1 = {
	keywords: [
		"face",
		"grimace",
		"teeth"
	],
	char: "😬",
	fitzpatrick_scale: false,
	category: "people"
};
var grin$1 = {
	keywords: [
		"face",
		"happy",
		"smile",
		"joy",
		"kawaii"
	],
	char: "😁",
	fitzpatrick_scale: false,
	category: "people"
};
var joy$1 = {
	keywords: [
		"face",
		"cry",
		"tears",
		"weep",
		"happy",
		"happytears",
		"haha"
	],
	char: "😂",
	fitzpatrick_scale: false,
	category: "people"
};
var rofl$1 = {
	keywords: [
		"face",
		"rolling",
		"floor",
		"laughing",
		"lol",
		"haha"
	],
	char: "🤣",
	fitzpatrick_scale: false,
	category: "people"
};
var partying$1 = {
	keywords: [
		"face",
		"celebration",
		"woohoo"
	],
	char: "🥳",
	fitzpatrick_scale: false,
	category: "people"
};
var smiley$1 = {
	keywords: [
		"face",
		"happy",
		"joy",
		"haha",
		":D",
		":)",
		"smile",
		"funny"
	],
	char: "😃",
	fitzpatrick_scale: false,
	category: "people"
};
var smile$2 = {
	keywords: [
		"face",
		"happy",
		"joy",
		"funny",
		"haha",
		"laugh",
		"like",
		":D",
		":)"
	],
	char: "😄",
	fitzpatrick_scale: false,
	category: "people"
};
var sweat_smile$1 = {
	keywords: [
		"face",
		"hot",
		"happy",
		"laugh",
		"sweat",
		"smile",
		"relief"
	],
	char: "😅",
	fitzpatrick_scale: false,
	category: "people"
};
var laughing$1 = {
	keywords: [
		"happy",
		"joy",
		"lol",
		"satisfied",
		"haha",
		"face",
		"glad",
		"XD",
		"laugh"
	],
	char: "😆",
	fitzpatrick_scale: false,
	category: "people"
};
var innocent$1 = {
	keywords: [
		"face",
		"angel",
		"heaven",
		"halo"
	],
	char: "😇",
	fitzpatrick_scale: false,
	category: "people"
};
var wink$1 = {
	keywords: [
		"face",
		"happy",
		"mischievous",
		"secret",
		";)",
		"smile",
		"eye"
	],
	char: "😉",
	fitzpatrick_scale: false,
	category: "people"
};
var blush$1 = {
	keywords: [
		"face",
		"smile",
		"happy",
		"flushed",
		"crush",
		"embarrassed",
		"shy",
		"joy"
	],
	char: "😊",
	fitzpatrick_scale: false,
	category: "people"
};
var slightly_smiling_face$1 = {
	keywords: [
		"face",
		"smile"
	],
	char: "🙂",
	fitzpatrick_scale: false,
	category: "people"
};
var upside_down_face$1 = {
	keywords: [
		"face",
		"flipped",
		"silly",
		"smile"
	],
	char: "🙃",
	fitzpatrick_scale: false,
	category: "people"
};
var relaxed$1 = {
	keywords: [
		"face",
		"blush",
		"massage",
		"happiness"
	],
	char: "☺️",
	fitzpatrick_scale: false,
	category: "people"
};
var yum$1 = {
	keywords: [
		"happy",
		"joy",
		"tongue",
		"smile",
		"face",
		"silly",
		"yummy",
		"nom",
		"delicious",
		"savouring"
	],
	char: "😋",
	fitzpatrick_scale: false,
	category: "people"
};
var relieved$1 = {
	keywords: [
		"face",
		"relaxed",
		"phew",
		"massage",
		"happiness"
	],
	char: "😌",
	fitzpatrick_scale: false,
	category: "people"
};
var heart_eyes$1 = {
	keywords: [
		"face",
		"love",
		"like",
		"affection",
		"valentines",
		"infatuation",
		"crush",
		"heart"
	],
	char: "😍",
	fitzpatrick_scale: false,
	category: "people"
};
var smiling_face_with_three_hearts$1 = {
	keywords: [
		"face",
		"love",
		"like",
		"affection",
		"valentines",
		"infatuation",
		"crush",
		"hearts",
		"adore"
	],
	char: "🥰",
	fitzpatrick_scale: false,
	category: "people"
};
var kissing_heart$1 = {
	keywords: [
		"face",
		"love",
		"like",
		"affection",
		"valentines",
		"infatuation",
		"kiss"
	],
	char: "😘",
	fitzpatrick_scale: false,
	category: "people"
};
var kissing$1 = {
	keywords: [
		"love",
		"like",
		"face",
		"3",
		"valentines",
		"infatuation",
		"kiss"
	],
	char: "😗",
	fitzpatrick_scale: false,
	category: "people"
};
var kissing_smiling_eyes$1 = {
	keywords: [
		"face",
		"affection",
		"valentines",
		"infatuation",
		"kiss"
	],
	char: "😙",
	fitzpatrick_scale: false,
	category: "people"
};
var kissing_closed_eyes$1 = {
	keywords: [
		"face",
		"love",
		"like",
		"affection",
		"valentines",
		"infatuation",
		"kiss"
	],
	char: "😚",
	fitzpatrick_scale: false,
	category: "people"
};
var stuck_out_tongue_winking_eye$1 = {
	keywords: [
		"face",
		"prank",
		"childish",
		"playful",
		"mischievous",
		"smile",
		"wink",
		"tongue"
	],
	char: "😜",
	fitzpatrick_scale: false,
	category: "people"
};
var zany$1 = {
	keywords: [
		"face",
		"goofy",
		"crazy"
	],
	char: "🤪",
	fitzpatrick_scale: false,
	category: "people"
};
var raised_eyebrow$1 = {
	keywords: [
		"face",
		"distrust",
		"scepticism",
		"disapproval",
		"disbelief",
		"surprise"
	],
	char: "🤨",
	fitzpatrick_scale: false,
	category: "people"
};
var monocle$1 = {
	keywords: [
		"face",
		"stuffy",
		"wealthy"
	],
	char: "🧐",
	fitzpatrick_scale: false,
	category: "people"
};
var stuck_out_tongue_closed_eyes$1 = {
	keywords: [
		"face",
		"prank",
		"playful",
		"mischievous",
		"smile",
		"tongue"
	],
	char: "😝",
	fitzpatrick_scale: false,
	category: "people"
};
var stuck_out_tongue$1 = {
	keywords: [
		"face",
		"prank",
		"childish",
		"playful",
		"mischievous",
		"smile",
		"tongue"
	],
	char: "😛",
	fitzpatrick_scale: false,
	category: "people"
};
var money_mouth_face$1 = {
	keywords: [
		"face",
		"rich",
		"dollar",
		"money"
	],
	char: "🤑",
	fitzpatrick_scale: false,
	category: "people"
};
var nerd_face$1 = {
	keywords: [
		"face",
		"nerdy",
		"geek",
		"dork"
	],
	char: "🤓",
	fitzpatrick_scale: false,
	category: "people"
};
var sunglasses$1 = {
	keywords: [
		"face",
		"cool",
		"smile",
		"summer",
		"beach",
		"sunglass"
	],
	char: "😎",
	fitzpatrick_scale: false,
	category: "people"
};
var star_struck$1 = {
	keywords: [
		"face",
		"smile",
		"starry",
		"eyes",
		"grinning"
	],
	char: "🤩",
	fitzpatrick_scale: false,
	category: "people"
};
var clown_face$1 = {
	keywords: [
		"face"
	],
	char: "🤡",
	fitzpatrick_scale: false,
	category: "people"
};
var cowboy_hat_face$1 = {
	keywords: [
		"face",
		"cowgirl",
		"hat"
	],
	char: "🤠",
	fitzpatrick_scale: false,
	category: "people"
};
var hugs$1 = {
	keywords: [
		"face",
		"smile",
		"hug"
	],
	char: "🤗",
	fitzpatrick_scale: false,
	category: "people"
};
var smirk$1 = {
	keywords: [
		"face",
		"smile",
		"mean",
		"prank",
		"smug",
		"sarcasm"
	],
	char: "😏",
	fitzpatrick_scale: false,
	category: "people"
};
var no_mouth$1 = {
	keywords: [
		"face",
		"hellokitty"
	],
	char: "😶",
	fitzpatrick_scale: false,
	category: "people"
};
var neutral_face$1 = {
	keywords: [
		"indifference",
		"meh",
		":|",
		"neutral"
	],
	char: "😐",
	fitzpatrick_scale: false,
	category: "people"
};
var expressionless$1 = {
	keywords: [
		"face",
		"indifferent",
		"-_-",
		"meh",
		"deadpan"
	],
	char: "😑",
	fitzpatrick_scale: false,
	category: "people"
};
var unamused$1 = {
	keywords: [
		"indifference",
		"bored",
		"straight face",
		"serious",
		"sarcasm",
		"unimpressed",
		"skeptical",
		"dubious",
		"side_eye"
	],
	char: "😒",
	fitzpatrick_scale: false,
	category: "people"
};
var roll_eyes$1 = {
	keywords: [
		"face",
		"eyeroll",
		"frustrated"
	],
	char: "🙄",
	fitzpatrick_scale: false,
	category: "people"
};
var thinking$1 = {
	keywords: [
		"face",
		"hmmm",
		"think",
		"consider"
	],
	char: "🤔",
	fitzpatrick_scale: false,
	category: "people"
};
var lying_face$1 = {
	keywords: [
		"face",
		"lie",
		"pinocchio"
	],
	char: "🤥",
	fitzpatrick_scale: false,
	category: "people"
};
var hand_over_mouth$1 = {
	keywords: [
		"face",
		"whoops",
		"shock",
		"surprise"
	],
	char: "🤭",
	fitzpatrick_scale: false,
	category: "people"
};
var shushing$1 = {
	keywords: [
		"face",
		"quiet",
		"shhh"
	],
	char: "🤫",
	fitzpatrick_scale: false,
	category: "people"
};
var symbols_over_mouth$1 = {
	keywords: [
		"face",
		"swearing",
		"cursing",
		"cussing",
		"profanity",
		"expletive"
	],
	char: "🤬",
	fitzpatrick_scale: false,
	category: "people"
};
var exploding_head$1 = {
	keywords: [
		"face",
		"shocked",
		"mind",
		"blown"
	],
	char: "🤯",
	fitzpatrick_scale: false,
	category: "people"
};
var flushed$1 = {
	keywords: [
		"face",
		"blush",
		"shy",
		"flattered"
	],
	char: "😳",
	fitzpatrick_scale: false,
	category: "people"
};
var disappointed$1 = {
	keywords: [
		"face",
		"sad",
		"upset",
		"depressed",
		":("
	],
	char: "😞",
	fitzpatrick_scale: false,
	category: "people"
};
var worried$1 = {
	keywords: [
		"face",
		"concern",
		"nervous",
		":("
	],
	char: "😟",
	fitzpatrick_scale: false,
	category: "people"
};
var angry$1 = {
	keywords: [
		"mad",
		"face",
		"annoyed",
		"frustrated"
	],
	char: "😠",
	fitzpatrick_scale: false,
	category: "people"
};
var rage$1 = {
	keywords: [
		"angry",
		"mad",
		"hate",
		"despise"
	],
	char: "😡",
	fitzpatrick_scale: false,
	category: "people"
};
var pensive$1 = {
	keywords: [
		"face",
		"sad",
		"depressed",
		"upset"
	],
	char: "😔",
	fitzpatrick_scale: false,
	category: "people"
};
var confused$1 = {
	keywords: [
		"face",
		"indifference",
		"huh",
		"weird",
		"hmmm",
		":/"
	],
	char: "😕",
	fitzpatrick_scale: false,
	category: "people"
};
var slightly_frowning_face$1 = {
	keywords: [
		"face",
		"frowning",
		"disappointed",
		"sad",
		"upset"
	],
	char: "🙁",
	fitzpatrick_scale: false,
	category: "people"
};
var frowning_face$1 = {
	keywords: [
		"face",
		"sad",
		"upset",
		"frown"
	],
	char: "☹",
	fitzpatrick_scale: false,
	category: "people"
};
var persevere$1 = {
	keywords: [
		"face",
		"sick",
		"no",
		"upset",
		"oops"
	],
	char: "😣",
	fitzpatrick_scale: false,
	category: "people"
};
var confounded$1 = {
	keywords: [
		"face",
		"confused",
		"sick",
		"unwell",
		"oops",
		":S"
	],
	char: "😖",
	fitzpatrick_scale: false,
	category: "people"
};
var tired_face$1 = {
	keywords: [
		"sick",
		"whine",
		"upset",
		"frustrated"
	],
	char: "😫",
	fitzpatrick_scale: false,
	category: "people"
};
var weary$1 = {
	keywords: [
		"face",
		"tired",
		"sleepy",
		"sad",
		"frustrated",
		"upset"
	],
	char: "😩",
	fitzpatrick_scale: false,
	category: "people"
};
var pleading$1 = {
	keywords: [
		"face",
		"begging",
		"mercy"
	],
	char: "🥺",
	fitzpatrick_scale: false,
	category: "people"
};
var triumph$1 = {
	keywords: [
		"face",
		"gas",
		"phew",
		"proud",
		"pride"
	],
	char: "😤",
	fitzpatrick_scale: false,
	category: "people"
};
var open_mouth$1 = {
	keywords: [
		"face",
		"surprise",
		"impressed",
		"wow",
		"whoa",
		":O"
	],
	char: "😮",
	fitzpatrick_scale: false,
	category: "people"
};
var scream$1 = {
	keywords: [
		"face",
		"munch",
		"scared",
		"omg"
	],
	char: "😱",
	fitzpatrick_scale: false,
	category: "people"
};
var fearful$1 = {
	keywords: [
		"face",
		"scared",
		"terrified",
		"nervous",
		"oops",
		"huh"
	],
	char: "😨",
	fitzpatrick_scale: false,
	category: "people"
};
var cold_sweat$1 = {
	keywords: [
		"face",
		"nervous",
		"sweat"
	],
	char: "😰",
	fitzpatrick_scale: false,
	category: "people"
};
var hushed$1 = {
	keywords: [
		"face",
		"woo",
		"shh"
	],
	char: "😯",
	fitzpatrick_scale: false,
	category: "people"
};
var frowning$1 = {
	keywords: [
		"face",
		"aw",
		"what"
	],
	char: "😦",
	fitzpatrick_scale: false,
	category: "people"
};
var anguished$1 = {
	keywords: [
		"face",
		"stunned",
		"nervous"
	],
	char: "😧",
	fitzpatrick_scale: false,
	category: "people"
};
var cry$1 = {
	keywords: [
		"face",
		"tears",
		"sad",
		"depressed",
		"upset",
		":'("
	],
	char: "😢",
	fitzpatrick_scale: false,
	category: "people"
};
var disappointed_relieved$1 = {
	keywords: [
		"face",
		"phew",
		"sweat",
		"nervous"
	],
	char: "😥",
	fitzpatrick_scale: false,
	category: "people"
};
var drooling_face$1 = {
	keywords: [
		"face"
	],
	char: "🤤",
	fitzpatrick_scale: false,
	category: "people"
};
var sleepy$1 = {
	keywords: [
		"face",
		"tired",
		"rest",
		"nap"
	],
	char: "😪",
	fitzpatrick_scale: false,
	category: "people"
};
var sweat$1 = {
	keywords: [
		"face",
		"hot",
		"sad",
		"tired",
		"exercise"
	],
	char: "😓",
	fitzpatrick_scale: false,
	category: "people"
};
var hot$1 = {
	keywords: [
		"face",
		"feverish",
		"heat",
		"red",
		"sweating"
	],
	char: "🥵",
	fitzpatrick_scale: false,
	category: "people"
};
var cold$1 = {
	keywords: [
		"face",
		"blue",
		"freezing",
		"frozen",
		"frostbite",
		"icicles"
	],
	char: "🥶",
	fitzpatrick_scale: false,
	category: "people"
};
var sob$1 = {
	keywords: [
		"face",
		"cry",
		"tears",
		"sad",
		"upset",
		"depressed"
	],
	char: "😭",
	fitzpatrick_scale: false,
	category: "people"
};
var dizzy_face$1 = {
	keywords: [
		"spent",
		"unconscious",
		"xox",
		"dizzy"
	],
	char: "😵",
	fitzpatrick_scale: false,
	category: "people"
};
var astonished$1 = {
	keywords: [
		"face",
		"xox",
		"surprised",
		"poisoned"
	],
	char: "😲",
	fitzpatrick_scale: false,
	category: "people"
};
var zipper_mouth_face$1 = {
	keywords: [
		"face",
		"sealed",
		"zipper",
		"secret"
	],
	char: "🤐",
	fitzpatrick_scale: false,
	category: "people"
};
var nauseated_face$1 = {
	keywords: [
		"face",
		"vomit",
		"gross",
		"green",
		"sick",
		"throw up",
		"ill"
	],
	char: "🤢",
	fitzpatrick_scale: false,
	category: "people"
};
var sneezing_face$1 = {
	keywords: [
		"face",
		"gesundheit",
		"sneeze",
		"sick",
		"allergy"
	],
	char: "🤧",
	fitzpatrick_scale: false,
	category: "people"
};
var vomiting$1 = {
	keywords: [
		"face",
		"sick"
	],
	char: "🤮",
	fitzpatrick_scale: false,
	category: "people"
};
var mask$1 = {
	keywords: [
		"face",
		"sick",
		"ill",
		"disease"
	],
	char: "😷",
	fitzpatrick_scale: false,
	category: "people"
};
var face_with_thermometer$1 = {
	keywords: [
		"sick",
		"temperature",
		"thermometer",
		"cold",
		"fever"
	],
	char: "🤒",
	fitzpatrick_scale: false,
	category: "people"
};
var face_with_head_bandage$1 = {
	keywords: [
		"injured",
		"clumsy",
		"bandage",
		"hurt"
	],
	char: "🤕",
	fitzpatrick_scale: false,
	category: "people"
};
var woozy$1 = {
	keywords: [
		"face",
		"dizzy",
		"intoxicated",
		"tipsy",
		"wavy"
	],
	char: "🥴",
	fitzpatrick_scale: false,
	category: "people"
};
var sleeping$1 = {
	keywords: [
		"face",
		"tired",
		"sleepy",
		"night",
		"zzz"
	],
	char: "😴",
	fitzpatrick_scale: false,
	category: "people"
};
var zzz$1 = {
	keywords: [
		"sleepy",
		"tired",
		"dream"
	],
	char: "💤",
	fitzpatrick_scale: false,
	category: "people"
};
var poop$1 = {
	keywords: [
		"hankey",
		"shitface",
		"fail",
		"turd",
		"shit"
	],
	char: "💩",
	fitzpatrick_scale: false,
	category: "people"
};
var smiling_imp$1 = {
	keywords: [
		"devil",
		"horns"
	],
	char: "😈",
	fitzpatrick_scale: false,
	category: "people"
};
var imp$1 = {
	keywords: [
		"devil",
		"angry",
		"horns"
	],
	char: "👿",
	fitzpatrick_scale: false,
	category: "people"
};
var japanese_ogre$1 = {
	keywords: [
		"monster",
		"red",
		"mask",
		"halloween",
		"scary",
		"creepy",
		"devil",
		"demon",
		"japanese",
		"ogre"
	],
	char: "👹",
	fitzpatrick_scale: false,
	category: "people"
};
var japanese_goblin$1 = {
	keywords: [
		"red",
		"evil",
		"mask",
		"monster",
		"scary",
		"creepy",
		"japanese",
		"goblin"
	],
	char: "👺",
	fitzpatrick_scale: false,
	category: "people"
};
var skull$1 = {
	keywords: [
		"dead",
		"skeleton",
		"creepy",
		"death"
	],
	char: "💀",
	fitzpatrick_scale: false,
	category: "people"
};
var ghost$1 = {
	keywords: [
		"halloween",
		"spooky",
		"scary"
	],
	char: "👻",
	fitzpatrick_scale: false,
	category: "people"
};
var alien$1 = {
	keywords: [
		"UFO",
		"paul",
		"weird",
		"outer_space"
	],
	char: "👽",
	fitzpatrick_scale: false,
	category: "people"
};
var robot$1 = {
	keywords: [
		"computer",
		"machine",
		"bot"
	],
	char: "🤖",
	fitzpatrick_scale: false,
	category: "people"
};
var smiley_cat$1 = {
	keywords: [
		"animal",
		"cats",
		"happy",
		"smile"
	],
	char: "😺",
	fitzpatrick_scale: false,
	category: "people"
};
var smile_cat$1 = {
	keywords: [
		"animal",
		"cats",
		"smile"
	],
	char: "😸",
	fitzpatrick_scale: false,
	category: "people"
};
var joy_cat$1 = {
	keywords: [
		"animal",
		"cats",
		"haha",
		"happy",
		"tears"
	],
	char: "😹",
	fitzpatrick_scale: false,
	category: "people"
};
var heart_eyes_cat$1 = {
	keywords: [
		"animal",
		"love",
		"like",
		"affection",
		"cats",
		"valentines",
		"heart"
	],
	char: "😻",
	fitzpatrick_scale: false,
	category: "people"
};
var smirk_cat$1 = {
	keywords: [
		"animal",
		"cats",
		"smirk"
	],
	char: "😼",
	fitzpatrick_scale: false,
	category: "people"
};
var kissing_cat$1 = {
	keywords: [
		"animal",
		"cats",
		"kiss"
	],
	char: "😽",
	fitzpatrick_scale: false,
	category: "people"
};
var scream_cat$1 = {
	keywords: [
		"animal",
		"cats",
		"munch",
		"scared",
		"scream"
	],
	char: "🙀",
	fitzpatrick_scale: false,
	category: "people"
};
var crying_cat_face$1 = {
	keywords: [
		"animal",
		"tears",
		"weep",
		"sad",
		"cats",
		"upset",
		"cry"
	],
	char: "😿",
	fitzpatrick_scale: false,
	category: "people"
};
var pouting_cat$1 = {
	keywords: [
		"animal",
		"cats"
	],
	char: "😾",
	fitzpatrick_scale: false,
	category: "people"
};
var palms_up$1 = {
	keywords: [
		"hands",
		"gesture",
		"cupped",
		"prayer"
	],
	char: "🤲",
	fitzpatrick_scale: true,
	category: "people"
};
var raised_hands$1 = {
	keywords: [
		"gesture",
		"hooray",
		"yea",
		"celebration",
		"hands"
	],
	char: "🙌",
	fitzpatrick_scale: true,
	category: "people"
};
var clap$1 = {
	keywords: [
		"hands",
		"praise",
		"applause",
		"congrats",
		"yay"
	],
	char: "👏",
	fitzpatrick_scale: true,
	category: "people"
};
var wave$1 = {
	keywords: [
		"hands",
		"gesture",
		"goodbye",
		"solong",
		"farewell",
		"hello",
		"hi",
		"palm"
	],
	char: "👋",
	fitzpatrick_scale: true,
	category: "people"
};
var call_me_hand$1 = {
	keywords: [
		"hands",
		"gesture"
	],
	char: "🤙",
	fitzpatrick_scale: true,
	category: "people"
};
var facepunch$1 = {
	keywords: [
		"angry",
		"violence",
		"fist",
		"hit",
		"attack",
		"hand"
	],
	char: "👊",
	fitzpatrick_scale: true,
	category: "people"
};
var fist$1 = {
	keywords: [
		"fingers",
		"hand",
		"grasp"
	],
	char: "✊",
	fitzpatrick_scale: true,
	category: "people"
};
var fist_left$1 = {
	keywords: [
		"hand",
		"fistbump"
	],
	char: "🤛",
	fitzpatrick_scale: true,
	category: "people"
};
var fist_right$1 = {
	keywords: [
		"hand",
		"fistbump"
	],
	char: "🤜",
	fitzpatrick_scale: true,
	category: "people"
};
var v$1 = {
	keywords: [
		"fingers",
		"ohyeah",
		"hand",
		"peace",
		"victory",
		"two"
	],
	char: "✌",
	fitzpatrick_scale: true,
	category: "people"
};
var ok_hand$1 = {
	keywords: [
		"fingers",
		"limbs",
		"perfect",
		"ok",
		"okay"
	],
	char: "👌",
	fitzpatrick_scale: true,
	category: "people"
};
var raised_hand$1 = {
	keywords: [
		"fingers",
		"stop",
		"highfive",
		"palm",
		"ban"
	],
	char: "✋",
	fitzpatrick_scale: true,
	category: "people"
};
var raised_back_of_hand$1 = {
	keywords: [
		"fingers",
		"raised",
		"backhand"
	],
	char: "🤚",
	fitzpatrick_scale: true,
	category: "people"
};
var open_hands$1 = {
	keywords: [
		"fingers",
		"butterfly",
		"hands",
		"open"
	],
	char: "👐",
	fitzpatrick_scale: true,
	category: "people"
};
var muscle$1 = {
	keywords: [
		"arm",
		"flex",
		"hand",
		"summer",
		"strong",
		"biceps"
	],
	char: "💪",
	fitzpatrick_scale: true,
	category: "people"
};
var pray$1 = {
	keywords: [
		"please",
		"hope",
		"wish",
		"namaste",
		"highfive"
	],
	char: "🙏",
	fitzpatrick_scale: true,
	category: "people"
};
var foot$1 = {
	keywords: [
		"kick",
		"stomp"
	],
	char: "🦶",
	fitzpatrick_scale: true,
	category: "people"
};
var leg$2 = {
	keywords: [
		"kick",
		"limb"
	],
	char: "🦵",
	fitzpatrick_scale: true,
	category: "people"
};
var handshake$1 = {
	keywords: [
		"agreement",
		"shake"
	],
	char: "🤝",
	fitzpatrick_scale: false,
	category: "people"
};
var point_up$1 = {
	keywords: [
		"hand",
		"fingers",
		"direction",
		"up"
	],
	char: "☝",
	fitzpatrick_scale: true,
	category: "people"
};
var point_up_2$1 = {
	keywords: [
		"fingers",
		"hand",
		"direction",
		"up"
	],
	char: "👆",
	fitzpatrick_scale: true,
	category: "people"
};
var point_down$1 = {
	keywords: [
		"fingers",
		"hand",
		"direction",
		"down"
	],
	char: "👇",
	fitzpatrick_scale: true,
	category: "people"
};
var point_left$1 = {
	keywords: [
		"direction",
		"fingers",
		"hand",
		"left"
	],
	char: "👈",
	fitzpatrick_scale: true,
	category: "people"
};
var point_right$1 = {
	keywords: [
		"fingers",
		"hand",
		"direction",
		"right"
	],
	char: "👉",
	fitzpatrick_scale: true,
	category: "people"
};
var fu$1 = {
	keywords: [
		"hand",
		"fingers",
		"rude",
		"middle",
		"flipping"
	],
	char: "🖕",
	fitzpatrick_scale: true,
	category: "people"
};
var raised_hand_with_fingers_splayed$1 = {
	keywords: [
		"hand",
		"fingers",
		"palm"
	],
	char: "🖐",
	fitzpatrick_scale: true,
	category: "people"
};
var love_you$1 = {
	keywords: [
		"hand",
		"fingers",
		"gesture"
	],
	char: "🤟",
	fitzpatrick_scale: true,
	category: "people"
};
var metal$1 = {
	keywords: [
		"hand",
		"fingers",
		"evil_eye",
		"sign_of_horns",
		"rock_on"
	],
	char: "🤘",
	fitzpatrick_scale: true,
	category: "people"
};
var crossed_fingers$1 = {
	keywords: [
		"good",
		"lucky"
	],
	char: "🤞",
	fitzpatrick_scale: true,
	category: "people"
};
var vulcan_salute$1 = {
	keywords: [
		"hand",
		"fingers",
		"spock",
		"star trek"
	],
	char: "🖖",
	fitzpatrick_scale: true,
	category: "people"
};
var writing_hand$1 = {
	keywords: [
		"lower_left_ballpoint_pen",
		"stationery",
		"write",
		"compose"
	],
	char: "✍",
	fitzpatrick_scale: true,
	category: "people"
};
var selfie$1 = {
	keywords: [
		"camera",
		"phone"
	],
	char: "🤳",
	fitzpatrick_scale: true,
	category: "people"
};
var nail_care$1 = {
	keywords: [
		"beauty",
		"manicure",
		"finger",
		"fashion",
		"nail"
	],
	char: "💅",
	fitzpatrick_scale: true,
	category: "people"
};
var lips$1 = {
	keywords: [
		"mouth",
		"kiss"
	],
	char: "👄",
	fitzpatrick_scale: false,
	category: "people"
};
var tooth$1 = {
	keywords: [
		"teeth",
		"dentist"
	],
	char: "🦷",
	fitzpatrick_scale: false,
	category: "people"
};
var tongue$1 = {
	keywords: [
		"mouth",
		"playful"
	],
	char: "👅",
	fitzpatrick_scale: false,
	category: "people"
};
var ear$1 = {
	keywords: [
		"face",
		"hear",
		"sound",
		"listen"
	],
	char: "👂",
	fitzpatrick_scale: true,
	category: "people"
};
var nose$1 = {
	keywords: [
		"smell",
		"sniff"
	],
	char: "👃",
	fitzpatrick_scale: true,
	category: "people"
};
var eye$1 = {
	keywords: [
		"face",
		"look",
		"see",
		"watch",
		"stare"
	],
	char: "👁",
	fitzpatrick_scale: false,
	category: "people"
};
var eyes$1 = {
	keywords: [
		"look",
		"watch",
		"stalk",
		"peek",
		"see"
	],
	char: "👀",
	fitzpatrick_scale: false,
	category: "people"
};
var brain$1 = {
	keywords: [
		"smart",
		"intelligent"
	],
	char: "🧠",
	fitzpatrick_scale: false,
	category: "people"
};
var bust_in_silhouette$1 = {
	keywords: [
		"user",
		"person",
		"human"
	],
	char: "👤",
	fitzpatrick_scale: false,
	category: "people"
};
var busts_in_silhouette$1 = {
	keywords: [
		"user",
		"person",
		"human",
		"group",
		"team"
	],
	char: "👥",
	fitzpatrick_scale: false,
	category: "people"
};
var speaking_head$1 = {
	keywords: [
		"user",
		"person",
		"human",
		"sing",
		"say",
		"talk"
	],
	char: "🗣",
	fitzpatrick_scale: false,
	category: "people"
};
var baby$1 = {
	keywords: [
		"child",
		"boy",
		"girl",
		"toddler"
	],
	char: "👶",
	fitzpatrick_scale: true,
	category: "people"
};
var child$1 = {
	keywords: [
		"gender-neutral",
		"young"
	],
	char: "🧒",
	fitzpatrick_scale: true,
	category: "people"
};
var boy$1 = {
	keywords: [
		"man",
		"male",
		"guy",
		"teenager"
	],
	char: "👦",
	fitzpatrick_scale: true,
	category: "people"
};
var girl$1 = {
	keywords: [
		"female",
		"woman",
		"teenager"
	],
	char: "👧",
	fitzpatrick_scale: true,
	category: "people"
};
var adult$1 = {
	keywords: [
		"gender-neutral",
		"person"
	],
	char: "🧑",
	fitzpatrick_scale: true,
	category: "people"
};
var man$1 = {
	keywords: [
		"mustache",
		"father",
		"dad",
		"guy",
		"classy",
		"sir",
		"moustache"
	],
	char: "👨",
	fitzpatrick_scale: true,
	category: "people"
};
var woman$1 = {
	keywords: [
		"female",
		"girls",
		"lady"
	],
	char: "👩",
	fitzpatrick_scale: true,
	category: "people"
};
var blonde_woman$1 = {
	keywords: [
		"woman",
		"female",
		"girl",
		"blonde",
		"person"
	],
	char: "👱‍♀️",
	fitzpatrick_scale: true,
	category: "people"
};
var blonde_man$1 = {
	keywords: [
		"man",
		"male",
		"boy",
		"blonde",
		"guy",
		"person"
	],
	char: "👱",
	fitzpatrick_scale: true,
	category: "people"
};
var bearded_person$1 = {
	keywords: [
		"person",
		"bewhiskered"
	],
	char: "🧔",
	fitzpatrick_scale: true,
	category: "people"
};
var older_adult$1 = {
	keywords: [
		"human",
		"elder",
		"senior",
		"gender-neutral"
	],
	char: "🧓",
	fitzpatrick_scale: true,
	category: "people"
};
var older_man$1 = {
	keywords: [
		"human",
		"male",
		"men",
		"old",
		"elder",
		"senior"
	],
	char: "👴",
	fitzpatrick_scale: true,
	category: "people"
};
var older_woman$1 = {
	keywords: [
		"human",
		"female",
		"women",
		"lady",
		"old",
		"elder",
		"senior"
	],
	char: "👵",
	fitzpatrick_scale: true,
	category: "people"
};
var man_with_gua_pi_mao$1 = {
	keywords: [
		"male",
		"boy",
		"chinese"
	],
	char: "👲",
	fitzpatrick_scale: true,
	category: "people"
};
var woman_with_headscarf$1 = {
	keywords: [
		"female",
		"hijab",
		"mantilla",
		"tichel"
	],
	char: "🧕",
	fitzpatrick_scale: true,
	category: "people"
};
var woman_with_turban$1 = {
	keywords: [
		"female",
		"indian",
		"hinduism",
		"arabs",
		"woman"
	],
	char: "👳‍♀️",
	fitzpatrick_scale: true,
	category: "people"
};
var man_with_turban$1 = {
	keywords: [
		"male",
		"indian",
		"hinduism",
		"arabs"
	],
	char: "👳",
	fitzpatrick_scale: true,
	category: "people"
};
var policewoman$1 = {
	keywords: [
		"woman",
		"police",
		"law",
		"legal",
		"enforcement",
		"arrest",
		"911",
		"female"
	],
	char: "👮‍♀️",
	fitzpatrick_scale: true,
	category: "people"
};
var policeman$1 = {
	keywords: [
		"man",
		"police",
		"law",
		"legal",
		"enforcement",
		"arrest",
		"911"
	],
	char: "👮",
	fitzpatrick_scale: true,
	category: "people"
};
var construction_worker_woman$1 = {
	keywords: [
		"female",
		"human",
		"wip",
		"build",
		"construction",
		"worker",
		"labor",
		"woman"
	],
	char: "👷‍♀️",
	fitzpatrick_scale: true,
	category: "people"
};
var construction_worker_man$1 = {
	keywords: [
		"male",
		"human",
		"wip",
		"guy",
		"build",
		"construction",
		"worker",
		"labor"
	],
	char: "👷",
	fitzpatrick_scale: true,
	category: "people"
};
var guardswoman$1 = {
	keywords: [
		"uk",
		"gb",
		"british",
		"female",
		"royal",
		"woman"
	],
	char: "💂‍♀️",
	fitzpatrick_scale: true,
	category: "people"
};
var guardsman$1 = {
	keywords: [
		"uk",
		"gb",
		"british",
		"male",
		"guy",
		"royal"
	],
	char: "💂",
	fitzpatrick_scale: true,
	category: "people"
};
var female_detective$1 = {
	keywords: [
		"human",
		"spy",
		"detective",
		"female",
		"woman"
	],
	char: "🕵️‍♀️",
	fitzpatrick_scale: true,
	category: "people"
};
var male_detective$1 = {
	keywords: [
		"human",
		"spy",
		"detective"
	],
	char: "🕵",
	fitzpatrick_scale: true,
	category: "people"
};
var woman_health_worker$1 = {
	keywords: [
		"doctor",
		"nurse",
		"therapist",
		"healthcare",
		"woman",
		"human"
	],
	char: "👩‍⚕️",
	fitzpatrick_scale: true,
	category: "people"
};
var man_health_worker$1 = {
	keywords: [
		"doctor",
		"nurse",
		"therapist",
		"healthcare",
		"man",
		"human"
	],
	char: "👨‍⚕️",
	fitzpatrick_scale: true,
	category: "people"
};
var woman_farmer$1 = {
	keywords: [
		"rancher",
		"gardener",
		"woman",
		"human"
	],
	char: "👩‍🌾",
	fitzpatrick_scale: true,
	category: "people"
};
var man_farmer$1 = {
	keywords: [
		"rancher",
		"gardener",
		"man",
		"human"
	],
	char: "👨‍🌾",
	fitzpatrick_scale: true,
	category: "people"
};
var woman_cook$1 = {
	keywords: [
		"chef",
		"woman",
		"human"
	],
	char: "👩‍🍳",
	fitzpatrick_scale: true,
	category: "people"
};
var man_cook$1 = {
	keywords: [
		"chef",
		"man",
		"human"
	],
	char: "👨‍🍳",
	fitzpatrick_scale: true,
	category: "people"
};
var woman_student$1 = {
	keywords: [
		"graduate",
		"woman",
		"human"
	],
	char: "👩‍🎓",
	fitzpatrick_scale: true,
	category: "people"
};
var man_student$1 = {
	keywords: [
		"graduate",
		"man",
		"human"
	],
	char: "👨‍🎓",
	fitzpatrick_scale: true,
	category: "people"
};
var woman_singer$1 = {
	keywords: [
		"rockstar",
		"entertainer",
		"woman",
		"human"
	],
	char: "👩‍🎤",
	fitzpatrick_scale: true,
	category: "people"
};
var man_singer$1 = {
	keywords: [
		"rockstar",
		"entertainer",
		"man",
		"human"
	],
	char: "👨‍🎤",
	fitzpatrick_scale: true,
	category: "people"
};
var woman_teacher$1 = {
	keywords: [
		"instructor",
		"professor",
		"woman",
		"human"
	],
	char: "👩‍🏫",
	fitzpatrick_scale: true,
	category: "people"
};
var man_teacher$1 = {
	keywords: [
		"instructor",
		"professor",
		"man",
		"human"
	],
	char: "👨‍🏫",
	fitzpatrick_scale: true,
	category: "people"
};
var woman_factory_worker$1 = {
	keywords: [
		"assembly",
		"industrial",
		"woman",
		"human"
	],
	char: "👩‍🏭",
	fitzpatrick_scale: true,
	category: "people"
};
var man_factory_worker$1 = {
	keywords: [
		"assembly",
		"industrial",
		"man",
		"human"
	],
	char: "👨‍🏭",
	fitzpatrick_scale: true,
	category: "people"
};
var woman_technologist$1 = {
	keywords: [
		"coder",
		"developer",
		"engineer",
		"programmer",
		"software",
		"woman",
		"human",
		"laptop",
		"computer"
	],
	char: "👩‍💻",
	fitzpatrick_scale: true,
	category: "people"
};
var man_technologist$1 = {
	keywords: [
		"coder",
		"developer",
		"engineer",
		"programmer",
		"software",
		"man",
		"human",
		"laptop",
		"computer"
	],
	char: "👨‍💻",
	fitzpatrick_scale: true,
	category: "people"
};
var woman_office_worker$1 = {
	keywords: [
		"business",
		"manager",
		"woman",
		"human"
	],
	char: "👩‍💼",
	fitzpatrick_scale: true,
	category: "people"
};
var man_office_worker$1 = {
	keywords: [
		"business",
		"manager",
		"man",
		"human"
	],
	char: "👨‍💼",
	fitzpatrick_scale: true,
	category: "people"
};
var woman_mechanic$1 = {
	keywords: [
		"plumber",
		"woman",
		"human",
		"wrench"
	],
	char: "👩‍🔧",
	fitzpatrick_scale: true,
	category: "people"
};
var man_mechanic$1 = {
	keywords: [
		"plumber",
		"man",
		"human",
		"wrench"
	],
	char: "👨‍🔧",
	fitzpatrick_scale: true,
	category: "people"
};
var woman_scientist$1 = {
	keywords: [
		"biologist",
		"chemist",
		"engineer",
		"physicist",
		"woman",
		"human"
	],
	char: "👩‍🔬",
	fitzpatrick_scale: true,
	category: "people"
};
var man_scientist$1 = {
	keywords: [
		"biologist",
		"chemist",
		"engineer",
		"physicist",
		"man",
		"human"
	],
	char: "👨‍🔬",
	fitzpatrick_scale: true,
	category: "people"
};
var woman_artist$1 = {
	keywords: [
		"painter",
		"woman",
		"human"
	],
	char: "👩‍🎨",
	fitzpatrick_scale: true,
	category: "people"
};
var man_artist$1 = {
	keywords: [
		"painter",
		"man",
		"human"
	],
	char: "👨‍🎨",
	fitzpatrick_scale: true,
	category: "people"
};
var woman_firefighter$1 = {
	keywords: [
		"fireman",
		"woman",
		"human"
	],
	char: "👩‍🚒",
	fitzpatrick_scale: true,
	category: "people"
};
var man_firefighter$1 = {
	keywords: [
		"fireman",
		"man",
		"human"
	],
	char: "👨‍🚒",
	fitzpatrick_scale: true,
	category: "people"
};
var woman_pilot$1 = {
	keywords: [
		"aviator",
		"plane",
		"woman",
		"human"
	],
	char: "👩‍✈️",
	fitzpatrick_scale: true,
	category: "people"
};
var man_pilot$1 = {
	keywords: [
		"aviator",
		"plane",
		"man",
		"human"
	],
	char: "👨‍✈️",
	fitzpatrick_scale: true,
	category: "people"
};
var woman_astronaut$1 = {
	keywords: [
		"space",
		"rocket",
		"woman",
		"human"
	],
	char: "👩‍🚀",
	fitzpatrick_scale: true,
	category: "people"
};
var man_astronaut$1 = {
	keywords: [
		"space",
		"rocket",
		"man",
		"human"
	],
	char: "👨‍🚀",
	fitzpatrick_scale: true,
	category: "people"
};
var woman_judge$1 = {
	keywords: [
		"justice",
		"court",
		"woman",
		"human"
	],
	char: "👩‍⚖️",
	fitzpatrick_scale: true,
	category: "people"
};
var man_judge$1 = {
	keywords: [
		"justice",
		"court",
		"man",
		"human"
	],
	char: "👨‍⚖️",
	fitzpatrick_scale: true,
	category: "people"
};
var woman_superhero$1 = {
	keywords: [
		"woman",
		"female",
		"good",
		"heroine",
		"superpowers"
	],
	char: "🦸‍♀️",
	fitzpatrick_scale: true,
	category: "people"
};
var man_superhero$1 = {
	keywords: [
		"man",
		"male",
		"good",
		"hero",
		"superpowers"
	],
	char: "🦸‍♂️",
	fitzpatrick_scale: true,
	category: "people"
};
var woman_supervillain$1 = {
	keywords: [
		"woman",
		"female",
		"evil",
		"bad",
		"criminal",
		"heroine",
		"superpowers"
	],
	char: "🦹‍♀️",
	fitzpatrick_scale: true,
	category: "people"
};
var man_supervillain$1 = {
	keywords: [
		"man",
		"male",
		"evil",
		"bad",
		"criminal",
		"hero",
		"superpowers"
	],
	char: "🦹‍♂️",
	fitzpatrick_scale: true,
	category: "people"
};
var mrs_claus$1 = {
	keywords: [
		"woman",
		"female",
		"xmas",
		"mother christmas"
	],
	char: "🤶",
	fitzpatrick_scale: true,
	category: "people"
};
var santa$1 = {
	keywords: [
		"festival",
		"man",
		"male",
		"xmas",
		"father christmas"
	],
	char: "🎅",
	fitzpatrick_scale: true,
	category: "people"
};
var sorceress$1 = {
	keywords: [
		"woman",
		"female",
		"mage",
		"witch"
	],
	char: "🧙‍♀️",
	fitzpatrick_scale: true,
	category: "people"
};
var wizard$1 = {
	keywords: [
		"man",
		"male",
		"mage",
		"sorcerer"
	],
	char: "🧙‍♂️",
	fitzpatrick_scale: true,
	category: "people"
};
var woman_elf$1 = {
	keywords: [
		"woman",
		"female"
	],
	char: "🧝‍♀️",
	fitzpatrick_scale: true,
	category: "people"
};
var man_elf$1 = {
	keywords: [
		"man",
		"male"
	],
	char: "🧝‍♂️",
	fitzpatrick_scale: true,
	category: "people"
};
var woman_vampire$1 = {
	keywords: [
		"woman",
		"female"
	],
	char: "🧛‍♀️",
	fitzpatrick_scale: true,
	category: "people"
};
var man_vampire$1 = {
	keywords: [
		"man",
		"male",
		"dracula"
	],
	char: "🧛‍♂️",
	fitzpatrick_scale: true,
	category: "people"
};
var woman_zombie$1 = {
	keywords: [
		"woman",
		"female",
		"undead",
		"walking dead"
	],
	char: "🧟‍♀️",
	fitzpatrick_scale: false,
	category: "people"
};
var man_zombie$1 = {
	keywords: [
		"man",
		"male",
		"dracula",
		"undead",
		"walking dead"
	],
	char: "🧟‍♂️",
	fitzpatrick_scale: false,
	category: "people"
};
var woman_genie$1 = {
	keywords: [
		"woman",
		"female"
	],
	char: "🧞‍♀️",
	fitzpatrick_scale: false,
	category: "people"
};
var man_genie$1 = {
	keywords: [
		"man",
		"male"
	],
	char: "🧞‍♂️",
	fitzpatrick_scale: false,
	category: "people"
};
var mermaid$1 = {
	keywords: [
		"woman",
		"female",
		"merwoman",
		"ariel"
	],
	char: "🧜‍♀️",
	fitzpatrick_scale: true,
	category: "people"
};
var merman$1 = {
	keywords: [
		"man",
		"male",
		"triton"
	],
	char: "🧜‍♂️",
	fitzpatrick_scale: true,
	category: "people"
};
var woman_fairy$1 = {
	keywords: [
		"woman",
		"female"
	],
	char: "🧚‍♀️",
	fitzpatrick_scale: true,
	category: "people"
};
var man_fairy$1 = {
	keywords: [
		"man",
		"male"
	],
	char: "🧚‍♂️",
	fitzpatrick_scale: true,
	category: "people"
};
var angel$1 = {
	keywords: [
		"heaven",
		"wings",
		"halo"
	],
	char: "👼",
	fitzpatrick_scale: true,
	category: "people"
};
var pregnant_woman$1 = {
	keywords: [
		"baby"
	],
	char: "🤰",
	fitzpatrick_scale: true,
	category: "people"
};
var breastfeeding$1 = {
	keywords: [
		"nursing",
		"baby"
	],
	char: "🤱",
	fitzpatrick_scale: true,
	category: "people"
};
var princess$1 = {
	keywords: [
		"girl",
		"woman",
		"female",
		"blond",
		"crown",
		"royal",
		"queen"
	],
	char: "👸",
	fitzpatrick_scale: true,
	category: "people"
};
var prince$1 = {
	keywords: [
		"boy",
		"man",
		"male",
		"crown",
		"royal",
		"king"
	],
	char: "🤴",
	fitzpatrick_scale: true,
	category: "people"
};
var bride_with_veil$1 = {
	keywords: [
		"couple",
		"marriage",
		"wedding",
		"woman",
		"bride"
	],
	char: "👰",
	fitzpatrick_scale: true,
	category: "people"
};
var man_in_tuxedo$1 = {
	keywords: [
		"couple",
		"marriage",
		"wedding",
		"groom"
	],
	char: "🤵",
	fitzpatrick_scale: true,
	category: "people"
};
var running_woman$1 = {
	keywords: [
		"woman",
		"walking",
		"exercise",
		"race",
		"running",
		"female"
	],
	char: "🏃‍♀️",
	fitzpatrick_scale: true,
	category: "people"
};
var running_man$1 = {
	keywords: [
		"man",
		"walking",
		"exercise",
		"race",
		"running"
	],
	char: "🏃",
	fitzpatrick_scale: true,
	category: "people"
};
var walking_woman$1 = {
	keywords: [
		"human",
		"feet",
		"steps",
		"woman",
		"female"
	],
	char: "🚶‍♀️",
	fitzpatrick_scale: true,
	category: "people"
};
var walking_man$1 = {
	keywords: [
		"human",
		"feet",
		"steps"
	],
	char: "🚶",
	fitzpatrick_scale: true,
	category: "people"
};
var dancer$1 = {
	keywords: [
		"female",
		"girl",
		"woman",
		"fun"
	],
	char: "💃",
	fitzpatrick_scale: true,
	category: "people"
};
var man_dancing$1 = {
	keywords: [
		"male",
		"boy",
		"fun",
		"dancer"
	],
	char: "🕺",
	fitzpatrick_scale: true,
	category: "people"
};
var dancing_women$1 = {
	keywords: [
		"female",
		"bunny",
		"women",
		"girls"
	],
	char: "👯",
	fitzpatrick_scale: false,
	category: "people"
};
var dancing_men$1 = {
	keywords: [
		"male",
		"bunny",
		"men",
		"boys"
	],
	char: "👯‍♂️",
	fitzpatrick_scale: false,
	category: "people"
};
var couple$1 = {
	keywords: [
		"pair",
		"people",
		"human",
		"love",
		"date",
		"dating",
		"like",
		"affection",
		"valentines",
		"marriage"
	],
	char: "👫",
	fitzpatrick_scale: false,
	category: "people"
};
var two_men_holding_hands$1 = {
	keywords: [
		"pair",
		"couple",
		"love",
		"like",
		"bromance",
		"friendship",
		"people",
		"human"
	],
	char: "👬",
	fitzpatrick_scale: false,
	category: "people"
};
var two_women_holding_hands$1 = {
	keywords: [
		"pair",
		"friendship",
		"couple",
		"love",
		"like",
		"female",
		"people",
		"human"
	],
	char: "👭",
	fitzpatrick_scale: false,
	category: "people"
};
var bowing_woman$1 = {
	keywords: [
		"woman",
		"female",
		"girl"
	],
	char: "🙇‍♀️",
	fitzpatrick_scale: true,
	category: "people"
};
var bowing_man$1 = {
	keywords: [
		"man",
		"male",
		"boy"
	],
	char: "🙇",
	fitzpatrick_scale: true,
	category: "people"
};
var man_facepalming$1 = {
	keywords: [
		"man",
		"male",
		"boy",
		"disbelief"
	],
	char: "🤦‍♂️",
	fitzpatrick_scale: true,
	category: "people"
};
var woman_facepalming$1 = {
	keywords: [
		"woman",
		"female",
		"girl",
		"disbelief"
	],
	char: "🤦‍♀️",
	fitzpatrick_scale: true,
	category: "people"
};
var woman_shrugging$1 = {
	keywords: [
		"woman",
		"female",
		"girl",
		"confused",
		"indifferent",
		"doubt"
	],
	char: "🤷",
	fitzpatrick_scale: true,
	category: "people"
};
var man_shrugging$1 = {
	keywords: [
		"man",
		"male",
		"boy",
		"confused",
		"indifferent",
		"doubt"
	],
	char: "🤷‍♂️",
	fitzpatrick_scale: true,
	category: "people"
};
var tipping_hand_woman$1 = {
	keywords: [
		"female",
		"girl",
		"woman",
		"human",
		"information"
	],
	char: "💁",
	fitzpatrick_scale: true,
	category: "people"
};
var tipping_hand_man$1 = {
	keywords: [
		"male",
		"boy",
		"man",
		"human",
		"information"
	],
	char: "💁‍♂️",
	fitzpatrick_scale: true,
	category: "people"
};
var no_good_woman$1 = {
	keywords: [
		"female",
		"girl",
		"woman",
		"nope"
	],
	char: "🙅",
	fitzpatrick_scale: true,
	category: "people"
};
var no_good_man$1 = {
	keywords: [
		"male",
		"boy",
		"man",
		"nope"
	],
	char: "🙅‍♂️",
	fitzpatrick_scale: true,
	category: "people"
};
var ok_woman$1 = {
	keywords: [
		"women",
		"girl",
		"female",
		"pink",
		"human",
		"woman"
	],
	char: "🙆",
	fitzpatrick_scale: true,
	category: "people"
};
var ok_man$1 = {
	keywords: [
		"men",
		"boy",
		"male",
		"blue",
		"human",
		"man"
	],
	char: "🙆‍♂️",
	fitzpatrick_scale: true,
	category: "people"
};
var raising_hand_woman$1 = {
	keywords: [
		"female",
		"girl",
		"woman"
	],
	char: "🙋",
	fitzpatrick_scale: true,
	category: "people"
};
var raising_hand_man$1 = {
	keywords: [
		"male",
		"boy",
		"man"
	],
	char: "🙋‍♂️",
	fitzpatrick_scale: true,
	category: "people"
};
var pouting_woman$1 = {
	keywords: [
		"female",
		"girl",
		"woman"
	],
	char: "🙎",
	fitzpatrick_scale: true,
	category: "people"
};
var pouting_man$1 = {
	keywords: [
		"male",
		"boy",
		"man"
	],
	char: "🙎‍♂️",
	fitzpatrick_scale: true,
	category: "people"
};
var frowning_woman$1 = {
	keywords: [
		"female",
		"girl",
		"woman",
		"sad",
		"depressed",
		"discouraged",
		"unhappy"
	],
	char: "🙍",
	fitzpatrick_scale: true,
	category: "people"
};
var frowning_man$1 = {
	keywords: [
		"male",
		"boy",
		"man",
		"sad",
		"depressed",
		"discouraged",
		"unhappy"
	],
	char: "🙍‍♂️",
	fitzpatrick_scale: true,
	category: "people"
};
var haircut_woman$1 = {
	keywords: [
		"female",
		"girl",
		"woman"
	],
	char: "💇",
	fitzpatrick_scale: true,
	category: "people"
};
var haircut_man$1 = {
	keywords: [
		"male",
		"boy",
		"man"
	],
	char: "💇‍♂️",
	fitzpatrick_scale: true,
	category: "people"
};
var massage_woman$1 = {
	keywords: [
		"female",
		"girl",
		"woman",
		"head"
	],
	char: "💆",
	fitzpatrick_scale: true,
	category: "people"
};
var massage_man$1 = {
	keywords: [
		"male",
		"boy",
		"man",
		"head"
	],
	char: "💆‍♂️",
	fitzpatrick_scale: true,
	category: "people"
};
var woman_in_steamy_room$1 = {
	keywords: [
		"female",
		"woman",
		"spa",
		"steamroom",
		"sauna"
	],
	char: "🧖‍♀️",
	fitzpatrick_scale: true,
	category: "people"
};
var man_in_steamy_room$1 = {
	keywords: [
		"male",
		"man",
		"spa",
		"steamroom",
		"sauna"
	],
	char: "🧖‍♂️",
	fitzpatrick_scale: true,
	category: "people"
};
var couple_with_heart_woman_man$1 = {
	keywords: [
		"pair",
		"love",
		"like",
		"affection",
		"human",
		"dating",
		"valentines",
		"marriage"
	],
	char: "💑",
	fitzpatrick_scale: false,
	category: "people"
};
var couple_with_heart_woman_woman$1 = {
	keywords: [
		"pair",
		"love",
		"like",
		"affection",
		"human",
		"dating",
		"valentines",
		"marriage"
	],
	char: "👩‍❤️‍👩",
	fitzpatrick_scale: false,
	category: "people"
};
var couple_with_heart_man_man$1 = {
	keywords: [
		"pair",
		"love",
		"like",
		"affection",
		"human",
		"dating",
		"valentines",
		"marriage"
	],
	char: "👨‍❤️‍👨",
	fitzpatrick_scale: false,
	category: "people"
};
var couplekiss_man_woman$1 = {
	keywords: [
		"pair",
		"valentines",
		"love",
		"like",
		"dating",
		"marriage"
	],
	char: "💏",
	fitzpatrick_scale: false,
	category: "people"
};
var couplekiss_woman_woman$1 = {
	keywords: [
		"pair",
		"valentines",
		"love",
		"like",
		"dating",
		"marriage"
	],
	char: "👩‍❤️‍💋‍👩",
	fitzpatrick_scale: false,
	category: "people"
};
var couplekiss_man_man$1 = {
	keywords: [
		"pair",
		"valentines",
		"love",
		"like",
		"dating",
		"marriage"
	],
	char: "👨‍❤️‍💋‍👨",
	fitzpatrick_scale: false,
	category: "people"
};
var family_man_woman_boy$1 = {
	keywords: [
		"home",
		"parents",
		"child",
		"mom",
		"dad",
		"father",
		"mother",
		"people",
		"human"
	],
	char: "👪",
	fitzpatrick_scale: false,
	category: "people"
};
var family_man_woman_girl$1 = {
	keywords: [
		"home",
		"parents",
		"people",
		"human",
		"child"
	],
	char: "👨‍👩‍👧",
	fitzpatrick_scale: false,
	category: "people"
};
var family_man_woman_girl_boy$1 = {
	keywords: [
		"home",
		"parents",
		"people",
		"human",
		"children"
	],
	char: "👨‍👩‍👧‍👦",
	fitzpatrick_scale: false,
	category: "people"
};
var family_man_woman_boy_boy$1 = {
	keywords: [
		"home",
		"parents",
		"people",
		"human",
		"children"
	],
	char: "👨‍👩‍👦‍👦",
	fitzpatrick_scale: false,
	category: "people"
};
var family_man_woman_girl_girl$1 = {
	keywords: [
		"home",
		"parents",
		"people",
		"human",
		"children"
	],
	char: "👨‍👩‍👧‍👧",
	fitzpatrick_scale: false,
	category: "people"
};
var family_woman_woman_boy$1 = {
	keywords: [
		"home",
		"parents",
		"people",
		"human",
		"children"
	],
	char: "👩‍👩‍👦",
	fitzpatrick_scale: false,
	category: "people"
};
var family_woman_woman_girl$1 = {
	keywords: [
		"home",
		"parents",
		"people",
		"human",
		"children"
	],
	char: "👩‍👩‍👧",
	fitzpatrick_scale: false,
	category: "people"
};
var family_woman_woman_girl_boy$1 = {
	keywords: [
		"home",
		"parents",
		"people",
		"human",
		"children"
	],
	char: "👩‍👩‍👧‍👦",
	fitzpatrick_scale: false,
	category: "people"
};
var family_woman_woman_boy_boy$1 = {
	keywords: [
		"home",
		"parents",
		"people",
		"human",
		"children"
	],
	char: "👩‍👩‍👦‍👦",
	fitzpatrick_scale: false,
	category: "people"
};
var family_woman_woman_girl_girl$1 = {
	keywords: [
		"home",
		"parents",
		"people",
		"human",
		"children"
	],
	char: "👩‍👩‍👧‍👧",
	fitzpatrick_scale: false,
	category: "people"
};
var family_man_man_boy$1 = {
	keywords: [
		"home",
		"parents",
		"people",
		"human",
		"children"
	],
	char: "👨‍👨‍👦",
	fitzpatrick_scale: false,
	category: "people"
};
var family_man_man_girl$1 = {
	keywords: [
		"home",
		"parents",
		"people",
		"human",
		"children"
	],
	char: "👨‍👨‍👧",
	fitzpatrick_scale: false,
	category: "people"
};
var family_man_man_girl_boy$1 = {
	keywords: [
		"home",
		"parents",
		"people",
		"human",
		"children"
	],
	char: "👨‍👨‍👧‍👦",
	fitzpatrick_scale: false,
	category: "people"
};
var family_man_man_boy_boy$1 = {
	keywords: [
		"home",
		"parents",
		"people",
		"human",
		"children"
	],
	char: "👨‍👨‍👦‍👦",
	fitzpatrick_scale: false,
	category: "people"
};
var family_man_man_girl_girl$1 = {
	keywords: [
		"home",
		"parents",
		"people",
		"human",
		"children"
	],
	char: "👨‍👨‍👧‍👧",
	fitzpatrick_scale: false,
	category: "people"
};
var family_woman_boy$1 = {
	keywords: [
		"home",
		"parent",
		"people",
		"human",
		"child"
	],
	char: "👩‍👦",
	fitzpatrick_scale: false,
	category: "people"
};
var family_woman_girl$1 = {
	keywords: [
		"home",
		"parent",
		"people",
		"human",
		"child"
	],
	char: "👩‍👧",
	fitzpatrick_scale: false,
	category: "people"
};
var family_woman_girl_boy$1 = {
	keywords: [
		"home",
		"parent",
		"people",
		"human",
		"children"
	],
	char: "👩‍👧‍👦",
	fitzpatrick_scale: false,
	category: "people"
};
var family_woman_boy_boy$1 = {
	keywords: [
		"home",
		"parent",
		"people",
		"human",
		"children"
	],
	char: "👩‍👦‍👦",
	fitzpatrick_scale: false,
	category: "people"
};
var family_woman_girl_girl$1 = {
	keywords: [
		"home",
		"parent",
		"people",
		"human",
		"children"
	],
	char: "👩‍👧‍👧",
	fitzpatrick_scale: false,
	category: "people"
};
var family_man_boy$1 = {
	keywords: [
		"home",
		"parent",
		"people",
		"human",
		"child"
	],
	char: "👨‍👦",
	fitzpatrick_scale: false,
	category: "people"
};
var family_man_girl$1 = {
	keywords: [
		"home",
		"parent",
		"people",
		"human",
		"child"
	],
	char: "👨‍👧",
	fitzpatrick_scale: false,
	category: "people"
};
var family_man_girl_boy$1 = {
	keywords: [
		"home",
		"parent",
		"people",
		"human",
		"children"
	],
	char: "👨‍👧‍👦",
	fitzpatrick_scale: false,
	category: "people"
};
var family_man_boy_boy$1 = {
	keywords: [
		"home",
		"parent",
		"people",
		"human",
		"children"
	],
	char: "👨‍👦‍👦",
	fitzpatrick_scale: false,
	category: "people"
};
var family_man_girl_girl$1 = {
	keywords: [
		"home",
		"parent",
		"people",
		"human",
		"children"
	],
	char: "👨‍👧‍👧",
	fitzpatrick_scale: false,
	category: "people"
};
var yarn$1 = {
	keywords: [
		"ball",
		"crochet",
		"knit"
	],
	char: "🧶",
	fitzpatrick_scale: false,
	category: "people"
};
var thread$1 = {
	keywords: [
		"needle",
		"sewing",
		"spool",
		"string"
	],
	char: "🧵",
	fitzpatrick_scale: false,
	category: "people"
};
var coat$1 = {
	keywords: [
		"jacket"
	],
	char: "🧥",
	fitzpatrick_scale: false,
	category: "people"
};
var labcoat$1 = {
	keywords: [
		"doctor",
		"experiment",
		"scientist",
		"chemist"
	],
	char: "🥼",
	fitzpatrick_scale: false,
	category: "people"
};
var womans_clothes$1 = {
	keywords: [
		"fashion",
		"shopping_bags",
		"female"
	],
	char: "👚",
	fitzpatrick_scale: false,
	category: "people"
};
var tshirt$1 = {
	keywords: [
		"fashion",
		"cloth",
		"casual",
		"shirt",
		"tee"
	],
	char: "👕",
	fitzpatrick_scale: false,
	category: "people"
};
var jeans$1 = {
	keywords: [
		"fashion",
		"shopping"
	],
	char: "👖",
	fitzpatrick_scale: false,
	category: "people"
};
var necktie$1 = {
	keywords: [
		"shirt",
		"suitup",
		"formal",
		"fashion",
		"cloth",
		"business"
	],
	char: "👔",
	fitzpatrick_scale: false,
	category: "people"
};
var dress$1 = {
	keywords: [
		"clothes",
		"fashion",
		"shopping"
	],
	char: "👗",
	fitzpatrick_scale: false,
	category: "people"
};
var bikini$1 = {
	keywords: [
		"swimming",
		"female",
		"woman",
		"girl",
		"fashion",
		"beach",
		"summer"
	],
	char: "👙",
	fitzpatrick_scale: false,
	category: "people"
};
var kimono$1 = {
	keywords: [
		"dress",
		"fashion",
		"women",
		"female",
		"japanese"
	],
	char: "👘",
	fitzpatrick_scale: false,
	category: "people"
};
var lipstick$1 = {
	keywords: [
		"female",
		"girl",
		"fashion",
		"woman"
	],
	char: "💄",
	fitzpatrick_scale: false,
	category: "people"
};
var kiss$1 = {
	keywords: [
		"face",
		"lips",
		"love",
		"like",
		"affection",
		"valentines"
	],
	char: "💋",
	fitzpatrick_scale: false,
	category: "people"
};
var footprints$1 = {
	keywords: [
		"feet",
		"tracking",
		"walking",
		"beach"
	],
	char: "👣",
	fitzpatrick_scale: false,
	category: "people"
};
var flat_shoe$1 = {
	keywords: [
		"ballet",
		"slip-on",
		"slipper"
	],
	char: "🥿",
	fitzpatrick_scale: false,
	category: "people"
};
var high_heel$1 = {
	keywords: [
		"fashion",
		"shoes",
		"female",
		"pumps",
		"stiletto"
	],
	char: "👠",
	fitzpatrick_scale: false,
	category: "people"
};
var sandal$1 = {
	keywords: [
		"shoes",
		"fashion",
		"flip flops"
	],
	char: "👡",
	fitzpatrick_scale: false,
	category: "people"
};
var boot$1 = {
	keywords: [
		"shoes",
		"fashion"
	],
	char: "👢",
	fitzpatrick_scale: false,
	category: "people"
};
var mans_shoe$1 = {
	keywords: [
		"fashion",
		"male"
	],
	char: "👞",
	fitzpatrick_scale: false,
	category: "people"
};
var athletic_shoe$1 = {
	keywords: [
		"shoes",
		"sports",
		"sneakers"
	],
	char: "👟",
	fitzpatrick_scale: false,
	category: "people"
};
var hiking_boot$1 = {
	keywords: [
		"backpacking",
		"camping",
		"hiking"
	],
	char: "🥾",
	fitzpatrick_scale: false,
	category: "people"
};
var socks$1 = {
	keywords: [
		"stockings",
		"clothes"
	],
	char: "🧦",
	fitzpatrick_scale: false,
	category: "people"
};
var gloves$1 = {
	keywords: [
		"hands",
		"winter",
		"clothes"
	],
	char: "🧤",
	fitzpatrick_scale: false,
	category: "people"
};
var scarf$1 = {
	keywords: [
		"neck",
		"winter",
		"clothes"
	],
	char: "🧣",
	fitzpatrick_scale: false,
	category: "people"
};
var womans_hat$1 = {
	keywords: [
		"fashion",
		"accessories",
		"female",
		"lady",
		"spring"
	],
	char: "👒",
	fitzpatrick_scale: false,
	category: "people"
};
var tophat$1 = {
	keywords: [
		"magic",
		"gentleman",
		"classy",
		"circus"
	],
	char: "🎩",
	fitzpatrick_scale: false,
	category: "people"
};
var billed_hat$1 = {
	keywords: [
		"cap",
		"baseball"
	],
	char: "🧢",
	fitzpatrick_scale: false,
	category: "people"
};
var rescue_worker_helmet$1 = {
	keywords: [
		"construction",
		"build"
	],
	char: "⛑",
	fitzpatrick_scale: false,
	category: "people"
};
var mortar_board$1 = {
	keywords: [
		"school",
		"college",
		"degree",
		"university",
		"graduation",
		"cap",
		"hat",
		"legal",
		"learn",
		"education"
	],
	char: "🎓",
	fitzpatrick_scale: false,
	category: "people"
};
var crown$1 = {
	keywords: [
		"king",
		"kod",
		"leader",
		"royalty",
		"lord"
	],
	char: "👑",
	fitzpatrick_scale: false,
	category: "people"
};
var school_satchel$1 = {
	keywords: [
		"student",
		"education",
		"bag",
		"backpack"
	],
	char: "🎒",
	fitzpatrick_scale: false,
	category: "people"
};
var luggage$1 = {
	keywords: [
		"packing",
		"travel"
	],
	char: "🧳",
	fitzpatrick_scale: false,
	category: "people"
};
var pouch$1 = {
	keywords: [
		"bag",
		"accessories",
		"shopping"
	],
	char: "👝",
	fitzpatrick_scale: false,
	category: "people"
};
var purse$1 = {
	keywords: [
		"fashion",
		"accessories",
		"money",
		"sales",
		"shopping"
	],
	char: "👛",
	fitzpatrick_scale: false,
	category: "people"
};
var handbag$1 = {
	keywords: [
		"fashion",
		"accessory",
		"accessories",
		"shopping"
	],
	char: "👜",
	fitzpatrick_scale: false,
	category: "people"
};
var briefcase$1 = {
	keywords: [
		"business",
		"documents",
		"work",
		"law",
		"legal",
		"job",
		"career"
	],
	char: "💼",
	fitzpatrick_scale: false,
	category: "people"
};
var eyeglasses$1 = {
	keywords: [
		"fashion",
		"accessories",
		"eyesight",
		"nerdy",
		"dork",
		"geek"
	],
	char: "👓",
	fitzpatrick_scale: false,
	category: "people"
};
var dark_sunglasses$1 = {
	keywords: [
		"face",
		"cool",
		"accessories"
	],
	char: "🕶",
	fitzpatrick_scale: false,
	category: "people"
};
var goggles$1 = {
	keywords: [
		"eyes",
		"protection",
		"safety"
	],
	char: "🥽",
	fitzpatrick_scale: false,
	category: "people"
};
var ring$2 = {
	keywords: [
		"wedding",
		"propose",
		"marriage",
		"valentines",
		"diamond",
		"fashion",
		"jewelry",
		"gem",
		"engagement"
	],
	char: "💍",
	fitzpatrick_scale: false,
	category: "people"
};
var closed_umbrella$1 = {
	keywords: [
		"weather",
		"rain",
		"drizzle"
	],
	char: "🌂",
	fitzpatrick_scale: false,
	category: "people"
};
var dog$1 = {
	keywords: [
		"animal",
		"friend",
		"nature",
		"woof",
		"puppy",
		"pet",
		"faithful"
	],
	char: "🐶",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var cat$1 = {
	keywords: [
		"animal",
		"meow",
		"nature",
		"pet",
		"kitten"
	],
	char: "🐱",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var mouse$1 = {
	keywords: [
		"animal",
		"nature",
		"cheese_wedge",
		"rodent"
	],
	char: "🐭",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var hamster$1 = {
	keywords: [
		"animal",
		"nature"
	],
	char: "🐹",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var rabbit$1 = {
	keywords: [
		"animal",
		"nature",
		"pet",
		"spring",
		"magic",
		"bunny"
	],
	char: "🐰",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var fox_face$1 = {
	keywords: [
		"animal",
		"nature",
		"face"
	],
	char: "🦊",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var bear$1 = {
	keywords: [
		"animal",
		"nature",
		"wild"
	],
	char: "🐻",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var panda_face$1 = {
	keywords: [
		"animal",
		"nature",
		"panda"
	],
	char: "🐼",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var koala$1 = {
	keywords: [
		"animal",
		"nature"
	],
	char: "🐨",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var tiger$1 = {
	keywords: [
		"animal",
		"cat",
		"danger",
		"wild",
		"nature",
		"roar"
	],
	char: "🐯",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var lion$1 = {
	keywords: [
		"animal",
		"nature"
	],
	char: "🦁",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var cow$1 = {
	keywords: [
		"beef",
		"ox",
		"animal",
		"nature",
		"moo",
		"milk"
	],
	char: "🐮",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var pig$1 = {
	keywords: [
		"animal",
		"oink",
		"nature"
	],
	char: "🐷",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var pig_nose$1 = {
	keywords: [
		"animal",
		"oink"
	],
	char: "🐽",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var frog$1 = {
	keywords: [
		"animal",
		"nature",
		"croak",
		"toad"
	],
	char: "🐸",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var squid$1 = {
	keywords: [
		"animal",
		"nature",
		"ocean",
		"sea"
	],
	char: "🦑",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var octopus$1 = {
	keywords: [
		"animal",
		"creature",
		"ocean",
		"sea",
		"nature",
		"beach"
	],
	char: "🐙",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var shrimp$1 = {
	keywords: [
		"animal",
		"ocean",
		"nature",
		"seafood"
	],
	char: "🦐",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var monkey_face$1 = {
	keywords: [
		"animal",
		"nature",
		"circus"
	],
	char: "🐵",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var gorilla$1 = {
	keywords: [
		"animal",
		"nature",
		"circus"
	],
	char: "🦍",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var see_no_evil$1 = {
	keywords: [
		"monkey",
		"animal",
		"nature",
		"haha"
	],
	char: "🙈",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var hear_no_evil$1 = {
	keywords: [
		"animal",
		"monkey",
		"nature"
	],
	char: "🙉",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var speak_no_evil$1 = {
	keywords: [
		"monkey",
		"animal",
		"nature",
		"omg"
	],
	char: "🙊",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var monkey$1 = {
	keywords: [
		"animal",
		"nature",
		"banana",
		"circus"
	],
	char: "🐒",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var chicken$1 = {
	keywords: [
		"animal",
		"cluck",
		"nature",
		"bird"
	],
	char: "🐔",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var penguin$1 = {
	keywords: [
		"animal",
		"nature"
	],
	char: "🐧",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var bird$1 = {
	keywords: [
		"animal",
		"nature",
		"fly",
		"tweet",
		"spring"
	],
	char: "🐦",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var baby_chick$1 = {
	keywords: [
		"animal",
		"chicken",
		"bird"
	],
	char: "🐤",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var hatching_chick$1 = {
	keywords: [
		"animal",
		"chicken",
		"egg",
		"born",
		"baby",
		"bird"
	],
	char: "🐣",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var hatched_chick$1 = {
	keywords: [
		"animal",
		"chicken",
		"baby",
		"bird"
	],
	char: "🐥",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var duck$1 = {
	keywords: [
		"animal",
		"nature",
		"bird",
		"mallard"
	],
	char: "🦆",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var eagle$1 = {
	keywords: [
		"animal",
		"nature",
		"bird"
	],
	char: "🦅",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var owl$1 = {
	keywords: [
		"animal",
		"nature",
		"bird",
		"hoot"
	],
	char: "🦉",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var bat$1 = {
	keywords: [
		"animal",
		"nature",
		"blind",
		"vampire"
	],
	char: "🦇",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var wolf$1 = {
	keywords: [
		"animal",
		"nature",
		"wild"
	],
	char: "🐺",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var boar$1 = {
	keywords: [
		"animal",
		"nature"
	],
	char: "🐗",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var horse$1 = {
	keywords: [
		"animal",
		"brown",
		"nature"
	],
	char: "🐴",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var unicorn$1 = {
	keywords: [
		"animal",
		"nature",
		"mystical"
	],
	char: "🦄",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var honeybee$1 = {
	keywords: [
		"animal",
		"insect",
		"nature",
		"bug",
		"spring",
		"honey"
	],
	char: "🐝",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var bug$1 = {
	keywords: [
		"animal",
		"insect",
		"nature",
		"worm"
	],
	char: "🐛",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var butterfly$1 = {
	keywords: [
		"animal",
		"insect",
		"nature",
		"caterpillar"
	],
	char: "🦋",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var snail$1 = {
	keywords: [
		"slow",
		"animal",
		"shell"
	],
	char: "🐌",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var beetle$1 = {
	keywords: [
		"animal",
		"insect",
		"nature",
		"ladybug"
	],
	char: "🐞",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var ant$1 = {
	keywords: [
		"animal",
		"insect",
		"nature",
		"bug"
	],
	char: "🐜",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var grasshopper$1 = {
	keywords: [
		"animal",
		"cricket",
		"chirp"
	],
	char: "🦗",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var spider$1 = {
	keywords: [
		"animal",
		"arachnid"
	],
	char: "🕷",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var scorpion$1 = {
	keywords: [
		"animal",
		"arachnid"
	],
	char: "🦂",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var crab$1 = {
	keywords: [
		"animal",
		"crustacean"
	],
	char: "🦀",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var snake$1 = {
	keywords: [
		"animal",
		"evil",
		"nature",
		"hiss",
		"python"
	],
	char: "🐍",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var lizard$1 = {
	keywords: [
		"animal",
		"nature",
		"reptile"
	],
	char: "🦎",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var sauropod$1 = {
	keywords: [
		"animal",
		"nature",
		"dinosaur",
		"brachiosaurus",
		"brontosaurus",
		"diplodocus",
		"extinct"
	],
	char: "🦕",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var turtle$1 = {
	keywords: [
		"animal",
		"slow",
		"nature",
		"tortoise"
	],
	char: "🐢",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var tropical_fish$1 = {
	keywords: [
		"animal",
		"swim",
		"ocean",
		"beach",
		"nemo"
	],
	char: "🐠",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var fish$1 = {
	keywords: [
		"animal",
		"food",
		"nature"
	],
	char: "🐟",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var blowfish$1 = {
	keywords: [
		"animal",
		"nature",
		"food",
		"sea",
		"ocean"
	],
	char: "🐡",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var dolphin$1 = {
	keywords: [
		"animal",
		"nature",
		"fish",
		"sea",
		"ocean",
		"flipper",
		"fins",
		"beach"
	],
	char: "🐬",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var shark$1 = {
	keywords: [
		"animal",
		"nature",
		"fish",
		"sea",
		"ocean",
		"jaws",
		"fins",
		"beach"
	],
	char: "🦈",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var whale$1 = {
	keywords: [
		"animal",
		"nature",
		"sea",
		"ocean"
	],
	char: "🐳",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var whale2$1 = {
	keywords: [
		"animal",
		"nature",
		"sea",
		"ocean"
	],
	char: "🐋",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var crocodile$1 = {
	keywords: [
		"animal",
		"nature",
		"reptile",
		"lizard",
		"alligator"
	],
	char: "🐊",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var leopard$1 = {
	keywords: [
		"animal",
		"nature"
	],
	char: "🐆",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var zebra$1 = {
	keywords: [
		"animal",
		"nature",
		"stripes",
		"safari"
	],
	char: "🦓",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var tiger2$1 = {
	keywords: [
		"animal",
		"nature",
		"roar"
	],
	char: "🐅",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var water_buffalo$1 = {
	keywords: [
		"animal",
		"nature",
		"ox",
		"cow"
	],
	char: "🐃",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var ox$1 = {
	keywords: [
		"animal",
		"cow",
		"beef"
	],
	char: "🐂",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var cow2$1 = {
	keywords: [
		"beef",
		"ox",
		"animal",
		"nature",
		"moo",
		"milk"
	],
	char: "🐄",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var deer$1 = {
	keywords: [
		"animal",
		"nature",
		"horns",
		"venison"
	],
	char: "🦌",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var dromedary_camel$1 = {
	keywords: [
		"animal",
		"hot",
		"desert",
		"hump"
	],
	char: "🐪",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var camel$1 = {
	keywords: [
		"animal",
		"nature",
		"hot",
		"desert",
		"hump"
	],
	char: "🐫",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var giraffe$1 = {
	keywords: [
		"animal",
		"nature",
		"spots",
		"safari"
	],
	char: "🦒",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var elephant$1 = {
	keywords: [
		"animal",
		"nature",
		"nose",
		"th",
		"circus"
	],
	char: "🐘",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var rhinoceros$1 = {
	keywords: [
		"animal",
		"nature",
		"horn"
	],
	char: "🦏",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var goat$1 = {
	keywords: [
		"animal",
		"nature"
	],
	char: "🐐",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var ram$1 = {
	keywords: [
		"animal",
		"sheep",
		"nature"
	],
	char: "🐏",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var sheep$1 = {
	keywords: [
		"animal",
		"nature",
		"wool",
		"shipit"
	],
	char: "🐑",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var racehorse$1 = {
	keywords: [
		"animal",
		"gamble",
		"luck"
	],
	char: "🐎",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var pig2$1 = {
	keywords: [
		"animal",
		"nature"
	],
	char: "🐖",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var rat$1 = {
	keywords: [
		"animal",
		"mouse",
		"rodent"
	],
	char: "🐀",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var mouse2$1 = {
	keywords: [
		"animal",
		"nature",
		"rodent"
	],
	char: "🐁",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var rooster$1 = {
	keywords: [
		"animal",
		"nature",
		"chicken"
	],
	char: "🐓",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var turkey$1 = {
	keywords: [
		"animal",
		"bird"
	],
	char: "🦃",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var dove$1 = {
	keywords: [
		"animal",
		"bird"
	],
	char: "🕊",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var dog2$1 = {
	keywords: [
		"animal",
		"nature",
		"friend",
		"doge",
		"pet",
		"faithful"
	],
	char: "🐕",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var poodle$1 = {
	keywords: [
		"dog",
		"animal",
		"101",
		"nature",
		"pet"
	],
	char: "🐩",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var cat2$1 = {
	keywords: [
		"animal",
		"meow",
		"pet",
		"cats"
	],
	char: "🐈",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var rabbit2$1 = {
	keywords: [
		"animal",
		"nature",
		"pet",
		"magic",
		"spring"
	],
	char: "🐇",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var chipmunk$1 = {
	keywords: [
		"animal",
		"nature",
		"rodent",
		"squirrel"
	],
	char: "🐿",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var hedgehog$1 = {
	keywords: [
		"animal",
		"nature",
		"spiny"
	],
	char: "🦔",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var raccoon$1 = {
	keywords: [
		"animal",
		"nature"
	],
	char: "🦝",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var llama$1 = {
	keywords: [
		"animal",
		"nature",
		"alpaca"
	],
	char: "🦙",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var hippopotamus$1 = {
	keywords: [
		"animal",
		"nature"
	],
	char: "🦛",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var kangaroo$1 = {
	keywords: [
		"animal",
		"nature",
		"australia",
		"joey",
		"hop",
		"marsupial"
	],
	char: "🦘",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var badger$1 = {
	keywords: [
		"animal",
		"nature",
		"honey"
	],
	char: "🦡",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var swan$1 = {
	keywords: [
		"animal",
		"nature",
		"bird"
	],
	char: "🦢",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var peacock$1 = {
	keywords: [
		"animal",
		"nature",
		"peahen",
		"bird"
	],
	char: "🦚",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var parrot$1 = {
	keywords: [
		"animal",
		"nature",
		"bird",
		"pirate",
		"talk"
	],
	char: "🦜",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var lobster$1 = {
	keywords: [
		"animal",
		"nature",
		"bisque",
		"claws",
		"seafood"
	],
	char: "🦞",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var mosquito$1 = {
	keywords: [
		"animal",
		"nature",
		"insect",
		"malaria"
	],
	char: "🦟",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var paw_prints$1 = {
	keywords: [
		"animal",
		"tracking",
		"footprints",
		"dog",
		"cat",
		"pet",
		"feet"
	],
	char: "🐾",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var dragon$1 = {
	keywords: [
		"animal",
		"myth",
		"nature",
		"chinese",
		"green"
	],
	char: "🐉",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var dragon_face$1 = {
	keywords: [
		"animal",
		"myth",
		"nature",
		"chinese",
		"green"
	],
	char: "🐲",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var cactus$1 = {
	keywords: [
		"vegetable",
		"plant",
		"nature"
	],
	char: "🌵",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var christmas_tree$1 = {
	keywords: [
		"festival",
		"vacation",
		"december",
		"xmas",
		"celebration"
	],
	char: "🎄",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var evergreen_tree$1 = {
	keywords: [
		"plant",
		"nature"
	],
	char: "🌲",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var deciduous_tree$1 = {
	keywords: [
		"plant",
		"nature"
	],
	char: "🌳",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var palm_tree$1 = {
	keywords: [
		"plant",
		"vegetable",
		"nature",
		"summer",
		"beach",
		"mojito",
		"tropical"
	],
	char: "🌴",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var seedling$1 = {
	keywords: [
		"plant",
		"nature",
		"grass",
		"lawn",
		"spring"
	],
	char: "🌱",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var herb$1 = {
	keywords: [
		"vegetable",
		"plant",
		"medicine",
		"weed",
		"grass",
		"lawn"
	],
	char: "🌿",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var shamrock$1 = {
	keywords: [
		"vegetable",
		"plant",
		"nature",
		"irish",
		"clover"
	],
	char: "☘",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var four_leaf_clover$1 = {
	keywords: [
		"vegetable",
		"plant",
		"nature",
		"lucky",
		"irish"
	],
	char: "🍀",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var bamboo$1 = {
	keywords: [
		"plant",
		"nature",
		"vegetable",
		"panda",
		"pine_decoration"
	],
	char: "🎍",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var tanabata_tree$1 = {
	keywords: [
		"plant",
		"nature",
		"branch",
		"summer"
	],
	char: "🎋",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var leaves$1 = {
	keywords: [
		"nature",
		"plant",
		"tree",
		"vegetable",
		"grass",
		"lawn",
		"spring"
	],
	char: "🍃",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var fallen_leaf$1 = {
	keywords: [
		"nature",
		"plant",
		"vegetable",
		"leaves"
	],
	char: "🍂",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var maple_leaf$1 = {
	keywords: [
		"nature",
		"plant",
		"vegetable",
		"ca",
		"fall"
	],
	char: "🍁",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var ear_of_rice$1 = {
	keywords: [
		"nature",
		"plant"
	],
	char: "🌾",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var hibiscus$1 = {
	keywords: [
		"plant",
		"vegetable",
		"flowers",
		"beach"
	],
	char: "🌺",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var sunflower$1 = {
	keywords: [
		"nature",
		"plant",
		"fall"
	],
	char: "🌻",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var rose$1 = {
	keywords: [
		"flowers",
		"valentines",
		"love",
		"spring"
	],
	char: "🌹",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var wilted_flower$1 = {
	keywords: [
		"plant",
		"nature",
		"flower"
	],
	char: "🥀",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var tulip$1 = {
	keywords: [
		"flowers",
		"plant",
		"nature",
		"summer",
		"spring"
	],
	char: "🌷",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var blossom$1 = {
	keywords: [
		"nature",
		"flowers",
		"yellow"
	],
	char: "🌼",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var cherry_blossom$1 = {
	keywords: [
		"nature",
		"plant",
		"spring",
		"flower"
	],
	char: "🌸",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var bouquet$1 = {
	keywords: [
		"flowers",
		"nature",
		"spring"
	],
	char: "💐",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var mushroom$1 = {
	keywords: [
		"plant",
		"vegetable"
	],
	char: "🍄",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var chestnut$1 = {
	keywords: [
		"food",
		"squirrel"
	],
	char: "🌰",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var jack_o_lantern$1 = {
	keywords: [
		"halloween",
		"light",
		"pumpkin",
		"creepy",
		"fall"
	],
	char: "🎃",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var shell$1 = {
	keywords: [
		"nature",
		"sea",
		"beach"
	],
	char: "🐚",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var spider_web$1 = {
	keywords: [
		"animal",
		"insect",
		"arachnid",
		"silk"
	],
	char: "🕸",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var earth_americas$1 = {
	keywords: [
		"globe",
		"world",
		"USA",
		"international"
	],
	char: "🌎",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var earth_africa$1 = {
	keywords: [
		"globe",
		"world",
		"international"
	],
	char: "🌍",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var earth_asia$1 = {
	keywords: [
		"globe",
		"world",
		"east",
		"international"
	],
	char: "🌏",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var full_moon$1 = {
	keywords: [
		"nature",
		"yellow",
		"twilight",
		"planet",
		"space",
		"night",
		"evening",
		"sleep"
	],
	char: "🌕",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var waning_gibbous_moon$1 = {
	keywords: [
		"nature",
		"twilight",
		"planet",
		"space",
		"night",
		"evening",
		"sleep",
		"waxing_gibbous_moon"
	],
	char: "🌖",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var last_quarter_moon$1 = {
	keywords: [
		"nature",
		"twilight",
		"planet",
		"space",
		"night",
		"evening",
		"sleep"
	],
	char: "🌗",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var waning_crescent_moon$1 = {
	keywords: [
		"nature",
		"twilight",
		"planet",
		"space",
		"night",
		"evening",
		"sleep"
	],
	char: "🌘",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var new_moon$1 = {
	keywords: [
		"nature",
		"twilight",
		"planet",
		"space",
		"night",
		"evening",
		"sleep"
	],
	char: "🌑",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var waxing_crescent_moon$1 = {
	keywords: [
		"nature",
		"twilight",
		"planet",
		"space",
		"night",
		"evening",
		"sleep"
	],
	char: "🌒",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var first_quarter_moon$1 = {
	keywords: [
		"nature",
		"twilight",
		"planet",
		"space",
		"night",
		"evening",
		"sleep"
	],
	char: "🌓",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var waxing_gibbous_moon$1 = {
	keywords: [
		"nature",
		"night",
		"sky",
		"gray",
		"twilight",
		"planet",
		"space",
		"evening",
		"sleep"
	],
	char: "🌔",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var new_moon_with_face$1 = {
	keywords: [
		"nature",
		"twilight",
		"planet",
		"space",
		"night",
		"evening",
		"sleep"
	],
	char: "🌚",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var full_moon_with_face$1 = {
	keywords: [
		"nature",
		"twilight",
		"planet",
		"space",
		"night",
		"evening",
		"sleep"
	],
	char: "🌝",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var first_quarter_moon_with_face$1 = {
	keywords: [
		"nature",
		"twilight",
		"planet",
		"space",
		"night",
		"evening",
		"sleep"
	],
	char: "🌛",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var last_quarter_moon_with_face$1 = {
	keywords: [
		"nature",
		"twilight",
		"planet",
		"space",
		"night",
		"evening",
		"sleep"
	],
	char: "🌜",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var sun_with_face$1 = {
	keywords: [
		"nature",
		"morning",
		"sky"
	],
	char: "🌞",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var crescent_moon$1 = {
	keywords: [
		"night",
		"sleep",
		"sky",
		"evening",
		"magic"
	],
	char: "🌙",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var star$2 = {
	keywords: [
		"night",
		"yellow"
	],
	char: "⭐",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var star2$1 = {
	keywords: [
		"night",
		"sparkle",
		"awesome",
		"good",
		"magic"
	],
	char: "🌟",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var dizzy$1 = {
	keywords: [
		"star",
		"sparkle",
		"shoot",
		"magic"
	],
	char: "💫",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var sparkles$1 = {
	keywords: [
		"stars",
		"shine",
		"shiny",
		"cool",
		"awesome",
		"good",
		"magic"
	],
	char: "✨",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var comet$1 = {
	keywords: [
		"space"
	],
	char: "☄",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var sunny$1 = {
	keywords: [
		"weather",
		"nature",
		"brightness",
		"summer",
		"beach",
		"spring"
	],
	char: "☀️",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var sun_behind_small_cloud$1 = {
	keywords: [
		"weather"
	],
	char: "🌤",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var partly_sunny$1 = {
	keywords: [
		"weather",
		"nature",
		"cloudy",
		"morning",
		"fall",
		"spring"
	],
	char: "⛅",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var sun_behind_large_cloud$1 = {
	keywords: [
		"weather"
	],
	char: "🌥",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var sun_behind_rain_cloud$1 = {
	keywords: [
		"weather"
	],
	char: "🌦",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var cloud$1 = {
	keywords: [
		"weather",
		"sky"
	],
	char: "☁️",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var cloud_with_rain$1 = {
	keywords: [
		"weather"
	],
	char: "🌧",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var cloud_with_lightning_and_rain$1 = {
	keywords: [
		"weather",
		"lightning"
	],
	char: "⛈",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var cloud_with_lightning$1 = {
	keywords: [
		"weather",
		"thunder"
	],
	char: "🌩",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var zap$1 = {
	keywords: [
		"thunder",
		"weather",
		"lightning bolt",
		"fast"
	],
	char: "⚡",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var fire$1 = {
	keywords: [
		"hot",
		"cook",
		"flame"
	],
	char: "🔥",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var boom$1 = {
	keywords: [
		"bomb",
		"explode",
		"explosion",
		"collision",
		"blown"
	],
	char: "💥",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var snowflake$1 = {
	keywords: [
		"winter",
		"season",
		"cold",
		"weather",
		"christmas",
		"xmas"
	],
	char: "❄️",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var cloud_with_snow$1 = {
	keywords: [
		"weather"
	],
	char: "🌨",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var snowman$1 = {
	keywords: [
		"winter",
		"season",
		"cold",
		"weather",
		"christmas",
		"xmas",
		"frozen",
		"without_snow"
	],
	char: "⛄",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var snowman_with_snow$1 = {
	keywords: [
		"winter",
		"season",
		"cold",
		"weather",
		"christmas",
		"xmas",
		"frozen"
	],
	char: "☃",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var wind_face$1 = {
	keywords: [
		"gust",
		"air"
	],
	char: "🌬",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var dash$2 = {
	keywords: [
		"wind",
		"air",
		"fast",
		"shoo",
		"fart",
		"smoke",
		"puff"
	],
	char: "💨",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var tornado$1 = {
	keywords: [
		"weather",
		"cyclone",
		"twister"
	],
	char: "🌪",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var fog$1 = {
	keywords: [
		"weather"
	],
	char: "🌫",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var open_umbrella$1 = {
	keywords: [
		"weather",
		"spring"
	],
	char: "☂",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var umbrella$1 = {
	keywords: [
		"rainy",
		"weather",
		"spring"
	],
	char: "☔",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var droplet$1 = {
	keywords: [
		"water",
		"drip",
		"faucet",
		"spring"
	],
	char: "💧",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var sweat_drops$1 = {
	keywords: [
		"water",
		"drip",
		"oops"
	],
	char: "💦",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var ocean$1 = {
	keywords: [
		"sea",
		"water",
		"wave",
		"nature",
		"tsunami",
		"disaster"
	],
	char: "🌊",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var green_apple$1 = {
	keywords: [
		"fruit",
		"nature"
	],
	char: "🍏",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var apple$1 = {
	keywords: [
		"fruit",
		"mac",
		"school"
	],
	char: "🍎",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var pear$1 = {
	keywords: [
		"fruit",
		"nature",
		"food"
	],
	char: "🍐",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var tangerine$1 = {
	keywords: [
		"food",
		"fruit",
		"nature",
		"orange"
	],
	char: "🍊",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var lemon$1 = {
	keywords: [
		"fruit",
		"nature"
	],
	char: "🍋",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var banana$1 = {
	keywords: [
		"fruit",
		"food",
		"monkey"
	],
	char: "🍌",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var watermelon$1 = {
	keywords: [
		"fruit",
		"food",
		"picnic",
		"summer"
	],
	char: "🍉",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var grapes$1 = {
	keywords: [
		"fruit",
		"food",
		"wine"
	],
	char: "🍇",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var strawberry$1 = {
	keywords: [
		"fruit",
		"food",
		"nature"
	],
	char: "🍓",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var melon$1 = {
	keywords: [
		"fruit",
		"nature",
		"food"
	],
	char: "🍈",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var cherries$1 = {
	keywords: [
		"food",
		"fruit"
	],
	char: "🍒",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var peach$1 = {
	keywords: [
		"fruit",
		"nature",
		"food"
	],
	char: "🍑",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var pineapple$1 = {
	keywords: [
		"fruit",
		"nature",
		"food"
	],
	char: "🍍",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var coconut$1 = {
	keywords: [
		"fruit",
		"nature",
		"food",
		"palm"
	],
	char: "🥥",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var kiwi_fruit$1 = {
	keywords: [
		"fruit",
		"food"
	],
	char: "🥝",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var mango$1 = {
	keywords: [
		"fruit",
		"food",
		"tropical"
	],
	char: "🥭",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var avocado$1 = {
	keywords: [
		"fruit",
		"food"
	],
	char: "🥑",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var broccoli$1 = {
	keywords: [
		"fruit",
		"food",
		"vegetable"
	],
	char: "🥦",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var tomato$1 = {
	keywords: [
		"fruit",
		"vegetable",
		"nature",
		"food"
	],
	char: "🍅",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var eggplant$1 = {
	keywords: [
		"vegetable",
		"nature",
		"food",
		"aubergine"
	],
	char: "🍆",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var cucumber$1 = {
	keywords: [
		"fruit",
		"food",
		"pickle"
	],
	char: "🥒",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var carrot$1 = {
	keywords: [
		"vegetable",
		"food",
		"orange"
	],
	char: "🥕",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var hot_pepper$1 = {
	keywords: [
		"food",
		"spicy",
		"chilli",
		"chili"
	],
	char: "🌶",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var potato$1 = {
	keywords: [
		"food",
		"tuber",
		"vegatable",
		"starch"
	],
	char: "🥔",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var corn$1 = {
	keywords: [
		"food",
		"vegetable",
		"plant"
	],
	char: "🌽",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var leafy_greens$1 = {
	keywords: [
		"food",
		"vegetable",
		"plant",
		"bok choy",
		"cabbage",
		"kale",
		"lettuce"
	],
	char: "🥬",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var sweet_potato$1 = {
	keywords: [
		"food",
		"nature"
	],
	char: "🍠",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var peanuts$1 = {
	keywords: [
		"food",
		"nut"
	],
	char: "🥜",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var honey_pot$1 = {
	keywords: [
		"bees",
		"sweet",
		"kitchen"
	],
	char: "🍯",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var croissant$1 = {
	keywords: [
		"food",
		"bread",
		"french"
	],
	char: "🥐",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var bread$1 = {
	keywords: [
		"food",
		"wheat",
		"breakfast",
		"toast"
	],
	char: "🍞",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var baguette_bread$1 = {
	keywords: [
		"food",
		"bread",
		"french"
	],
	char: "🥖",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var bagel$1 = {
	keywords: [
		"food",
		"bread",
		"bakery",
		"schmear"
	],
	char: "🥯",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var pretzel$1 = {
	keywords: [
		"food",
		"bread",
		"twisted"
	],
	char: "🥨",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var cheese$1 = {
	keywords: [
		"food",
		"chadder"
	],
	char: "🧀",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var egg$1 = {
	keywords: [
		"food",
		"chicken",
		"breakfast"
	],
	char: "🥚",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var bacon$1 = {
	keywords: [
		"food",
		"breakfast",
		"pork",
		"pig",
		"meat"
	],
	char: "🥓",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var steak$1 = {
	keywords: [
		"food",
		"cow",
		"meat",
		"cut",
		"chop",
		"lambchop",
		"porkchop"
	],
	char: "🥩",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var pancakes$1 = {
	keywords: [
		"food",
		"breakfast",
		"flapjacks",
		"hotcakes"
	],
	char: "🥞",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var poultry_leg$1 = {
	keywords: [
		"food",
		"meat",
		"drumstick",
		"bird",
		"chicken",
		"turkey"
	],
	char: "🍗",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var meat_on_bone$1 = {
	keywords: [
		"good",
		"food",
		"drumstick"
	],
	char: "🍖",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var bone$1 = {
	keywords: [
		"skeleton"
	],
	char: "🦴",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var fried_shrimp$1 = {
	keywords: [
		"food",
		"animal",
		"appetizer",
		"summer"
	],
	char: "🍤",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var fried_egg$1 = {
	keywords: [
		"food",
		"breakfast",
		"kitchen",
		"egg"
	],
	char: "🍳",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var hamburger$1 = {
	keywords: [
		"meat",
		"fast food",
		"beef",
		"cheeseburger",
		"mcdonalds",
		"burger king"
	],
	char: "🍔",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var fries$1 = {
	keywords: [
		"chips",
		"snack",
		"fast food"
	],
	char: "🍟",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var stuffed_flatbread$1 = {
	keywords: [
		"food",
		"flatbread",
		"stuffed",
		"gyro"
	],
	char: "🥙",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var hotdog$1 = {
	keywords: [
		"food",
		"frankfurter"
	],
	char: "🌭",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var pizza$1 = {
	keywords: [
		"food",
		"party"
	],
	char: "🍕",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var sandwich$1 = {
	keywords: [
		"food",
		"lunch",
		"bread"
	],
	char: "🥪",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var canned_food$1 = {
	keywords: [
		"food",
		"soup"
	],
	char: "🥫",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var spaghetti$1 = {
	keywords: [
		"food",
		"italian",
		"noodle"
	],
	char: "🍝",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var taco$1 = {
	keywords: [
		"food",
		"mexican"
	],
	char: "🌮",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var burrito$1 = {
	keywords: [
		"food",
		"mexican"
	],
	char: "🌯",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var green_salad$1 = {
	keywords: [
		"food",
		"healthy",
		"lettuce"
	],
	char: "🥗",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var shallow_pan_of_food$1 = {
	keywords: [
		"food",
		"cooking",
		"casserole",
		"paella"
	],
	char: "🥘",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var ramen$1 = {
	keywords: [
		"food",
		"japanese",
		"noodle",
		"chopsticks"
	],
	char: "🍜",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var stew$1 = {
	keywords: [
		"food",
		"meat",
		"soup"
	],
	char: "🍲",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var fish_cake$1 = {
	keywords: [
		"food",
		"japan",
		"sea",
		"beach",
		"narutomaki",
		"pink",
		"swirl",
		"kamaboko",
		"surimi",
		"ramen"
	],
	char: "🍥",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var fortune_cookie$1 = {
	keywords: [
		"food",
		"prophecy"
	],
	char: "🥠",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var sushi$1 = {
	keywords: [
		"food",
		"fish",
		"japanese",
		"rice"
	],
	char: "🍣",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var bento$1 = {
	keywords: [
		"food",
		"japanese",
		"box"
	],
	char: "🍱",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var curry$1 = {
	keywords: [
		"food",
		"spicy",
		"hot",
		"indian"
	],
	char: "🍛",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var rice_ball$1 = {
	keywords: [
		"food",
		"japanese"
	],
	char: "🍙",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var rice$1 = {
	keywords: [
		"food",
		"china",
		"asian"
	],
	char: "🍚",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var rice_cracker$1 = {
	keywords: [
		"food",
		"japanese"
	],
	char: "🍘",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var oden$1 = {
	keywords: [
		"food",
		"japanese"
	],
	char: "🍢",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var dango$1 = {
	keywords: [
		"food",
		"dessert",
		"sweet",
		"japanese",
		"barbecue",
		"meat"
	],
	char: "🍡",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var shaved_ice$1 = {
	keywords: [
		"hot",
		"dessert",
		"summer"
	],
	char: "🍧",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var ice_cream$1 = {
	keywords: [
		"food",
		"hot",
		"dessert"
	],
	char: "🍨",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var icecream$1 = {
	keywords: [
		"food",
		"hot",
		"dessert",
		"summer"
	],
	char: "🍦",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var pie$1 = {
	keywords: [
		"food",
		"dessert",
		"pastry"
	],
	char: "🥧",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var cake$1 = {
	keywords: [
		"food",
		"dessert"
	],
	char: "🍰",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var cupcake$1 = {
	keywords: [
		"food",
		"dessert",
		"bakery",
		"sweet"
	],
	char: "🧁",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var moon_cake$1 = {
	keywords: [
		"food",
		"autumn"
	],
	char: "🥮",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var birthday$1 = {
	keywords: [
		"food",
		"dessert",
		"cake"
	],
	char: "🎂",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var custard$1 = {
	keywords: [
		"dessert",
		"food"
	],
	char: "🍮",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var candy$1 = {
	keywords: [
		"snack",
		"dessert",
		"sweet",
		"lolly"
	],
	char: "🍬",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var lollipop$1 = {
	keywords: [
		"food",
		"snack",
		"candy",
		"sweet"
	],
	char: "🍭",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var chocolate_bar$1 = {
	keywords: [
		"food",
		"snack",
		"dessert",
		"sweet"
	],
	char: "🍫",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var popcorn$1 = {
	keywords: [
		"food",
		"movie theater",
		"films",
		"snack"
	],
	char: "🍿",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var dumpling$1 = {
	keywords: [
		"food",
		"empanada",
		"pierogi",
		"potsticker"
	],
	char: "🥟",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var doughnut$1 = {
	keywords: [
		"food",
		"dessert",
		"snack",
		"sweet",
		"donut"
	],
	char: "🍩",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var cookie$1 = {
	keywords: [
		"food",
		"snack",
		"oreo",
		"chocolate",
		"sweet",
		"dessert"
	],
	char: "🍪",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var milk_glass$1 = {
	keywords: [
		"beverage",
		"drink",
		"cow"
	],
	char: "🥛",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var beer$1 = {
	keywords: [
		"relax",
		"beverage",
		"drink",
		"drunk",
		"party",
		"pub",
		"summer",
		"alcohol",
		"booze"
	],
	char: "🍺",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var beers$1 = {
	keywords: [
		"relax",
		"beverage",
		"drink",
		"drunk",
		"party",
		"pub",
		"summer",
		"alcohol",
		"booze"
	],
	char: "🍻",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var clinking_glasses$1 = {
	keywords: [
		"beverage",
		"drink",
		"party",
		"alcohol",
		"celebrate",
		"cheers",
		"wine",
		"champagne",
		"toast"
	],
	char: "🥂",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var wine_glass$1 = {
	keywords: [
		"drink",
		"beverage",
		"drunk",
		"alcohol",
		"booze"
	],
	char: "🍷",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var tumbler_glass$1 = {
	keywords: [
		"drink",
		"beverage",
		"drunk",
		"alcohol",
		"liquor",
		"booze",
		"bourbon",
		"scotch",
		"whisky",
		"glass",
		"shot"
	],
	char: "🥃",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var cocktail$1 = {
	keywords: [
		"drink",
		"drunk",
		"alcohol",
		"beverage",
		"booze",
		"mojito"
	],
	char: "🍸",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var tropical_drink$1 = {
	keywords: [
		"beverage",
		"cocktail",
		"summer",
		"beach",
		"alcohol",
		"booze",
		"mojito"
	],
	char: "🍹",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var champagne$1 = {
	keywords: [
		"drink",
		"wine",
		"bottle",
		"celebration"
	],
	char: "🍾",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var sake$1 = {
	keywords: [
		"wine",
		"drink",
		"drunk",
		"beverage",
		"japanese",
		"alcohol",
		"booze"
	],
	char: "🍶",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var tea$1 = {
	keywords: [
		"drink",
		"bowl",
		"breakfast",
		"green",
		"british"
	],
	char: "🍵",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var cup_with_straw$1 = {
	keywords: [
		"drink",
		"soda"
	],
	char: "🥤",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var coffee$1 = {
	keywords: [
		"beverage",
		"caffeine",
		"latte",
		"espresso"
	],
	char: "☕",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var baby_bottle$1 = {
	keywords: [
		"food",
		"container",
		"milk"
	],
	char: "🍼",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var salt$1 = {
	keywords: [
		"condiment",
		"shaker"
	],
	char: "🧂",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var spoon$1 = {
	keywords: [
		"cutlery",
		"kitchen",
		"tableware"
	],
	char: "🥄",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var fork_and_knife$1 = {
	keywords: [
		"cutlery",
		"kitchen"
	],
	char: "🍴",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var plate_with_cutlery$1 = {
	keywords: [
		"food",
		"eat",
		"meal",
		"lunch",
		"dinner",
		"restaurant"
	],
	char: "🍽",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var bowl_with_spoon$1 = {
	keywords: [
		"food",
		"breakfast",
		"cereal",
		"oatmeal",
		"porridge"
	],
	char: "🥣",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var takeout_box$1 = {
	keywords: [
		"food",
		"leftovers"
	],
	char: "🥡",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var chopsticks$1 = {
	keywords: [
		"food"
	],
	char: "🥢",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var soccer$1 = {
	keywords: [
		"sports",
		"football"
	],
	char: "⚽",
	fitzpatrick_scale: false,
	category: "activity"
};
var basketball$1 = {
	keywords: [
		"sports",
		"balls",
		"NBA"
	],
	char: "🏀",
	fitzpatrick_scale: false,
	category: "activity"
};
var football$1 = {
	keywords: [
		"sports",
		"balls",
		"NFL"
	],
	char: "🏈",
	fitzpatrick_scale: false,
	category: "activity"
};
var baseball$1 = {
	keywords: [
		"sports",
		"balls"
	],
	char: "⚾",
	fitzpatrick_scale: false,
	category: "activity"
};
var softball$1 = {
	keywords: [
		"sports",
		"balls"
	],
	char: "🥎",
	fitzpatrick_scale: false,
	category: "activity"
};
var tennis$1 = {
	keywords: [
		"sports",
		"balls",
		"green"
	],
	char: "🎾",
	fitzpatrick_scale: false,
	category: "activity"
};
var volleyball$1 = {
	keywords: [
		"sports",
		"balls"
	],
	char: "🏐",
	fitzpatrick_scale: false,
	category: "activity"
};
var rugby_football$1 = {
	keywords: [
		"sports",
		"team"
	],
	char: "🏉",
	fitzpatrick_scale: false,
	category: "activity"
};
var flying_disc$1 = {
	keywords: [
		"sports",
		"frisbee",
		"ultimate"
	],
	char: "🥏",
	fitzpatrick_scale: false,
	category: "activity"
};
var golf$1 = {
	keywords: [
		"sports",
		"business",
		"flag",
		"hole",
		"summer"
	],
	char: "⛳",
	fitzpatrick_scale: false,
	category: "activity"
};
var golfing_woman$1 = {
	keywords: [
		"sports",
		"business",
		"woman",
		"female"
	],
	char: "🏌️‍♀️",
	fitzpatrick_scale: false,
	category: "activity"
};
var golfing_man$1 = {
	keywords: [
		"sports",
		"business"
	],
	char: "🏌",
	fitzpatrick_scale: true,
	category: "activity"
};
var ping_pong$1 = {
	keywords: [
		"sports",
		"pingpong"
	],
	char: "🏓",
	fitzpatrick_scale: false,
	category: "activity"
};
var badminton$1 = {
	keywords: [
		"sports"
	],
	char: "🏸",
	fitzpatrick_scale: false,
	category: "activity"
};
var goal_net$1 = {
	keywords: [
		"sports"
	],
	char: "🥅",
	fitzpatrick_scale: false,
	category: "activity"
};
var ice_hockey$1 = {
	keywords: [
		"sports"
	],
	char: "🏒",
	fitzpatrick_scale: false,
	category: "activity"
};
var field_hockey$1 = {
	keywords: [
		"sports"
	],
	char: "🏑",
	fitzpatrick_scale: false,
	category: "activity"
};
var lacrosse$1 = {
	keywords: [
		"sports",
		"ball",
		"stick"
	],
	char: "🥍",
	fitzpatrick_scale: false,
	category: "activity"
};
var cricket$1 = {
	keywords: [
		"sports"
	],
	char: "🏏",
	fitzpatrick_scale: false,
	category: "activity"
};
var ski$1 = {
	keywords: [
		"sports",
		"winter",
		"cold",
		"snow"
	],
	char: "🎿",
	fitzpatrick_scale: false,
	category: "activity"
};
var skier$1 = {
	keywords: [
		"sports",
		"winter",
		"snow"
	],
	char: "⛷",
	fitzpatrick_scale: false,
	category: "activity"
};
var snowboarder$1 = {
	keywords: [
		"sports",
		"winter"
	],
	char: "🏂",
	fitzpatrick_scale: true,
	category: "activity"
};
var person_fencing$1 = {
	keywords: [
		"sports",
		"fencing",
		"sword"
	],
	char: "🤺",
	fitzpatrick_scale: false,
	category: "activity"
};
var women_wrestling$1 = {
	keywords: [
		"sports",
		"wrestlers"
	],
	char: "🤼‍♀️",
	fitzpatrick_scale: false,
	category: "activity"
};
var men_wrestling$1 = {
	keywords: [
		"sports",
		"wrestlers"
	],
	char: "🤼‍♂️",
	fitzpatrick_scale: false,
	category: "activity"
};
var woman_cartwheeling$1 = {
	keywords: [
		"gymnastics"
	],
	char: "🤸‍♀️",
	fitzpatrick_scale: true,
	category: "activity"
};
var man_cartwheeling$1 = {
	keywords: [
		"gymnastics"
	],
	char: "🤸‍♂️",
	fitzpatrick_scale: true,
	category: "activity"
};
var woman_playing_handball$1 = {
	keywords: [
		"sports"
	],
	char: "🤾‍♀️",
	fitzpatrick_scale: true,
	category: "activity"
};
var man_playing_handball$1 = {
	keywords: [
		"sports"
	],
	char: "🤾‍♂️",
	fitzpatrick_scale: true,
	category: "activity"
};
var ice_skate$1 = {
	keywords: [
		"sports"
	],
	char: "⛸",
	fitzpatrick_scale: false,
	category: "activity"
};
var curling_stone$1 = {
	keywords: [
		"sports"
	],
	char: "🥌",
	fitzpatrick_scale: false,
	category: "activity"
};
var skateboard$1 = {
	keywords: [
		"board"
	],
	char: "🛹",
	fitzpatrick_scale: false,
	category: "activity"
};
var sled$1 = {
	keywords: [
		"sleigh",
		"luge",
		"toboggan"
	],
	char: "🛷",
	fitzpatrick_scale: false,
	category: "activity"
};
var bow_and_arrow$1 = {
	keywords: [
		"sports"
	],
	char: "🏹",
	fitzpatrick_scale: false,
	category: "activity"
};
var fishing_pole_and_fish$1 = {
	keywords: [
		"food",
		"hobby",
		"summer"
	],
	char: "🎣",
	fitzpatrick_scale: false,
	category: "activity"
};
var boxing_glove$1 = {
	keywords: [
		"sports",
		"fighting"
	],
	char: "🥊",
	fitzpatrick_scale: false,
	category: "activity"
};
var martial_arts_uniform$1 = {
	keywords: [
		"judo",
		"karate",
		"taekwondo"
	],
	char: "🥋",
	fitzpatrick_scale: false,
	category: "activity"
};
var rowing_woman$1 = {
	keywords: [
		"sports",
		"hobby",
		"water",
		"ship",
		"woman",
		"female"
	],
	char: "🚣‍♀️",
	fitzpatrick_scale: true,
	category: "activity"
};
var rowing_man$1 = {
	keywords: [
		"sports",
		"hobby",
		"water",
		"ship"
	],
	char: "🚣",
	fitzpatrick_scale: true,
	category: "activity"
};
var climbing_woman$1 = {
	keywords: [
		"sports",
		"hobby",
		"woman",
		"female",
		"rock"
	],
	char: "🧗‍♀️",
	fitzpatrick_scale: true,
	category: "activity"
};
var climbing_man$1 = {
	keywords: [
		"sports",
		"hobby",
		"man",
		"male",
		"rock"
	],
	char: "🧗‍♂️",
	fitzpatrick_scale: true,
	category: "activity"
};
var swimming_woman$1 = {
	keywords: [
		"sports",
		"exercise",
		"human",
		"athlete",
		"water",
		"summer",
		"woman",
		"female"
	],
	char: "🏊‍♀️",
	fitzpatrick_scale: true,
	category: "activity"
};
var swimming_man$1 = {
	keywords: [
		"sports",
		"exercise",
		"human",
		"athlete",
		"water",
		"summer"
	],
	char: "🏊",
	fitzpatrick_scale: true,
	category: "activity"
};
var woman_playing_water_polo$1 = {
	keywords: [
		"sports",
		"pool"
	],
	char: "🤽‍♀️",
	fitzpatrick_scale: true,
	category: "activity"
};
var man_playing_water_polo$1 = {
	keywords: [
		"sports",
		"pool"
	],
	char: "🤽‍♂️",
	fitzpatrick_scale: true,
	category: "activity"
};
var woman_in_lotus_position$1 = {
	keywords: [
		"woman",
		"female",
		"meditation",
		"yoga",
		"serenity",
		"zen",
		"mindfulness"
	],
	char: "🧘‍♀️",
	fitzpatrick_scale: true,
	category: "activity"
};
var man_in_lotus_position$1 = {
	keywords: [
		"man",
		"male",
		"meditation",
		"yoga",
		"serenity",
		"zen",
		"mindfulness"
	],
	char: "🧘‍♂️",
	fitzpatrick_scale: true,
	category: "activity"
};
var surfing_woman$1 = {
	keywords: [
		"sports",
		"ocean",
		"sea",
		"summer",
		"beach",
		"woman",
		"female"
	],
	char: "🏄‍♀️",
	fitzpatrick_scale: true,
	category: "activity"
};
var surfing_man$1 = {
	keywords: [
		"sports",
		"ocean",
		"sea",
		"summer",
		"beach"
	],
	char: "🏄",
	fitzpatrick_scale: true,
	category: "activity"
};
var bath$1 = {
	keywords: [
		"clean",
		"shower",
		"bathroom"
	],
	char: "🛀",
	fitzpatrick_scale: true,
	category: "activity"
};
var basketball_woman$1 = {
	keywords: [
		"sports",
		"human",
		"woman",
		"female"
	],
	char: "⛹️‍♀️",
	fitzpatrick_scale: true,
	category: "activity"
};
var basketball_man$1 = {
	keywords: [
		"sports",
		"human"
	],
	char: "⛹",
	fitzpatrick_scale: true,
	category: "activity"
};
var weight_lifting_woman$1 = {
	keywords: [
		"sports",
		"training",
		"exercise",
		"woman",
		"female"
	],
	char: "🏋️‍♀️",
	fitzpatrick_scale: true,
	category: "activity"
};
var weight_lifting_man$1 = {
	keywords: [
		"sports",
		"training",
		"exercise"
	],
	char: "🏋",
	fitzpatrick_scale: true,
	category: "activity"
};
var biking_woman$1 = {
	keywords: [
		"sports",
		"bike",
		"exercise",
		"hipster",
		"woman",
		"female"
	],
	char: "🚴‍♀️",
	fitzpatrick_scale: true,
	category: "activity"
};
var biking_man$1 = {
	keywords: [
		"sports",
		"bike",
		"exercise",
		"hipster"
	],
	char: "🚴",
	fitzpatrick_scale: true,
	category: "activity"
};
var mountain_biking_woman$1 = {
	keywords: [
		"transportation",
		"sports",
		"human",
		"race",
		"bike",
		"woman",
		"female"
	],
	char: "🚵‍♀️",
	fitzpatrick_scale: true,
	category: "activity"
};
var mountain_biking_man$1 = {
	keywords: [
		"transportation",
		"sports",
		"human",
		"race",
		"bike"
	],
	char: "🚵",
	fitzpatrick_scale: true,
	category: "activity"
};
var horse_racing$1 = {
	keywords: [
		"animal",
		"betting",
		"competition",
		"gambling",
		"luck"
	],
	char: "🏇",
	fitzpatrick_scale: true,
	category: "activity"
};
var business_suit_levitating$1 = {
	keywords: [
		"suit",
		"business",
		"levitate",
		"hover",
		"jump"
	],
	char: "🕴",
	fitzpatrick_scale: true,
	category: "activity"
};
var trophy$1 = {
	keywords: [
		"win",
		"award",
		"contest",
		"place",
		"ftw",
		"ceremony"
	],
	char: "🏆",
	fitzpatrick_scale: false,
	category: "activity"
};
var running_shirt_with_sash$1 = {
	keywords: [
		"play",
		"pageant"
	],
	char: "🎽",
	fitzpatrick_scale: false,
	category: "activity"
};
var medal_sports$1 = {
	keywords: [
		"award",
		"winning"
	],
	char: "🏅",
	fitzpatrick_scale: false,
	category: "activity"
};
var medal_military$1 = {
	keywords: [
		"award",
		"winning",
		"army"
	],
	char: "🎖",
	fitzpatrick_scale: false,
	category: "activity"
};
var reminder_ribbon$1 = {
	keywords: [
		"sports",
		"cause",
		"support",
		"awareness"
	],
	char: "🎗",
	fitzpatrick_scale: false,
	category: "activity"
};
var rosette$1 = {
	keywords: [
		"flower",
		"decoration",
		"military"
	],
	char: "🏵",
	fitzpatrick_scale: false,
	category: "activity"
};
var ticket$1 = {
	keywords: [
		"event",
		"concert",
		"pass"
	],
	char: "🎫",
	fitzpatrick_scale: false,
	category: "activity"
};
var tickets$1 = {
	keywords: [
		"sports",
		"concert",
		"entrance"
	],
	char: "🎟",
	fitzpatrick_scale: false,
	category: "activity"
};
var performing_arts$1 = {
	keywords: [
		"acting",
		"theater",
		"drama"
	],
	char: "🎭",
	fitzpatrick_scale: false,
	category: "activity"
};
var art$1 = {
	keywords: [
		"design",
		"paint",
		"draw",
		"colors"
	],
	char: "🎨",
	fitzpatrick_scale: false,
	category: "activity"
};
var circus_tent$1 = {
	keywords: [
		"festival",
		"carnival",
		"party"
	],
	char: "🎪",
	fitzpatrick_scale: false,
	category: "activity"
};
var woman_juggling$1 = {
	keywords: [
		"juggle",
		"balance",
		"skill",
		"multitask"
	],
	char: "🤹‍♀️",
	fitzpatrick_scale: true,
	category: "activity"
};
var man_juggling$1 = {
	keywords: [
		"juggle",
		"balance",
		"skill",
		"multitask"
	],
	char: "🤹‍♂️",
	fitzpatrick_scale: true,
	category: "activity"
};
var microphone$1 = {
	keywords: [
		"sound",
		"music",
		"PA",
		"sing",
		"talkshow"
	],
	char: "🎤",
	fitzpatrick_scale: false,
	category: "activity"
};
var headphones$1 = {
	keywords: [
		"music",
		"score",
		"gadgets"
	],
	char: "🎧",
	fitzpatrick_scale: false,
	category: "activity"
};
var musical_score$1 = {
	keywords: [
		"treble",
		"clef",
		"compose"
	],
	char: "🎼",
	fitzpatrick_scale: false,
	category: "activity"
};
var musical_keyboard$1 = {
	keywords: [
		"piano",
		"instrument",
		"compose"
	],
	char: "🎹",
	fitzpatrick_scale: false,
	category: "activity"
};
var drum$1 = {
	keywords: [
		"music",
		"instrument",
		"drumsticks",
		"snare"
	],
	char: "🥁",
	fitzpatrick_scale: false,
	category: "activity"
};
var saxophone$1 = {
	keywords: [
		"music",
		"instrument",
		"jazz",
		"blues"
	],
	char: "🎷",
	fitzpatrick_scale: false,
	category: "activity"
};
var trumpet$1 = {
	keywords: [
		"music",
		"brass"
	],
	char: "🎺",
	fitzpatrick_scale: false,
	category: "activity"
};
var guitar$1 = {
	keywords: [
		"music",
		"instrument"
	],
	char: "🎸",
	fitzpatrick_scale: false,
	category: "activity"
};
var violin$1 = {
	keywords: [
		"music",
		"instrument",
		"orchestra",
		"symphony"
	],
	char: "🎻",
	fitzpatrick_scale: false,
	category: "activity"
};
var clapper$1 = {
	keywords: [
		"movie",
		"film",
		"record"
	],
	char: "🎬",
	fitzpatrick_scale: false,
	category: "activity"
};
var video_game$1 = {
	keywords: [
		"play",
		"console",
		"PS4",
		"controller"
	],
	char: "🎮",
	fitzpatrick_scale: false,
	category: "activity"
};
var space_invader$1 = {
	keywords: [
		"game",
		"arcade",
		"play"
	],
	char: "👾",
	fitzpatrick_scale: false,
	category: "activity"
};
var dart$1 = {
	keywords: [
		"game",
		"play",
		"bar",
		"target",
		"bullseye"
	],
	char: "🎯",
	fitzpatrick_scale: false,
	category: "activity"
};
var game_die$1 = {
	keywords: [
		"dice",
		"random",
		"tabletop",
		"play",
		"luck"
	],
	char: "🎲",
	fitzpatrick_scale: false,
	category: "activity"
};
var chess_pawn$1 = {
	keywords: [
		"expendable"
	],
	char: "♟",
	fitzpatrick_scale: false,
	category: "activity"
};
var slot_machine$1 = {
	keywords: [
		"bet",
		"gamble",
		"vegas",
		"fruit machine",
		"luck",
		"casino"
	],
	char: "🎰",
	fitzpatrick_scale: false,
	category: "activity"
};
var jigsaw$1 = {
	keywords: [
		"interlocking",
		"puzzle",
		"piece"
	],
	char: "🧩",
	fitzpatrick_scale: false,
	category: "activity"
};
var bowling$1 = {
	keywords: [
		"sports",
		"fun",
		"play"
	],
	char: "🎳",
	fitzpatrick_scale: false,
	category: "activity"
};
var red_car$1 = {
	keywords: [
		"red",
		"transportation",
		"vehicle"
	],
	char: "🚗",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var taxi$1 = {
	keywords: [
		"uber",
		"vehicle",
		"cars",
		"transportation"
	],
	char: "🚕",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var blue_car$1 = {
	keywords: [
		"transportation",
		"vehicle"
	],
	char: "🚙",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var bus$1 = {
	keywords: [
		"car",
		"vehicle",
		"transportation"
	],
	char: "🚌",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var trolleybus$1 = {
	keywords: [
		"bart",
		"transportation",
		"vehicle"
	],
	char: "🚎",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var racing_car$1 = {
	keywords: [
		"sports",
		"race",
		"fast",
		"formula",
		"f1"
	],
	char: "🏎",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var police_car$1 = {
	keywords: [
		"vehicle",
		"cars",
		"transportation",
		"law",
		"legal",
		"enforcement"
	],
	char: "🚓",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var ambulance$1 = {
	keywords: [
		"health",
		"911",
		"hospital"
	],
	char: "🚑",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var fire_engine$1 = {
	keywords: [
		"transportation",
		"cars",
		"vehicle"
	],
	char: "🚒",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var minibus$1 = {
	keywords: [
		"vehicle",
		"car",
		"transportation"
	],
	char: "🚐",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var truck$1 = {
	keywords: [
		"cars",
		"transportation"
	],
	char: "🚚",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var articulated_lorry$1 = {
	keywords: [
		"vehicle",
		"cars",
		"transportation",
		"express"
	],
	char: "🚛",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var tractor$1 = {
	keywords: [
		"vehicle",
		"car",
		"farming",
		"agriculture"
	],
	char: "🚜",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var kick_scooter$1 = {
	keywords: [
		"vehicle",
		"kick",
		"razor"
	],
	char: "🛴",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var motorcycle$1 = {
	keywords: [
		"race",
		"sports",
		"fast"
	],
	char: "🏍",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var bike$1 = {
	keywords: [
		"sports",
		"bicycle",
		"exercise",
		"hipster"
	],
	char: "🚲",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var motor_scooter$1 = {
	keywords: [
		"vehicle",
		"vespa",
		"sasha"
	],
	char: "🛵",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var rotating_light$1 = {
	keywords: [
		"police",
		"ambulance",
		"911",
		"emergency",
		"alert",
		"error",
		"pinged",
		"law",
		"legal"
	],
	char: "🚨",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var oncoming_police_car$1 = {
	keywords: [
		"vehicle",
		"law",
		"legal",
		"enforcement",
		"911"
	],
	char: "🚔",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var oncoming_bus$1 = {
	keywords: [
		"vehicle",
		"transportation"
	],
	char: "🚍",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var oncoming_automobile$1 = {
	keywords: [
		"car",
		"vehicle",
		"transportation"
	],
	char: "🚘",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var oncoming_taxi$1 = {
	keywords: [
		"vehicle",
		"cars",
		"uber"
	],
	char: "🚖",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var aerial_tramway$1 = {
	keywords: [
		"transportation",
		"vehicle",
		"ski"
	],
	char: "🚡",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var mountain_cableway$1 = {
	keywords: [
		"transportation",
		"vehicle",
		"ski"
	],
	char: "🚠",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var suspension_railway$1 = {
	keywords: [
		"vehicle",
		"transportation"
	],
	char: "🚟",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var railway_car$1 = {
	keywords: [
		"transportation",
		"vehicle"
	],
	char: "🚃",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var train$1 = {
	keywords: [
		"transportation",
		"vehicle",
		"carriage",
		"public",
		"travel"
	],
	char: "🚋",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var monorail$1 = {
	keywords: [
		"transportation",
		"vehicle"
	],
	char: "🚝",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var bullettrain_side$1 = {
	keywords: [
		"transportation",
		"vehicle"
	],
	char: "🚄",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var bullettrain_front$1 = {
	keywords: [
		"transportation",
		"vehicle",
		"speed",
		"fast",
		"public",
		"travel"
	],
	char: "🚅",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var light_rail$1 = {
	keywords: [
		"transportation",
		"vehicle"
	],
	char: "🚈",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var mountain_railway$1 = {
	keywords: [
		"transportation",
		"vehicle"
	],
	char: "🚞",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var steam_locomotive$1 = {
	keywords: [
		"transportation",
		"vehicle",
		"train"
	],
	char: "🚂",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var train2$1 = {
	keywords: [
		"transportation",
		"vehicle"
	],
	char: "🚆",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var metro$1 = {
	keywords: [
		"transportation",
		"blue-square",
		"mrt",
		"underground",
		"tube"
	],
	char: "🚇",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var tram$1 = {
	keywords: [
		"transportation",
		"vehicle"
	],
	char: "🚊",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var station$1 = {
	keywords: [
		"transportation",
		"vehicle",
		"public"
	],
	char: "🚉",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var flying_saucer$1 = {
	keywords: [
		"transportation",
		"vehicle",
		"ufo"
	],
	char: "🛸",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var helicopter$1 = {
	keywords: [
		"transportation",
		"vehicle",
		"fly"
	],
	char: "🚁",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var small_airplane$1 = {
	keywords: [
		"flight",
		"transportation",
		"fly",
		"vehicle"
	],
	char: "🛩",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var airplane$1 = {
	keywords: [
		"vehicle",
		"transportation",
		"flight",
		"fly"
	],
	char: "✈️",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var flight_departure$1 = {
	keywords: [
		"airport",
		"flight",
		"landing"
	],
	char: "🛫",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var flight_arrival$1 = {
	keywords: [
		"airport",
		"flight",
		"boarding"
	],
	char: "🛬",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var sailboat$1 = {
	keywords: [
		"ship",
		"summer",
		"transportation",
		"water",
		"sailing"
	],
	char: "⛵",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var motor_boat$1 = {
	keywords: [
		"ship"
	],
	char: "🛥",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var speedboat$1 = {
	keywords: [
		"ship",
		"transportation",
		"vehicle",
		"summer"
	],
	char: "🚤",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var ferry$1 = {
	keywords: [
		"boat",
		"ship",
		"yacht"
	],
	char: "⛴",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var passenger_ship$1 = {
	keywords: [
		"yacht",
		"cruise",
		"ferry"
	],
	char: "🛳",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var rocket$1 = {
	keywords: [
		"launch",
		"ship",
		"staffmode",
		"NASA",
		"outer space",
		"outer_space",
		"fly"
	],
	char: "🚀",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var artificial_satellite$1 = {
	keywords: [
		"communication",
		"gps",
		"orbit",
		"spaceflight",
		"NASA",
		"ISS"
	],
	char: "🛰",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var seat$1 = {
	keywords: [
		"sit",
		"airplane",
		"transport",
		"bus",
		"flight",
		"fly"
	],
	char: "💺",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var canoe$1 = {
	keywords: [
		"boat",
		"paddle",
		"water",
		"ship"
	],
	char: "🛶",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var anchor$1 = {
	keywords: [
		"ship",
		"ferry",
		"sea",
		"boat"
	],
	char: "⚓",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var construction$1 = {
	keywords: [
		"wip",
		"progress",
		"caution",
		"warning"
	],
	char: "🚧",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var fuelpump$1 = {
	keywords: [
		"gas station",
		"petroleum"
	],
	char: "⛽",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var busstop$1 = {
	keywords: [
		"transportation",
		"wait"
	],
	char: "🚏",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var vertical_traffic_light$1 = {
	keywords: [
		"transportation",
		"driving"
	],
	char: "🚦",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var traffic_light$1 = {
	keywords: [
		"transportation",
		"signal"
	],
	char: "🚥",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var checkered_flag$1 = {
	keywords: [
		"contest",
		"finishline",
		"race",
		"gokart"
	],
	char: "🏁",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var ship$1 = {
	keywords: [
		"transportation",
		"titanic",
		"deploy"
	],
	char: "🚢",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var ferris_wheel$1 = {
	keywords: [
		"photo",
		"carnival",
		"londoneye"
	],
	char: "🎡",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var roller_coaster$1 = {
	keywords: [
		"carnival",
		"playground",
		"photo",
		"fun"
	],
	char: "🎢",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var carousel_horse$1 = {
	keywords: [
		"photo",
		"carnival"
	],
	char: "🎠",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var building_construction$1 = {
	keywords: [
		"wip",
		"working",
		"progress"
	],
	char: "🏗",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var foggy$1 = {
	keywords: [
		"photo",
		"mountain"
	],
	char: "🌁",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var tokyo_tower$1 = {
	keywords: [
		"photo",
		"japanese"
	],
	char: "🗼",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var factory$1 = {
	keywords: [
		"building",
		"industry",
		"pollution",
		"smoke"
	],
	char: "🏭",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var fountain$1 = {
	keywords: [
		"photo",
		"summer",
		"water",
		"fresh"
	],
	char: "⛲",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var rice_scene$1 = {
	keywords: [
		"photo",
		"japan",
		"asia",
		"tsukimi"
	],
	char: "🎑",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var mountain$1 = {
	keywords: [
		"photo",
		"nature",
		"environment"
	],
	char: "⛰",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var mountain_snow$1 = {
	keywords: [
		"photo",
		"nature",
		"environment",
		"winter",
		"cold"
	],
	char: "🏔",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var mount_fuji$1 = {
	keywords: [
		"photo",
		"mountain",
		"nature",
		"japanese"
	],
	char: "🗻",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var volcano$1 = {
	keywords: [
		"photo",
		"nature",
		"disaster"
	],
	char: "🌋",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var japan$1 = {
	keywords: [
		"nation",
		"country",
		"japanese",
		"asia"
	],
	char: "🗾",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var camping$1 = {
	keywords: [
		"photo",
		"outdoors",
		"tent"
	],
	char: "🏕",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var tent$1 = {
	keywords: [
		"photo",
		"camping",
		"outdoors"
	],
	char: "⛺",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var national_park$1 = {
	keywords: [
		"photo",
		"environment",
		"nature"
	],
	char: "🏞",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var motorway$1 = {
	keywords: [
		"road",
		"cupertino",
		"interstate",
		"highway"
	],
	char: "🛣",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var railway_track$1 = {
	keywords: [
		"train",
		"transportation"
	],
	char: "🛤",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var sunrise$1 = {
	keywords: [
		"morning",
		"view",
		"vacation",
		"photo"
	],
	char: "🌅",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var sunrise_over_mountains$1 = {
	keywords: [
		"view",
		"vacation",
		"photo"
	],
	char: "🌄",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var desert$1 = {
	keywords: [
		"photo",
		"warm",
		"saharah"
	],
	char: "🏜",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var beach_umbrella$1 = {
	keywords: [
		"weather",
		"summer",
		"sunny",
		"sand",
		"mojito"
	],
	char: "🏖",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var desert_island$1 = {
	keywords: [
		"photo",
		"tropical",
		"mojito"
	],
	char: "🏝",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var city_sunrise$1 = {
	keywords: [
		"photo",
		"good morning",
		"dawn"
	],
	char: "🌇",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var city_sunset$1 = {
	keywords: [
		"photo",
		"evening",
		"sky",
		"buildings"
	],
	char: "🌆",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var cityscape$1 = {
	keywords: [
		"photo",
		"night life",
		"urban"
	],
	char: "🏙",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var night_with_stars$1 = {
	keywords: [
		"evening",
		"city",
		"downtown"
	],
	char: "🌃",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var bridge_at_night$1 = {
	keywords: [
		"photo",
		"sanfrancisco"
	],
	char: "🌉",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var milky_way$1 = {
	keywords: [
		"photo",
		"space",
		"stars"
	],
	char: "🌌",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var stars$1 = {
	keywords: [
		"night",
		"photo"
	],
	char: "🌠",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var sparkler$1 = {
	keywords: [
		"stars",
		"night",
		"shine"
	],
	char: "🎇",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var fireworks$1 = {
	keywords: [
		"photo",
		"festival",
		"carnival",
		"congratulations"
	],
	char: "🎆",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var rainbow$1 = {
	keywords: [
		"nature",
		"happy",
		"unicorn_face",
		"photo",
		"sky",
		"spring"
	],
	char: "🌈",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var houses$1 = {
	keywords: [
		"buildings",
		"photo"
	],
	char: "🏘",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var european_castle$1 = {
	keywords: [
		"building",
		"royalty",
		"history"
	],
	char: "🏰",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var japanese_castle$1 = {
	keywords: [
		"photo",
		"building"
	],
	char: "🏯",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var stadium$1 = {
	keywords: [
		"photo",
		"place",
		"sports",
		"concert",
		"venue"
	],
	char: "🏟",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var statue_of_liberty$1 = {
	keywords: [
		"american",
		"newyork"
	],
	char: "🗽",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var house$1 = {
	keywords: [
		"building",
		"home"
	],
	char: "🏠",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var house_with_garden$1 = {
	keywords: [
		"home",
		"plant",
		"nature"
	],
	char: "🏡",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var derelict_house$1 = {
	keywords: [
		"abandon",
		"evict",
		"broken",
		"building"
	],
	char: "🏚",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var office$1 = {
	keywords: [
		"building",
		"bureau",
		"work"
	],
	char: "🏢",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var department_store$1 = {
	keywords: [
		"building",
		"shopping",
		"mall"
	],
	char: "🏬",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var post_office$1 = {
	keywords: [
		"building",
		"envelope",
		"communication"
	],
	char: "🏣",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var european_post_office$1 = {
	keywords: [
		"building",
		"email"
	],
	char: "🏤",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var hospital$1 = {
	keywords: [
		"building",
		"health",
		"surgery",
		"doctor"
	],
	char: "🏥",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var bank$1 = {
	keywords: [
		"building",
		"money",
		"sales",
		"cash",
		"business",
		"enterprise"
	],
	char: "🏦",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var hotel$1 = {
	keywords: [
		"building",
		"accomodation",
		"checkin"
	],
	char: "🏨",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var convenience_store$1 = {
	keywords: [
		"building",
		"shopping",
		"groceries"
	],
	char: "🏪",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var school$1 = {
	keywords: [
		"building",
		"student",
		"education",
		"learn",
		"teach"
	],
	char: "🏫",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var love_hotel$1 = {
	keywords: [
		"like",
		"affection",
		"dating"
	],
	char: "🏩",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var wedding$1 = {
	keywords: [
		"love",
		"like",
		"affection",
		"couple",
		"marriage",
		"bride",
		"groom"
	],
	char: "💒",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var classical_building$1 = {
	keywords: [
		"art",
		"culture",
		"history"
	],
	char: "🏛",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var church$1 = {
	keywords: [
		"building",
		"religion",
		"christ"
	],
	char: "⛪",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var mosque$1 = {
	keywords: [
		"islam",
		"worship",
		"minaret"
	],
	char: "🕌",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var synagogue$1 = {
	keywords: [
		"judaism",
		"worship",
		"temple",
		"jewish"
	],
	char: "🕍",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var kaaba$1 = {
	keywords: [
		"mecca",
		"mosque",
		"islam"
	],
	char: "🕋",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var shinto_shrine$1 = {
	keywords: [
		"temple",
		"japan",
		"kyoto"
	],
	char: "⛩",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var watch$1 = {
	keywords: [
		"time",
		"accessories"
	],
	char: "⌚",
	fitzpatrick_scale: false,
	category: "objects"
};
var iphone$1 = {
	keywords: [
		"technology",
		"apple",
		"gadgets",
		"dial"
	],
	char: "📱",
	fitzpatrick_scale: false,
	category: "objects"
};
var calling$1 = {
	keywords: [
		"iphone",
		"incoming"
	],
	char: "📲",
	fitzpatrick_scale: false,
	category: "objects"
};
var computer$1 = {
	keywords: [
		"technology",
		"laptop",
		"screen",
		"display",
		"monitor"
	],
	char: "💻",
	fitzpatrick_scale: false,
	category: "objects"
};
var keyboard$1 = {
	keywords: [
		"technology",
		"computer",
		"type",
		"input",
		"text"
	],
	char: "⌨",
	fitzpatrick_scale: false,
	category: "objects"
};
var desktop_computer$1 = {
	keywords: [
		"technology",
		"computing",
		"screen"
	],
	char: "🖥",
	fitzpatrick_scale: false,
	category: "objects"
};
var printer$1 = {
	keywords: [
		"paper",
		"ink"
	],
	char: "🖨",
	fitzpatrick_scale: false,
	category: "objects"
};
var computer_mouse$1 = {
	keywords: [
		"click"
	],
	char: "🖱",
	fitzpatrick_scale: false,
	category: "objects"
};
var trackball$1 = {
	keywords: [
		"technology",
		"trackpad"
	],
	char: "🖲",
	fitzpatrick_scale: false,
	category: "objects"
};
var joystick$1 = {
	keywords: [
		"game",
		"play"
	],
	char: "🕹",
	fitzpatrick_scale: false,
	category: "objects"
};
var clamp$1 = {
	keywords: [
		"tool"
	],
	char: "🗜",
	fitzpatrick_scale: false,
	category: "objects"
};
var minidisc$1 = {
	keywords: [
		"technology",
		"record",
		"data",
		"disk",
		"90s"
	],
	char: "💽",
	fitzpatrick_scale: false,
	category: "objects"
};
var floppy_disk$1 = {
	keywords: [
		"oldschool",
		"technology",
		"save",
		"90s",
		"80s"
	],
	char: "💾",
	fitzpatrick_scale: false,
	category: "objects"
};
var cd$1 = {
	keywords: [
		"technology",
		"dvd",
		"disk",
		"disc",
		"90s"
	],
	char: "💿",
	fitzpatrick_scale: false,
	category: "objects"
};
var dvd$1 = {
	keywords: [
		"cd",
		"disk",
		"disc"
	],
	char: "📀",
	fitzpatrick_scale: false,
	category: "objects"
};
var vhs$1 = {
	keywords: [
		"record",
		"video",
		"oldschool",
		"90s",
		"80s"
	],
	char: "📼",
	fitzpatrick_scale: false,
	category: "objects"
};
var camera$1 = {
	keywords: [
		"gadgets",
		"photography"
	],
	char: "📷",
	fitzpatrick_scale: false,
	category: "objects"
};
var camera_flash$1 = {
	keywords: [
		"photography",
		"gadgets"
	],
	char: "📸",
	fitzpatrick_scale: false,
	category: "objects"
};
var video_camera$1 = {
	keywords: [
		"film",
		"record"
	],
	char: "📹",
	fitzpatrick_scale: false,
	category: "objects"
};
var movie_camera$1 = {
	keywords: [
		"film",
		"record"
	],
	char: "🎥",
	fitzpatrick_scale: false,
	category: "objects"
};
var film_projector$1 = {
	keywords: [
		"video",
		"tape",
		"record",
		"movie"
	],
	char: "📽",
	fitzpatrick_scale: false,
	category: "objects"
};
var film_strip$1 = {
	keywords: [
		"movie"
	],
	char: "🎞",
	fitzpatrick_scale: false,
	category: "objects"
};
var telephone_receiver$1 = {
	keywords: [
		"technology",
		"communication",
		"dial"
	],
	char: "📞",
	fitzpatrick_scale: false,
	category: "objects"
};
var phone$2 = {
	keywords: [
		"technology",
		"communication",
		"dial",
		"telephone"
	],
	char: "☎️",
	fitzpatrick_scale: false,
	category: "objects"
};
var pager$1 = {
	keywords: [
		"bbcall",
		"oldschool",
		"90s"
	],
	char: "📟",
	fitzpatrick_scale: false,
	category: "objects"
};
var fax$1 = {
	keywords: [
		"communication",
		"technology"
	],
	char: "📠",
	fitzpatrick_scale: false,
	category: "objects"
};
var tv$1 = {
	keywords: [
		"technology",
		"program",
		"oldschool",
		"show",
		"television"
	],
	char: "📺",
	fitzpatrick_scale: false,
	category: "objects"
};
var radio$1 = {
	keywords: [
		"communication",
		"music",
		"podcast",
		"program"
	],
	char: "📻",
	fitzpatrick_scale: false,
	category: "objects"
};
var studio_microphone$1 = {
	keywords: [
		"sing",
		"recording",
		"artist",
		"talkshow"
	],
	char: "🎙",
	fitzpatrick_scale: false,
	category: "objects"
};
var level_slider$1 = {
	keywords: [
		"scale"
	],
	char: "🎚",
	fitzpatrick_scale: false,
	category: "objects"
};
var control_knobs$1 = {
	keywords: [
		"dial"
	],
	char: "🎛",
	fitzpatrick_scale: false,
	category: "objects"
};
var compass$1 = {
	keywords: [
		"magnetic",
		"navigation",
		"orienteering"
	],
	char: "🧭",
	fitzpatrick_scale: false,
	category: "objects"
};
var stopwatch$1 = {
	keywords: [
		"time",
		"deadline"
	],
	char: "⏱",
	fitzpatrick_scale: false,
	category: "objects"
};
var timer_clock$1 = {
	keywords: [
		"alarm"
	],
	char: "⏲",
	fitzpatrick_scale: false,
	category: "objects"
};
var alarm_clock$1 = {
	keywords: [
		"time",
		"wake"
	],
	char: "⏰",
	fitzpatrick_scale: false,
	category: "objects"
};
var mantelpiece_clock$1 = {
	keywords: [
		"time"
	],
	char: "🕰",
	fitzpatrick_scale: false,
	category: "objects"
};
var hourglass_flowing_sand$1 = {
	keywords: [
		"oldschool",
		"time",
		"countdown"
	],
	char: "⏳",
	fitzpatrick_scale: false,
	category: "objects"
};
var hourglass$1 = {
	keywords: [
		"time",
		"clock",
		"oldschool",
		"limit",
		"exam",
		"quiz",
		"test"
	],
	char: "⌛",
	fitzpatrick_scale: false,
	category: "objects"
};
var satellite$1 = {
	keywords: [
		"communication",
		"future",
		"radio",
		"space"
	],
	char: "📡",
	fitzpatrick_scale: false,
	category: "objects"
};
var battery$1 = {
	keywords: [
		"power",
		"energy",
		"sustain"
	],
	char: "🔋",
	fitzpatrick_scale: false,
	category: "objects"
};
var electric_plug$1 = {
	keywords: [
		"charger",
		"power"
	],
	char: "🔌",
	fitzpatrick_scale: false,
	category: "objects"
};
var bulb$1 = {
	keywords: [
		"light",
		"electricity",
		"idea"
	],
	char: "💡",
	fitzpatrick_scale: false,
	category: "objects"
};
var flashlight$1 = {
	keywords: [
		"dark",
		"camping",
		"sight",
		"night"
	],
	char: "🔦",
	fitzpatrick_scale: false,
	category: "objects"
};
var candle$1 = {
	keywords: [
		"fire",
		"wax"
	],
	char: "🕯",
	fitzpatrick_scale: false,
	category: "objects"
};
var fire_extinguisher$1 = {
	keywords: [
		"quench"
	],
	char: "🧯",
	fitzpatrick_scale: false,
	category: "objects"
};
var wastebasket$1 = {
	keywords: [
		"bin",
		"trash",
		"rubbish",
		"garbage",
		"toss"
	],
	char: "🗑",
	fitzpatrick_scale: false,
	category: "objects"
};
var oil_drum$1 = {
	keywords: [
		"barrell"
	],
	char: "🛢",
	fitzpatrick_scale: false,
	category: "objects"
};
var money_with_wings$1 = {
	keywords: [
		"dollar",
		"bills",
		"payment",
		"sale"
	],
	char: "💸",
	fitzpatrick_scale: false,
	category: "objects"
};
var dollar$2 = {
	keywords: [
		"money",
		"sales",
		"bill",
		"currency"
	],
	char: "💵",
	fitzpatrick_scale: false,
	category: "objects"
};
var yen$2 = {
	keywords: [
		"money",
		"sales",
		"japanese",
		"dollar",
		"currency"
	],
	char: "💴",
	fitzpatrick_scale: false,
	category: "objects"
};
var euro$2 = {
	keywords: [
		"money",
		"sales",
		"dollar",
		"currency"
	],
	char: "💶",
	fitzpatrick_scale: false,
	category: "objects"
};
var pound$2 = {
	keywords: [
		"british",
		"sterling",
		"money",
		"sales",
		"bills",
		"uk",
		"england",
		"currency"
	],
	char: "💷",
	fitzpatrick_scale: false,
	category: "objects"
};
var moneybag$1 = {
	keywords: [
		"dollar",
		"payment",
		"coins",
		"sale"
	],
	char: "💰",
	fitzpatrick_scale: false,
	category: "objects"
};
var credit_card$1 = {
	keywords: [
		"money",
		"sales",
		"dollar",
		"bill",
		"payment",
		"shopping"
	],
	char: "💳",
	fitzpatrick_scale: false,
	category: "objects"
};
var gem$1 = {
	keywords: [
		"blue",
		"ruby",
		"diamond",
		"jewelry"
	],
	char: "💎",
	fitzpatrick_scale: false,
	category: "objects"
};
var balance_scale$1 = {
	keywords: [
		"law",
		"fairness",
		"weight"
	],
	char: "⚖",
	fitzpatrick_scale: false,
	category: "objects"
};
var toolbox$1 = {
	keywords: [
		"tools",
		"diy",
		"fix",
		"maintainer",
		"mechanic"
	],
	char: "🧰",
	fitzpatrick_scale: false,
	category: "objects"
};
var wrench$1 = {
	keywords: [
		"tools",
		"diy",
		"ikea",
		"fix",
		"maintainer"
	],
	char: "🔧",
	fitzpatrick_scale: false,
	category: "objects"
};
var hammer$1 = {
	keywords: [
		"tools",
		"build",
		"create"
	],
	char: "🔨",
	fitzpatrick_scale: false,
	category: "objects"
};
var hammer_and_pick$1 = {
	keywords: [
		"tools",
		"build",
		"create"
	],
	char: "⚒",
	fitzpatrick_scale: false,
	category: "objects"
};
var hammer_and_wrench$1 = {
	keywords: [
		"tools",
		"build",
		"create"
	],
	char: "🛠",
	fitzpatrick_scale: false,
	category: "objects"
};
var pick$1 = {
	keywords: [
		"tools",
		"dig"
	],
	char: "⛏",
	fitzpatrick_scale: false,
	category: "objects"
};
var nut_and_bolt$1 = {
	keywords: [
		"handy",
		"tools",
		"fix"
	],
	char: "🔩",
	fitzpatrick_scale: false,
	category: "objects"
};
var gear$1 = {
	keywords: [
		"cog"
	],
	char: "⚙",
	fitzpatrick_scale: false,
	category: "objects"
};
var brick$1 = {
	keywords: [
		"bricks"
	],
	char: "🧱",
	fitzpatrick_scale: false,
	category: "objects"
};
var chains$1 = {
	keywords: [
		"lock",
		"arrest"
	],
	char: "⛓",
	fitzpatrick_scale: false,
	category: "objects"
};
var magnet$1 = {
	keywords: [
		"attraction",
		"magnetic"
	],
	char: "🧲",
	fitzpatrick_scale: false,
	category: "objects"
};
var gun$1 = {
	keywords: [
		"violence",
		"weapon",
		"pistol",
		"revolver"
	],
	char: "🔫",
	fitzpatrick_scale: false,
	category: "objects"
};
var bomb$1 = {
	keywords: [
		"boom",
		"explode",
		"explosion",
		"terrorism"
	],
	char: "💣",
	fitzpatrick_scale: false,
	category: "objects"
};
var firecracker$1 = {
	keywords: [
		"dynamite",
		"boom",
		"explode",
		"explosion",
		"explosive"
	],
	char: "🧨",
	fitzpatrick_scale: false,
	category: "objects"
};
var hocho$1 = {
	keywords: [
		"knife",
		"blade",
		"cutlery",
		"kitchen",
		"weapon"
	],
	char: "🔪",
	fitzpatrick_scale: false,
	category: "objects"
};
var dagger$2 = {
	keywords: [
		"weapon"
	],
	char: "🗡",
	fitzpatrick_scale: false,
	category: "objects"
};
var crossed_swords$1 = {
	keywords: [
		"weapon"
	],
	char: "⚔",
	fitzpatrick_scale: false,
	category: "objects"
};
var shield$1 = {
	keywords: [
		"protection",
		"security"
	],
	char: "🛡",
	fitzpatrick_scale: false,
	category: "objects"
};
var smoking$1 = {
	keywords: [
		"kills",
		"tobacco",
		"cigarette",
		"joint",
		"smoke"
	],
	char: "🚬",
	fitzpatrick_scale: false,
	category: "objects"
};
var skull_and_crossbones$1 = {
	keywords: [
		"poison",
		"danger",
		"deadly",
		"scary",
		"death",
		"pirate",
		"evil"
	],
	char: "☠",
	fitzpatrick_scale: false,
	category: "objects"
};
var coffin$1 = {
	keywords: [
		"vampire",
		"dead",
		"die",
		"death",
		"rip",
		"graveyard",
		"cemetery",
		"casket",
		"funeral",
		"box"
	],
	char: "⚰",
	fitzpatrick_scale: false,
	category: "objects"
};
var funeral_urn$1 = {
	keywords: [
		"dead",
		"die",
		"death",
		"rip",
		"ashes"
	],
	char: "⚱",
	fitzpatrick_scale: false,
	category: "objects"
};
var amphora$1 = {
	keywords: [
		"vase",
		"jar"
	],
	char: "🏺",
	fitzpatrick_scale: false,
	category: "objects"
};
var crystal_ball$1 = {
	keywords: [
		"disco",
		"party",
		"magic",
		"circus",
		"fortune_teller"
	],
	char: "🔮",
	fitzpatrick_scale: false,
	category: "objects"
};
var prayer_beads$1 = {
	keywords: [
		"dhikr",
		"religious"
	],
	char: "📿",
	fitzpatrick_scale: false,
	category: "objects"
};
var nazar_amulet$1 = {
	keywords: [
		"bead",
		"charm"
	],
	char: "🧿",
	fitzpatrick_scale: false,
	category: "objects"
};
var barber$1 = {
	keywords: [
		"hair",
		"salon",
		"style"
	],
	char: "💈",
	fitzpatrick_scale: false,
	category: "objects"
};
var alembic$1 = {
	keywords: [
		"distilling",
		"science",
		"experiment",
		"chemistry"
	],
	char: "⚗",
	fitzpatrick_scale: false,
	category: "objects"
};
var telescope$1 = {
	keywords: [
		"stars",
		"space",
		"zoom",
		"science",
		"astronomy"
	],
	char: "🔭",
	fitzpatrick_scale: false,
	category: "objects"
};
var microscope$1 = {
	keywords: [
		"laboratory",
		"experiment",
		"zoomin",
		"science",
		"study"
	],
	char: "🔬",
	fitzpatrick_scale: false,
	category: "objects"
};
var hole$1 = {
	keywords: [
		"embarrassing"
	],
	char: "🕳",
	fitzpatrick_scale: false,
	category: "objects"
};
var pill$1 = {
	keywords: [
		"health",
		"medicine",
		"doctor",
		"pharmacy",
		"drug"
	],
	char: "💊",
	fitzpatrick_scale: false,
	category: "objects"
};
var syringe$1 = {
	keywords: [
		"health",
		"hospital",
		"drugs",
		"blood",
		"medicine",
		"needle",
		"doctor",
		"nurse"
	],
	char: "💉",
	fitzpatrick_scale: false,
	category: "objects"
};
var dna$1 = {
	keywords: [
		"biologist",
		"genetics",
		"life"
	],
	char: "🧬",
	fitzpatrick_scale: false,
	category: "objects"
};
var microbe$1 = {
	keywords: [
		"amoeba",
		"bacteria",
		"germs"
	],
	char: "🦠",
	fitzpatrick_scale: false,
	category: "objects"
};
var petri_dish$1 = {
	keywords: [
		"bacteria",
		"biology",
		"culture",
		"lab"
	],
	char: "🧫",
	fitzpatrick_scale: false,
	category: "objects"
};
var test_tube$1 = {
	keywords: [
		"chemistry",
		"experiment",
		"lab",
		"science"
	],
	char: "🧪",
	fitzpatrick_scale: false,
	category: "objects"
};
var thermometer$1 = {
	keywords: [
		"weather",
		"temperature",
		"hot",
		"cold"
	],
	char: "🌡",
	fitzpatrick_scale: false,
	category: "objects"
};
var broom$1 = {
	keywords: [
		"cleaning",
		"sweeping",
		"witch"
	],
	char: "🧹",
	fitzpatrick_scale: false,
	category: "objects"
};
var basket$1 = {
	keywords: [
		"laundry"
	],
	char: "🧺",
	fitzpatrick_scale: false,
	category: "objects"
};
var toilet_paper$1 = {
	keywords: [
		"roll"
	],
	char: "🧻",
	fitzpatrick_scale: false,
	category: "objects"
};
var label$1 = {
	keywords: [
		"sale",
		"tag"
	],
	char: "🏷",
	fitzpatrick_scale: false,
	category: "objects"
};
var bookmark$1 = {
	keywords: [
		"favorite",
		"label",
		"save"
	],
	char: "🔖",
	fitzpatrick_scale: false,
	category: "objects"
};
var toilet$1 = {
	keywords: [
		"restroom",
		"wc",
		"washroom",
		"bathroom",
		"potty"
	],
	char: "🚽",
	fitzpatrick_scale: false,
	category: "objects"
};
var shower$1 = {
	keywords: [
		"clean",
		"water",
		"bathroom"
	],
	char: "🚿",
	fitzpatrick_scale: false,
	category: "objects"
};
var bathtub$1 = {
	keywords: [
		"clean",
		"shower",
		"bathroom"
	],
	char: "🛁",
	fitzpatrick_scale: false,
	category: "objects"
};
var soap$1 = {
	keywords: [
		"bar",
		"bathing",
		"cleaning",
		"lather"
	],
	char: "🧼",
	fitzpatrick_scale: false,
	category: "objects"
};
var sponge$1 = {
	keywords: [
		"absorbing",
		"cleaning",
		"porous"
	],
	char: "🧽",
	fitzpatrick_scale: false,
	category: "objects"
};
var lotion_bottle$1 = {
	keywords: [
		"moisturizer",
		"sunscreen"
	],
	char: "🧴",
	fitzpatrick_scale: false,
	category: "objects"
};
var key$1 = {
	keywords: [
		"lock",
		"door",
		"password"
	],
	char: "🔑",
	fitzpatrick_scale: false,
	category: "objects"
};
var old_key$1 = {
	keywords: [
		"lock",
		"door",
		"password"
	],
	char: "🗝",
	fitzpatrick_scale: false,
	category: "objects"
};
var couch_and_lamp$1 = {
	keywords: [
		"read",
		"chill"
	],
	char: "🛋",
	fitzpatrick_scale: false,
	category: "objects"
};
var sleeping_bed$1 = {
	keywords: [
		"bed",
		"rest"
	],
	char: "🛌",
	fitzpatrick_scale: true,
	category: "objects"
};
var bed$1 = {
	keywords: [
		"sleep",
		"rest"
	],
	char: "🛏",
	fitzpatrick_scale: false,
	category: "objects"
};
var door$1 = {
	keywords: [
		"house",
		"entry",
		"exit"
	],
	char: "🚪",
	fitzpatrick_scale: false,
	category: "objects"
};
var bellhop_bell$1 = {
	keywords: [
		"service"
	],
	char: "🛎",
	fitzpatrick_scale: false,
	category: "objects"
};
var teddy_bear$1 = {
	keywords: [
		"plush",
		"stuffed"
	],
	char: "🧸",
	fitzpatrick_scale: false,
	category: "objects"
};
var framed_picture$1 = {
	keywords: [
		"photography"
	],
	char: "🖼",
	fitzpatrick_scale: false,
	category: "objects"
};
var world_map$1 = {
	keywords: [
		"location",
		"direction"
	],
	char: "🗺",
	fitzpatrick_scale: false,
	category: "objects"
};
var parasol_on_ground$1 = {
	keywords: [
		"weather",
		"summer"
	],
	char: "⛱",
	fitzpatrick_scale: false,
	category: "objects"
};
var moyai$1 = {
	keywords: [
		"rock",
		"easter island",
		"moai"
	],
	char: "🗿",
	fitzpatrick_scale: false,
	category: "objects"
};
var shopping$1 = {
	keywords: [
		"mall",
		"buy",
		"purchase"
	],
	char: "🛍",
	fitzpatrick_scale: false,
	category: "objects"
};
var shopping_cart$1 = {
	keywords: [
		"trolley"
	],
	char: "🛒",
	fitzpatrick_scale: false,
	category: "objects"
};
var balloon$1 = {
	keywords: [
		"party",
		"celebration",
		"birthday",
		"circus"
	],
	char: "🎈",
	fitzpatrick_scale: false,
	category: "objects"
};
var flags$1 = {
	keywords: [
		"fish",
		"japanese",
		"koinobori",
		"carp",
		"banner"
	],
	char: "🎏",
	fitzpatrick_scale: false,
	category: "objects"
};
var ribbon$1 = {
	keywords: [
		"decoration",
		"pink",
		"girl",
		"bowtie"
	],
	char: "🎀",
	fitzpatrick_scale: false,
	category: "objects"
};
var gift$1 = {
	keywords: [
		"present",
		"birthday",
		"christmas",
		"xmas"
	],
	char: "🎁",
	fitzpatrick_scale: false,
	category: "objects"
};
var confetti_ball$1 = {
	keywords: [
		"festival",
		"party",
		"birthday",
		"circus"
	],
	char: "🎊",
	fitzpatrick_scale: false,
	category: "objects"
};
var tada$1 = {
	keywords: [
		"party",
		"congratulations",
		"birthday",
		"magic",
		"circus",
		"celebration"
	],
	char: "🎉",
	fitzpatrick_scale: false,
	category: "objects"
};
var dolls$1 = {
	keywords: [
		"japanese",
		"toy",
		"kimono"
	],
	char: "🎎",
	fitzpatrick_scale: false,
	category: "objects"
};
var wind_chime$1 = {
	keywords: [
		"nature",
		"ding",
		"spring",
		"bell"
	],
	char: "🎐",
	fitzpatrick_scale: false,
	category: "objects"
};
var crossed_flags$1 = {
	keywords: [
		"japanese",
		"nation",
		"country",
		"border"
	],
	char: "🎌",
	fitzpatrick_scale: false,
	category: "objects"
};
var izakaya_lantern$1 = {
	keywords: [
		"light",
		"paper",
		"halloween",
		"spooky"
	],
	char: "🏮",
	fitzpatrick_scale: false,
	category: "objects"
};
var red_envelope$1 = {
	keywords: [
		"gift"
	],
	char: "🧧",
	fitzpatrick_scale: false,
	category: "objects"
};
var email$1 = {
	keywords: [
		"letter",
		"postal",
		"inbox",
		"communication"
	],
	char: "✉️",
	fitzpatrick_scale: false,
	category: "objects"
};
var envelope_with_arrow$1 = {
	keywords: [
		"email",
		"communication"
	],
	char: "📩",
	fitzpatrick_scale: false,
	category: "objects"
};
var incoming_envelope$1 = {
	keywords: [
		"email",
		"inbox"
	],
	char: "📨",
	fitzpatrick_scale: false,
	category: "objects"
};
var love_letter$1 = {
	keywords: [
		"email",
		"like",
		"affection",
		"envelope",
		"valentines"
	],
	char: "💌",
	fitzpatrick_scale: false,
	category: "objects"
};
var postbox$1 = {
	keywords: [
		"email",
		"letter",
		"envelope"
	],
	char: "📮",
	fitzpatrick_scale: false,
	category: "objects"
};
var mailbox_closed$1 = {
	keywords: [
		"email",
		"communication",
		"inbox"
	],
	char: "📪",
	fitzpatrick_scale: false,
	category: "objects"
};
var mailbox$1 = {
	keywords: [
		"email",
		"inbox",
		"communication"
	],
	char: "📫",
	fitzpatrick_scale: false,
	category: "objects"
};
var mailbox_with_mail$1 = {
	keywords: [
		"email",
		"inbox",
		"communication"
	],
	char: "📬",
	fitzpatrick_scale: false,
	category: "objects"
};
var mailbox_with_no_mail$1 = {
	keywords: [
		"email",
		"inbox"
	],
	char: "📭",
	fitzpatrick_scale: false,
	category: "objects"
};
var postal_horn$1 = {
	keywords: [
		"instrument",
		"music"
	],
	char: "📯",
	fitzpatrick_scale: false,
	category: "objects"
};
var inbox_tray$1 = {
	keywords: [
		"email",
		"documents"
	],
	char: "📥",
	fitzpatrick_scale: false,
	category: "objects"
};
var outbox_tray$1 = {
	keywords: [
		"inbox",
		"email"
	],
	char: "📤",
	fitzpatrick_scale: false,
	category: "objects"
};
var scroll$1 = {
	keywords: [
		"documents",
		"ancient",
		"history",
		"paper"
	],
	char: "📜",
	fitzpatrick_scale: false,
	category: "objects"
};
var page_with_curl$1 = {
	keywords: [
		"documents",
		"office",
		"paper"
	],
	char: "📃",
	fitzpatrick_scale: false,
	category: "objects"
};
var bookmark_tabs$1 = {
	keywords: [
		"favorite",
		"save",
		"order",
		"tidy"
	],
	char: "📑",
	fitzpatrick_scale: false,
	category: "objects"
};
var receipt$1 = {
	keywords: [
		"accounting",
		"expenses"
	],
	char: "🧾",
	fitzpatrick_scale: false,
	category: "objects"
};
var bar_chart$1 = {
	keywords: [
		"graph",
		"presentation",
		"stats"
	],
	char: "📊",
	fitzpatrick_scale: false,
	category: "objects"
};
var chart_with_upwards_trend$1 = {
	keywords: [
		"graph",
		"presentation",
		"stats",
		"recovery",
		"business",
		"economics",
		"money",
		"sales",
		"good",
		"success"
	],
	char: "📈",
	fitzpatrick_scale: false,
	category: "objects"
};
var chart_with_downwards_trend$1 = {
	keywords: [
		"graph",
		"presentation",
		"stats",
		"recession",
		"business",
		"economics",
		"money",
		"sales",
		"bad",
		"failure"
	],
	char: "📉",
	fitzpatrick_scale: false,
	category: "objects"
};
var page_facing_up$1 = {
	keywords: [
		"documents",
		"office",
		"paper",
		"information"
	],
	char: "📄",
	fitzpatrick_scale: false,
	category: "objects"
};
var date$1 = {
	keywords: [
		"calendar",
		"schedule"
	],
	char: "📅",
	fitzpatrick_scale: false,
	category: "objects"
};
var calendar$1 = {
	keywords: [
		"schedule",
		"date",
		"planning"
	],
	char: "📆",
	fitzpatrick_scale: false,
	category: "objects"
};
var spiral_calendar$1 = {
	keywords: [
		"date",
		"schedule",
		"planning"
	],
	char: "🗓",
	fitzpatrick_scale: false,
	category: "objects"
};
var card_index$1 = {
	keywords: [
		"business",
		"stationery"
	],
	char: "📇",
	fitzpatrick_scale: false,
	category: "objects"
};
var card_file_box$1 = {
	keywords: [
		"business",
		"stationery"
	],
	char: "🗃",
	fitzpatrick_scale: false,
	category: "objects"
};
var ballot_box$1 = {
	keywords: [
		"election",
		"vote"
	],
	char: "🗳",
	fitzpatrick_scale: false,
	category: "objects"
};
var file_cabinet$1 = {
	keywords: [
		"filing",
		"organizing"
	],
	char: "🗄",
	fitzpatrick_scale: false,
	category: "objects"
};
var clipboard$2 = {
	keywords: [
		"stationery",
		"documents"
	],
	char: "📋",
	fitzpatrick_scale: false,
	category: "objects"
};
var spiral_notepad$1 = {
	keywords: [
		"memo",
		"stationery"
	],
	char: "🗒",
	fitzpatrick_scale: false,
	category: "objects"
};
var file_folder$1 = {
	keywords: [
		"documents",
		"business",
		"office"
	],
	char: "📁",
	fitzpatrick_scale: false,
	category: "objects"
};
var open_file_folder$1 = {
	keywords: [
		"documents",
		"load"
	],
	char: "📂",
	fitzpatrick_scale: false,
	category: "objects"
};
var card_index_dividers$1 = {
	keywords: [
		"organizing",
		"business",
		"stationery"
	],
	char: "🗂",
	fitzpatrick_scale: false,
	category: "objects"
};
var newspaper_roll$1 = {
	keywords: [
		"press",
		"headline"
	],
	char: "🗞",
	fitzpatrick_scale: false,
	category: "objects"
};
var newspaper$1 = {
	keywords: [
		"press",
		"headline"
	],
	char: "📰",
	fitzpatrick_scale: false,
	category: "objects"
};
var notebook$1 = {
	keywords: [
		"stationery",
		"record",
		"notes",
		"paper",
		"study"
	],
	char: "📓",
	fitzpatrick_scale: false,
	category: "objects"
};
var closed_book$1 = {
	keywords: [
		"read",
		"library",
		"knowledge",
		"textbook",
		"learn"
	],
	char: "📕",
	fitzpatrick_scale: false,
	category: "objects"
};
var green_book$1 = {
	keywords: [
		"read",
		"library",
		"knowledge",
		"study"
	],
	char: "📗",
	fitzpatrick_scale: false,
	category: "objects"
};
var blue_book$1 = {
	keywords: [
		"read",
		"library",
		"knowledge",
		"learn",
		"study"
	],
	char: "📘",
	fitzpatrick_scale: false,
	category: "objects"
};
var orange_book$1 = {
	keywords: [
		"read",
		"library",
		"knowledge",
		"textbook",
		"study"
	],
	char: "📙",
	fitzpatrick_scale: false,
	category: "objects"
};
var notebook_with_decorative_cover$1 = {
	keywords: [
		"classroom",
		"notes",
		"record",
		"paper",
		"study"
	],
	char: "📔",
	fitzpatrick_scale: false,
	category: "objects"
};
var ledger$1 = {
	keywords: [
		"notes",
		"paper"
	],
	char: "📒",
	fitzpatrick_scale: false,
	category: "objects"
};
var books$1 = {
	keywords: [
		"literature",
		"library",
		"study"
	],
	char: "📚",
	fitzpatrick_scale: false,
	category: "objects"
};
var open_book$1 = {
	keywords: [
		"book",
		"read",
		"library",
		"knowledge",
		"literature",
		"learn",
		"study"
	],
	char: "📖",
	fitzpatrick_scale: false,
	category: "objects"
};
var safety_pin$1 = {
	keywords: [
		"diaper"
	],
	char: "🧷",
	fitzpatrick_scale: false,
	category: "objects"
};
var link$3 = {
	keywords: [
		"rings",
		"url"
	],
	char: "🔗",
	fitzpatrick_scale: false,
	category: "objects"
};
var paperclip$1 = {
	keywords: [
		"documents",
		"stationery"
	],
	char: "📎",
	fitzpatrick_scale: false,
	category: "objects"
};
var paperclips$1 = {
	keywords: [
		"documents",
		"stationery"
	],
	char: "🖇",
	fitzpatrick_scale: false,
	category: "objects"
};
var scissors$1 = {
	keywords: [
		"stationery",
		"cut"
	],
	char: "✂️",
	fitzpatrick_scale: false,
	category: "objects"
};
var triangular_ruler$1 = {
	keywords: [
		"stationery",
		"math",
		"architect",
		"sketch"
	],
	char: "📐",
	fitzpatrick_scale: false,
	category: "objects"
};
var straight_ruler$1 = {
	keywords: [
		"stationery",
		"calculate",
		"length",
		"math",
		"school",
		"drawing",
		"architect",
		"sketch"
	],
	char: "📏",
	fitzpatrick_scale: false,
	category: "objects"
};
var abacus$1 = {
	keywords: [
		"calculation"
	],
	char: "🧮",
	fitzpatrick_scale: false,
	category: "objects"
};
var pushpin$1 = {
	keywords: [
		"stationery",
		"mark",
		"here"
	],
	char: "📌",
	fitzpatrick_scale: false,
	category: "objects"
};
var round_pushpin$1 = {
	keywords: [
		"stationery",
		"location",
		"map",
		"here"
	],
	char: "📍",
	fitzpatrick_scale: false,
	category: "objects"
};
var triangular_flag_on_post$1 = {
	keywords: [
		"mark",
		"milestone",
		"place"
	],
	char: "🚩",
	fitzpatrick_scale: false,
	category: "objects"
};
var white_flag$1 = {
	keywords: [
		"losing",
		"loser",
		"lost",
		"surrender",
		"give up",
		"fail"
	],
	char: "🏳",
	fitzpatrick_scale: false,
	category: "objects"
};
var black_flag$1 = {
	keywords: [
		"pirate"
	],
	char: "🏴",
	fitzpatrick_scale: false,
	category: "objects"
};
var rainbow_flag$1 = {
	keywords: [
		"flag",
		"rainbow",
		"pride",
		"gay",
		"lgbt",
		"glbt",
		"queer",
		"homosexual",
		"lesbian",
		"bisexual",
		"transgender"
	],
	char: "🏳️‍🌈",
	fitzpatrick_scale: false,
	category: "objects"
};
var closed_lock_with_key$1 = {
	keywords: [
		"security",
		"privacy"
	],
	char: "🔐",
	fitzpatrick_scale: false,
	category: "objects"
};
var lock$1 = {
	keywords: [
		"security",
		"password",
		"padlock"
	],
	char: "🔒",
	fitzpatrick_scale: false,
	category: "objects"
};
var unlock$1 = {
	keywords: [
		"privacy",
		"security"
	],
	char: "🔓",
	fitzpatrick_scale: false,
	category: "objects"
};
var lock_with_ink_pen$1 = {
	keywords: [
		"security",
		"secret"
	],
	char: "🔏",
	fitzpatrick_scale: false,
	category: "objects"
};
var pen$1 = {
	keywords: [
		"stationery",
		"writing",
		"write"
	],
	char: "🖊",
	fitzpatrick_scale: false,
	category: "objects"
};
var fountain_pen$1 = {
	keywords: [
		"stationery",
		"writing",
		"write"
	],
	char: "🖋",
	fitzpatrick_scale: false,
	category: "objects"
};
var black_nib$1 = {
	keywords: [
		"pen",
		"stationery",
		"writing",
		"write"
	],
	char: "✒️",
	fitzpatrick_scale: false,
	category: "objects"
};
var memo$1 = {
	keywords: [
		"write",
		"documents",
		"stationery",
		"pencil",
		"paper",
		"writing",
		"legal",
		"exam",
		"quiz",
		"test",
		"study",
		"compose"
	],
	char: "📝",
	fitzpatrick_scale: false,
	category: "objects"
};
var pencil2$1 = {
	keywords: [
		"stationery",
		"write",
		"paper",
		"writing",
		"school",
		"study"
	],
	char: "✏️",
	fitzpatrick_scale: false,
	category: "objects"
};
var crayon$1 = {
	keywords: [
		"drawing",
		"creativity"
	],
	char: "🖍",
	fitzpatrick_scale: false,
	category: "objects"
};
var paintbrush$1 = {
	keywords: [
		"drawing",
		"creativity",
		"art"
	],
	char: "🖌",
	fitzpatrick_scale: false,
	category: "objects"
};
var mag$1 = {
	keywords: [
		"search",
		"zoom",
		"find",
		"detective"
	],
	char: "🔍",
	fitzpatrick_scale: false,
	category: "objects"
};
var mag_right$1 = {
	keywords: [
		"search",
		"zoom",
		"find",
		"detective"
	],
	char: "🔎",
	fitzpatrick_scale: false,
	category: "objects"
};
var heart$1 = {
	keywords: [
		"love",
		"like",
		"valentines"
	],
	char: "❤️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var orange_heart$1 = {
	keywords: [
		"love",
		"like",
		"affection",
		"valentines"
	],
	char: "🧡",
	fitzpatrick_scale: false,
	category: "symbols"
};
var yellow_heart$1 = {
	keywords: [
		"love",
		"like",
		"affection",
		"valentines"
	],
	char: "💛",
	fitzpatrick_scale: false,
	category: "symbols"
};
var green_heart$1 = {
	keywords: [
		"love",
		"like",
		"affection",
		"valentines"
	],
	char: "💚",
	fitzpatrick_scale: false,
	category: "symbols"
};
var blue_heart$1 = {
	keywords: [
		"love",
		"like",
		"affection",
		"valentines"
	],
	char: "💙",
	fitzpatrick_scale: false,
	category: "symbols"
};
var purple_heart$1 = {
	keywords: [
		"love",
		"like",
		"affection",
		"valentines"
	],
	char: "💜",
	fitzpatrick_scale: false,
	category: "symbols"
};
var black_heart$1 = {
	keywords: [
		"evil"
	],
	char: "🖤",
	fitzpatrick_scale: false,
	category: "symbols"
};
var broken_heart$1 = {
	keywords: [
		"sad",
		"sorry",
		"break",
		"heart",
		"heartbreak"
	],
	char: "💔",
	fitzpatrick_scale: false,
	category: "symbols"
};
var heavy_heart_exclamation$1 = {
	keywords: [
		"decoration",
		"love"
	],
	char: "❣",
	fitzpatrick_scale: false,
	category: "symbols"
};
var two_hearts$1 = {
	keywords: [
		"love",
		"like",
		"affection",
		"valentines",
		"heart"
	],
	char: "💕",
	fitzpatrick_scale: false,
	category: "symbols"
};
var revolving_hearts$1 = {
	keywords: [
		"love",
		"like",
		"affection",
		"valentines"
	],
	char: "💞",
	fitzpatrick_scale: false,
	category: "symbols"
};
var heartbeat$1 = {
	keywords: [
		"love",
		"like",
		"affection",
		"valentines",
		"pink",
		"heart"
	],
	char: "💓",
	fitzpatrick_scale: false,
	category: "symbols"
};
var heartpulse$1 = {
	keywords: [
		"like",
		"love",
		"affection",
		"valentines",
		"pink"
	],
	char: "💗",
	fitzpatrick_scale: false,
	category: "symbols"
};
var sparkling_heart$1 = {
	keywords: [
		"love",
		"like",
		"affection",
		"valentines"
	],
	char: "💖",
	fitzpatrick_scale: false,
	category: "symbols"
};
var cupid$1 = {
	keywords: [
		"love",
		"like",
		"heart",
		"affection",
		"valentines"
	],
	char: "💘",
	fitzpatrick_scale: false,
	category: "symbols"
};
var gift_heart$1 = {
	keywords: [
		"love",
		"valentines"
	],
	char: "💝",
	fitzpatrick_scale: false,
	category: "symbols"
};
var heart_decoration$1 = {
	keywords: [
		"purple-square",
		"love",
		"like"
	],
	char: "💟",
	fitzpatrick_scale: false,
	category: "symbols"
};
var peace_symbol$1 = {
	keywords: [
		"hippie"
	],
	char: "☮",
	fitzpatrick_scale: false,
	category: "symbols"
};
var latin_cross$1 = {
	keywords: [
		"christianity"
	],
	char: "✝",
	fitzpatrick_scale: false,
	category: "symbols"
};
var star_and_crescent$1 = {
	keywords: [
		"islam"
	],
	char: "☪",
	fitzpatrick_scale: false,
	category: "symbols"
};
var om$1 = {
	keywords: [
		"hinduism",
		"buddhism",
		"sikhism",
		"jainism"
	],
	char: "🕉",
	fitzpatrick_scale: false,
	category: "symbols"
};
var wheel_of_dharma$1 = {
	keywords: [
		"hinduism",
		"buddhism",
		"sikhism",
		"jainism"
	],
	char: "☸",
	fitzpatrick_scale: false,
	category: "symbols"
};
var star_of_david$1 = {
	keywords: [
		"judaism"
	],
	char: "✡",
	fitzpatrick_scale: false,
	category: "symbols"
};
var six_pointed_star$1 = {
	keywords: [
		"purple-square",
		"religion",
		"jewish",
		"hexagram"
	],
	char: "🔯",
	fitzpatrick_scale: false,
	category: "symbols"
};
var menorah$1 = {
	keywords: [
		"hanukkah",
		"candles",
		"jewish"
	],
	char: "🕎",
	fitzpatrick_scale: false,
	category: "symbols"
};
var yin_yang$1 = {
	keywords: [
		"balance"
	],
	char: "☯",
	fitzpatrick_scale: false,
	category: "symbols"
};
var orthodox_cross$1 = {
	keywords: [
		"suppedaneum",
		"religion"
	],
	char: "☦",
	fitzpatrick_scale: false,
	category: "symbols"
};
var place_of_worship$1 = {
	keywords: [
		"religion",
		"church",
		"temple",
		"prayer"
	],
	char: "🛐",
	fitzpatrick_scale: false,
	category: "symbols"
};
var ophiuchus$1 = {
	keywords: [
		"sign",
		"purple-square",
		"constellation",
		"astrology"
	],
	char: "⛎",
	fitzpatrick_scale: false,
	category: "symbols"
};
var aries$1 = {
	keywords: [
		"sign",
		"purple-square",
		"zodiac",
		"astrology"
	],
	char: "♈",
	fitzpatrick_scale: false,
	category: "symbols"
};
var taurus$1 = {
	keywords: [
		"purple-square",
		"sign",
		"zodiac",
		"astrology"
	],
	char: "♉",
	fitzpatrick_scale: false,
	category: "symbols"
};
var gemini$1 = {
	keywords: [
		"sign",
		"zodiac",
		"purple-square",
		"astrology"
	],
	char: "♊",
	fitzpatrick_scale: false,
	category: "symbols"
};
var cancer$1 = {
	keywords: [
		"sign",
		"zodiac",
		"purple-square",
		"astrology"
	],
	char: "♋",
	fitzpatrick_scale: false,
	category: "symbols"
};
var leo$1 = {
	keywords: [
		"sign",
		"purple-square",
		"zodiac",
		"astrology"
	],
	char: "♌",
	fitzpatrick_scale: false,
	category: "symbols"
};
var virgo$1 = {
	keywords: [
		"sign",
		"zodiac",
		"purple-square",
		"astrology"
	],
	char: "♍",
	fitzpatrick_scale: false,
	category: "symbols"
};
var libra$1 = {
	keywords: [
		"sign",
		"purple-square",
		"zodiac",
		"astrology"
	],
	char: "♎",
	fitzpatrick_scale: false,
	category: "symbols"
};
var scorpius$1 = {
	keywords: [
		"sign",
		"zodiac",
		"purple-square",
		"astrology",
		"scorpio"
	],
	char: "♏",
	fitzpatrick_scale: false,
	category: "symbols"
};
var sagittarius$1 = {
	keywords: [
		"sign",
		"zodiac",
		"purple-square",
		"astrology"
	],
	char: "♐",
	fitzpatrick_scale: false,
	category: "symbols"
};
var capricorn$1 = {
	keywords: [
		"sign",
		"zodiac",
		"purple-square",
		"astrology"
	],
	char: "♑",
	fitzpatrick_scale: false,
	category: "symbols"
};
var aquarius$1 = {
	keywords: [
		"sign",
		"purple-square",
		"zodiac",
		"astrology"
	],
	char: "♒",
	fitzpatrick_scale: false,
	category: "symbols"
};
var pisces$1 = {
	keywords: [
		"purple-square",
		"sign",
		"zodiac",
		"astrology"
	],
	char: "♓",
	fitzpatrick_scale: false,
	category: "symbols"
};
var id$1 = {
	keywords: [
		"purple-square",
		"words"
	],
	char: "🆔",
	fitzpatrick_scale: false,
	category: "symbols"
};
var atom_symbol$1 = {
	keywords: [
		"science",
		"physics",
		"chemistry"
	],
	char: "⚛",
	fitzpatrick_scale: false,
	category: "symbols"
};
var u7a7a$1 = {
	keywords: [
		"kanji",
		"japanese",
		"chinese",
		"empty",
		"sky",
		"blue-square"
	],
	char: "🈳",
	fitzpatrick_scale: false,
	category: "symbols"
};
var u5272$1 = {
	keywords: [
		"cut",
		"divide",
		"chinese",
		"kanji",
		"pink-square"
	],
	char: "🈹",
	fitzpatrick_scale: false,
	category: "symbols"
};
var radioactive$1 = {
	keywords: [
		"nuclear",
		"danger"
	],
	char: "☢",
	fitzpatrick_scale: false,
	category: "symbols"
};
var biohazard$1 = {
	keywords: [
		"danger"
	],
	char: "☣",
	fitzpatrick_scale: false,
	category: "symbols"
};
var mobile_phone_off$1 = {
	keywords: [
		"mute",
		"orange-square",
		"silence",
		"quiet"
	],
	char: "📴",
	fitzpatrick_scale: false,
	category: "symbols"
};
var vibration_mode$1 = {
	keywords: [
		"orange-square",
		"phone"
	],
	char: "📳",
	fitzpatrick_scale: false,
	category: "symbols"
};
var u6709$1 = {
	keywords: [
		"orange-square",
		"chinese",
		"have",
		"kanji"
	],
	char: "🈶",
	fitzpatrick_scale: false,
	category: "symbols"
};
var u7121$1 = {
	keywords: [
		"nothing",
		"chinese",
		"kanji",
		"japanese",
		"orange-square"
	],
	char: "🈚",
	fitzpatrick_scale: false,
	category: "symbols"
};
var u7533$1 = {
	keywords: [
		"chinese",
		"japanese",
		"kanji",
		"orange-square"
	],
	char: "🈸",
	fitzpatrick_scale: false,
	category: "symbols"
};
var u55b6$1 = {
	keywords: [
		"japanese",
		"opening hours",
		"orange-square"
	],
	char: "🈺",
	fitzpatrick_scale: false,
	category: "symbols"
};
var u6708$1 = {
	keywords: [
		"chinese",
		"month",
		"moon",
		"japanese",
		"orange-square",
		"kanji"
	],
	char: "🈷️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var eight_pointed_black_star$1 = {
	keywords: [
		"orange-square",
		"shape",
		"polygon"
	],
	char: "✴️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var vs$1 = {
	keywords: [
		"words",
		"orange-square"
	],
	char: "🆚",
	fitzpatrick_scale: false,
	category: "symbols"
};
var accept$1 = {
	keywords: [
		"ok",
		"good",
		"chinese",
		"kanji",
		"agree",
		"yes",
		"orange-circle"
	],
	char: "🉑",
	fitzpatrick_scale: false,
	category: "symbols"
};
var white_flower$1 = {
	keywords: [
		"japanese",
		"spring"
	],
	char: "💮",
	fitzpatrick_scale: false,
	category: "symbols"
};
var ideograph_advantage$1 = {
	keywords: [
		"chinese",
		"kanji",
		"obtain",
		"get",
		"circle"
	],
	char: "🉐",
	fitzpatrick_scale: false,
	category: "symbols"
};
var secret$1 = {
	keywords: [
		"privacy",
		"chinese",
		"sshh",
		"kanji",
		"red-circle"
	],
	char: "㊙️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var congratulations$1 = {
	keywords: [
		"chinese",
		"kanji",
		"japanese",
		"red-circle"
	],
	char: "㊗️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var u5408$1 = {
	keywords: [
		"japanese",
		"chinese",
		"join",
		"kanji",
		"red-square"
	],
	char: "🈴",
	fitzpatrick_scale: false,
	category: "symbols"
};
var u6e80$1 = {
	keywords: [
		"full",
		"chinese",
		"japanese",
		"red-square",
		"kanji"
	],
	char: "🈵",
	fitzpatrick_scale: false,
	category: "symbols"
};
var u7981$1 = {
	keywords: [
		"kanji",
		"japanese",
		"chinese",
		"forbidden",
		"limit",
		"restricted",
		"red-square"
	],
	char: "🈲",
	fitzpatrick_scale: false,
	category: "symbols"
};
var a$2 = {
	keywords: [
		"red-square",
		"alphabet",
		"letter"
	],
	char: "🅰️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var b$1 = {
	keywords: [
		"red-square",
		"alphabet",
		"letter"
	],
	char: "🅱️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var ab$1 = {
	keywords: [
		"red-square",
		"alphabet"
	],
	char: "🆎",
	fitzpatrick_scale: false,
	category: "symbols"
};
var cl$1 = {
	keywords: [
		"alphabet",
		"words",
		"red-square"
	],
	char: "🆑",
	fitzpatrick_scale: false,
	category: "symbols"
};
var o2$1 = {
	keywords: [
		"alphabet",
		"red-square",
		"letter"
	],
	char: "🅾️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var sos$1 = {
	keywords: [
		"help",
		"red-square",
		"words",
		"emergency",
		"911"
	],
	char: "🆘",
	fitzpatrick_scale: false,
	category: "symbols"
};
var no_entry$1 = {
	keywords: [
		"limit",
		"security",
		"privacy",
		"bad",
		"denied",
		"stop",
		"circle"
	],
	char: "⛔",
	fitzpatrick_scale: false,
	category: "symbols"
};
var name_badge$1 = {
	keywords: [
		"fire",
		"forbid"
	],
	char: "📛",
	fitzpatrick_scale: false,
	category: "symbols"
};
var no_entry_sign$1 = {
	keywords: [
		"forbid",
		"stop",
		"limit",
		"denied",
		"disallow",
		"circle"
	],
	char: "🚫",
	fitzpatrick_scale: false,
	category: "symbols"
};
var x$1 = {
	keywords: [
		"no",
		"delete",
		"remove",
		"cancel",
		"red"
	],
	char: "❌",
	fitzpatrick_scale: false,
	category: "symbols"
};
var o$2 = {
	keywords: [
		"circle",
		"round"
	],
	char: "⭕",
	fitzpatrick_scale: false,
	category: "symbols"
};
var stop_sign$1 = {
	keywords: [
		"stop"
	],
	char: "🛑",
	fitzpatrick_scale: false,
	category: "symbols"
};
var anger$1 = {
	keywords: [
		"angry",
		"mad"
	],
	char: "💢",
	fitzpatrick_scale: false,
	category: "symbols"
};
var hotsprings$1 = {
	keywords: [
		"bath",
		"warm",
		"relax"
	],
	char: "♨️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var no_pedestrians$1 = {
	keywords: [
		"rules",
		"crossing",
		"walking",
		"circle"
	],
	char: "🚷",
	fitzpatrick_scale: false,
	category: "symbols"
};
var do_not_litter$1 = {
	keywords: [
		"trash",
		"bin",
		"garbage",
		"circle"
	],
	char: "🚯",
	fitzpatrick_scale: false,
	category: "symbols"
};
var no_bicycles$1 = {
	keywords: [
		"cyclist",
		"prohibited",
		"circle"
	],
	char: "🚳",
	fitzpatrick_scale: false,
	category: "symbols"
};
var underage$1 = {
	keywords: [
		"18",
		"drink",
		"pub",
		"night",
		"minor",
		"circle"
	],
	char: "🔞",
	fitzpatrick_scale: false,
	category: "symbols"
};
var no_mobile_phones$1 = {
	keywords: [
		"iphone",
		"mute",
		"circle"
	],
	char: "📵",
	fitzpatrick_scale: false,
	category: "symbols"
};
var exclamation$1 = {
	keywords: [
		"heavy_exclamation_mark",
		"danger",
		"surprise",
		"punctuation",
		"wow",
		"warning"
	],
	char: "❗",
	fitzpatrick_scale: false,
	category: "symbols"
};
var grey_exclamation$1 = {
	keywords: [
		"surprise",
		"punctuation",
		"gray",
		"wow",
		"warning"
	],
	char: "❕",
	fitzpatrick_scale: false,
	category: "symbols"
};
var question$1 = {
	keywords: [
		"doubt",
		"confused"
	],
	char: "❓",
	fitzpatrick_scale: false,
	category: "symbols"
};
var grey_question$1 = {
	keywords: [
		"doubts",
		"gray",
		"huh",
		"confused"
	],
	char: "❔",
	fitzpatrick_scale: false,
	category: "symbols"
};
var bangbang$1 = {
	keywords: [
		"exclamation",
		"surprise"
	],
	char: "‼️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var interrobang$1 = {
	keywords: [
		"wat",
		"punctuation",
		"surprise"
	],
	char: "⁉️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var low_brightness$1 = {
	keywords: [
		"sun",
		"afternoon",
		"warm",
		"summer"
	],
	char: "🔅",
	fitzpatrick_scale: false,
	category: "symbols"
};
var high_brightness$1 = {
	keywords: [
		"sun",
		"light"
	],
	char: "🔆",
	fitzpatrick_scale: false,
	category: "symbols"
};
var trident$1 = {
	keywords: [
		"weapon",
		"spear"
	],
	char: "🔱",
	fitzpatrick_scale: false,
	category: "symbols"
};
var fleur_de_lis$1 = {
	keywords: [
		"decorative",
		"scout"
	],
	char: "⚜",
	fitzpatrick_scale: false,
	category: "symbols"
};
var part_alternation_mark$1 = {
	keywords: [
		"graph",
		"presentation",
		"stats",
		"business",
		"economics",
		"bad"
	],
	char: "〽️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var warning$1 = {
	keywords: [
		"exclamation",
		"wip",
		"alert",
		"error",
		"problem",
		"issue"
	],
	char: "⚠️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var children_crossing$1 = {
	keywords: [
		"school",
		"warning",
		"danger",
		"sign",
		"driving",
		"yellow-diamond"
	],
	char: "🚸",
	fitzpatrick_scale: false,
	category: "symbols"
};
var beginner$1 = {
	keywords: [
		"badge",
		"shield"
	],
	char: "🔰",
	fitzpatrick_scale: false,
	category: "symbols"
};
var recycle$1 = {
	keywords: [
		"arrow",
		"environment",
		"garbage",
		"trash"
	],
	char: "♻️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var u6307$1 = {
	keywords: [
		"chinese",
		"point",
		"green-square",
		"kanji"
	],
	char: "🈯",
	fitzpatrick_scale: false,
	category: "symbols"
};
var chart$1 = {
	keywords: [
		"green-square",
		"graph",
		"presentation",
		"stats"
	],
	char: "💹",
	fitzpatrick_scale: false,
	category: "symbols"
};
var sparkle$1 = {
	keywords: [
		"stars",
		"green-square",
		"awesome",
		"good",
		"fireworks"
	],
	char: "❇️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var eight_spoked_asterisk$1 = {
	keywords: [
		"star",
		"sparkle",
		"green-square"
	],
	char: "✳️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var negative_squared_cross_mark$1 = {
	keywords: [
		"x",
		"green-square",
		"no",
		"deny"
	],
	char: "❎",
	fitzpatrick_scale: false,
	category: "symbols"
};
var white_check_mark$1 = {
	keywords: [
		"green-square",
		"ok",
		"agree",
		"vote",
		"election",
		"answer",
		"tick"
	],
	char: "✅",
	fitzpatrick_scale: false,
	category: "symbols"
};
var diamond_shape_with_a_dot_inside$1 = {
	keywords: [
		"jewel",
		"blue",
		"gem",
		"crystal",
		"fancy"
	],
	char: "💠",
	fitzpatrick_scale: false,
	category: "symbols"
};
var cyclone$1 = {
	keywords: [
		"weather",
		"swirl",
		"blue",
		"cloud",
		"vortex",
		"spiral",
		"whirlpool",
		"spin",
		"tornado",
		"hurricane",
		"typhoon"
	],
	char: "🌀",
	fitzpatrick_scale: false,
	category: "symbols"
};
var loop$1 = {
	keywords: [
		"tape",
		"cassette"
	],
	char: "➿",
	fitzpatrick_scale: false,
	category: "symbols"
};
var globe_with_meridians$1 = {
	keywords: [
		"earth",
		"international",
		"world",
		"internet",
		"interweb",
		"i18n"
	],
	char: "🌐",
	fitzpatrick_scale: false,
	category: "symbols"
};
var m$1 = {
	keywords: [
		"alphabet",
		"blue-circle",
		"letter"
	],
	char: "Ⓜ️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var atm$1 = {
	keywords: [
		"money",
		"sales",
		"cash",
		"blue-square",
		"payment",
		"bank"
	],
	char: "🏧",
	fitzpatrick_scale: false,
	category: "symbols"
};
var sa$1 = {
	keywords: [
		"japanese",
		"blue-square",
		"katakana"
	],
	char: "🈂️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var passport_control$1 = {
	keywords: [
		"custom",
		"blue-square"
	],
	char: "🛂",
	fitzpatrick_scale: false,
	category: "symbols"
};
var customs$1 = {
	keywords: [
		"passport",
		"border",
		"blue-square"
	],
	char: "🛃",
	fitzpatrick_scale: false,
	category: "symbols"
};
var baggage_claim$1 = {
	keywords: [
		"blue-square",
		"airport",
		"transport"
	],
	char: "🛄",
	fitzpatrick_scale: false,
	category: "symbols"
};
var left_luggage$1 = {
	keywords: [
		"blue-square",
		"travel"
	],
	char: "🛅",
	fitzpatrick_scale: false,
	category: "symbols"
};
var wheelchair$1 = {
	keywords: [
		"blue-square",
		"disabled",
		"a11y",
		"accessibility"
	],
	char: "♿",
	fitzpatrick_scale: false,
	category: "symbols"
};
var no_smoking$1 = {
	keywords: [
		"cigarette",
		"blue-square",
		"smell",
		"smoke"
	],
	char: "🚭",
	fitzpatrick_scale: false,
	category: "symbols"
};
var wc$1 = {
	keywords: [
		"toilet",
		"restroom",
		"blue-square"
	],
	char: "🚾",
	fitzpatrick_scale: false,
	category: "symbols"
};
var parking$1 = {
	keywords: [
		"cars",
		"blue-square",
		"alphabet",
		"letter"
	],
	char: "🅿️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var potable_water$1 = {
	keywords: [
		"blue-square",
		"liquid",
		"restroom",
		"cleaning",
		"faucet"
	],
	char: "🚰",
	fitzpatrick_scale: false,
	category: "symbols"
};
var mens$1 = {
	keywords: [
		"toilet",
		"restroom",
		"wc",
		"blue-square",
		"gender",
		"male"
	],
	char: "🚹",
	fitzpatrick_scale: false,
	category: "symbols"
};
var womens$1 = {
	keywords: [
		"purple-square",
		"woman",
		"female",
		"toilet",
		"loo",
		"restroom",
		"gender"
	],
	char: "🚺",
	fitzpatrick_scale: false,
	category: "symbols"
};
var baby_symbol$1 = {
	keywords: [
		"orange-square",
		"child"
	],
	char: "🚼",
	fitzpatrick_scale: false,
	category: "symbols"
};
var restroom$1 = {
	keywords: [
		"blue-square",
		"toilet",
		"refresh",
		"wc",
		"gender"
	],
	char: "🚻",
	fitzpatrick_scale: false,
	category: "symbols"
};
var put_litter_in_its_place$1 = {
	keywords: [
		"blue-square",
		"sign",
		"human",
		"info"
	],
	char: "🚮",
	fitzpatrick_scale: false,
	category: "symbols"
};
var cinema$1 = {
	keywords: [
		"blue-square",
		"record",
		"film",
		"movie",
		"curtain",
		"stage",
		"theater"
	],
	char: "🎦",
	fitzpatrick_scale: false,
	category: "symbols"
};
var signal_strength$1 = {
	keywords: [
		"blue-square",
		"reception",
		"phone",
		"internet",
		"connection",
		"wifi",
		"bluetooth",
		"bars"
	],
	char: "📶",
	fitzpatrick_scale: false,
	category: "symbols"
};
var koko$1 = {
	keywords: [
		"blue-square",
		"here",
		"katakana",
		"japanese",
		"destination"
	],
	char: "🈁",
	fitzpatrick_scale: false,
	category: "symbols"
};
var ng$1 = {
	keywords: [
		"blue-square",
		"words",
		"shape",
		"icon"
	],
	char: "🆖",
	fitzpatrick_scale: false,
	category: "symbols"
};
var ok$1 = {
	keywords: [
		"good",
		"agree",
		"yes",
		"blue-square"
	],
	char: "🆗",
	fitzpatrick_scale: false,
	category: "symbols"
};
var up$1 = {
	keywords: [
		"blue-square",
		"above",
		"high"
	],
	char: "🆙",
	fitzpatrick_scale: false,
	category: "symbols"
};
var cool$1 = {
	keywords: [
		"words",
		"blue-square"
	],
	char: "🆒",
	fitzpatrick_scale: false,
	category: "symbols"
};
var free$1 = {
	keywords: [
		"blue-square",
		"words"
	],
	char: "🆓",
	fitzpatrick_scale: false,
	category: "symbols"
};
var zero$2 = {
	keywords: [
		"0",
		"numbers",
		"blue-square",
		"null"
	],
	char: "0️⃣",
	fitzpatrick_scale: false,
	category: "symbols"
};
var one$1 = {
	keywords: [
		"blue-square",
		"numbers",
		"1"
	],
	char: "1️⃣",
	fitzpatrick_scale: false,
	category: "symbols"
};
var two$1 = {
	keywords: [
		"numbers",
		"2",
		"prime",
		"blue-square"
	],
	char: "2️⃣",
	fitzpatrick_scale: false,
	category: "symbols"
};
var three$1 = {
	keywords: [
		"3",
		"numbers",
		"prime",
		"blue-square"
	],
	char: "3️⃣",
	fitzpatrick_scale: false,
	category: "symbols"
};
var four$1 = {
	keywords: [
		"4",
		"numbers",
		"blue-square"
	],
	char: "4️⃣",
	fitzpatrick_scale: false,
	category: "symbols"
};
var five$1 = {
	keywords: [
		"5",
		"numbers",
		"blue-square",
		"prime"
	],
	char: "5️⃣",
	fitzpatrick_scale: false,
	category: "symbols"
};
var six$1 = {
	keywords: [
		"6",
		"numbers",
		"blue-square"
	],
	char: "6️⃣",
	fitzpatrick_scale: false,
	category: "symbols"
};
var seven$1 = {
	keywords: [
		"7",
		"numbers",
		"blue-square",
		"prime"
	],
	char: "7️⃣",
	fitzpatrick_scale: false,
	category: "symbols"
};
var eight$1 = {
	keywords: [
		"8",
		"blue-square",
		"numbers"
	],
	char: "8️⃣",
	fitzpatrick_scale: false,
	category: "symbols"
};
var nine$1 = {
	keywords: [
		"blue-square",
		"numbers",
		"9"
	],
	char: "9️⃣",
	fitzpatrick_scale: false,
	category: "symbols"
};
var keycap_ten$1 = {
	keywords: [
		"numbers",
		"10",
		"blue-square"
	],
	char: "🔟",
	fitzpatrick_scale: false,
	category: "symbols"
};
var asterisk$1 = {
	keywords: [
		"star",
		"keycap"
	],
	char: "*⃣",
	fitzpatrick_scale: false,
	category: "symbols"
};
var eject_button$1 = {
	keywords: [
		"blue-square"
	],
	char: "⏏️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var arrow_forward$1 = {
	keywords: [
		"blue-square",
		"right",
		"direction",
		"play"
	],
	char: "▶️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var pause_button$1 = {
	keywords: [
		"pause",
		"blue-square"
	],
	char: "⏸",
	fitzpatrick_scale: false,
	category: "symbols"
};
var next_track_button$1 = {
	keywords: [
		"forward",
		"next",
		"blue-square"
	],
	char: "⏭",
	fitzpatrick_scale: false,
	category: "symbols"
};
var stop_button$1 = {
	keywords: [
		"blue-square"
	],
	char: "⏹",
	fitzpatrick_scale: false,
	category: "symbols"
};
var record_button$1 = {
	keywords: [
		"blue-square"
	],
	char: "⏺",
	fitzpatrick_scale: false,
	category: "symbols"
};
var play_or_pause_button$1 = {
	keywords: [
		"blue-square",
		"play",
		"pause"
	],
	char: "⏯",
	fitzpatrick_scale: false,
	category: "symbols"
};
var previous_track_button$1 = {
	keywords: [
		"backward"
	],
	char: "⏮",
	fitzpatrick_scale: false,
	category: "symbols"
};
var fast_forward$1 = {
	keywords: [
		"blue-square",
		"play",
		"speed",
		"continue"
	],
	char: "⏩",
	fitzpatrick_scale: false,
	category: "symbols"
};
var rewind$1 = {
	keywords: [
		"play",
		"blue-square"
	],
	char: "⏪",
	fitzpatrick_scale: false,
	category: "symbols"
};
var twisted_rightwards_arrows$1 = {
	keywords: [
		"blue-square",
		"shuffle",
		"music",
		"random"
	],
	char: "🔀",
	fitzpatrick_scale: false,
	category: "symbols"
};
var repeat$1 = {
	keywords: [
		"loop",
		"record"
	],
	char: "🔁",
	fitzpatrick_scale: false,
	category: "symbols"
};
var repeat_one$1 = {
	keywords: [
		"blue-square",
		"loop"
	],
	char: "🔂",
	fitzpatrick_scale: false,
	category: "symbols"
};
var arrow_backward$1 = {
	keywords: [
		"blue-square",
		"left",
		"direction"
	],
	char: "◀️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var arrow_up_small$1 = {
	keywords: [
		"blue-square",
		"triangle",
		"direction",
		"point",
		"forward",
		"top"
	],
	char: "🔼",
	fitzpatrick_scale: false,
	category: "symbols"
};
var arrow_down_small$1 = {
	keywords: [
		"blue-square",
		"direction",
		"bottom"
	],
	char: "🔽",
	fitzpatrick_scale: false,
	category: "symbols"
};
var arrow_double_up$1 = {
	keywords: [
		"blue-square",
		"direction",
		"top"
	],
	char: "⏫",
	fitzpatrick_scale: false,
	category: "symbols"
};
var arrow_double_down$1 = {
	keywords: [
		"blue-square",
		"direction",
		"bottom"
	],
	char: "⏬",
	fitzpatrick_scale: false,
	category: "symbols"
};
var arrow_right$1 = {
	keywords: [
		"blue-square",
		"next"
	],
	char: "➡️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var arrow_left$1 = {
	keywords: [
		"blue-square",
		"previous",
		"back"
	],
	char: "⬅️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var arrow_up$1 = {
	keywords: [
		"blue-square",
		"continue",
		"top",
		"direction"
	],
	char: "⬆️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var arrow_down$1 = {
	keywords: [
		"blue-square",
		"direction",
		"bottom"
	],
	char: "⬇️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var arrow_upper_right$1 = {
	keywords: [
		"blue-square",
		"point",
		"direction",
		"diagonal",
		"northeast"
	],
	char: "↗️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var arrow_lower_right$1 = {
	keywords: [
		"blue-square",
		"direction",
		"diagonal",
		"southeast"
	],
	char: "↘️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var arrow_lower_left$1 = {
	keywords: [
		"blue-square",
		"direction",
		"diagonal",
		"southwest"
	],
	char: "↙️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var arrow_upper_left$1 = {
	keywords: [
		"blue-square",
		"point",
		"direction",
		"diagonal",
		"northwest"
	],
	char: "↖️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var arrow_up_down$1 = {
	keywords: [
		"blue-square",
		"direction",
		"way",
		"vertical"
	],
	char: "↕️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var left_right_arrow$1 = {
	keywords: [
		"shape",
		"direction",
		"horizontal",
		"sideways"
	],
	char: "↔️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var arrows_counterclockwise$1 = {
	keywords: [
		"blue-square",
		"sync",
		"cycle"
	],
	char: "🔄",
	fitzpatrick_scale: false,
	category: "symbols"
};
var arrow_right_hook$1 = {
	keywords: [
		"blue-square",
		"return",
		"rotate",
		"direction"
	],
	char: "↪️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var leftwards_arrow_with_hook$1 = {
	keywords: [
		"back",
		"return",
		"blue-square",
		"undo",
		"enter"
	],
	char: "↩️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var arrow_heading_up$1 = {
	keywords: [
		"blue-square",
		"direction",
		"top"
	],
	char: "⤴️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var arrow_heading_down$1 = {
	keywords: [
		"blue-square",
		"direction",
		"bottom"
	],
	char: "⤵️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var hash$1 = {
	keywords: [
		"symbol",
		"blue-square",
		"twitter"
	],
	char: "#️⃣",
	fitzpatrick_scale: false,
	category: "symbols"
};
var information_source$1 = {
	keywords: [
		"blue-square",
		"alphabet",
		"letter"
	],
	char: "ℹ️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var abc$1 = {
	keywords: [
		"blue-square",
		"alphabet"
	],
	char: "🔤",
	fitzpatrick_scale: false,
	category: "symbols"
};
var abcd$1 = {
	keywords: [
		"blue-square",
		"alphabet"
	],
	char: "🔡",
	fitzpatrick_scale: false,
	category: "symbols"
};
var capital_abcd$1 = {
	keywords: [
		"alphabet",
		"words",
		"blue-square"
	],
	char: "🔠",
	fitzpatrick_scale: false,
	category: "symbols"
};
var symbols$1 = {
	keywords: [
		"blue-square",
		"music",
		"note",
		"ampersand",
		"percent",
		"glyphs",
		"characters"
	],
	char: "🔣",
	fitzpatrick_scale: false,
	category: "symbols"
};
var musical_note$1 = {
	keywords: [
		"score",
		"tone",
		"sound"
	],
	char: "🎵",
	fitzpatrick_scale: false,
	category: "symbols"
};
var notes$1 = {
	keywords: [
		"music",
		"score"
	],
	char: "🎶",
	fitzpatrick_scale: false,
	category: "symbols"
};
var wavy_dash$1 = {
	keywords: [
		"draw",
		"line",
		"moustache",
		"mustache",
		"squiggle",
		"scribble"
	],
	char: "〰️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var curly_loop$1 = {
	keywords: [
		"scribble",
		"draw",
		"shape",
		"squiggle"
	],
	char: "➰",
	fitzpatrick_scale: false,
	category: "symbols"
};
var heavy_check_mark$1 = {
	keywords: [
		"ok",
		"nike",
		"answer",
		"yes",
		"tick"
	],
	char: "✔️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var arrows_clockwise$1 = {
	keywords: [
		"sync",
		"cycle",
		"round",
		"repeat"
	],
	char: "🔃",
	fitzpatrick_scale: false,
	category: "symbols"
};
var heavy_plus_sign$1 = {
	keywords: [
		"math",
		"calculation",
		"addition",
		"more",
		"increase"
	],
	char: "➕",
	fitzpatrick_scale: false,
	category: "symbols"
};
var heavy_minus_sign$1 = {
	keywords: [
		"math",
		"calculation",
		"subtract",
		"less"
	],
	char: "➖",
	fitzpatrick_scale: false,
	category: "symbols"
};
var heavy_division_sign$1 = {
	keywords: [
		"divide",
		"math",
		"calculation"
	],
	char: "➗",
	fitzpatrick_scale: false,
	category: "symbols"
};
var heavy_multiplication_x$1 = {
	keywords: [
		"math",
		"calculation"
	],
	char: "✖️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var infinity$1 = {
	keywords: [
		"forever"
	],
	char: "♾",
	fitzpatrick_scale: false,
	category: "symbols"
};
var heavy_dollar_sign$1 = {
	keywords: [
		"money",
		"sales",
		"payment",
		"currency",
		"buck"
	],
	char: "💲",
	fitzpatrick_scale: false,
	category: "symbols"
};
var currency_exchange$1 = {
	keywords: [
		"money",
		"sales",
		"dollar",
		"travel"
	],
	char: "💱",
	fitzpatrick_scale: false,
	category: "symbols"
};
var copyright$1 = {
	keywords: [
		"ip",
		"license",
		"circle",
		"law",
		"legal"
	],
	char: "©️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var registered$1 = {
	keywords: [
		"alphabet",
		"circle"
	],
	char: "®️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var tm$1 = {
	keywords: [
		"trademark",
		"brand",
		"law",
		"legal"
	],
	char: "™️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var end$1 = {
	keywords: [
		"words",
		"arrow"
	],
	char: "🔚",
	fitzpatrick_scale: false,
	category: "symbols"
};
var back$1 = {
	keywords: [
		"arrow",
		"words",
		"return"
	],
	char: "🔙",
	fitzpatrick_scale: false,
	category: "symbols"
};
var on$1 = {
	keywords: [
		"arrow",
		"words"
	],
	char: "🔛",
	fitzpatrick_scale: false,
	category: "symbols"
};
var top$2 = {
	keywords: [
		"words",
		"blue-square"
	],
	char: "🔝",
	fitzpatrick_scale: false,
	category: "symbols"
};
var soon$1 = {
	keywords: [
		"arrow",
		"words"
	],
	char: "🔜",
	fitzpatrick_scale: false,
	category: "symbols"
};
var ballot_box_with_check$1 = {
	keywords: [
		"ok",
		"agree",
		"confirm",
		"black-square",
		"vote",
		"election",
		"yes",
		"tick"
	],
	char: "☑️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var radio_button$1 = {
	keywords: [
		"input",
		"old",
		"music",
		"circle"
	],
	char: "🔘",
	fitzpatrick_scale: false,
	category: "symbols"
};
var white_circle$1 = {
	keywords: [
		"shape",
		"round"
	],
	char: "⚪",
	fitzpatrick_scale: false,
	category: "symbols"
};
var black_circle$1 = {
	keywords: [
		"shape",
		"button",
		"round"
	],
	char: "⚫",
	fitzpatrick_scale: false,
	category: "symbols"
};
var red_circle$1 = {
	keywords: [
		"shape",
		"error",
		"danger"
	],
	char: "🔴",
	fitzpatrick_scale: false,
	category: "symbols"
};
var large_blue_circle$1 = {
	keywords: [
		"shape",
		"icon",
		"button"
	],
	char: "🔵",
	fitzpatrick_scale: false,
	category: "symbols"
};
var small_orange_diamond$1 = {
	keywords: [
		"shape",
		"jewel",
		"gem"
	],
	char: "🔸",
	fitzpatrick_scale: false,
	category: "symbols"
};
var small_blue_diamond$1 = {
	keywords: [
		"shape",
		"jewel",
		"gem"
	],
	char: "🔹",
	fitzpatrick_scale: false,
	category: "symbols"
};
var large_orange_diamond$1 = {
	keywords: [
		"shape",
		"jewel",
		"gem"
	],
	char: "🔶",
	fitzpatrick_scale: false,
	category: "symbols"
};
var large_blue_diamond$1 = {
	keywords: [
		"shape",
		"jewel",
		"gem"
	],
	char: "🔷",
	fitzpatrick_scale: false,
	category: "symbols"
};
var small_red_triangle$1 = {
	keywords: [
		"shape",
		"direction",
		"up",
		"top"
	],
	char: "🔺",
	fitzpatrick_scale: false,
	category: "symbols"
};
var black_small_square$1 = {
	keywords: [
		"shape",
		"icon"
	],
	char: "▪️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var white_small_square$1 = {
	keywords: [
		"shape",
		"icon"
	],
	char: "▫️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var black_large_square$1 = {
	keywords: [
		"shape",
		"icon",
		"button"
	],
	char: "⬛",
	fitzpatrick_scale: false,
	category: "symbols"
};
var white_large_square$1 = {
	keywords: [
		"shape",
		"icon",
		"stone",
		"button"
	],
	char: "⬜",
	fitzpatrick_scale: false,
	category: "symbols"
};
var small_red_triangle_down$1 = {
	keywords: [
		"shape",
		"direction",
		"bottom"
	],
	char: "🔻",
	fitzpatrick_scale: false,
	category: "symbols"
};
var black_medium_square$1 = {
	keywords: [
		"shape",
		"button",
		"icon"
	],
	char: "◼️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var white_medium_square$1 = {
	keywords: [
		"shape",
		"stone",
		"icon"
	],
	char: "◻️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var black_medium_small_square$1 = {
	keywords: [
		"icon",
		"shape",
		"button"
	],
	char: "◾",
	fitzpatrick_scale: false,
	category: "symbols"
};
var white_medium_small_square$1 = {
	keywords: [
		"shape",
		"stone",
		"icon",
		"button"
	],
	char: "◽",
	fitzpatrick_scale: false,
	category: "symbols"
};
var black_square_button$1 = {
	keywords: [
		"shape",
		"input",
		"frame"
	],
	char: "🔲",
	fitzpatrick_scale: false,
	category: "symbols"
};
var white_square_button$1 = {
	keywords: [
		"shape",
		"input"
	],
	char: "🔳",
	fitzpatrick_scale: false,
	category: "symbols"
};
var speaker$1 = {
	keywords: [
		"sound",
		"volume",
		"silence",
		"broadcast"
	],
	char: "🔈",
	fitzpatrick_scale: false,
	category: "symbols"
};
var sound$1 = {
	keywords: [
		"volume",
		"speaker",
		"broadcast"
	],
	char: "🔉",
	fitzpatrick_scale: false,
	category: "symbols"
};
var loud_sound$1 = {
	keywords: [
		"volume",
		"noise",
		"noisy",
		"speaker",
		"broadcast"
	],
	char: "🔊",
	fitzpatrick_scale: false,
	category: "symbols"
};
var mute$1 = {
	keywords: [
		"sound",
		"volume",
		"silence",
		"quiet"
	],
	char: "🔇",
	fitzpatrick_scale: false,
	category: "symbols"
};
var mega$1 = {
	keywords: [
		"sound",
		"speaker",
		"volume"
	],
	char: "📣",
	fitzpatrick_scale: false,
	category: "symbols"
};
var loudspeaker$1 = {
	keywords: [
		"volume",
		"sound"
	],
	char: "📢",
	fitzpatrick_scale: false,
	category: "symbols"
};
var bell$1 = {
	keywords: [
		"sound",
		"notification",
		"christmas",
		"xmas",
		"chime"
	],
	char: "🔔",
	fitzpatrick_scale: false,
	category: "symbols"
};
var no_bell$1 = {
	keywords: [
		"sound",
		"volume",
		"mute",
		"quiet",
		"silent"
	],
	char: "🔕",
	fitzpatrick_scale: false,
	category: "symbols"
};
var black_joker$1 = {
	keywords: [
		"poker",
		"cards",
		"game",
		"play",
		"magic"
	],
	char: "🃏",
	fitzpatrick_scale: false,
	category: "symbols"
};
var mahjong$1 = {
	keywords: [
		"game",
		"play",
		"chinese",
		"kanji"
	],
	char: "🀄",
	fitzpatrick_scale: false,
	category: "symbols"
};
var spades$2 = {
	keywords: [
		"poker",
		"cards",
		"suits",
		"magic"
	],
	char: "♠️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var clubs$2 = {
	keywords: [
		"poker",
		"cards",
		"magic",
		"suits"
	],
	char: "♣️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var hearts$2 = {
	keywords: [
		"poker",
		"cards",
		"magic",
		"suits"
	],
	char: "♥️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var diamonds$1 = {
	keywords: [
		"poker",
		"cards",
		"magic",
		"suits"
	],
	char: "♦️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var flower_playing_cards$1 = {
	keywords: [
		"game",
		"sunset",
		"red"
	],
	char: "🎴",
	fitzpatrick_scale: false,
	category: "symbols"
};
var thought_balloon$1 = {
	keywords: [
		"bubble",
		"cloud",
		"speech",
		"thinking",
		"dream"
	],
	char: "💭",
	fitzpatrick_scale: false,
	category: "symbols"
};
var right_anger_bubble$1 = {
	keywords: [
		"caption",
		"speech",
		"thinking",
		"mad"
	],
	char: "🗯",
	fitzpatrick_scale: false,
	category: "symbols"
};
var speech_balloon$1 = {
	keywords: [
		"bubble",
		"words",
		"message",
		"talk",
		"chatting"
	],
	char: "💬",
	fitzpatrick_scale: false,
	category: "symbols"
};
var left_speech_bubble$1 = {
	keywords: [
		"words",
		"message",
		"talk",
		"chatting"
	],
	char: "🗨",
	fitzpatrick_scale: false,
	category: "symbols"
};
var clock1$1 = {
	keywords: [
		"time",
		"late",
		"early",
		"schedule"
	],
	char: "🕐",
	fitzpatrick_scale: false,
	category: "symbols"
};
var clock2$1 = {
	keywords: [
		"time",
		"late",
		"early",
		"schedule"
	],
	char: "🕑",
	fitzpatrick_scale: false,
	category: "symbols"
};
var clock3$1 = {
	keywords: [
		"time",
		"late",
		"early",
		"schedule"
	],
	char: "🕒",
	fitzpatrick_scale: false,
	category: "symbols"
};
var clock4$1 = {
	keywords: [
		"time",
		"late",
		"early",
		"schedule"
	],
	char: "🕓",
	fitzpatrick_scale: false,
	category: "symbols"
};
var clock5$1 = {
	keywords: [
		"time",
		"late",
		"early",
		"schedule"
	],
	char: "🕔",
	fitzpatrick_scale: false,
	category: "symbols"
};
var clock6$1 = {
	keywords: [
		"time",
		"late",
		"early",
		"schedule",
		"dawn",
		"dusk"
	],
	char: "🕕",
	fitzpatrick_scale: false,
	category: "symbols"
};
var clock7$1 = {
	keywords: [
		"time",
		"late",
		"early",
		"schedule"
	],
	char: "🕖",
	fitzpatrick_scale: false,
	category: "symbols"
};
var clock8$1 = {
	keywords: [
		"time",
		"late",
		"early",
		"schedule"
	],
	char: "🕗",
	fitzpatrick_scale: false,
	category: "symbols"
};
var clock9$1 = {
	keywords: [
		"time",
		"late",
		"early",
		"schedule"
	],
	char: "🕘",
	fitzpatrick_scale: false,
	category: "symbols"
};
var clock10$1 = {
	keywords: [
		"time",
		"late",
		"early",
		"schedule"
	],
	char: "🕙",
	fitzpatrick_scale: false,
	category: "symbols"
};
var clock11$1 = {
	keywords: [
		"time",
		"late",
		"early",
		"schedule"
	],
	char: "🕚",
	fitzpatrick_scale: false,
	category: "symbols"
};
var clock12$1 = {
	keywords: [
		"time",
		"noon",
		"midnight",
		"midday",
		"late",
		"early",
		"schedule"
	],
	char: "🕛",
	fitzpatrick_scale: false,
	category: "symbols"
};
var clock130$1 = {
	keywords: [
		"time",
		"late",
		"early",
		"schedule"
	],
	char: "🕜",
	fitzpatrick_scale: false,
	category: "symbols"
};
var clock230$1 = {
	keywords: [
		"time",
		"late",
		"early",
		"schedule"
	],
	char: "🕝",
	fitzpatrick_scale: false,
	category: "symbols"
};
var clock330$1 = {
	keywords: [
		"time",
		"late",
		"early",
		"schedule"
	],
	char: "🕞",
	fitzpatrick_scale: false,
	category: "symbols"
};
var clock430$1 = {
	keywords: [
		"time",
		"late",
		"early",
		"schedule"
	],
	char: "🕟",
	fitzpatrick_scale: false,
	category: "symbols"
};
var clock530$1 = {
	keywords: [
		"time",
		"late",
		"early",
		"schedule"
	],
	char: "🕠",
	fitzpatrick_scale: false,
	category: "symbols"
};
var clock630$1 = {
	keywords: [
		"time",
		"late",
		"early",
		"schedule"
	],
	char: "🕡",
	fitzpatrick_scale: false,
	category: "symbols"
};
var clock730$1 = {
	keywords: [
		"time",
		"late",
		"early",
		"schedule"
	],
	char: "🕢",
	fitzpatrick_scale: false,
	category: "symbols"
};
var clock830$1 = {
	keywords: [
		"time",
		"late",
		"early",
		"schedule"
	],
	char: "🕣",
	fitzpatrick_scale: false,
	category: "symbols"
};
var clock930$1 = {
	keywords: [
		"time",
		"late",
		"early",
		"schedule"
	],
	char: "🕤",
	fitzpatrick_scale: false,
	category: "symbols"
};
var clock1030$1 = {
	keywords: [
		"time",
		"late",
		"early",
		"schedule"
	],
	char: "🕥",
	fitzpatrick_scale: false,
	category: "symbols"
};
var clock1130$1 = {
	keywords: [
		"time",
		"late",
		"early",
		"schedule"
	],
	char: "🕦",
	fitzpatrick_scale: false,
	category: "symbols"
};
var clock1230$1 = {
	keywords: [
		"time",
		"late",
		"early",
		"schedule"
	],
	char: "🕧",
	fitzpatrick_scale: false,
	category: "symbols"
};
var afghanistan$1 = {
	keywords: [
		"af",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇦🇫",
	fitzpatrick_scale: false,
	category: "flags"
};
var aland_islands$1 = {
	keywords: [
		"Åland",
		"islands",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇦🇽",
	fitzpatrick_scale: false,
	category: "flags"
};
var albania$1 = {
	keywords: [
		"al",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇦🇱",
	fitzpatrick_scale: false,
	category: "flags"
};
var algeria$1 = {
	keywords: [
		"dz",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇩🇿",
	fitzpatrick_scale: false,
	category: "flags"
};
var american_samoa$1 = {
	keywords: [
		"american",
		"ws",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇦🇸",
	fitzpatrick_scale: false,
	category: "flags"
};
var andorra$1 = {
	keywords: [
		"ad",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇦🇩",
	fitzpatrick_scale: false,
	category: "flags"
};
var angola$1 = {
	keywords: [
		"ao",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇦🇴",
	fitzpatrick_scale: false,
	category: "flags"
};
var anguilla$1 = {
	keywords: [
		"ai",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇦🇮",
	fitzpatrick_scale: false,
	category: "flags"
};
var antarctica$1 = {
	keywords: [
		"aq",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇦🇶",
	fitzpatrick_scale: false,
	category: "flags"
};
var antigua_barbuda$1 = {
	keywords: [
		"antigua",
		"barbuda",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇦🇬",
	fitzpatrick_scale: false,
	category: "flags"
};
var argentina$1 = {
	keywords: [
		"ar",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇦🇷",
	fitzpatrick_scale: false,
	category: "flags"
};
var armenia$1 = {
	keywords: [
		"am",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇦🇲",
	fitzpatrick_scale: false,
	category: "flags"
};
var aruba$1 = {
	keywords: [
		"aw",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇦🇼",
	fitzpatrick_scale: false,
	category: "flags"
};
var australia$1 = {
	keywords: [
		"au",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇦🇺",
	fitzpatrick_scale: false,
	category: "flags"
};
var austria$1 = {
	keywords: [
		"at",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇦🇹",
	fitzpatrick_scale: false,
	category: "flags"
};
var azerbaijan$1 = {
	keywords: [
		"az",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇦🇿",
	fitzpatrick_scale: false,
	category: "flags"
};
var bahamas$1 = {
	keywords: [
		"bs",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇧🇸",
	fitzpatrick_scale: false,
	category: "flags"
};
var bahrain$1 = {
	keywords: [
		"bh",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇧🇭",
	fitzpatrick_scale: false,
	category: "flags"
};
var bangladesh$1 = {
	keywords: [
		"bd",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇧🇩",
	fitzpatrick_scale: false,
	category: "flags"
};
var barbados$1 = {
	keywords: [
		"bb",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇧🇧",
	fitzpatrick_scale: false,
	category: "flags"
};
var belarus$1 = {
	keywords: [
		"by",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇧🇾",
	fitzpatrick_scale: false,
	category: "flags"
};
var belgium$1 = {
	keywords: [
		"be",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇧🇪",
	fitzpatrick_scale: false,
	category: "flags"
};
var belize$1 = {
	keywords: [
		"bz",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇧🇿",
	fitzpatrick_scale: false,
	category: "flags"
};
var benin$1 = {
	keywords: [
		"bj",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇧🇯",
	fitzpatrick_scale: false,
	category: "flags"
};
var bermuda$1 = {
	keywords: [
		"bm",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇧🇲",
	fitzpatrick_scale: false,
	category: "flags"
};
var bhutan$1 = {
	keywords: [
		"bt",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇧🇹",
	fitzpatrick_scale: false,
	category: "flags"
};
var bolivia$1 = {
	keywords: [
		"bo",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇧🇴",
	fitzpatrick_scale: false,
	category: "flags"
};
var caribbean_netherlands$1 = {
	keywords: [
		"bonaire",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇧🇶",
	fitzpatrick_scale: false,
	category: "flags"
};
var bosnia_herzegovina$1 = {
	keywords: [
		"bosnia",
		"herzegovina",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇧🇦",
	fitzpatrick_scale: false,
	category: "flags"
};
var botswana$1 = {
	keywords: [
		"bw",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇧🇼",
	fitzpatrick_scale: false,
	category: "flags"
};
var brazil$1 = {
	keywords: [
		"br",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇧🇷",
	fitzpatrick_scale: false,
	category: "flags"
};
var british_indian_ocean_territory$1 = {
	keywords: [
		"british",
		"indian",
		"ocean",
		"territory",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇮🇴",
	fitzpatrick_scale: false,
	category: "flags"
};
var british_virgin_islands$1 = {
	keywords: [
		"british",
		"virgin",
		"islands",
		"bvi",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇻🇬",
	fitzpatrick_scale: false,
	category: "flags"
};
var brunei$1 = {
	keywords: [
		"bn",
		"darussalam",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇧🇳",
	fitzpatrick_scale: false,
	category: "flags"
};
var bulgaria$1 = {
	keywords: [
		"bg",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇧🇬",
	fitzpatrick_scale: false,
	category: "flags"
};
var burkina_faso$1 = {
	keywords: [
		"burkina",
		"faso",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇧🇫",
	fitzpatrick_scale: false,
	category: "flags"
};
var burundi$1 = {
	keywords: [
		"bi",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇧🇮",
	fitzpatrick_scale: false,
	category: "flags"
};
var cape_verde$1 = {
	keywords: [
		"cabo",
		"verde",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇨🇻",
	fitzpatrick_scale: false,
	category: "flags"
};
var cambodia$1 = {
	keywords: [
		"kh",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇰🇭",
	fitzpatrick_scale: false,
	category: "flags"
};
var cameroon$1 = {
	keywords: [
		"cm",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇨🇲",
	fitzpatrick_scale: false,
	category: "flags"
};
var canada$1 = {
	keywords: [
		"ca",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇨🇦",
	fitzpatrick_scale: false,
	category: "flags"
};
var canary_islands$1 = {
	keywords: [
		"canary",
		"islands",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇮🇨",
	fitzpatrick_scale: false,
	category: "flags"
};
var cayman_islands$1 = {
	keywords: [
		"cayman",
		"islands",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇰🇾",
	fitzpatrick_scale: false,
	category: "flags"
};
var central_african_republic$1 = {
	keywords: [
		"central",
		"african",
		"republic",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇨🇫",
	fitzpatrick_scale: false,
	category: "flags"
};
var chad$1 = {
	keywords: [
		"td",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇹🇩",
	fitzpatrick_scale: false,
	category: "flags"
};
var chile$1 = {
	keywords: [
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇨🇱",
	fitzpatrick_scale: false,
	category: "flags"
};
var cn$1 = {
	keywords: [
		"china",
		"chinese",
		"prc",
		"flag",
		"country",
		"nation",
		"banner"
	],
	char: "🇨🇳",
	fitzpatrick_scale: false,
	category: "flags"
};
var christmas_island$1 = {
	keywords: [
		"christmas",
		"island",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇨🇽",
	fitzpatrick_scale: false,
	category: "flags"
};
var cocos_islands$1 = {
	keywords: [
		"cocos",
		"keeling",
		"islands",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇨🇨",
	fitzpatrick_scale: false,
	category: "flags"
};
var colombia$1 = {
	keywords: [
		"co",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇨🇴",
	fitzpatrick_scale: false,
	category: "flags"
};
var comoros$1 = {
	keywords: [
		"km",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇰🇲",
	fitzpatrick_scale: false,
	category: "flags"
};
var congo_brazzaville$1 = {
	keywords: [
		"congo",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇨🇬",
	fitzpatrick_scale: false,
	category: "flags"
};
var congo_kinshasa$1 = {
	keywords: [
		"congo",
		"democratic",
		"republic",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇨🇩",
	fitzpatrick_scale: false,
	category: "flags"
};
var cook_islands$1 = {
	keywords: [
		"cook",
		"islands",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇨🇰",
	fitzpatrick_scale: false,
	category: "flags"
};
var costa_rica$1 = {
	keywords: [
		"costa",
		"rica",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇨🇷",
	fitzpatrick_scale: false,
	category: "flags"
};
var croatia$1 = {
	keywords: [
		"hr",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇭🇷",
	fitzpatrick_scale: false,
	category: "flags"
};
var cuba$1 = {
	keywords: [
		"cu",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇨🇺",
	fitzpatrick_scale: false,
	category: "flags"
};
var curacao$1 = {
	keywords: [
		"curaçao",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇨🇼",
	fitzpatrick_scale: false,
	category: "flags"
};
var cyprus$1 = {
	keywords: [
		"cy",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇨🇾",
	fitzpatrick_scale: false,
	category: "flags"
};
var czech_republic$1 = {
	keywords: [
		"cz",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇨🇿",
	fitzpatrick_scale: false,
	category: "flags"
};
var denmark$1 = {
	keywords: [
		"dk",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇩🇰",
	fitzpatrick_scale: false,
	category: "flags"
};
var djibouti$1 = {
	keywords: [
		"dj",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇩🇯",
	fitzpatrick_scale: false,
	category: "flags"
};
var dominica$1 = {
	keywords: [
		"dm",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇩🇲",
	fitzpatrick_scale: false,
	category: "flags"
};
var dominican_republic$1 = {
	keywords: [
		"dominican",
		"republic",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇩🇴",
	fitzpatrick_scale: false,
	category: "flags"
};
var ecuador$1 = {
	keywords: [
		"ec",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇪🇨",
	fitzpatrick_scale: false,
	category: "flags"
};
var egypt$1 = {
	keywords: [
		"eg",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇪🇬",
	fitzpatrick_scale: false,
	category: "flags"
};
var el_salvador$1 = {
	keywords: [
		"el",
		"salvador",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇸🇻",
	fitzpatrick_scale: false,
	category: "flags"
};
var equatorial_guinea$1 = {
	keywords: [
		"equatorial",
		"gn",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇬🇶",
	fitzpatrick_scale: false,
	category: "flags"
};
var eritrea$1 = {
	keywords: [
		"er",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇪🇷",
	fitzpatrick_scale: false,
	category: "flags"
};
var estonia$1 = {
	keywords: [
		"ee",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇪🇪",
	fitzpatrick_scale: false,
	category: "flags"
};
var ethiopia$1 = {
	keywords: [
		"et",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇪🇹",
	fitzpatrick_scale: false,
	category: "flags"
};
var eu$1 = {
	keywords: [
		"european",
		"union",
		"flag",
		"banner"
	],
	char: "🇪🇺",
	fitzpatrick_scale: false,
	category: "flags"
};
var falkland_islands$1 = {
	keywords: [
		"falkland",
		"islands",
		"malvinas",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇫🇰",
	fitzpatrick_scale: false,
	category: "flags"
};
var faroe_islands$1 = {
	keywords: [
		"faroe",
		"islands",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇫🇴",
	fitzpatrick_scale: false,
	category: "flags"
};
var fiji$1 = {
	keywords: [
		"fj",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇫🇯",
	fitzpatrick_scale: false,
	category: "flags"
};
var finland$1 = {
	keywords: [
		"fi",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇫🇮",
	fitzpatrick_scale: false,
	category: "flags"
};
var fr$1 = {
	keywords: [
		"banner",
		"flag",
		"nation",
		"france",
		"french",
		"country"
	],
	char: "🇫🇷",
	fitzpatrick_scale: false,
	category: "flags"
};
var french_guiana$1 = {
	keywords: [
		"french",
		"guiana",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇬🇫",
	fitzpatrick_scale: false,
	category: "flags"
};
var french_polynesia$1 = {
	keywords: [
		"french",
		"polynesia",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇵🇫",
	fitzpatrick_scale: false,
	category: "flags"
};
var french_southern_territories$1 = {
	keywords: [
		"french",
		"southern",
		"territories",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇹🇫",
	fitzpatrick_scale: false,
	category: "flags"
};
var gabon$1 = {
	keywords: [
		"ga",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇬🇦",
	fitzpatrick_scale: false,
	category: "flags"
};
var gambia$1 = {
	keywords: [
		"gm",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇬🇲",
	fitzpatrick_scale: false,
	category: "flags"
};
var georgia$1 = {
	keywords: [
		"ge",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇬🇪",
	fitzpatrick_scale: false,
	category: "flags"
};
var de$1 = {
	keywords: [
		"german",
		"nation",
		"flag",
		"country",
		"banner"
	],
	char: "🇩🇪",
	fitzpatrick_scale: false,
	category: "flags"
};
var ghana$1 = {
	keywords: [
		"gh",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇬🇭",
	fitzpatrick_scale: false,
	category: "flags"
};
var gibraltar$1 = {
	keywords: [
		"gi",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇬🇮",
	fitzpatrick_scale: false,
	category: "flags"
};
var greece$1 = {
	keywords: [
		"gr",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇬🇷",
	fitzpatrick_scale: false,
	category: "flags"
};
var greenland$1 = {
	keywords: [
		"gl",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇬🇱",
	fitzpatrick_scale: false,
	category: "flags"
};
var grenada$1 = {
	keywords: [
		"gd",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇬🇩",
	fitzpatrick_scale: false,
	category: "flags"
};
var guadeloupe$1 = {
	keywords: [
		"gp",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇬🇵",
	fitzpatrick_scale: false,
	category: "flags"
};
var guam$1 = {
	keywords: [
		"gu",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇬🇺",
	fitzpatrick_scale: false,
	category: "flags"
};
var guatemala$1 = {
	keywords: [
		"gt",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇬🇹",
	fitzpatrick_scale: false,
	category: "flags"
};
var guernsey$1 = {
	keywords: [
		"gg",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇬🇬",
	fitzpatrick_scale: false,
	category: "flags"
};
var guinea$1 = {
	keywords: [
		"gn",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇬🇳",
	fitzpatrick_scale: false,
	category: "flags"
};
var guinea_bissau$1 = {
	keywords: [
		"gw",
		"bissau",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇬🇼",
	fitzpatrick_scale: false,
	category: "flags"
};
var guyana$1 = {
	keywords: [
		"gy",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇬🇾",
	fitzpatrick_scale: false,
	category: "flags"
};
var haiti$1 = {
	keywords: [
		"ht",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇭🇹",
	fitzpatrick_scale: false,
	category: "flags"
};
var honduras$1 = {
	keywords: [
		"hn",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇭🇳",
	fitzpatrick_scale: false,
	category: "flags"
};
var hong_kong$1 = {
	keywords: [
		"hong",
		"kong",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇭🇰",
	fitzpatrick_scale: false,
	category: "flags"
};
var hungary$1 = {
	keywords: [
		"hu",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇭🇺",
	fitzpatrick_scale: false,
	category: "flags"
};
var iceland$1 = {
	keywords: [
		"is",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇮🇸",
	fitzpatrick_scale: false,
	category: "flags"
};
var india$1 = {
	keywords: [
		"in",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇮🇳",
	fitzpatrick_scale: false,
	category: "flags"
};
var indonesia$1 = {
	keywords: [
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇮🇩",
	fitzpatrick_scale: false,
	category: "flags"
};
var iran$1 = {
	keywords: [
		"iran,",
		"islamic",
		"republic",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇮🇷",
	fitzpatrick_scale: false,
	category: "flags"
};
var iraq$1 = {
	keywords: [
		"iq",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇮🇶",
	fitzpatrick_scale: false,
	category: "flags"
};
var ireland$1 = {
	keywords: [
		"ie",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇮🇪",
	fitzpatrick_scale: false,
	category: "flags"
};
var isle_of_man$1 = {
	keywords: [
		"isle",
		"man",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇮🇲",
	fitzpatrick_scale: false,
	category: "flags"
};
var israel$1 = {
	keywords: [
		"il",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇮🇱",
	fitzpatrick_scale: false,
	category: "flags"
};
var it$2 = {
	keywords: [
		"italy",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇮🇹",
	fitzpatrick_scale: false,
	category: "flags"
};
var cote_divoire$1 = {
	keywords: [
		"ivory",
		"coast",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇨🇮",
	fitzpatrick_scale: false,
	category: "flags"
};
var jamaica$1 = {
	keywords: [
		"jm",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇯🇲",
	fitzpatrick_scale: false,
	category: "flags"
};
var jp$1 = {
	keywords: [
		"japanese",
		"nation",
		"flag",
		"country",
		"banner"
	],
	char: "🇯🇵",
	fitzpatrick_scale: false,
	category: "flags"
};
var jersey$1 = {
	keywords: [
		"je",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇯🇪",
	fitzpatrick_scale: false,
	category: "flags"
};
var jordan$1 = {
	keywords: [
		"jo",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇯🇴",
	fitzpatrick_scale: false,
	category: "flags"
};
var kazakhstan$1 = {
	keywords: [
		"kz",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇰🇿",
	fitzpatrick_scale: false,
	category: "flags"
};
var kenya$1 = {
	keywords: [
		"ke",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇰🇪",
	fitzpatrick_scale: false,
	category: "flags"
};
var kiribati$1 = {
	keywords: [
		"ki",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇰🇮",
	fitzpatrick_scale: false,
	category: "flags"
};
var kosovo$1 = {
	keywords: [
		"xk",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇽🇰",
	fitzpatrick_scale: false,
	category: "flags"
};
var kuwait$1 = {
	keywords: [
		"kw",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇰🇼",
	fitzpatrick_scale: false,
	category: "flags"
};
var kyrgyzstan$1 = {
	keywords: [
		"kg",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇰🇬",
	fitzpatrick_scale: false,
	category: "flags"
};
var laos$1 = {
	keywords: [
		"lao",
		"democratic",
		"republic",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇱🇦",
	fitzpatrick_scale: false,
	category: "flags"
};
var latvia$1 = {
	keywords: [
		"lv",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇱🇻",
	fitzpatrick_scale: false,
	category: "flags"
};
var lebanon$1 = {
	keywords: [
		"lb",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇱🇧",
	fitzpatrick_scale: false,
	category: "flags"
};
var lesotho$1 = {
	keywords: [
		"ls",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇱🇸",
	fitzpatrick_scale: false,
	category: "flags"
};
var liberia$1 = {
	keywords: [
		"lr",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇱🇷",
	fitzpatrick_scale: false,
	category: "flags"
};
var libya$1 = {
	keywords: [
		"ly",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇱🇾",
	fitzpatrick_scale: false,
	category: "flags"
};
var liechtenstein$1 = {
	keywords: [
		"li",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇱🇮",
	fitzpatrick_scale: false,
	category: "flags"
};
var lithuania$1 = {
	keywords: [
		"lt",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇱🇹",
	fitzpatrick_scale: false,
	category: "flags"
};
var luxembourg$1 = {
	keywords: [
		"lu",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇱🇺",
	fitzpatrick_scale: false,
	category: "flags"
};
var macau$1 = {
	keywords: [
		"macao",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇲🇴",
	fitzpatrick_scale: false,
	category: "flags"
};
var macedonia$1 = {
	keywords: [
		"macedonia,",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇲🇰",
	fitzpatrick_scale: false,
	category: "flags"
};
var madagascar$1 = {
	keywords: [
		"mg",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇲🇬",
	fitzpatrick_scale: false,
	category: "flags"
};
var malawi$1 = {
	keywords: [
		"mw",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇲🇼",
	fitzpatrick_scale: false,
	category: "flags"
};
var malaysia$1 = {
	keywords: [
		"my",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇲🇾",
	fitzpatrick_scale: false,
	category: "flags"
};
var maldives$1 = {
	keywords: [
		"mv",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇲🇻",
	fitzpatrick_scale: false,
	category: "flags"
};
var mali$1 = {
	keywords: [
		"ml",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇲🇱",
	fitzpatrick_scale: false,
	category: "flags"
};
var malta$1 = {
	keywords: [
		"mt",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇲🇹",
	fitzpatrick_scale: false,
	category: "flags"
};
var marshall_islands$1 = {
	keywords: [
		"marshall",
		"islands",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇲🇭",
	fitzpatrick_scale: false,
	category: "flags"
};
var martinique$1 = {
	keywords: [
		"mq",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇲🇶",
	fitzpatrick_scale: false,
	category: "flags"
};
var mauritania$1 = {
	keywords: [
		"mr",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇲🇷",
	fitzpatrick_scale: false,
	category: "flags"
};
var mauritius$1 = {
	keywords: [
		"mu",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇲🇺",
	fitzpatrick_scale: false,
	category: "flags"
};
var mayotte$1 = {
	keywords: [
		"yt",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇾🇹",
	fitzpatrick_scale: false,
	category: "flags"
};
var mexico$1 = {
	keywords: [
		"mx",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇲🇽",
	fitzpatrick_scale: false,
	category: "flags"
};
var micronesia$1 = {
	keywords: [
		"micronesia,",
		"federated",
		"states",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇫🇲",
	fitzpatrick_scale: false,
	category: "flags"
};
var moldova$1 = {
	keywords: [
		"moldova,",
		"republic",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇲🇩",
	fitzpatrick_scale: false,
	category: "flags"
};
var monaco$1 = {
	keywords: [
		"mc",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇲🇨",
	fitzpatrick_scale: false,
	category: "flags"
};
var mongolia$1 = {
	keywords: [
		"mn",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇲🇳",
	fitzpatrick_scale: false,
	category: "flags"
};
var montenegro$1 = {
	keywords: [
		"me",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇲🇪",
	fitzpatrick_scale: false,
	category: "flags"
};
var montserrat$1 = {
	keywords: [
		"ms",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇲🇸",
	fitzpatrick_scale: false,
	category: "flags"
};
var morocco$1 = {
	keywords: [
		"ma",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇲🇦",
	fitzpatrick_scale: false,
	category: "flags"
};
var mozambique$1 = {
	keywords: [
		"mz",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇲🇿",
	fitzpatrick_scale: false,
	category: "flags"
};
var myanmar$1 = {
	keywords: [
		"mm",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇲🇲",
	fitzpatrick_scale: false,
	category: "flags"
};
var namibia$1 = {
	keywords: [
		"na",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇳🇦",
	fitzpatrick_scale: false,
	category: "flags"
};
var nauru$1 = {
	keywords: [
		"nr",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇳🇷",
	fitzpatrick_scale: false,
	category: "flags"
};
var nepal$1 = {
	keywords: [
		"np",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇳🇵",
	fitzpatrick_scale: false,
	category: "flags"
};
var netherlands$1 = {
	keywords: [
		"nl",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇳🇱",
	fitzpatrick_scale: false,
	category: "flags"
};
var new_caledonia$1 = {
	keywords: [
		"new",
		"caledonia",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇳🇨",
	fitzpatrick_scale: false,
	category: "flags"
};
var new_zealand$1 = {
	keywords: [
		"new",
		"zealand",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇳🇿",
	fitzpatrick_scale: false,
	category: "flags"
};
var nicaragua$1 = {
	keywords: [
		"ni",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇳🇮",
	fitzpatrick_scale: false,
	category: "flags"
};
var niger$1 = {
	keywords: [
		"ne",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇳🇪",
	fitzpatrick_scale: false,
	category: "flags"
};
var nigeria$1 = {
	keywords: [
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇳🇬",
	fitzpatrick_scale: false,
	category: "flags"
};
var niue$1 = {
	keywords: [
		"nu",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇳🇺",
	fitzpatrick_scale: false,
	category: "flags"
};
var norfolk_island$1 = {
	keywords: [
		"norfolk",
		"island",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇳🇫",
	fitzpatrick_scale: false,
	category: "flags"
};
var northern_mariana_islands$1 = {
	keywords: [
		"northern",
		"mariana",
		"islands",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇲🇵",
	fitzpatrick_scale: false,
	category: "flags"
};
var north_korea$1 = {
	keywords: [
		"north",
		"korea",
		"nation",
		"flag",
		"country",
		"banner"
	],
	char: "🇰🇵",
	fitzpatrick_scale: false,
	category: "flags"
};
var norway$1 = {
	keywords: [
		"no",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇳🇴",
	fitzpatrick_scale: false,
	category: "flags"
};
var oman$1 = {
	keywords: [
		"om_symbol",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇴🇲",
	fitzpatrick_scale: false,
	category: "flags"
};
var pakistan$1 = {
	keywords: [
		"pk",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇵🇰",
	fitzpatrick_scale: false,
	category: "flags"
};
var palau$1 = {
	keywords: [
		"pw",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇵🇼",
	fitzpatrick_scale: false,
	category: "flags"
};
var palestinian_territories$1 = {
	keywords: [
		"palestine",
		"palestinian",
		"territories",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇵🇸",
	fitzpatrick_scale: false,
	category: "flags"
};
var panama$1 = {
	keywords: [
		"pa",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇵🇦",
	fitzpatrick_scale: false,
	category: "flags"
};
var papua_new_guinea$1 = {
	keywords: [
		"papua",
		"new",
		"guinea",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇵🇬",
	fitzpatrick_scale: false,
	category: "flags"
};
var paraguay$1 = {
	keywords: [
		"py",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇵🇾",
	fitzpatrick_scale: false,
	category: "flags"
};
var peru$1 = {
	keywords: [
		"pe",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇵🇪",
	fitzpatrick_scale: false,
	category: "flags"
};
var philippines$1 = {
	keywords: [
		"ph",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇵🇭",
	fitzpatrick_scale: false,
	category: "flags"
};
var pitcairn_islands$1 = {
	keywords: [
		"pitcairn",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇵🇳",
	fitzpatrick_scale: false,
	category: "flags"
};
var poland$1 = {
	keywords: [
		"pl",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇵🇱",
	fitzpatrick_scale: false,
	category: "flags"
};
var portugal$1 = {
	keywords: [
		"pt",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇵🇹",
	fitzpatrick_scale: false,
	category: "flags"
};
var puerto_rico$1 = {
	keywords: [
		"puerto",
		"rico",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇵🇷",
	fitzpatrick_scale: false,
	category: "flags"
};
var qatar$1 = {
	keywords: [
		"qa",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇶🇦",
	fitzpatrick_scale: false,
	category: "flags"
};
var reunion$1 = {
	keywords: [
		"réunion",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇷🇪",
	fitzpatrick_scale: false,
	category: "flags"
};
var romania$1 = {
	keywords: [
		"ro",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇷🇴",
	fitzpatrick_scale: false,
	category: "flags"
};
var ru$1 = {
	keywords: [
		"russian",
		"federation",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇷🇺",
	fitzpatrick_scale: false,
	category: "flags"
};
var rwanda$1 = {
	keywords: [
		"rw",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇷🇼",
	fitzpatrick_scale: false,
	category: "flags"
};
var st_barthelemy$1 = {
	keywords: [
		"saint",
		"barthélemy",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇧🇱",
	fitzpatrick_scale: false,
	category: "flags"
};
var st_helena$1 = {
	keywords: [
		"saint",
		"helena",
		"ascension",
		"tristan",
		"cunha",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇸🇭",
	fitzpatrick_scale: false,
	category: "flags"
};
var st_kitts_nevis$1 = {
	keywords: [
		"saint",
		"kitts",
		"nevis",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇰🇳",
	fitzpatrick_scale: false,
	category: "flags"
};
var st_lucia$1 = {
	keywords: [
		"saint",
		"lucia",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇱🇨",
	fitzpatrick_scale: false,
	category: "flags"
};
var st_pierre_miquelon$1 = {
	keywords: [
		"saint",
		"pierre",
		"miquelon",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇵🇲",
	fitzpatrick_scale: false,
	category: "flags"
};
var st_vincent_grenadines$1 = {
	keywords: [
		"saint",
		"vincent",
		"grenadines",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇻🇨",
	fitzpatrick_scale: false,
	category: "flags"
};
var samoa$1 = {
	keywords: [
		"ws",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇼🇸",
	fitzpatrick_scale: false,
	category: "flags"
};
var san_marino$1 = {
	keywords: [
		"san",
		"marino",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇸🇲",
	fitzpatrick_scale: false,
	category: "flags"
};
var sao_tome_principe$1 = {
	keywords: [
		"sao",
		"tome",
		"principe",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇸🇹",
	fitzpatrick_scale: false,
	category: "flags"
};
var saudi_arabia$1 = {
	keywords: [
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇸🇦",
	fitzpatrick_scale: false,
	category: "flags"
};
var senegal$1 = {
	keywords: [
		"sn",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇸🇳",
	fitzpatrick_scale: false,
	category: "flags"
};
var serbia$1 = {
	keywords: [
		"rs",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇷🇸",
	fitzpatrick_scale: false,
	category: "flags"
};
var seychelles$1 = {
	keywords: [
		"sc",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇸🇨",
	fitzpatrick_scale: false,
	category: "flags"
};
var sierra_leone$1 = {
	keywords: [
		"sierra",
		"leone",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇸🇱",
	fitzpatrick_scale: false,
	category: "flags"
};
var singapore$1 = {
	keywords: [
		"sg",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇸🇬",
	fitzpatrick_scale: false,
	category: "flags"
};
var sint_maarten$1 = {
	keywords: [
		"sint",
		"maarten",
		"dutch",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇸🇽",
	fitzpatrick_scale: false,
	category: "flags"
};
var slovakia$1 = {
	keywords: [
		"sk",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇸🇰",
	fitzpatrick_scale: false,
	category: "flags"
};
var slovenia$1 = {
	keywords: [
		"si",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇸🇮",
	fitzpatrick_scale: false,
	category: "flags"
};
var solomon_islands$1 = {
	keywords: [
		"solomon",
		"islands",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇸🇧",
	fitzpatrick_scale: false,
	category: "flags"
};
var somalia$1 = {
	keywords: [
		"so",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇸🇴",
	fitzpatrick_scale: false,
	category: "flags"
};
var south_africa$1 = {
	keywords: [
		"south",
		"africa",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇿🇦",
	fitzpatrick_scale: false,
	category: "flags"
};
var south_georgia_south_sandwich_islands$1 = {
	keywords: [
		"south",
		"georgia",
		"sandwich",
		"islands",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇬🇸",
	fitzpatrick_scale: false,
	category: "flags"
};
var kr$1 = {
	keywords: [
		"south",
		"korea",
		"nation",
		"flag",
		"country",
		"banner"
	],
	char: "🇰🇷",
	fitzpatrick_scale: false,
	category: "flags"
};
var south_sudan$1 = {
	keywords: [
		"south",
		"sd",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇸🇸",
	fitzpatrick_scale: false,
	category: "flags"
};
var es$1 = {
	keywords: [
		"spain",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇪🇸",
	fitzpatrick_scale: false,
	category: "flags"
};
var sri_lanka$1 = {
	keywords: [
		"sri",
		"lanka",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇱🇰",
	fitzpatrick_scale: false,
	category: "flags"
};
var sudan$1 = {
	keywords: [
		"sd",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇸🇩",
	fitzpatrick_scale: false,
	category: "flags"
};
var suriname$1 = {
	keywords: [
		"sr",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇸🇷",
	fitzpatrick_scale: false,
	category: "flags"
};
var swaziland$1 = {
	keywords: [
		"sz",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇸🇿",
	fitzpatrick_scale: false,
	category: "flags"
};
var sweden$1 = {
	keywords: [
		"se",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇸🇪",
	fitzpatrick_scale: false,
	category: "flags"
};
var switzerland$1 = {
	keywords: [
		"ch",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇨🇭",
	fitzpatrick_scale: false,
	category: "flags"
};
var syria$1 = {
	keywords: [
		"syrian",
		"arab",
		"republic",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇸🇾",
	fitzpatrick_scale: false,
	category: "flags"
};
var taiwan$1 = {
	keywords: [
		"tw",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇹🇼",
	fitzpatrick_scale: false,
	category: "flags"
};
var tajikistan$1 = {
	keywords: [
		"tj",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇹🇯",
	fitzpatrick_scale: false,
	category: "flags"
};
var tanzania$1 = {
	keywords: [
		"tanzania,",
		"united",
		"republic",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇹🇿",
	fitzpatrick_scale: false,
	category: "flags"
};
var thailand$1 = {
	keywords: [
		"th",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇹🇭",
	fitzpatrick_scale: false,
	category: "flags"
};
var timor_leste$1 = {
	keywords: [
		"timor",
		"leste",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇹🇱",
	fitzpatrick_scale: false,
	category: "flags"
};
var togo$1 = {
	keywords: [
		"tg",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇹🇬",
	fitzpatrick_scale: false,
	category: "flags"
};
var tokelau$1 = {
	keywords: [
		"tk",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇹🇰",
	fitzpatrick_scale: false,
	category: "flags"
};
var tonga$1 = {
	keywords: [
		"to",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇹🇴",
	fitzpatrick_scale: false,
	category: "flags"
};
var trinidad_tobago$1 = {
	keywords: [
		"trinidad",
		"tobago",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇹🇹",
	fitzpatrick_scale: false,
	category: "flags"
};
var tunisia$1 = {
	keywords: [
		"tn",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇹🇳",
	fitzpatrick_scale: false,
	category: "flags"
};
var tr$1 = {
	keywords: [
		"turkey",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇹🇷",
	fitzpatrick_scale: false,
	category: "flags"
};
var turkmenistan$1 = {
	keywords: [
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇹🇲",
	fitzpatrick_scale: false,
	category: "flags"
};
var turks_caicos_islands$1 = {
	keywords: [
		"turks",
		"caicos",
		"islands",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇹🇨",
	fitzpatrick_scale: false,
	category: "flags"
};
var tuvalu$1 = {
	keywords: [
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇹🇻",
	fitzpatrick_scale: false,
	category: "flags"
};
var uganda$1 = {
	keywords: [
		"ug",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇺🇬",
	fitzpatrick_scale: false,
	category: "flags"
};
var ukraine$1 = {
	keywords: [
		"ua",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇺🇦",
	fitzpatrick_scale: false,
	category: "flags"
};
var united_arab_emirates$1 = {
	keywords: [
		"united",
		"arab",
		"emirates",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇦🇪",
	fitzpatrick_scale: false,
	category: "flags"
};
var uk$1 = {
	keywords: [
		"united",
		"kingdom",
		"great",
		"britain",
		"northern",
		"ireland",
		"flag",
		"nation",
		"country",
		"banner",
		"british",
		"UK",
		"english",
		"england",
		"union jack"
	],
	char: "🇬🇧",
	fitzpatrick_scale: false,
	category: "flags"
};
var england$1 = {
	keywords: [
		"flag",
		"english"
	],
	char: "🏴󠁧󠁢󠁥󠁮󠁧󠁿",
	fitzpatrick_scale: false,
	category: "flags"
};
var scotland$1 = {
	keywords: [
		"flag",
		"scottish"
	],
	char: "🏴󠁧󠁢󠁳󠁣󠁴󠁿",
	fitzpatrick_scale: false,
	category: "flags"
};
var wales$1 = {
	keywords: [
		"flag",
		"welsh"
	],
	char: "🏴󠁧󠁢󠁷󠁬󠁳󠁿",
	fitzpatrick_scale: false,
	category: "flags"
};
var us$1 = {
	keywords: [
		"united",
		"states",
		"america",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇺🇸",
	fitzpatrick_scale: false,
	category: "flags"
};
var us_virgin_islands$1 = {
	keywords: [
		"virgin",
		"islands",
		"us",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇻🇮",
	fitzpatrick_scale: false,
	category: "flags"
};
var uruguay$1 = {
	keywords: [
		"uy",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇺🇾",
	fitzpatrick_scale: false,
	category: "flags"
};
var uzbekistan$1 = {
	keywords: [
		"uz",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇺🇿",
	fitzpatrick_scale: false,
	category: "flags"
};
var vanuatu$1 = {
	keywords: [
		"vu",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇻🇺",
	fitzpatrick_scale: false,
	category: "flags"
};
var vatican_city$1 = {
	keywords: [
		"vatican",
		"city",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇻🇦",
	fitzpatrick_scale: false,
	category: "flags"
};
var venezuela$1 = {
	keywords: [
		"ve",
		"bolivarian",
		"republic",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇻🇪",
	fitzpatrick_scale: false,
	category: "flags"
};
var vietnam$1 = {
	keywords: [
		"viet",
		"nam",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇻🇳",
	fitzpatrick_scale: false,
	category: "flags"
};
var wallis_futuna$1 = {
	keywords: [
		"wallis",
		"futuna",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇼🇫",
	fitzpatrick_scale: false,
	category: "flags"
};
var western_sahara$1 = {
	keywords: [
		"western",
		"sahara",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇪🇭",
	fitzpatrick_scale: false,
	category: "flags"
};
var yemen$1 = {
	keywords: [
		"ye",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇾🇪",
	fitzpatrick_scale: false,
	category: "flags"
};
var zambia$1 = {
	keywords: [
		"zm",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇿🇲",
	fitzpatrick_scale: false,
	category: "flags"
};
var zimbabwe$1 = {
	keywords: [
		"zw",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇿🇼",
	fitzpatrick_scale: false,
	category: "flags"
};
var united_nations$1 = {
	keywords: [
		"un",
		"flag",
		"banner"
	],
	char: "🇺🇳",
	fitzpatrick_scale: false,
	category: "flags"
};
var pirate_flag$1 = {
	keywords: [
		"skull",
		"crossbones",
		"flag",
		"banner"
	],
	char: "🏴‍☠️",
	fitzpatrick_scale: false,
	category: "flags"
};
var old_emojilib = {
	"100": {
	keywords: [
		"score",
		"perfect",
		"numbers",
		"century",
		"exam",
		"quiz",
		"test",
		"pass",
		"hundred"
	],
	char: "💯",
	fitzpatrick_scale: false,
	category: "symbols"
},
	"1234": {
	keywords: [
		"numbers",
		"blue-square"
	],
	char: "🔢",
	fitzpatrick_scale: false,
	category: "symbols"
},
	grinning: grinning$1,
	grimacing: grimacing$1,
	grin: grin$1,
	joy: joy$1,
	rofl: rofl$1,
	partying: partying$1,
	smiley: smiley$1,
	smile: smile$2,
	sweat_smile: sweat_smile$1,
	laughing: laughing$1,
	innocent: innocent$1,
	wink: wink$1,
	blush: blush$1,
	slightly_smiling_face: slightly_smiling_face$1,
	upside_down_face: upside_down_face$1,
	relaxed: relaxed$1,
	yum: yum$1,
	relieved: relieved$1,
	heart_eyes: heart_eyes$1,
	smiling_face_with_three_hearts: smiling_face_with_three_hearts$1,
	kissing_heart: kissing_heart$1,
	kissing: kissing$1,
	kissing_smiling_eyes: kissing_smiling_eyes$1,
	kissing_closed_eyes: kissing_closed_eyes$1,
	stuck_out_tongue_winking_eye: stuck_out_tongue_winking_eye$1,
	zany: zany$1,
	raised_eyebrow: raised_eyebrow$1,
	monocle: monocle$1,
	stuck_out_tongue_closed_eyes: stuck_out_tongue_closed_eyes$1,
	stuck_out_tongue: stuck_out_tongue$1,
	money_mouth_face: money_mouth_face$1,
	nerd_face: nerd_face$1,
	sunglasses: sunglasses$1,
	star_struck: star_struck$1,
	clown_face: clown_face$1,
	cowboy_hat_face: cowboy_hat_face$1,
	hugs: hugs$1,
	smirk: smirk$1,
	no_mouth: no_mouth$1,
	neutral_face: neutral_face$1,
	expressionless: expressionless$1,
	unamused: unamused$1,
	roll_eyes: roll_eyes$1,
	thinking: thinking$1,
	lying_face: lying_face$1,
	hand_over_mouth: hand_over_mouth$1,
	shushing: shushing$1,
	symbols_over_mouth: symbols_over_mouth$1,
	exploding_head: exploding_head$1,
	flushed: flushed$1,
	disappointed: disappointed$1,
	worried: worried$1,
	angry: angry$1,
	rage: rage$1,
	pensive: pensive$1,
	confused: confused$1,
	slightly_frowning_face: slightly_frowning_face$1,
	frowning_face: frowning_face$1,
	persevere: persevere$1,
	confounded: confounded$1,
	tired_face: tired_face$1,
	weary: weary$1,
	pleading: pleading$1,
	triumph: triumph$1,
	open_mouth: open_mouth$1,
	scream: scream$1,
	fearful: fearful$1,
	cold_sweat: cold_sweat$1,
	hushed: hushed$1,
	frowning: frowning$1,
	anguished: anguished$1,
	cry: cry$1,
	disappointed_relieved: disappointed_relieved$1,
	drooling_face: drooling_face$1,
	sleepy: sleepy$1,
	sweat: sweat$1,
	hot: hot$1,
	cold: cold$1,
	sob: sob$1,
	dizzy_face: dizzy_face$1,
	astonished: astonished$1,
	zipper_mouth_face: zipper_mouth_face$1,
	nauseated_face: nauseated_face$1,
	sneezing_face: sneezing_face$1,
	vomiting: vomiting$1,
	mask: mask$1,
	face_with_thermometer: face_with_thermometer$1,
	face_with_head_bandage: face_with_head_bandage$1,
	woozy: woozy$1,
	sleeping: sleeping$1,
	zzz: zzz$1,
	poop: poop$1,
	smiling_imp: smiling_imp$1,
	imp: imp$1,
	japanese_ogre: japanese_ogre$1,
	japanese_goblin: japanese_goblin$1,
	skull: skull$1,
	ghost: ghost$1,
	alien: alien$1,
	robot: robot$1,
	smiley_cat: smiley_cat$1,
	smile_cat: smile_cat$1,
	joy_cat: joy_cat$1,
	heart_eyes_cat: heart_eyes_cat$1,
	smirk_cat: smirk_cat$1,
	kissing_cat: kissing_cat$1,
	scream_cat: scream_cat$1,
	crying_cat_face: crying_cat_face$1,
	pouting_cat: pouting_cat$1,
	palms_up: palms_up$1,
	raised_hands: raised_hands$1,
	clap: clap$1,
	wave: wave$1,
	call_me_hand: call_me_hand$1,
	"+1": {
	keywords: [
		"thumbsup",
		"yes",
		"awesome",
		"good",
		"agree",
		"accept",
		"cool",
		"hand",
		"like"
	],
	char: "👍",
	fitzpatrick_scale: true,
	category: "people"
},
	"-1": {
	keywords: [
		"thumbsdown",
		"no",
		"dislike",
		"hand"
	],
	char: "👎",
	fitzpatrick_scale: true,
	category: "people"
},
	facepunch: facepunch$1,
	fist: fist$1,
	fist_left: fist_left$1,
	fist_right: fist_right$1,
	v: v$1,
	ok_hand: ok_hand$1,
	raised_hand: raised_hand$1,
	raised_back_of_hand: raised_back_of_hand$1,
	open_hands: open_hands$1,
	muscle: muscle$1,
	pray: pray$1,
	foot: foot$1,
	leg: leg$2,
	handshake: handshake$1,
	point_up: point_up$1,
	point_up_2: point_up_2$1,
	point_down: point_down$1,
	point_left: point_left$1,
	point_right: point_right$1,
	fu: fu$1,
	raised_hand_with_fingers_splayed: raised_hand_with_fingers_splayed$1,
	love_you: love_you$1,
	metal: metal$1,
	crossed_fingers: crossed_fingers$1,
	vulcan_salute: vulcan_salute$1,
	writing_hand: writing_hand$1,
	selfie: selfie$1,
	nail_care: nail_care$1,
	lips: lips$1,
	tooth: tooth$1,
	tongue: tongue$1,
	ear: ear$1,
	nose: nose$1,
	eye: eye$1,
	eyes: eyes$1,
	brain: brain$1,
	bust_in_silhouette: bust_in_silhouette$1,
	busts_in_silhouette: busts_in_silhouette$1,
	speaking_head: speaking_head$1,
	baby: baby$1,
	child: child$1,
	boy: boy$1,
	girl: girl$1,
	adult: adult$1,
	man: man$1,
	woman: woman$1,
	blonde_woman: blonde_woman$1,
	blonde_man: blonde_man$1,
	bearded_person: bearded_person$1,
	older_adult: older_adult$1,
	older_man: older_man$1,
	older_woman: older_woman$1,
	man_with_gua_pi_mao: man_with_gua_pi_mao$1,
	woman_with_headscarf: woman_with_headscarf$1,
	woman_with_turban: woman_with_turban$1,
	man_with_turban: man_with_turban$1,
	policewoman: policewoman$1,
	policeman: policeman$1,
	construction_worker_woman: construction_worker_woman$1,
	construction_worker_man: construction_worker_man$1,
	guardswoman: guardswoman$1,
	guardsman: guardsman$1,
	female_detective: female_detective$1,
	male_detective: male_detective$1,
	woman_health_worker: woman_health_worker$1,
	man_health_worker: man_health_worker$1,
	woman_farmer: woman_farmer$1,
	man_farmer: man_farmer$1,
	woman_cook: woman_cook$1,
	man_cook: man_cook$1,
	woman_student: woman_student$1,
	man_student: man_student$1,
	woman_singer: woman_singer$1,
	man_singer: man_singer$1,
	woman_teacher: woman_teacher$1,
	man_teacher: man_teacher$1,
	woman_factory_worker: woman_factory_worker$1,
	man_factory_worker: man_factory_worker$1,
	woman_technologist: woman_technologist$1,
	man_technologist: man_technologist$1,
	woman_office_worker: woman_office_worker$1,
	man_office_worker: man_office_worker$1,
	woman_mechanic: woman_mechanic$1,
	man_mechanic: man_mechanic$1,
	woman_scientist: woman_scientist$1,
	man_scientist: man_scientist$1,
	woman_artist: woman_artist$1,
	man_artist: man_artist$1,
	woman_firefighter: woman_firefighter$1,
	man_firefighter: man_firefighter$1,
	woman_pilot: woman_pilot$1,
	man_pilot: man_pilot$1,
	woman_astronaut: woman_astronaut$1,
	man_astronaut: man_astronaut$1,
	woman_judge: woman_judge$1,
	man_judge: man_judge$1,
	woman_superhero: woman_superhero$1,
	man_superhero: man_superhero$1,
	woman_supervillain: woman_supervillain$1,
	man_supervillain: man_supervillain$1,
	mrs_claus: mrs_claus$1,
	santa: santa$1,
	sorceress: sorceress$1,
	wizard: wizard$1,
	woman_elf: woman_elf$1,
	man_elf: man_elf$1,
	woman_vampire: woman_vampire$1,
	man_vampire: man_vampire$1,
	woman_zombie: woman_zombie$1,
	man_zombie: man_zombie$1,
	woman_genie: woman_genie$1,
	man_genie: man_genie$1,
	mermaid: mermaid$1,
	merman: merman$1,
	woman_fairy: woman_fairy$1,
	man_fairy: man_fairy$1,
	angel: angel$1,
	pregnant_woman: pregnant_woman$1,
	breastfeeding: breastfeeding$1,
	princess: princess$1,
	prince: prince$1,
	bride_with_veil: bride_with_veil$1,
	man_in_tuxedo: man_in_tuxedo$1,
	running_woman: running_woman$1,
	running_man: running_man$1,
	walking_woman: walking_woman$1,
	walking_man: walking_man$1,
	dancer: dancer$1,
	man_dancing: man_dancing$1,
	dancing_women: dancing_women$1,
	dancing_men: dancing_men$1,
	couple: couple$1,
	two_men_holding_hands: two_men_holding_hands$1,
	two_women_holding_hands: two_women_holding_hands$1,
	bowing_woman: bowing_woman$1,
	bowing_man: bowing_man$1,
	man_facepalming: man_facepalming$1,
	woman_facepalming: woman_facepalming$1,
	woman_shrugging: woman_shrugging$1,
	man_shrugging: man_shrugging$1,
	tipping_hand_woman: tipping_hand_woman$1,
	tipping_hand_man: tipping_hand_man$1,
	no_good_woman: no_good_woman$1,
	no_good_man: no_good_man$1,
	ok_woman: ok_woman$1,
	ok_man: ok_man$1,
	raising_hand_woman: raising_hand_woman$1,
	raising_hand_man: raising_hand_man$1,
	pouting_woman: pouting_woman$1,
	pouting_man: pouting_man$1,
	frowning_woman: frowning_woman$1,
	frowning_man: frowning_man$1,
	haircut_woman: haircut_woman$1,
	haircut_man: haircut_man$1,
	massage_woman: massage_woman$1,
	massage_man: massage_man$1,
	woman_in_steamy_room: woman_in_steamy_room$1,
	man_in_steamy_room: man_in_steamy_room$1,
	couple_with_heart_woman_man: couple_with_heart_woman_man$1,
	couple_with_heart_woman_woman: couple_with_heart_woman_woman$1,
	couple_with_heart_man_man: couple_with_heart_man_man$1,
	couplekiss_man_woman: couplekiss_man_woman$1,
	couplekiss_woman_woman: couplekiss_woman_woman$1,
	couplekiss_man_man: couplekiss_man_man$1,
	family_man_woman_boy: family_man_woman_boy$1,
	family_man_woman_girl: family_man_woman_girl$1,
	family_man_woman_girl_boy: family_man_woman_girl_boy$1,
	family_man_woman_boy_boy: family_man_woman_boy_boy$1,
	family_man_woman_girl_girl: family_man_woman_girl_girl$1,
	family_woman_woman_boy: family_woman_woman_boy$1,
	family_woman_woman_girl: family_woman_woman_girl$1,
	family_woman_woman_girl_boy: family_woman_woman_girl_boy$1,
	family_woman_woman_boy_boy: family_woman_woman_boy_boy$1,
	family_woman_woman_girl_girl: family_woman_woman_girl_girl$1,
	family_man_man_boy: family_man_man_boy$1,
	family_man_man_girl: family_man_man_girl$1,
	family_man_man_girl_boy: family_man_man_girl_boy$1,
	family_man_man_boy_boy: family_man_man_boy_boy$1,
	family_man_man_girl_girl: family_man_man_girl_girl$1,
	family_woman_boy: family_woman_boy$1,
	family_woman_girl: family_woman_girl$1,
	family_woman_girl_boy: family_woman_girl_boy$1,
	family_woman_boy_boy: family_woman_boy_boy$1,
	family_woman_girl_girl: family_woman_girl_girl$1,
	family_man_boy: family_man_boy$1,
	family_man_girl: family_man_girl$1,
	family_man_girl_boy: family_man_girl_boy$1,
	family_man_boy_boy: family_man_boy_boy$1,
	family_man_girl_girl: family_man_girl_girl$1,
	yarn: yarn$1,
	thread: thread$1,
	coat: coat$1,
	labcoat: labcoat$1,
	womans_clothes: womans_clothes$1,
	tshirt: tshirt$1,
	jeans: jeans$1,
	necktie: necktie$1,
	dress: dress$1,
	bikini: bikini$1,
	kimono: kimono$1,
	lipstick: lipstick$1,
	kiss: kiss$1,
	footprints: footprints$1,
	flat_shoe: flat_shoe$1,
	high_heel: high_heel$1,
	sandal: sandal$1,
	boot: boot$1,
	mans_shoe: mans_shoe$1,
	athletic_shoe: athletic_shoe$1,
	hiking_boot: hiking_boot$1,
	socks: socks$1,
	gloves: gloves$1,
	scarf: scarf$1,
	womans_hat: womans_hat$1,
	tophat: tophat$1,
	billed_hat: billed_hat$1,
	rescue_worker_helmet: rescue_worker_helmet$1,
	mortar_board: mortar_board$1,
	crown: crown$1,
	school_satchel: school_satchel$1,
	luggage: luggage$1,
	pouch: pouch$1,
	purse: purse$1,
	handbag: handbag$1,
	briefcase: briefcase$1,
	eyeglasses: eyeglasses$1,
	dark_sunglasses: dark_sunglasses$1,
	goggles: goggles$1,
	ring: ring$2,
	closed_umbrella: closed_umbrella$1,
	dog: dog$1,
	cat: cat$1,
	mouse: mouse$1,
	hamster: hamster$1,
	rabbit: rabbit$1,
	fox_face: fox_face$1,
	bear: bear$1,
	panda_face: panda_face$1,
	koala: koala$1,
	tiger: tiger$1,
	lion: lion$1,
	cow: cow$1,
	pig: pig$1,
	pig_nose: pig_nose$1,
	frog: frog$1,
	squid: squid$1,
	octopus: octopus$1,
	shrimp: shrimp$1,
	monkey_face: monkey_face$1,
	gorilla: gorilla$1,
	see_no_evil: see_no_evil$1,
	hear_no_evil: hear_no_evil$1,
	speak_no_evil: speak_no_evil$1,
	monkey: monkey$1,
	chicken: chicken$1,
	penguin: penguin$1,
	bird: bird$1,
	baby_chick: baby_chick$1,
	hatching_chick: hatching_chick$1,
	hatched_chick: hatched_chick$1,
	duck: duck$1,
	eagle: eagle$1,
	owl: owl$1,
	bat: bat$1,
	wolf: wolf$1,
	boar: boar$1,
	horse: horse$1,
	unicorn: unicorn$1,
	honeybee: honeybee$1,
	bug: bug$1,
	butterfly: butterfly$1,
	snail: snail$1,
	beetle: beetle$1,
	ant: ant$1,
	grasshopper: grasshopper$1,
	spider: spider$1,
	scorpion: scorpion$1,
	crab: crab$1,
	snake: snake$1,
	lizard: lizard$1,
	"t-rex": {
	keywords: [
		"animal",
		"nature",
		"dinosaur",
		"tyrannosaurus",
		"extinct"
	],
	char: "🦖",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
},
	sauropod: sauropod$1,
	turtle: turtle$1,
	tropical_fish: tropical_fish$1,
	fish: fish$1,
	blowfish: blowfish$1,
	dolphin: dolphin$1,
	shark: shark$1,
	whale: whale$1,
	whale2: whale2$1,
	crocodile: crocodile$1,
	leopard: leopard$1,
	zebra: zebra$1,
	tiger2: tiger2$1,
	water_buffalo: water_buffalo$1,
	ox: ox$1,
	cow2: cow2$1,
	deer: deer$1,
	dromedary_camel: dromedary_camel$1,
	camel: camel$1,
	giraffe: giraffe$1,
	elephant: elephant$1,
	rhinoceros: rhinoceros$1,
	goat: goat$1,
	ram: ram$1,
	sheep: sheep$1,
	racehorse: racehorse$1,
	pig2: pig2$1,
	rat: rat$1,
	mouse2: mouse2$1,
	rooster: rooster$1,
	turkey: turkey$1,
	dove: dove$1,
	dog2: dog2$1,
	poodle: poodle$1,
	cat2: cat2$1,
	rabbit2: rabbit2$1,
	chipmunk: chipmunk$1,
	hedgehog: hedgehog$1,
	raccoon: raccoon$1,
	llama: llama$1,
	hippopotamus: hippopotamus$1,
	kangaroo: kangaroo$1,
	badger: badger$1,
	swan: swan$1,
	peacock: peacock$1,
	parrot: parrot$1,
	lobster: lobster$1,
	mosquito: mosquito$1,
	paw_prints: paw_prints$1,
	dragon: dragon$1,
	dragon_face: dragon_face$1,
	cactus: cactus$1,
	christmas_tree: christmas_tree$1,
	evergreen_tree: evergreen_tree$1,
	deciduous_tree: deciduous_tree$1,
	palm_tree: palm_tree$1,
	seedling: seedling$1,
	herb: herb$1,
	shamrock: shamrock$1,
	four_leaf_clover: four_leaf_clover$1,
	bamboo: bamboo$1,
	tanabata_tree: tanabata_tree$1,
	leaves: leaves$1,
	fallen_leaf: fallen_leaf$1,
	maple_leaf: maple_leaf$1,
	ear_of_rice: ear_of_rice$1,
	hibiscus: hibiscus$1,
	sunflower: sunflower$1,
	rose: rose$1,
	wilted_flower: wilted_flower$1,
	tulip: tulip$1,
	blossom: blossom$1,
	cherry_blossom: cherry_blossom$1,
	bouquet: bouquet$1,
	mushroom: mushroom$1,
	chestnut: chestnut$1,
	jack_o_lantern: jack_o_lantern$1,
	shell: shell$1,
	spider_web: spider_web$1,
	earth_americas: earth_americas$1,
	earth_africa: earth_africa$1,
	earth_asia: earth_asia$1,
	full_moon: full_moon$1,
	waning_gibbous_moon: waning_gibbous_moon$1,
	last_quarter_moon: last_quarter_moon$1,
	waning_crescent_moon: waning_crescent_moon$1,
	new_moon: new_moon$1,
	waxing_crescent_moon: waxing_crescent_moon$1,
	first_quarter_moon: first_quarter_moon$1,
	waxing_gibbous_moon: waxing_gibbous_moon$1,
	new_moon_with_face: new_moon_with_face$1,
	full_moon_with_face: full_moon_with_face$1,
	first_quarter_moon_with_face: first_quarter_moon_with_face$1,
	last_quarter_moon_with_face: last_quarter_moon_with_face$1,
	sun_with_face: sun_with_face$1,
	crescent_moon: crescent_moon$1,
	star: star$2,
	star2: star2$1,
	dizzy: dizzy$1,
	sparkles: sparkles$1,
	comet: comet$1,
	sunny: sunny$1,
	sun_behind_small_cloud: sun_behind_small_cloud$1,
	partly_sunny: partly_sunny$1,
	sun_behind_large_cloud: sun_behind_large_cloud$1,
	sun_behind_rain_cloud: sun_behind_rain_cloud$1,
	cloud: cloud$1,
	cloud_with_rain: cloud_with_rain$1,
	cloud_with_lightning_and_rain: cloud_with_lightning_and_rain$1,
	cloud_with_lightning: cloud_with_lightning$1,
	zap: zap$1,
	fire: fire$1,
	boom: boom$1,
	snowflake: snowflake$1,
	cloud_with_snow: cloud_with_snow$1,
	snowman: snowman$1,
	snowman_with_snow: snowman_with_snow$1,
	wind_face: wind_face$1,
	dash: dash$2,
	tornado: tornado$1,
	fog: fog$1,
	open_umbrella: open_umbrella$1,
	umbrella: umbrella$1,
	droplet: droplet$1,
	sweat_drops: sweat_drops$1,
	ocean: ocean$1,
	green_apple: green_apple$1,
	apple: apple$1,
	pear: pear$1,
	tangerine: tangerine$1,
	lemon: lemon$1,
	banana: banana$1,
	watermelon: watermelon$1,
	grapes: grapes$1,
	strawberry: strawberry$1,
	melon: melon$1,
	cherries: cherries$1,
	peach: peach$1,
	pineapple: pineapple$1,
	coconut: coconut$1,
	kiwi_fruit: kiwi_fruit$1,
	mango: mango$1,
	avocado: avocado$1,
	broccoli: broccoli$1,
	tomato: tomato$1,
	eggplant: eggplant$1,
	cucumber: cucumber$1,
	carrot: carrot$1,
	hot_pepper: hot_pepper$1,
	potato: potato$1,
	corn: corn$1,
	leafy_greens: leafy_greens$1,
	sweet_potato: sweet_potato$1,
	peanuts: peanuts$1,
	honey_pot: honey_pot$1,
	croissant: croissant$1,
	bread: bread$1,
	baguette_bread: baguette_bread$1,
	bagel: bagel$1,
	pretzel: pretzel$1,
	cheese: cheese$1,
	egg: egg$1,
	bacon: bacon$1,
	steak: steak$1,
	pancakes: pancakes$1,
	poultry_leg: poultry_leg$1,
	meat_on_bone: meat_on_bone$1,
	bone: bone$1,
	fried_shrimp: fried_shrimp$1,
	fried_egg: fried_egg$1,
	hamburger: hamburger$1,
	fries: fries$1,
	stuffed_flatbread: stuffed_flatbread$1,
	hotdog: hotdog$1,
	pizza: pizza$1,
	sandwich: sandwich$1,
	canned_food: canned_food$1,
	spaghetti: spaghetti$1,
	taco: taco$1,
	burrito: burrito$1,
	green_salad: green_salad$1,
	shallow_pan_of_food: shallow_pan_of_food$1,
	ramen: ramen$1,
	stew: stew$1,
	fish_cake: fish_cake$1,
	fortune_cookie: fortune_cookie$1,
	sushi: sushi$1,
	bento: bento$1,
	curry: curry$1,
	rice_ball: rice_ball$1,
	rice: rice$1,
	rice_cracker: rice_cracker$1,
	oden: oden$1,
	dango: dango$1,
	shaved_ice: shaved_ice$1,
	ice_cream: ice_cream$1,
	icecream: icecream$1,
	pie: pie$1,
	cake: cake$1,
	cupcake: cupcake$1,
	moon_cake: moon_cake$1,
	birthday: birthday$1,
	custard: custard$1,
	candy: candy$1,
	lollipop: lollipop$1,
	chocolate_bar: chocolate_bar$1,
	popcorn: popcorn$1,
	dumpling: dumpling$1,
	doughnut: doughnut$1,
	cookie: cookie$1,
	milk_glass: milk_glass$1,
	beer: beer$1,
	beers: beers$1,
	clinking_glasses: clinking_glasses$1,
	wine_glass: wine_glass$1,
	tumbler_glass: tumbler_glass$1,
	cocktail: cocktail$1,
	tropical_drink: tropical_drink$1,
	champagne: champagne$1,
	sake: sake$1,
	tea: tea$1,
	cup_with_straw: cup_with_straw$1,
	coffee: coffee$1,
	baby_bottle: baby_bottle$1,
	salt: salt$1,
	spoon: spoon$1,
	fork_and_knife: fork_and_knife$1,
	plate_with_cutlery: plate_with_cutlery$1,
	bowl_with_spoon: bowl_with_spoon$1,
	takeout_box: takeout_box$1,
	chopsticks: chopsticks$1,
	soccer: soccer$1,
	basketball: basketball$1,
	football: football$1,
	baseball: baseball$1,
	softball: softball$1,
	tennis: tennis$1,
	volleyball: volleyball$1,
	rugby_football: rugby_football$1,
	flying_disc: flying_disc$1,
	"8ball": {
	keywords: [
		"pool",
		"hobby",
		"game",
		"luck",
		"magic"
	],
	char: "🎱",
	fitzpatrick_scale: false,
	category: "activity"
},
	golf: golf$1,
	golfing_woman: golfing_woman$1,
	golfing_man: golfing_man$1,
	ping_pong: ping_pong$1,
	badminton: badminton$1,
	goal_net: goal_net$1,
	ice_hockey: ice_hockey$1,
	field_hockey: field_hockey$1,
	lacrosse: lacrosse$1,
	cricket: cricket$1,
	ski: ski$1,
	skier: skier$1,
	snowboarder: snowboarder$1,
	person_fencing: person_fencing$1,
	women_wrestling: women_wrestling$1,
	men_wrestling: men_wrestling$1,
	woman_cartwheeling: woman_cartwheeling$1,
	man_cartwheeling: man_cartwheeling$1,
	woman_playing_handball: woman_playing_handball$1,
	man_playing_handball: man_playing_handball$1,
	ice_skate: ice_skate$1,
	curling_stone: curling_stone$1,
	skateboard: skateboard$1,
	sled: sled$1,
	bow_and_arrow: bow_and_arrow$1,
	fishing_pole_and_fish: fishing_pole_and_fish$1,
	boxing_glove: boxing_glove$1,
	martial_arts_uniform: martial_arts_uniform$1,
	rowing_woman: rowing_woman$1,
	rowing_man: rowing_man$1,
	climbing_woman: climbing_woman$1,
	climbing_man: climbing_man$1,
	swimming_woman: swimming_woman$1,
	swimming_man: swimming_man$1,
	woman_playing_water_polo: woman_playing_water_polo$1,
	man_playing_water_polo: man_playing_water_polo$1,
	woman_in_lotus_position: woman_in_lotus_position$1,
	man_in_lotus_position: man_in_lotus_position$1,
	surfing_woman: surfing_woman$1,
	surfing_man: surfing_man$1,
	bath: bath$1,
	basketball_woman: basketball_woman$1,
	basketball_man: basketball_man$1,
	weight_lifting_woman: weight_lifting_woman$1,
	weight_lifting_man: weight_lifting_man$1,
	biking_woman: biking_woman$1,
	biking_man: biking_man$1,
	mountain_biking_woman: mountain_biking_woman$1,
	mountain_biking_man: mountain_biking_man$1,
	horse_racing: horse_racing$1,
	business_suit_levitating: business_suit_levitating$1,
	trophy: trophy$1,
	running_shirt_with_sash: running_shirt_with_sash$1,
	medal_sports: medal_sports$1,
	medal_military: medal_military$1,
	"1st_place_medal": {
	keywords: [
		"award",
		"winning",
		"first"
	],
	char: "🥇",
	fitzpatrick_scale: false,
	category: "activity"
},
	"2nd_place_medal": {
	keywords: [
		"award",
		"second"
	],
	char: "🥈",
	fitzpatrick_scale: false,
	category: "activity"
},
	"3rd_place_medal": {
	keywords: [
		"award",
		"third"
	],
	char: "🥉",
	fitzpatrick_scale: false,
	category: "activity"
},
	reminder_ribbon: reminder_ribbon$1,
	rosette: rosette$1,
	ticket: ticket$1,
	tickets: tickets$1,
	performing_arts: performing_arts$1,
	art: art$1,
	circus_tent: circus_tent$1,
	woman_juggling: woman_juggling$1,
	man_juggling: man_juggling$1,
	microphone: microphone$1,
	headphones: headphones$1,
	musical_score: musical_score$1,
	musical_keyboard: musical_keyboard$1,
	drum: drum$1,
	saxophone: saxophone$1,
	trumpet: trumpet$1,
	guitar: guitar$1,
	violin: violin$1,
	clapper: clapper$1,
	video_game: video_game$1,
	space_invader: space_invader$1,
	dart: dart$1,
	game_die: game_die$1,
	chess_pawn: chess_pawn$1,
	slot_machine: slot_machine$1,
	jigsaw: jigsaw$1,
	bowling: bowling$1,
	red_car: red_car$1,
	taxi: taxi$1,
	blue_car: blue_car$1,
	bus: bus$1,
	trolleybus: trolleybus$1,
	racing_car: racing_car$1,
	police_car: police_car$1,
	ambulance: ambulance$1,
	fire_engine: fire_engine$1,
	minibus: minibus$1,
	truck: truck$1,
	articulated_lorry: articulated_lorry$1,
	tractor: tractor$1,
	kick_scooter: kick_scooter$1,
	motorcycle: motorcycle$1,
	bike: bike$1,
	motor_scooter: motor_scooter$1,
	rotating_light: rotating_light$1,
	oncoming_police_car: oncoming_police_car$1,
	oncoming_bus: oncoming_bus$1,
	oncoming_automobile: oncoming_automobile$1,
	oncoming_taxi: oncoming_taxi$1,
	aerial_tramway: aerial_tramway$1,
	mountain_cableway: mountain_cableway$1,
	suspension_railway: suspension_railway$1,
	railway_car: railway_car$1,
	train: train$1,
	monorail: monorail$1,
	bullettrain_side: bullettrain_side$1,
	bullettrain_front: bullettrain_front$1,
	light_rail: light_rail$1,
	mountain_railway: mountain_railway$1,
	steam_locomotive: steam_locomotive$1,
	train2: train2$1,
	metro: metro$1,
	tram: tram$1,
	station: station$1,
	flying_saucer: flying_saucer$1,
	helicopter: helicopter$1,
	small_airplane: small_airplane$1,
	airplane: airplane$1,
	flight_departure: flight_departure$1,
	flight_arrival: flight_arrival$1,
	sailboat: sailboat$1,
	motor_boat: motor_boat$1,
	speedboat: speedboat$1,
	ferry: ferry$1,
	passenger_ship: passenger_ship$1,
	rocket: rocket$1,
	artificial_satellite: artificial_satellite$1,
	seat: seat$1,
	canoe: canoe$1,
	anchor: anchor$1,
	construction: construction$1,
	fuelpump: fuelpump$1,
	busstop: busstop$1,
	vertical_traffic_light: vertical_traffic_light$1,
	traffic_light: traffic_light$1,
	checkered_flag: checkered_flag$1,
	ship: ship$1,
	ferris_wheel: ferris_wheel$1,
	roller_coaster: roller_coaster$1,
	carousel_horse: carousel_horse$1,
	building_construction: building_construction$1,
	foggy: foggy$1,
	tokyo_tower: tokyo_tower$1,
	factory: factory$1,
	fountain: fountain$1,
	rice_scene: rice_scene$1,
	mountain: mountain$1,
	mountain_snow: mountain_snow$1,
	mount_fuji: mount_fuji$1,
	volcano: volcano$1,
	japan: japan$1,
	camping: camping$1,
	tent: tent$1,
	national_park: national_park$1,
	motorway: motorway$1,
	railway_track: railway_track$1,
	sunrise: sunrise$1,
	sunrise_over_mountains: sunrise_over_mountains$1,
	desert: desert$1,
	beach_umbrella: beach_umbrella$1,
	desert_island: desert_island$1,
	city_sunrise: city_sunrise$1,
	city_sunset: city_sunset$1,
	cityscape: cityscape$1,
	night_with_stars: night_with_stars$1,
	bridge_at_night: bridge_at_night$1,
	milky_way: milky_way$1,
	stars: stars$1,
	sparkler: sparkler$1,
	fireworks: fireworks$1,
	rainbow: rainbow$1,
	houses: houses$1,
	european_castle: european_castle$1,
	japanese_castle: japanese_castle$1,
	stadium: stadium$1,
	statue_of_liberty: statue_of_liberty$1,
	house: house$1,
	house_with_garden: house_with_garden$1,
	derelict_house: derelict_house$1,
	office: office$1,
	department_store: department_store$1,
	post_office: post_office$1,
	european_post_office: european_post_office$1,
	hospital: hospital$1,
	bank: bank$1,
	hotel: hotel$1,
	convenience_store: convenience_store$1,
	school: school$1,
	love_hotel: love_hotel$1,
	wedding: wedding$1,
	classical_building: classical_building$1,
	church: church$1,
	mosque: mosque$1,
	synagogue: synagogue$1,
	kaaba: kaaba$1,
	shinto_shrine: shinto_shrine$1,
	watch: watch$1,
	iphone: iphone$1,
	calling: calling$1,
	computer: computer$1,
	keyboard: keyboard$1,
	desktop_computer: desktop_computer$1,
	printer: printer$1,
	computer_mouse: computer_mouse$1,
	trackball: trackball$1,
	joystick: joystick$1,
	clamp: clamp$1,
	minidisc: minidisc$1,
	floppy_disk: floppy_disk$1,
	cd: cd$1,
	dvd: dvd$1,
	vhs: vhs$1,
	camera: camera$1,
	camera_flash: camera_flash$1,
	video_camera: video_camera$1,
	movie_camera: movie_camera$1,
	film_projector: film_projector$1,
	film_strip: film_strip$1,
	telephone_receiver: telephone_receiver$1,
	phone: phone$2,
	pager: pager$1,
	fax: fax$1,
	tv: tv$1,
	radio: radio$1,
	studio_microphone: studio_microphone$1,
	level_slider: level_slider$1,
	control_knobs: control_knobs$1,
	compass: compass$1,
	stopwatch: stopwatch$1,
	timer_clock: timer_clock$1,
	alarm_clock: alarm_clock$1,
	mantelpiece_clock: mantelpiece_clock$1,
	hourglass_flowing_sand: hourglass_flowing_sand$1,
	hourglass: hourglass$1,
	satellite: satellite$1,
	battery: battery$1,
	electric_plug: electric_plug$1,
	bulb: bulb$1,
	flashlight: flashlight$1,
	candle: candle$1,
	fire_extinguisher: fire_extinguisher$1,
	wastebasket: wastebasket$1,
	oil_drum: oil_drum$1,
	money_with_wings: money_with_wings$1,
	dollar: dollar$2,
	yen: yen$2,
	euro: euro$2,
	pound: pound$2,
	moneybag: moneybag$1,
	credit_card: credit_card$1,
	gem: gem$1,
	balance_scale: balance_scale$1,
	toolbox: toolbox$1,
	wrench: wrench$1,
	hammer: hammer$1,
	hammer_and_pick: hammer_and_pick$1,
	hammer_and_wrench: hammer_and_wrench$1,
	pick: pick$1,
	nut_and_bolt: nut_and_bolt$1,
	gear: gear$1,
	brick: brick$1,
	chains: chains$1,
	magnet: magnet$1,
	gun: gun$1,
	bomb: bomb$1,
	firecracker: firecracker$1,
	hocho: hocho$1,
	dagger: dagger$2,
	crossed_swords: crossed_swords$1,
	shield: shield$1,
	smoking: smoking$1,
	skull_and_crossbones: skull_and_crossbones$1,
	coffin: coffin$1,
	funeral_urn: funeral_urn$1,
	amphora: amphora$1,
	crystal_ball: crystal_ball$1,
	prayer_beads: prayer_beads$1,
	nazar_amulet: nazar_amulet$1,
	barber: barber$1,
	alembic: alembic$1,
	telescope: telescope$1,
	microscope: microscope$1,
	hole: hole$1,
	pill: pill$1,
	syringe: syringe$1,
	dna: dna$1,
	microbe: microbe$1,
	petri_dish: petri_dish$1,
	test_tube: test_tube$1,
	thermometer: thermometer$1,
	broom: broom$1,
	basket: basket$1,
	toilet_paper: toilet_paper$1,
	label: label$1,
	bookmark: bookmark$1,
	toilet: toilet$1,
	shower: shower$1,
	bathtub: bathtub$1,
	soap: soap$1,
	sponge: sponge$1,
	lotion_bottle: lotion_bottle$1,
	key: key$1,
	old_key: old_key$1,
	couch_and_lamp: couch_and_lamp$1,
	sleeping_bed: sleeping_bed$1,
	bed: bed$1,
	door: door$1,
	bellhop_bell: bellhop_bell$1,
	teddy_bear: teddy_bear$1,
	framed_picture: framed_picture$1,
	world_map: world_map$1,
	parasol_on_ground: parasol_on_ground$1,
	moyai: moyai$1,
	shopping: shopping$1,
	shopping_cart: shopping_cart$1,
	balloon: balloon$1,
	flags: flags$1,
	ribbon: ribbon$1,
	gift: gift$1,
	confetti_ball: confetti_ball$1,
	tada: tada$1,
	dolls: dolls$1,
	wind_chime: wind_chime$1,
	crossed_flags: crossed_flags$1,
	izakaya_lantern: izakaya_lantern$1,
	red_envelope: red_envelope$1,
	email: email$1,
	envelope_with_arrow: envelope_with_arrow$1,
	incoming_envelope: incoming_envelope$1,
	"e-mail": {
	keywords: [
		"communication",
		"inbox"
	],
	char: "📧",
	fitzpatrick_scale: false,
	category: "objects"
},
	love_letter: love_letter$1,
	postbox: postbox$1,
	mailbox_closed: mailbox_closed$1,
	mailbox: mailbox$1,
	mailbox_with_mail: mailbox_with_mail$1,
	mailbox_with_no_mail: mailbox_with_no_mail$1,
	"package": {
	keywords: [
		"mail",
		"gift",
		"cardboard",
		"box",
		"moving"
	],
	char: "📦",
	fitzpatrick_scale: false,
	category: "objects"
},
	postal_horn: postal_horn$1,
	inbox_tray: inbox_tray$1,
	outbox_tray: outbox_tray$1,
	scroll: scroll$1,
	page_with_curl: page_with_curl$1,
	bookmark_tabs: bookmark_tabs$1,
	receipt: receipt$1,
	bar_chart: bar_chart$1,
	chart_with_upwards_trend: chart_with_upwards_trend$1,
	chart_with_downwards_trend: chart_with_downwards_trend$1,
	page_facing_up: page_facing_up$1,
	date: date$1,
	calendar: calendar$1,
	spiral_calendar: spiral_calendar$1,
	card_index: card_index$1,
	card_file_box: card_file_box$1,
	ballot_box: ballot_box$1,
	file_cabinet: file_cabinet$1,
	clipboard: clipboard$2,
	spiral_notepad: spiral_notepad$1,
	file_folder: file_folder$1,
	open_file_folder: open_file_folder$1,
	card_index_dividers: card_index_dividers$1,
	newspaper_roll: newspaper_roll$1,
	newspaper: newspaper$1,
	notebook: notebook$1,
	closed_book: closed_book$1,
	green_book: green_book$1,
	blue_book: blue_book$1,
	orange_book: orange_book$1,
	notebook_with_decorative_cover: notebook_with_decorative_cover$1,
	ledger: ledger$1,
	books: books$1,
	open_book: open_book$1,
	safety_pin: safety_pin$1,
	link: link$3,
	paperclip: paperclip$1,
	paperclips: paperclips$1,
	scissors: scissors$1,
	triangular_ruler: triangular_ruler$1,
	straight_ruler: straight_ruler$1,
	abacus: abacus$1,
	pushpin: pushpin$1,
	round_pushpin: round_pushpin$1,
	triangular_flag_on_post: triangular_flag_on_post$1,
	white_flag: white_flag$1,
	black_flag: black_flag$1,
	rainbow_flag: rainbow_flag$1,
	closed_lock_with_key: closed_lock_with_key$1,
	lock: lock$1,
	unlock: unlock$1,
	lock_with_ink_pen: lock_with_ink_pen$1,
	pen: pen$1,
	fountain_pen: fountain_pen$1,
	black_nib: black_nib$1,
	memo: memo$1,
	pencil2: pencil2$1,
	crayon: crayon$1,
	paintbrush: paintbrush$1,
	mag: mag$1,
	mag_right: mag_right$1,
	heart: heart$1,
	orange_heart: orange_heart$1,
	yellow_heart: yellow_heart$1,
	green_heart: green_heart$1,
	blue_heart: blue_heart$1,
	purple_heart: purple_heart$1,
	black_heart: black_heart$1,
	broken_heart: broken_heart$1,
	heavy_heart_exclamation: heavy_heart_exclamation$1,
	two_hearts: two_hearts$1,
	revolving_hearts: revolving_hearts$1,
	heartbeat: heartbeat$1,
	heartpulse: heartpulse$1,
	sparkling_heart: sparkling_heart$1,
	cupid: cupid$1,
	gift_heart: gift_heart$1,
	heart_decoration: heart_decoration$1,
	peace_symbol: peace_symbol$1,
	latin_cross: latin_cross$1,
	star_and_crescent: star_and_crescent$1,
	om: om$1,
	wheel_of_dharma: wheel_of_dharma$1,
	star_of_david: star_of_david$1,
	six_pointed_star: six_pointed_star$1,
	menorah: menorah$1,
	yin_yang: yin_yang$1,
	orthodox_cross: orthodox_cross$1,
	place_of_worship: place_of_worship$1,
	ophiuchus: ophiuchus$1,
	aries: aries$1,
	taurus: taurus$1,
	gemini: gemini$1,
	cancer: cancer$1,
	leo: leo$1,
	virgo: virgo$1,
	libra: libra$1,
	scorpius: scorpius$1,
	sagittarius: sagittarius$1,
	capricorn: capricorn$1,
	aquarius: aquarius$1,
	pisces: pisces$1,
	id: id$1,
	atom_symbol: atom_symbol$1,
	u7a7a: u7a7a$1,
	u5272: u5272$1,
	radioactive: radioactive$1,
	biohazard: biohazard$1,
	mobile_phone_off: mobile_phone_off$1,
	vibration_mode: vibration_mode$1,
	u6709: u6709$1,
	u7121: u7121$1,
	u7533: u7533$1,
	u55b6: u55b6$1,
	u6708: u6708$1,
	eight_pointed_black_star: eight_pointed_black_star$1,
	vs: vs$1,
	accept: accept$1,
	white_flower: white_flower$1,
	ideograph_advantage: ideograph_advantage$1,
	secret: secret$1,
	congratulations: congratulations$1,
	u5408: u5408$1,
	u6e80: u6e80$1,
	u7981: u7981$1,
	a: a$2,
	b: b$1,
	ab: ab$1,
	cl: cl$1,
	o2: o2$1,
	sos: sos$1,
	no_entry: no_entry$1,
	name_badge: name_badge$1,
	no_entry_sign: no_entry_sign$1,
	x: x$1,
	o: o$2,
	stop_sign: stop_sign$1,
	anger: anger$1,
	hotsprings: hotsprings$1,
	no_pedestrians: no_pedestrians$1,
	do_not_litter: do_not_litter$1,
	no_bicycles: no_bicycles$1,
	"non-potable_water": {
	keywords: [
		"drink",
		"faucet",
		"tap",
		"circle"
	],
	char: "🚱",
	fitzpatrick_scale: false,
	category: "symbols"
},
	underage: underage$1,
	no_mobile_phones: no_mobile_phones$1,
	exclamation: exclamation$1,
	grey_exclamation: grey_exclamation$1,
	question: question$1,
	grey_question: grey_question$1,
	bangbang: bangbang$1,
	interrobang: interrobang$1,
	low_brightness: low_brightness$1,
	high_brightness: high_brightness$1,
	trident: trident$1,
	fleur_de_lis: fleur_de_lis$1,
	part_alternation_mark: part_alternation_mark$1,
	warning: warning$1,
	children_crossing: children_crossing$1,
	beginner: beginner$1,
	recycle: recycle$1,
	u6307: u6307$1,
	chart: chart$1,
	sparkle: sparkle$1,
	eight_spoked_asterisk: eight_spoked_asterisk$1,
	negative_squared_cross_mark: negative_squared_cross_mark$1,
	white_check_mark: white_check_mark$1,
	diamond_shape_with_a_dot_inside: diamond_shape_with_a_dot_inside$1,
	cyclone: cyclone$1,
	loop: loop$1,
	globe_with_meridians: globe_with_meridians$1,
	m: m$1,
	atm: atm$1,
	sa: sa$1,
	passport_control: passport_control$1,
	customs: customs$1,
	baggage_claim: baggage_claim$1,
	left_luggage: left_luggage$1,
	wheelchair: wheelchair$1,
	no_smoking: no_smoking$1,
	wc: wc$1,
	parking: parking$1,
	potable_water: potable_water$1,
	mens: mens$1,
	womens: womens$1,
	baby_symbol: baby_symbol$1,
	restroom: restroom$1,
	put_litter_in_its_place: put_litter_in_its_place$1,
	cinema: cinema$1,
	signal_strength: signal_strength$1,
	koko: koko$1,
	ng: ng$1,
	ok: ok$1,
	up: up$1,
	cool: cool$1,
	"new": {
	keywords: [
		"blue-square",
		"words",
		"start"
	],
	char: "🆕",
	fitzpatrick_scale: false,
	category: "symbols"
},
	free: free$1,
	zero: zero$2,
	one: one$1,
	two: two$1,
	three: three$1,
	four: four$1,
	five: five$1,
	six: six$1,
	seven: seven$1,
	eight: eight$1,
	nine: nine$1,
	keycap_ten: keycap_ten$1,
	asterisk: asterisk$1,
	eject_button: eject_button$1,
	arrow_forward: arrow_forward$1,
	pause_button: pause_button$1,
	next_track_button: next_track_button$1,
	stop_button: stop_button$1,
	record_button: record_button$1,
	play_or_pause_button: play_or_pause_button$1,
	previous_track_button: previous_track_button$1,
	fast_forward: fast_forward$1,
	rewind: rewind$1,
	twisted_rightwards_arrows: twisted_rightwards_arrows$1,
	repeat: repeat$1,
	repeat_one: repeat_one$1,
	arrow_backward: arrow_backward$1,
	arrow_up_small: arrow_up_small$1,
	arrow_down_small: arrow_down_small$1,
	arrow_double_up: arrow_double_up$1,
	arrow_double_down: arrow_double_down$1,
	arrow_right: arrow_right$1,
	arrow_left: arrow_left$1,
	arrow_up: arrow_up$1,
	arrow_down: arrow_down$1,
	arrow_upper_right: arrow_upper_right$1,
	arrow_lower_right: arrow_lower_right$1,
	arrow_lower_left: arrow_lower_left$1,
	arrow_upper_left: arrow_upper_left$1,
	arrow_up_down: arrow_up_down$1,
	left_right_arrow: left_right_arrow$1,
	arrows_counterclockwise: arrows_counterclockwise$1,
	arrow_right_hook: arrow_right_hook$1,
	leftwards_arrow_with_hook: leftwards_arrow_with_hook$1,
	arrow_heading_up: arrow_heading_up$1,
	arrow_heading_down: arrow_heading_down$1,
	hash: hash$1,
	information_source: information_source$1,
	abc: abc$1,
	abcd: abcd$1,
	capital_abcd: capital_abcd$1,
	symbols: symbols$1,
	musical_note: musical_note$1,
	notes: notes$1,
	wavy_dash: wavy_dash$1,
	curly_loop: curly_loop$1,
	heavy_check_mark: heavy_check_mark$1,
	arrows_clockwise: arrows_clockwise$1,
	heavy_plus_sign: heavy_plus_sign$1,
	heavy_minus_sign: heavy_minus_sign$1,
	heavy_division_sign: heavy_division_sign$1,
	heavy_multiplication_x: heavy_multiplication_x$1,
	infinity: infinity$1,
	heavy_dollar_sign: heavy_dollar_sign$1,
	currency_exchange: currency_exchange$1,
	copyright: copyright$1,
	registered: registered$1,
	tm: tm$1,
	end: end$1,
	back: back$1,
	on: on$1,
	top: top$2,
	soon: soon$1,
	ballot_box_with_check: ballot_box_with_check$1,
	radio_button: radio_button$1,
	white_circle: white_circle$1,
	black_circle: black_circle$1,
	red_circle: red_circle$1,
	large_blue_circle: large_blue_circle$1,
	small_orange_diamond: small_orange_diamond$1,
	small_blue_diamond: small_blue_diamond$1,
	large_orange_diamond: large_orange_diamond$1,
	large_blue_diamond: large_blue_diamond$1,
	small_red_triangle: small_red_triangle$1,
	black_small_square: black_small_square$1,
	white_small_square: white_small_square$1,
	black_large_square: black_large_square$1,
	white_large_square: white_large_square$1,
	small_red_triangle_down: small_red_triangle_down$1,
	black_medium_square: black_medium_square$1,
	white_medium_square: white_medium_square$1,
	black_medium_small_square: black_medium_small_square$1,
	white_medium_small_square: white_medium_small_square$1,
	black_square_button: black_square_button$1,
	white_square_button: white_square_button$1,
	speaker: speaker$1,
	sound: sound$1,
	loud_sound: loud_sound$1,
	mute: mute$1,
	mega: mega$1,
	loudspeaker: loudspeaker$1,
	bell: bell$1,
	no_bell: no_bell$1,
	black_joker: black_joker$1,
	mahjong: mahjong$1,
	spades: spades$2,
	clubs: clubs$2,
	hearts: hearts$2,
	diamonds: diamonds$1,
	flower_playing_cards: flower_playing_cards$1,
	thought_balloon: thought_balloon$1,
	right_anger_bubble: right_anger_bubble$1,
	speech_balloon: speech_balloon$1,
	left_speech_bubble: left_speech_bubble$1,
	clock1: clock1$1,
	clock2: clock2$1,
	clock3: clock3$1,
	clock4: clock4$1,
	clock5: clock5$1,
	clock6: clock6$1,
	clock7: clock7$1,
	clock8: clock8$1,
	clock9: clock9$1,
	clock10: clock10$1,
	clock11: clock11$1,
	clock12: clock12$1,
	clock130: clock130$1,
	clock230: clock230$1,
	clock330: clock330$1,
	clock430: clock430$1,
	clock530: clock530$1,
	clock630: clock630$1,
	clock730: clock730$1,
	clock830: clock830$1,
	clock930: clock930$1,
	clock1030: clock1030$1,
	clock1130: clock1130$1,
	clock1230: clock1230$1,
	afghanistan: afghanistan$1,
	aland_islands: aland_islands$1,
	albania: albania$1,
	algeria: algeria$1,
	american_samoa: american_samoa$1,
	andorra: andorra$1,
	angola: angola$1,
	anguilla: anguilla$1,
	antarctica: antarctica$1,
	antigua_barbuda: antigua_barbuda$1,
	argentina: argentina$1,
	armenia: armenia$1,
	aruba: aruba$1,
	australia: australia$1,
	austria: austria$1,
	azerbaijan: azerbaijan$1,
	bahamas: bahamas$1,
	bahrain: bahrain$1,
	bangladesh: bangladesh$1,
	barbados: barbados$1,
	belarus: belarus$1,
	belgium: belgium$1,
	belize: belize$1,
	benin: benin$1,
	bermuda: bermuda$1,
	bhutan: bhutan$1,
	bolivia: bolivia$1,
	caribbean_netherlands: caribbean_netherlands$1,
	bosnia_herzegovina: bosnia_herzegovina$1,
	botswana: botswana$1,
	brazil: brazil$1,
	british_indian_ocean_territory: british_indian_ocean_territory$1,
	british_virgin_islands: british_virgin_islands$1,
	brunei: brunei$1,
	bulgaria: bulgaria$1,
	burkina_faso: burkina_faso$1,
	burundi: burundi$1,
	cape_verde: cape_verde$1,
	cambodia: cambodia$1,
	cameroon: cameroon$1,
	canada: canada$1,
	canary_islands: canary_islands$1,
	cayman_islands: cayman_islands$1,
	central_african_republic: central_african_republic$1,
	chad: chad$1,
	chile: chile$1,
	cn: cn$1,
	christmas_island: christmas_island$1,
	cocos_islands: cocos_islands$1,
	colombia: colombia$1,
	comoros: comoros$1,
	congo_brazzaville: congo_brazzaville$1,
	congo_kinshasa: congo_kinshasa$1,
	cook_islands: cook_islands$1,
	costa_rica: costa_rica$1,
	croatia: croatia$1,
	cuba: cuba$1,
	curacao: curacao$1,
	cyprus: cyprus$1,
	czech_republic: czech_republic$1,
	denmark: denmark$1,
	djibouti: djibouti$1,
	dominica: dominica$1,
	dominican_republic: dominican_republic$1,
	ecuador: ecuador$1,
	egypt: egypt$1,
	el_salvador: el_salvador$1,
	equatorial_guinea: equatorial_guinea$1,
	eritrea: eritrea$1,
	estonia: estonia$1,
	ethiopia: ethiopia$1,
	eu: eu$1,
	falkland_islands: falkland_islands$1,
	faroe_islands: faroe_islands$1,
	fiji: fiji$1,
	finland: finland$1,
	fr: fr$1,
	french_guiana: french_guiana$1,
	french_polynesia: french_polynesia$1,
	french_southern_territories: french_southern_territories$1,
	gabon: gabon$1,
	gambia: gambia$1,
	georgia: georgia$1,
	de: de$1,
	ghana: ghana$1,
	gibraltar: gibraltar$1,
	greece: greece$1,
	greenland: greenland$1,
	grenada: grenada$1,
	guadeloupe: guadeloupe$1,
	guam: guam$1,
	guatemala: guatemala$1,
	guernsey: guernsey$1,
	guinea: guinea$1,
	guinea_bissau: guinea_bissau$1,
	guyana: guyana$1,
	haiti: haiti$1,
	honduras: honduras$1,
	hong_kong: hong_kong$1,
	hungary: hungary$1,
	iceland: iceland$1,
	india: india$1,
	indonesia: indonesia$1,
	iran: iran$1,
	iraq: iraq$1,
	ireland: ireland$1,
	isle_of_man: isle_of_man$1,
	israel: israel$1,
	it: it$2,
	cote_divoire: cote_divoire$1,
	jamaica: jamaica$1,
	jp: jp$1,
	jersey: jersey$1,
	jordan: jordan$1,
	kazakhstan: kazakhstan$1,
	kenya: kenya$1,
	kiribati: kiribati$1,
	kosovo: kosovo$1,
	kuwait: kuwait$1,
	kyrgyzstan: kyrgyzstan$1,
	laos: laos$1,
	latvia: latvia$1,
	lebanon: lebanon$1,
	lesotho: lesotho$1,
	liberia: liberia$1,
	libya: libya$1,
	liechtenstein: liechtenstein$1,
	lithuania: lithuania$1,
	luxembourg: luxembourg$1,
	macau: macau$1,
	macedonia: macedonia$1,
	madagascar: madagascar$1,
	malawi: malawi$1,
	malaysia: malaysia$1,
	maldives: maldives$1,
	mali: mali$1,
	malta: malta$1,
	marshall_islands: marshall_islands$1,
	martinique: martinique$1,
	mauritania: mauritania$1,
	mauritius: mauritius$1,
	mayotte: mayotte$1,
	mexico: mexico$1,
	micronesia: micronesia$1,
	moldova: moldova$1,
	monaco: monaco$1,
	mongolia: mongolia$1,
	montenegro: montenegro$1,
	montserrat: montserrat$1,
	morocco: morocco$1,
	mozambique: mozambique$1,
	myanmar: myanmar$1,
	namibia: namibia$1,
	nauru: nauru$1,
	nepal: nepal$1,
	netherlands: netherlands$1,
	new_caledonia: new_caledonia$1,
	new_zealand: new_zealand$1,
	nicaragua: nicaragua$1,
	niger: niger$1,
	nigeria: nigeria$1,
	niue: niue$1,
	norfolk_island: norfolk_island$1,
	northern_mariana_islands: northern_mariana_islands$1,
	north_korea: north_korea$1,
	norway: norway$1,
	oman: oman$1,
	pakistan: pakistan$1,
	palau: palau$1,
	palestinian_territories: palestinian_territories$1,
	panama: panama$1,
	papua_new_guinea: papua_new_guinea$1,
	paraguay: paraguay$1,
	peru: peru$1,
	philippines: philippines$1,
	pitcairn_islands: pitcairn_islands$1,
	poland: poland$1,
	portugal: portugal$1,
	puerto_rico: puerto_rico$1,
	qatar: qatar$1,
	reunion: reunion$1,
	romania: romania$1,
	ru: ru$1,
	rwanda: rwanda$1,
	st_barthelemy: st_barthelemy$1,
	st_helena: st_helena$1,
	st_kitts_nevis: st_kitts_nevis$1,
	st_lucia: st_lucia$1,
	st_pierre_miquelon: st_pierre_miquelon$1,
	st_vincent_grenadines: st_vincent_grenadines$1,
	samoa: samoa$1,
	san_marino: san_marino$1,
	sao_tome_principe: sao_tome_principe$1,
	saudi_arabia: saudi_arabia$1,
	senegal: senegal$1,
	serbia: serbia$1,
	seychelles: seychelles$1,
	sierra_leone: sierra_leone$1,
	singapore: singapore$1,
	sint_maarten: sint_maarten$1,
	slovakia: slovakia$1,
	slovenia: slovenia$1,
	solomon_islands: solomon_islands$1,
	somalia: somalia$1,
	south_africa: south_africa$1,
	south_georgia_south_sandwich_islands: south_georgia_south_sandwich_islands$1,
	kr: kr$1,
	south_sudan: south_sudan$1,
	es: es$1,
	sri_lanka: sri_lanka$1,
	sudan: sudan$1,
	suriname: suriname$1,
	swaziland: swaziland$1,
	sweden: sweden$1,
	switzerland: switzerland$1,
	syria: syria$1,
	taiwan: taiwan$1,
	tajikistan: tajikistan$1,
	tanzania: tanzania$1,
	thailand: thailand$1,
	timor_leste: timor_leste$1,
	togo: togo$1,
	tokelau: tokelau$1,
	tonga: tonga$1,
	trinidad_tobago: trinidad_tobago$1,
	tunisia: tunisia$1,
	tr: tr$1,
	turkmenistan: turkmenistan$1,
	turks_caicos_islands: turks_caicos_islands$1,
	tuvalu: tuvalu$1,
	uganda: uganda$1,
	ukraine: ukraine$1,
	united_arab_emirates: united_arab_emirates$1,
	uk: uk$1,
	england: england$1,
	scotland: scotland$1,
	wales: wales$1,
	us: us$1,
	us_virgin_islands: us_virgin_islands$1,
	uruguay: uruguay$1,
	uzbekistan: uzbekistan$1,
	vanuatu: vanuatu$1,
	vatican_city: vatican_city$1,
	venezuela: venezuela$1,
	vietnam: vietnam$1,
	wallis_futuna: wallis_futuna$1,
	western_sahara: western_sahara$1,
	yemen: yemen$1,
	zambia: zambia$1,
	zimbabwe: zimbabwe$1,
	united_nations: united_nations$1,
	pirate_flag: pirate_flag$1
};var lib$3 = {exports: {}};var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };

/**
 * iterateObject
 * Iterates an object. Note the object field order may differ.
 *
 * @name iterateObject
 * @function
 * @param {Object} obj The input object.
 * @param {Function} fn A function that will be called with the current value, field name and provided object.
 * @return {Function} The `iterateObject` function.
 */
function iterateObject$2(obj, fn) {
    var i = 0,
        keys = [];

    if (Array.isArray(obj)) {
        for (; i < obj.length; ++i) {
            if (fn(obj[i], i, obj) === false) {
                break;
            }
        }
    } else if ((typeof obj === "undefined" ? "undefined" : _typeof(obj)) === "object" && obj !== null) {
        keys = Object.keys(obj);
        for (; i < keys.length; ++i) {
            if (fn(obj[keys[i]], keys[i], obj) === false) {
                break;
            }
        }
    }
}

var lib$2 = iterateObject$2;// Dependencies
var iterateObject$1 = lib$2;

/**
 * mapObject
 * Array-map like for objects.
 *
 * @name mapObject
 * @function
 * @param {Object} obj The input object.
 * @param {Function} fn A function returning the field values.
 * @param {Boolean|Object} clone If `true`, the input object will be cloned.
 * If `clone` is an object, it will be used as target object.
 * @return {Object} The modified object.
 */
function mapObject(obj, fn, clone) {
    var dst = clone === true ? {} : clone ? clone : obj;
    iterateObject$1(obj, function (v, n, o) {
        dst[n] = fn(v, n, o);
    });
    return dst;
}

var lib$1 = mapObject;var grinning = {
	keywords: [
		"face",
		"smile",
		"happy",
		"joy",
		":D",
		"grin"
	],
	char: "😀",
	fitzpatrick_scale: false,
	category: "people"
};
var grimacing = {
	keywords: [
		"face",
		"grimace",
		"teeth"
	],
	char: "😬",
	fitzpatrick_scale: false,
	category: "people"
};
var grin = {
	keywords: [
		"face",
		"happy",
		"smile",
		"joy",
		"kawaii"
	],
	char: "😁",
	fitzpatrick_scale: false,
	category: "people"
};
var joy = {
	keywords: [
		"face",
		"cry",
		"tears",
		"weep",
		"happy",
		"happytears",
		"haha"
	],
	char: "😂",
	fitzpatrick_scale: false,
	category: "people"
};
var rofl = {
	keywords: [
		"face",
		"rolling",
		"floor",
		"laughing",
		"lol",
		"haha"
	],
	char: "🤣",
	fitzpatrick_scale: false,
	category: "people"
};
var partying = {
	keywords: [
		"face",
		"celebration",
		"woohoo"
	],
	char: "🥳",
	fitzpatrick_scale: false,
	category: "people"
};
var smiley = {
	keywords: [
		"face",
		"happy",
		"joy",
		"haha",
		":D",
		":)",
		"smile",
		"funny"
	],
	char: "😃",
	fitzpatrick_scale: false,
	category: "people"
};
var smile$1 = {
	keywords: [
		"face",
		"happy",
		"joy",
		"funny",
		"haha",
		"laugh",
		"like",
		":D",
		":)"
	],
	char: "😄",
	fitzpatrick_scale: false,
	category: "people"
};
var sweat_smile = {
	keywords: [
		"face",
		"hot",
		"happy",
		"laugh",
		"sweat",
		"smile",
		"relief"
	],
	char: "😅",
	fitzpatrick_scale: false,
	category: "people"
};
var laughing = {
	keywords: [
		"happy",
		"joy",
		"lol",
		"satisfied",
		"haha",
		"face",
		"glad",
		"XD",
		"laugh"
	],
	char: "😆",
	fitzpatrick_scale: false,
	category: "people"
};
var innocent = {
	keywords: [
		"face",
		"angel",
		"heaven",
		"halo"
	],
	char: "😇",
	fitzpatrick_scale: false,
	category: "people"
};
var wink = {
	keywords: [
		"face",
		"happy",
		"mischievous",
		"secret",
		";)",
		"smile",
		"eye"
	],
	char: "😉",
	fitzpatrick_scale: false,
	category: "people"
};
var blush = {
	keywords: [
		"face",
		"smile",
		"happy",
		"flushed",
		"crush",
		"embarrassed",
		"shy",
		"joy"
	],
	char: "😊",
	fitzpatrick_scale: false,
	category: "people"
};
var slightly_smiling_face = {
	keywords: [
		"face",
		"smile"
	],
	char: "🙂",
	fitzpatrick_scale: false,
	category: "people"
};
var upside_down_face = {
	keywords: [
		"face",
		"flipped",
		"silly",
		"smile"
	],
	char: "🙃",
	fitzpatrick_scale: false,
	category: "people"
};
var relaxed = {
	keywords: [
		"face",
		"blush",
		"massage",
		"happiness"
	],
	char: "☺️",
	fitzpatrick_scale: false,
	category: "people"
};
var yum = {
	keywords: [
		"happy",
		"joy",
		"tongue",
		"smile",
		"face",
		"silly",
		"yummy",
		"nom",
		"delicious",
		"savouring"
	],
	char: "😋",
	fitzpatrick_scale: false,
	category: "people"
};
var relieved = {
	keywords: [
		"face",
		"relaxed",
		"phew",
		"massage",
		"happiness"
	],
	char: "😌",
	fitzpatrick_scale: false,
	category: "people"
};
var heart_eyes = {
	keywords: [
		"face",
		"love",
		"like",
		"affection",
		"valentines",
		"infatuation",
		"crush",
		"heart"
	],
	char: "😍",
	fitzpatrick_scale: false,
	category: "people"
};
var smiling_face_with_three_hearts = {
	keywords: [
		"face",
		"love",
		"like",
		"affection",
		"valentines",
		"infatuation",
		"crush",
		"hearts",
		"adore"
	],
	char: "🥰",
	fitzpatrick_scale: false,
	category: "people"
};
var kissing_heart = {
	keywords: [
		"face",
		"love",
		"like",
		"affection",
		"valentines",
		"infatuation",
		"kiss"
	],
	char: "😘",
	fitzpatrick_scale: false,
	category: "people"
};
var kissing = {
	keywords: [
		"love",
		"like",
		"face",
		"3",
		"valentines",
		"infatuation",
		"kiss"
	],
	char: "😗",
	fitzpatrick_scale: false,
	category: "people"
};
var kissing_smiling_eyes = {
	keywords: [
		"face",
		"affection",
		"valentines",
		"infatuation",
		"kiss"
	],
	char: "😙",
	fitzpatrick_scale: false,
	category: "people"
};
var kissing_closed_eyes = {
	keywords: [
		"face",
		"love",
		"like",
		"affection",
		"valentines",
		"infatuation",
		"kiss"
	],
	char: "😚",
	fitzpatrick_scale: false,
	category: "people"
};
var stuck_out_tongue_winking_eye = {
	keywords: [
		"face",
		"prank",
		"childish",
		"playful",
		"mischievous",
		"smile",
		"wink",
		"tongue"
	],
	char: "😜",
	fitzpatrick_scale: false,
	category: "people"
};
var zany = {
	keywords: [
		"face",
		"goofy",
		"crazy"
	],
	char: "🤪",
	fitzpatrick_scale: false,
	category: "people"
};
var raised_eyebrow = {
	keywords: [
		"face",
		"distrust",
		"scepticism",
		"disapproval",
		"disbelief",
		"surprise"
	],
	char: "🤨",
	fitzpatrick_scale: false,
	category: "people"
};
var monocle = {
	keywords: [
		"face",
		"stuffy",
		"wealthy"
	],
	char: "🧐",
	fitzpatrick_scale: false,
	category: "people"
};
var stuck_out_tongue_closed_eyes = {
	keywords: [
		"face",
		"prank",
		"playful",
		"mischievous",
		"smile",
		"tongue"
	],
	char: "😝",
	fitzpatrick_scale: false,
	category: "people"
};
var stuck_out_tongue = {
	keywords: [
		"face",
		"prank",
		"childish",
		"playful",
		"mischievous",
		"smile",
		"tongue"
	],
	char: "😛",
	fitzpatrick_scale: false,
	category: "people"
};
var money_mouth_face = {
	keywords: [
		"face",
		"rich",
		"dollar",
		"money"
	],
	char: "🤑",
	fitzpatrick_scale: false,
	category: "people"
};
var nerd_face = {
	keywords: [
		"face",
		"nerdy",
		"geek",
		"dork"
	],
	char: "🤓",
	fitzpatrick_scale: false,
	category: "people"
};
var sunglasses = {
	keywords: [
		"face",
		"cool",
		"smile",
		"summer",
		"beach",
		"sunglass"
	],
	char: "😎",
	fitzpatrick_scale: false,
	category: "people"
};
var star_struck = {
	keywords: [
		"face",
		"smile",
		"starry",
		"eyes",
		"grinning"
	],
	char: "🤩",
	fitzpatrick_scale: false,
	category: "people"
};
var clown_face = {
	keywords: [
		"face"
	],
	char: "🤡",
	fitzpatrick_scale: false,
	category: "people"
};
var cowboy_hat_face = {
	keywords: [
		"face",
		"cowgirl",
		"hat"
	],
	char: "🤠",
	fitzpatrick_scale: false,
	category: "people"
};
var hugs = {
	keywords: [
		"face",
		"smile",
		"hug"
	],
	char: "🤗",
	fitzpatrick_scale: false,
	category: "people"
};
var smirk = {
	keywords: [
		"face",
		"smile",
		"mean",
		"prank",
		"smug",
		"sarcasm"
	],
	char: "😏",
	fitzpatrick_scale: false,
	category: "people"
};
var no_mouth = {
	keywords: [
		"face",
		"hellokitty"
	],
	char: "😶",
	fitzpatrick_scale: false,
	category: "people"
};
var neutral_face = {
	keywords: [
		"indifference",
		"meh",
		":|",
		"neutral"
	],
	char: "😐",
	fitzpatrick_scale: false,
	category: "people"
};
var expressionless = {
	keywords: [
		"face",
		"indifferent",
		"-_-",
		"meh",
		"deadpan"
	],
	char: "😑",
	fitzpatrick_scale: false,
	category: "people"
};
var unamused = {
	keywords: [
		"indifference",
		"bored",
		"straight face",
		"serious",
		"sarcasm",
		"unimpressed",
		"skeptical",
		"dubious",
		"side_eye"
	],
	char: "😒",
	fitzpatrick_scale: false,
	category: "people"
};
var roll_eyes = {
	keywords: [
		"face",
		"eyeroll",
		"frustrated"
	],
	char: "🙄",
	fitzpatrick_scale: false,
	category: "people"
};
var thinking = {
	keywords: [
		"face",
		"hmmm",
		"think",
		"consider"
	],
	char: "🤔",
	fitzpatrick_scale: false,
	category: "people"
};
var lying_face = {
	keywords: [
		"face",
		"lie",
		"pinocchio"
	],
	char: "🤥",
	fitzpatrick_scale: false,
	category: "people"
};
var hand_over_mouth = {
	keywords: [
		"face",
		"whoops",
		"shock",
		"surprise"
	],
	char: "🤭",
	fitzpatrick_scale: false,
	category: "people"
};
var shushing = {
	keywords: [
		"face",
		"quiet",
		"shhh"
	],
	char: "🤫",
	fitzpatrick_scale: false,
	category: "people"
};
var symbols_over_mouth = {
	keywords: [
		"face",
		"swearing",
		"cursing",
		"cussing",
		"profanity",
		"expletive"
	],
	char: "🤬",
	fitzpatrick_scale: false,
	category: "people"
};
var exploding_head = {
	keywords: [
		"face",
		"shocked",
		"mind",
		"blown"
	],
	char: "🤯",
	fitzpatrick_scale: false,
	category: "people"
};
var flushed = {
	keywords: [
		"face",
		"blush",
		"shy",
		"flattered"
	],
	char: "😳",
	fitzpatrick_scale: false,
	category: "people"
};
var disappointed = {
	keywords: [
		"face",
		"sad",
		"upset",
		"depressed",
		":("
	],
	char: "😞",
	fitzpatrick_scale: false,
	category: "people"
};
var worried = {
	keywords: [
		"face",
		"concern",
		"nervous",
		":("
	],
	char: "😟",
	fitzpatrick_scale: false,
	category: "people"
};
var angry = {
	keywords: [
		"mad",
		"face",
		"annoyed",
		"frustrated"
	],
	char: "😠",
	fitzpatrick_scale: false,
	category: "people"
};
var rage = {
	keywords: [
		"angry",
		"mad",
		"hate",
		"despise"
	],
	char: "😡",
	fitzpatrick_scale: false,
	category: "people"
};
var pensive = {
	keywords: [
		"face",
		"sad",
		"depressed",
		"upset"
	],
	char: "😔",
	fitzpatrick_scale: false,
	category: "people"
};
var confused = {
	keywords: [
		"face",
		"indifference",
		"huh",
		"weird",
		"hmmm",
		":/"
	],
	char: "😕",
	fitzpatrick_scale: false,
	category: "people"
};
var slightly_frowning_face = {
	keywords: [
		"face",
		"frowning",
		"disappointed",
		"sad",
		"upset"
	],
	char: "🙁",
	fitzpatrick_scale: false,
	category: "people"
};
var frowning_face = {
	keywords: [
		"face",
		"sad",
		"upset",
		"frown"
	],
	char: "☹",
	fitzpatrick_scale: false,
	category: "people"
};
var persevere = {
	keywords: [
		"face",
		"sick",
		"no",
		"upset",
		"oops"
	],
	char: "😣",
	fitzpatrick_scale: false,
	category: "people"
};
var confounded = {
	keywords: [
		"face",
		"confused",
		"sick",
		"unwell",
		"oops",
		":S"
	],
	char: "😖",
	fitzpatrick_scale: false,
	category: "people"
};
var tired_face = {
	keywords: [
		"sick",
		"whine",
		"upset",
		"frustrated"
	],
	char: "😫",
	fitzpatrick_scale: false,
	category: "people"
};
var weary = {
	keywords: [
		"face",
		"tired",
		"sleepy",
		"sad",
		"frustrated",
		"upset"
	],
	char: "😩",
	fitzpatrick_scale: false,
	category: "people"
};
var pleading = {
	keywords: [
		"face",
		"begging",
		"mercy"
	],
	char: "🥺",
	fitzpatrick_scale: false,
	category: "people"
};
var triumph = {
	keywords: [
		"face",
		"gas",
		"phew",
		"proud",
		"pride"
	],
	char: "😤",
	fitzpatrick_scale: false,
	category: "people"
};
var open_mouth = {
	keywords: [
		"face",
		"surprise",
		"impressed",
		"wow",
		"whoa",
		":O"
	],
	char: "😮",
	fitzpatrick_scale: false,
	category: "people"
};
var scream = {
	keywords: [
		"face",
		"munch",
		"scared",
		"omg"
	],
	char: "😱",
	fitzpatrick_scale: false,
	category: "people"
};
var fearful = {
	keywords: [
		"face",
		"scared",
		"terrified",
		"nervous",
		"oops",
		"huh"
	],
	char: "😨",
	fitzpatrick_scale: false,
	category: "people"
};
var cold_sweat = {
	keywords: [
		"face",
		"nervous",
		"sweat"
	],
	char: "😰",
	fitzpatrick_scale: false,
	category: "people"
};
var hushed = {
	keywords: [
		"face",
		"woo",
		"shh"
	],
	char: "😯",
	fitzpatrick_scale: false,
	category: "people"
};
var frowning = {
	keywords: [
		"face",
		"aw",
		"what"
	],
	char: "😦",
	fitzpatrick_scale: false,
	category: "people"
};
var anguished = {
	keywords: [
		"face",
		"stunned",
		"nervous"
	],
	char: "😧",
	fitzpatrick_scale: false,
	category: "people"
};
var cry = {
	keywords: [
		"face",
		"tears",
		"sad",
		"depressed",
		"upset",
		":'("
	],
	char: "😢",
	fitzpatrick_scale: false,
	category: "people"
};
var disappointed_relieved = {
	keywords: [
		"face",
		"phew",
		"sweat",
		"nervous"
	],
	char: "😥",
	fitzpatrick_scale: false,
	category: "people"
};
var drooling_face = {
	keywords: [
		"face"
	],
	char: "🤤",
	fitzpatrick_scale: false,
	category: "people"
};
var sleepy = {
	keywords: [
		"face",
		"tired",
		"rest",
		"nap"
	],
	char: "😪",
	fitzpatrick_scale: false,
	category: "people"
};
var sweat = {
	keywords: [
		"face",
		"hot",
		"sad",
		"tired",
		"exercise"
	],
	char: "😓",
	fitzpatrick_scale: false,
	category: "people"
};
var hot = {
	keywords: [
		"face",
		"feverish",
		"heat",
		"red",
		"sweating"
	],
	char: "🥵",
	fitzpatrick_scale: false,
	category: "people"
};
var cold = {
	keywords: [
		"face",
		"blue",
		"freezing",
		"frozen",
		"frostbite",
		"icicles"
	],
	char: "🥶",
	fitzpatrick_scale: false,
	category: "people"
};
var sob = {
	keywords: [
		"face",
		"cry",
		"tears",
		"sad",
		"upset",
		"depressed"
	],
	char: "😭",
	fitzpatrick_scale: false,
	category: "people"
};
var dizzy_face = {
	keywords: [
		"spent",
		"unconscious",
		"xox",
		"dizzy"
	],
	char: "😵",
	fitzpatrick_scale: false,
	category: "people"
};
var astonished = {
	keywords: [
		"face",
		"xox",
		"surprised",
		"poisoned"
	],
	char: "😲",
	fitzpatrick_scale: false,
	category: "people"
};
var zipper_mouth_face = {
	keywords: [
		"face",
		"sealed",
		"zipper",
		"secret"
	],
	char: "🤐",
	fitzpatrick_scale: false,
	category: "people"
};
var nauseated_face = {
	keywords: [
		"face",
		"vomit",
		"gross",
		"green",
		"sick",
		"throw up",
		"ill"
	],
	char: "🤢",
	fitzpatrick_scale: false,
	category: "people"
};
var sneezing_face = {
	keywords: [
		"face",
		"gesundheit",
		"sneeze",
		"sick",
		"allergy"
	],
	char: "🤧",
	fitzpatrick_scale: false,
	category: "people"
};
var vomiting = {
	keywords: [
		"face",
		"sick"
	],
	char: "🤮",
	fitzpatrick_scale: false,
	category: "people"
};
var mask = {
	keywords: [
		"face",
		"sick",
		"ill",
		"disease"
	],
	char: "😷",
	fitzpatrick_scale: false,
	category: "people"
};
var face_with_thermometer = {
	keywords: [
		"sick",
		"temperature",
		"thermometer",
		"cold",
		"fever"
	],
	char: "🤒",
	fitzpatrick_scale: false,
	category: "people"
};
var face_with_head_bandage = {
	keywords: [
		"injured",
		"clumsy",
		"bandage",
		"hurt"
	],
	char: "🤕",
	fitzpatrick_scale: false,
	category: "people"
};
var woozy = {
	keywords: [
		"face",
		"dizzy",
		"intoxicated",
		"tipsy",
		"wavy"
	],
	char: "🥴",
	fitzpatrick_scale: false,
	category: "people"
};
var sleeping = {
	keywords: [
		"face",
		"tired",
		"sleepy",
		"night",
		"zzz"
	],
	char: "😴",
	fitzpatrick_scale: false,
	category: "people"
};
var zzz = {
	keywords: [
		"sleepy",
		"tired",
		"dream"
	],
	char: "💤",
	fitzpatrick_scale: false,
	category: "people"
};
var poop = {
	keywords: [
		"hankey",
		"shitface",
		"fail",
		"turd",
		"shit"
	],
	char: "💩",
	fitzpatrick_scale: false,
	category: "people"
};
var smiling_imp = {
	keywords: [
		"devil",
		"horns"
	],
	char: "😈",
	fitzpatrick_scale: false,
	category: "people"
};
var imp = {
	keywords: [
		"devil",
		"angry",
		"horns"
	],
	char: "👿",
	fitzpatrick_scale: false,
	category: "people"
};
var japanese_ogre = {
	keywords: [
		"monster",
		"red",
		"mask",
		"halloween",
		"scary",
		"creepy",
		"devil",
		"demon",
		"japanese",
		"ogre"
	],
	char: "👹",
	fitzpatrick_scale: false,
	category: "people"
};
var japanese_goblin = {
	keywords: [
		"red",
		"evil",
		"mask",
		"monster",
		"scary",
		"creepy",
		"japanese",
		"goblin"
	],
	char: "👺",
	fitzpatrick_scale: false,
	category: "people"
};
var skull = {
	keywords: [
		"dead",
		"skeleton",
		"creepy",
		"death"
	],
	char: "💀",
	fitzpatrick_scale: false,
	category: "people"
};
var ghost = {
	keywords: [
		"halloween",
		"spooky",
		"scary"
	],
	char: "👻",
	fitzpatrick_scale: false,
	category: "people"
};
var alien = {
	keywords: [
		"UFO",
		"paul",
		"weird",
		"outer_space"
	],
	char: "👽",
	fitzpatrick_scale: false,
	category: "people"
};
var robot = {
	keywords: [
		"computer",
		"machine",
		"bot"
	],
	char: "🤖",
	fitzpatrick_scale: false,
	category: "people"
};
var smiley_cat = {
	keywords: [
		"animal",
		"cats",
		"happy",
		"smile"
	],
	char: "😺",
	fitzpatrick_scale: false,
	category: "people"
};
var smile_cat = {
	keywords: [
		"animal",
		"cats",
		"smile"
	],
	char: "😸",
	fitzpatrick_scale: false,
	category: "people"
};
var joy_cat = {
	keywords: [
		"animal",
		"cats",
		"haha",
		"happy",
		"tears"
	],
	char: "😹",
	fitzpatrick_scale: false,
	category: "people"
};
var heart_eyes_cat = {
	keywords: [
		"animal",
		"love",
		"like",
		"affection",
		"cats",
		"valentines",
		"heart"
	],
	char: "😻",
	fitzpatrick_scale: false,
	category: "people"
};
var smirk_cat = {
	keywords: [
		"animal",
		"cats",
		"smirk"
	],
	char: "😼",
	fitzpatrick_scale: false,
	category: "people"
};
var kissing_cat = {
	keywords: [
		"animal",
		"cats",
		"kiss"
	],
	char: "😽",
	fitzpatrick_scale: false,
	category: "people"
};
var scream_cat = {
	keywords: [
		"animal",
		"cats",
		"munch",
		"scared",
		"scream"
	],
	char: "🙀",
	fitzpatrick_scale: false,
	category: "people"
};
var crying_cat_face = {
	keywords: [
		"animal",
		"tears",
		"weep",
		"sad",
		"cats",
		"upset",
		"cry"
	],
	char: "😿",
	fitzpatrick_scale: false,
	category: "people"
};
var pouting_cat = {
	keywords: [
		"animal",
		"cats"
	],
	char: "😾",
	fitzpatrick_scale: false,
	category: "people"
};
var palms_up = {
	keywords: [
		"hands",
		"gesture",
		"cupped",
		"prayer"
	],
	char: "🤲",
	fitzpatrick_scale: true,
	category: "people"
};
var raised_hands = {
	keywords: [
		"gesture",
		"hooray",
		"yea",
		"celebration",
		"hands"
	],
	char: "🙌",
	fitzpatrick_scale: true,
	category: "people"
};
var clap = {
	keywords: [
		"hands",
		"praise",
		"applause",
		"congrats",
		"yay"
	],
	char: "👏",
	fitzpatrick_scale: true,
	category: "people"
};
var wave = {
	keywords: [
		"hands",
		"gesture",
		"goodbye",
		"solong",
		"farewell",
		"hello",
		"hi",
		"palm"
	],
	char: "👋",
	fitzpatrick_scale: true,
	category: "people"
};
var call_me_hand = {
	keywords: [
		"hands",
		"gesture"
	],
	char: "🤙",
	fitzpatrick_scale: true,
	category: "people"
};
var facepunch = {
	keywords: [
		"angry",
		"violence",
		"fist",
		"hit",
		"attack",
		"hand"
	],
	char: "👊",
	fitzpatrick_scale: true,
	category: "people"
};
var fist = {
	keywords: [
		"fingers",
		"hand",
		"grasp"
	],
	char: "✊",
	fitzpatrick_scale: true,
	category: "people"
};
var fist_left = {
	keywords: [
		"hand",
		"fistbump"
	],
	char: "🤛",
	fitzpatrick_scale: true,
	category: "people"
};
var fist_right = {
	keywords: [
		"hand",
		"fistbump"
	],
	char: "🤜",
	fitzpatrick_scale: true,
	category: "people"
};
var v = {
	keywords: [
		"fingers",
		"ohyeah",
		"hand",
		"peace",
		"victory",
		"two"
	],
	char: "✌",
	fitzpatrick_scale: true,
	category: "people"
};
var ok_hand = {
	keywords: [
		"fingers",
		"limbs",
		"perfect",
		"ok",
		"okay"
	],
	char: "👌",
	fitzpatrick_scale: true,
	category: "people"
};
var raised_hand = {
	keywords: [
		"fingers",
		"stop",
		"highfive",
		"palm",
		"ban"
	],
	char: "✋",
	fitzpatrick_scale: true,
	category: "people"
};
var raised_back_of_hand = {
	keywords: [
		"fingers",
		"raised",
		"backhand"
	],
	char: "🤚",
	fitzpatrick_scale: true,
	category: "people"
};
var open_hands = {
	keywords: [
		"fingers",
		"butterfly",
		"hands",
		"open"
	],
	char: "👐",
	fitzpatrick_scale: true,
	category: "people"
};
var muscle = {
	keywords: [
		"arm",
		"flex",
		"hand",
		"summer",
		"strong",
		"biceps"
	],
	char: "💪",
	fitzpatrick_scale: true,
	category: "people"
};
var pray = {
	keywords: [
		"please",
		"hope",
		"wish",
		"namaste",
		"highfive"
	],
	char: "🙏",
	fitzpatrick_scale: true,
	category: "people"
};
var foot = {
	keywords: [
		"kick",
		"stomp"
	],
	char: "🦶",
	fitzpatrick_scale: true,
	category: "people"
};
var leg$1 = {
	keywords: [
		"kick",
		"limb"
	],
	char: "🦵",
	fitzpatrick_scale: true,
	category: "people"
};
var handshake = {
	keywords: [
		"agreement",
		"shake"
	],
	char: "🤝",
	fitzpatrick_scale: false,
	category: "people"
};
var point_up = {
	keywords: [
		"hand",
		"fingers",
		"direction",
		"up"
	],
	char: "☝",
	fitzpatrick_scale: true,
	category: "people"
};
var point_up_2 = {
	keywords: [
		"fingers",
		"hand",
		"direction",
		"up"
	],
	char: "👆",
	fitzpatrick_scale: true,
	category: "people"
};
var point_down = {
	keywords: [
		"fingers",
		"hand",
		"direction",
		"down"
	],
	char: "👇",
	fitzpatrick_scale: true,
	category: "people"
};
var point_left = {
	keywords: [
		"direction",
		"fingers",
		"hand",
		"left"
	],
	char: "👈",
	fitzpatrick_scale: true,
	category: "people"
};
var point_right = {
	keywords: [
		"fingers",
		"hand",
		"direction",
		"right"
	],
	char: "👉",
	fitzpatrick_scale: true,
	category: "people"
};
var fu = {
	keywords: [
		"hand",
		"fingers",
		"rude",
		"middle",
		"flipping"
	],
	char: "🖕",
	fitzpatrick_scale: true,
	category: "people"
};
var raised_hand_with_fingers_splayed = {
	keywords: [
		"hand",
		"fingers",
		"palm"
	],
	char: "🖐",
	fitzpatrick_scale: true,
	category: "people"
};
var love_you = {
	keywords: [
		"hand",
		"fingers",
		"gesture"
	],
	char: "🤟",
	fitzpatrick_scale: true,
	category: "people"
};
var metal = {
	keywords: [
		"hand",
		"fingers",
		"evil_eye",
		"sign_of_horns",
		"rock_on"
	],
	char: "🤘",
	fitzpatrick_scale: true,
	category: "people"
};
var crossed_fingers = {
	keywords: [
		"good",
		"lucky"
	],
	char: "🤞",
	fitzpatrick_scale: true,
	category: "people"
};
var vulcan_salute = {
	keywords: [
		"hand",
		"fingers",
		"spock",
		"star trek"
	],
	char: "🖖",
	fitzpatrick_scale: true,
	category: "people"
};
var writing_hand = {
	keywords: [
		"lower_left_ballpoint_pen",
		"stationery",
		"write",
		"compose"
	],
	char: "✍",
	fitzpatrick_scale: true,
	category: "people"
};
var selfie = {
	keywords: [
		"camera",
		"phone"
	],
	char: "🤳",
	fitzpatrick_scale: true,
	category: "people"
};
var nail_care = {
	keywords: [
		"beauty",
		"manicure",
		"finger",
		"fashion",
		"nail"
	],
	char: "💅",
	fitzpatrick_scale: true,
	category: "people"
};
var lips = {
	keywords: [
		"mouth",
		"kiss"
	],
	char: "👄",
	fitzpatrick_scale: false,
	category: "people"
};
var tooth = {
	keywords: [
		"teeth",
		"dentist"
	],
	char: "🦷",
	fitzpatrick_scale: false,
	category: "people"
};
var tongue = {
	keywords: [
		"mouth",
		"playful"
	],
	char: "👅",
	fitzpatrick_scale: false,
	category: "people"
};
var ear = {
	keywords: [
		"face",
		"hear",
		"sound",
		"listen"
	],
	char: "👂",
	fitzpatrick_scale: true,
	category: "people"
};
var nose = {
	keywords: [
		"smell",
		"sniff"
	],
	char: "👃",
	fitzpatrick_scale: true,
	category: "people"
};
var eye = {
	keywords: [
		"face",
		"look",
		"see",
		"watch",
		"stare"
	],
	char: "👁",
	fitzpatrick_scale: false,
	category: "people"
};
var eyes = {
	keywords: [
		"look",
		"watch",
		"stalk",
		"peek",
		"see"
	],
	char: "👀",
	fitzpatrick_scale: false,
	category: "people"
};
var brain = {
	keywords: [
		"smart",
		"intelligent"
	],
	char: "🧠",
	fitzpatrick_scale: false,
	category: "people"
};
var bust_in_silhouette = {
	keywords: [
		"user",
		"person",
		"human"
	],
	char: "👤",
	fitzpatrick_scale: false,
	category: "people"
};
var busts_in_silhouette = {
	keywords: [
		"user",
		"person",
		"human",
		"group",
		"team"
	],
	char: "👥",
	fitzpatrick_scale: false,
	category: "people"
};
var speaking_head = {
	keywords: [
		"user",
		"person",
		"human",
		"sing",
		"say",
		"talk"
	],
	char: "🗣",
	fitzpatrick_scale: false,
	category: "people"
};
var baby = {
	keywords: [
		"child",
		"boy",
		"girl",
		"toddler"
	],
	char: "👶",
	fitzpatrick_scale: true,
	category: "people"
};
var child = {
	keywords: [
		"gender-neutral",
		"young"
	],
	char: "🧒",
	fitzpatrick_scale: true,
	category: "people"
};
var boy = {
	keywords: [
		"man",
		"male",
		"guy",
		"teenager"
	],
	char: "👦",
	fitzpatrick_scale: true,
	category: "people"
};
var girl = {
	keywords: [
		"female",
		"woman",
		"teenager"
	],
	char: "👧",
	fitzpatrick_scale: true,
	category: "people"
};
var adult = {
	keywords: [
		"gender-neutral",
		"person"
	],
	char: "🧑",
	fitzpatrick_scale: true,
	category: "people"
};
var man = {
	keywords: [
		"mustache",
		"father",
		"dad",
		"guy",
		"classy",
		"sir",
		"moustache"
	],
	char: "👨",
	fitzpatrick_scale: true,
	category: "people"
};
var woman = {
	keywords: [
		"female",
		"girls",
		"lady"
	],
	char: "👩",
	fitzpatrick_scale: true,
	category: "people"
};
var blonde_woman = {
	keywords: [
		"woman",
		"female",
		"girl",
		"blonde",
		"person"
	],
	char: "👱‍♀️",
	fitzpatrick_scale: true,
	category: "people"
};
var blonde_man = {
	keywords: [
		"man",
		"male",
		"boy",
		"blonde",
		"guy",
		"person"
	],
	char: "👱",
	fitzpatrick_scale: true,
	category: "people"
};
var bearded_person = {
	keywords: [
		"person",
		"bewhiskered"
	],
	char: "🧔",
	fitzpatrick_scale: true,
	category: "people"
};
var older_adult = {
	keywords: [
		"human",
		"elder",
		"senior",
		"gender-neutral"
	],
	char: "🧓",
	fitzpatrick_scale: true,
	category: "people"
};
var older_man = {
	keywords: [
		"human",
		"male",
		"men",
		"old",
		"elder",
		"senior"
	],
	char: "👴",
	fitzpatrick_scale: true,
	category: "people"
};
var older_woman = {
	keywords: [
		"human",
		"female",
		"women",
		"lady",
		"old",
		"elder",
		"senior"
	],
	char: "👵",
	fitzpatrick_scale: true,
	category: "people"
};
var man_with_gua_pi_mao = {
	keywords: [
		"male",
		"boy",
		"chinese"
	],
	char: "👲",
	fitzpatrick_scale: true,
	category: "people"
};
var woman_with_headscarf = {
	keywords: [
		"female",
		"hijab",
		"mantilla",
		"tichel"
	],
	char: "🧕",
	fitzpatrick_scale: true,
	category: "people"
};
var woman_with_turban = {
	keywords: [
		"female",
		"indian",
		"hinduism",
		"arabs",
		"woman"
	],
	char: "👳‍♀️",
	fitzpatrick_scale: true,
	category: "people"
};
var man_with_turban = {
	keywords: [
		"male",
		"indian",
		"hinduism",
		"arabs"
	],
	char: "👳",
	fitzpatrick_scale: true,
	category: "people"
};
var policewoman = {
	keywords: [
		"woman",
		"police",
		"law",
		"legal",
		"enforcement",
		"arrest",
		"911",
		"female"
	],
	char: "👮‍♀️",
	fitzpatrick_scale: true,
	category: "people"
};
var policeman = {
	keywords: [
		"man",
		"police",
		"law",
		"legal",
		"enforcement",
		"arrest",
		"911"
	],
	char: "👮",
	fitzpatrick_scale: true,
	category: "people"
};
var construction_worker_woman = {
	keywords: [
		"female",
		"human",
		"wip",
		"build",
		"construction",
		"worker",
		"labor",
		"woman"
	],
	char: "👷‍♀️",
	fitzpatrick_scale: true,
	category: "people"
};
var construction_worker_man = {
	keywords: [
		"male",
		"human",
		"wip",
		"guy",
		"build",
		"construction",
		"worker",
		"labor"
	],
	char: "👷",
	fitzpatrick_scale: true,
	category: "people"
};
var guardswoman = {
	keywords: [
		"uk",
		"gb",
		"british",
		"female",
		"royal",
		"woman"
	],
	char: "💂‍♀️",
	fitzpatrick_scale: true,
	category: "people"
};
var guardsman = {
	keywords: [
		"uk",
		"gb",
		"british",
		"male",
		"guy",
		"royal"
	],
	char: "💂",
	fitzpatrick_scale: true,
	category: "people"
};
var female_detective = {
	keywords: [
		"human",
		"spy",
		"detective",
		"female",
		"woman"
	],
	char: "🕵️‍♀️",
	fitzpatrick_scale: true,
	category: "people"
};
var male_detective = {
	keywords: [
		"human",
		"spy",
		"detective"
	],
	char: "🕵",
	fitzpatrick_scale: true,
	category: "people"
};
var woman_health_worker = {
	keywords: [
		"doctor",
		"nurse",
		"therapist",
		"healthcare",
		"woman",
		"human"
	],
	char: "👩‍⚕️",
	fitzpatrick_scale: true,
	category: "people"
};
var man_health_worker = {
	keywords: [
		"doctor",
		"nurse",
		"therapist",
		"healthcare",
		"man",
		"human"
	],
	char: "👨‍⚕️",
	fitzpatrick_scale: true,
	category: "people"
};
var woman_farmer = {
	keywords: [
		"rancher",
		"gardener",
		"woman",
		"human"
	],
	char: "👩‍🌾",
	fitzpatrick_scale: true,
	category: "people"
};
var man_farmer = {
	keywords: [
		"rancher",
		"gardener",
		"man",
		"human"
	],
	char: "👨‍🌾",
	fitzpatrick_scale: true,
	category: "people"
};
var woman_cook = {
	keywords: [
		"chef",
		"woman",
		"human"
	],
	char: "👩‍🍳",
	fitzpatrick_scale: true,
	category: "people"
};
var man_cook = {
	keywords: [
		"chef",
		"man",
		"human"
	],
	char: "👨‍🍳",
	fitzpatrick_scale: true,
	category: "people"
};
var woman_student = {
	keywords: [
		"graduate",
		"woman",
		"human"
	],
	char: "👩‍🎓",
	fitzpatrick_scale: true,
	category: "people"
};
var man_student = {
	keywords: [
		"graduate",
		"man",
		"human"
	],
	char: "👨‍🎓",
	fitzpatrick_scale: true,
	category: "people"
};
var woman_singer = {
	keywords: [
		"rockstar",
		"entertainer",
		"woman",
		"human"
	],
	char: "👩‍🎤",
	fitzpatrick_scale: true,
	category: "people"
};
var man_singer = {
	keywords: [
		"rockstar",
		"entertainer",
		"man",
		"human"
	],
	char: "👨‍🎤",
	fitzpatrick_scale: true,
	category: "people"
};
var woman_teacher = {
	keywords: [
		"instructor",
		"professor",
		"woman",
		"human"
	],
	char: "👩‍🏫",
	fitzpatrick_scale: true,
	category: "people"
};
var man_teacher = {
	keywords: [
		"instructor",
		"professor",
		"man",
		"human"
	],
	char: "👨‍🏫",
	fitzpatrick_scale: true,
	category: "people"
};
var woman_factory_worker = {
	keywords: [
		"assembly",
		"industrial",
		"woman",
		"human"
	],
	char: "👩‍🏭",
	fitzpatrick_scale: true,
	category: "people"
};
var man_factory_worker = {
	keywords: [
		"assembly",
		"industrial",
		"man",
		"human"
	],
	char: "👨‍🏭",
	fitzpatrick_scale: true,
	category: "people"
};
var woman_technologist = {
	keywords: [
		"coder",
		"developer",
		"engineer",
		"programmer",
		"software",
		"woman",
		"human",
		"laptop",
		"computer"
	],
	char: "👩‍💻",
	fitzpatrick_scale: true,
	category: "people"
};
var man_technologist = {
	keywords: [
		"coder",
		"developer",
		"engineer",
		"programmer",
		"software",
		"man",
		"human",
		"laptop",
		"computer"
	],
	char: "👨‍💻",
	fitzpatrick_scale: true,
	category: "people"
};
var woman_office_worker = {
	keywords: [
		"business",
		"manager",
		"woman",
		"human"
	],
	char: "👩‍💼",
	fitzpatrick_scale: true,
	category: "people"
};
var man_office_worker = {
	keywords: [
		"business",
		"manager",
		"man",
		"human"
	],
	char: "👨‍💼",
	fitzpatrick_scale: true,
	category: "people"
};
var woman_mechanic = {
	keywords: [
		"plumber",
		"woman",
		"human",
		"wrench"
	],
	char: "👩‍🔧",
	fitzpatrick_scale: true,
	category: "people"
};
var man_mechanic = {
	keywords: [
		"plumber",
		"man",
		"human",
		"wrench"
	],
	char: "👨‍🔧",
	fitzpatrick_scale: true,
	category: "people"
};
var woman_scientist = {
	keywords: [
		"biologist",
		"chemist",
		"engineer",
		"physicist",
		"woman",
		"human"
	],
	char: "👩‍🔬",
	fitzpatrick_scale: true,
	category: "people"
};
var man_scientist = {
	keywords: [
		"biologist",
		"chemist",
		"engineer",
		"physicist",
		"man",
		"human"
	],
	char: "👨‍🔬",
	fitzpatrick_scale: true,
	category: "people"
};
var woman_artist = {
	keywords: [
		"painter",
		"woman",
		"human"
	],
	char: "👩‍🎨",
	fitzpatrick_scale: true,
	category: "people"
};
var man_artist = {
	keywords: [
		"painter",
		"man",
		"human"
	],
	char: "👨‍🎨",
	fitzpatrick_scale: true,
	category: "people"
};
var woman_firefighter = {
	keywords: [
		"fireman",
		"woman",
		"human"
	],
	char: "👩‍🚒",
	fitzpatrick_scale: true,
	category: "people"
};
var man_firefighter = {
	keywords: [
		"fireman",
		"man",
		"human"
	],
	char: "👨‍🚒",
	fitzpatrick_scale: true,
	category: "people"
};
var woman_pilot = {
	keywords: [
		"aviator",
		"plane",
		"woman",
		"human"
	],
	char: "👩‍✈️",
	fitzpatrick_scale: true,
	category: "people"
};
var man_pilot = {
	keywords: [
		"aviator",
		"plane",
		"man",
		"human"
	],
	char: "👨‍✈️",
	fitzpatrick_scale: true,
	category: "people"
};
var woman_astronaut = {
	keywords: [
		"space",
		"rocket",
		"woman",
		"human"
	],
	char: "👩‍🚀",
	fitzpatrick_scale: true,
	category: "people"
};
var man_astronaut = {
	keywords: [
		"space",
		"rocket",
		"man",
		"human"
	],
	char: "👨‍🚀",
	fitzpatrick_scale: true,
	category: "people"
};
var woman_judge = {
	keywords: [
		"justice",
		"court",
		"woman",
		"human"
	],
	char: "👩‍⚖️",
	fitzpatrick_scale: true,
	category: "people"
};
var man_judge = {
	keywords: [
		"justice",
		"court",
		"man",
		"human"
	],
	char: "👨‍⚖️",
	fitzpatrick_scale: true,
	category: "people"
};
var woman_superhero = {
	keywords: [
		"woman",
		"female",
		"good",
		"heroine",
		"superpowers"
	],
	char: "🦸‍♀️",
	fitzpatrick_scale: true,
	category: "people"
};
var man_superhero = {
	keywords: [
		"man",
		"male",
		"good",
		"hero",
		"superpowers"
	],
	char: "🦸‍♂️",
	fitzpatrick_scale: true,
	category: "people"
};
var woman_supervillain = {
	keywords: [
		"woman",
		"female",
		"evil",
		"bad",
		"criminal",
		"heroine",
		"superpowers"
	],
	char: "🦹‍♀️",
	fitzpatrick_scale: true,
	category: "people"
};
var man_supervillain = {
	keywords: [
		"man",
		"male",
		"evil",
		"bad",
		"criminal",
		"hero",
		"superpowers"
	],
	char: "🦹‍♂️",
	fitzpatrick_scale: true,
	category: "people"
};
var mrs_claus = {
	keywords: [
		"woman",
		"female",
		"xmas",
		"mother christmas"
	],
	char: "🤶",
	fitzpatrick_scale: true,
	category: "people"
};
var santa = {
	keywords: [
		"festival",
		"man",
		"male",
		"xmas",
		"father christmas"
	],
	char: "🎅",
	fitzpatrick_scale: true,
	category: "people"
};
var sorceress = {
	keywords: [
		"woman",
		"female",
		"mage",
		"witch"
	],
	char: "🧙‍♀️",
	fitzpatrick_scale: true,
	category: "people"
};
var wizard = {
	keywords: [
		"man",
		"male",
		"mage",
		"sorcerer"
	],
	char: "🧙‍♂️",
	fitzpatrick_scale: true,
	category: "people"
};
var woman_elf = {
	keywords: [
		"woman",
		"female"
	],
	char: "🧝‍♀️",
	fitzpatrick_scale: true,
	category: "people"
};
var man_elf = {
	keywords: [
		"man",
		"male"
	],
	char: "🧝‍♂️",
	fitzpatrick_scale: true,
	category: "people"
};
var woman_vampire = {
	keywords: [
		"woman",
		"female"
	],
	char: "🧛‍♀️",
	fitzpatrick_scale: true,
	category: "people"
};
var man_vampire = {
	keywords: [
		"man",
		"male",
		"dracula"
	],
	char: "🧛‍♂️",
	fitzpatrick_scale: true,
	category: "people"
};
var woman_zombie = {
	keywords: [
		"woman",
		"female",
		"undead",
		"walking dead"
	],
	char: "🧟‍♀️",
	fitzpatrick_scale: false,
	category: "people"
};
var man_zombie = {
	keywords: [
		"man",
		"male",
		"dracula",
		"undead",
		"walking dead"
	],
	char: "🧟‍♂️",
	fitzpatrick_scale: false,
	category: "people"
};
var woman_genie = {
	keywords: [
		"woman",
		"female"
	],
	char: "🧞‍♀️",
	fitzpatrick_scale: false,
	category: "people"
};
var man_genie = {
	keywords: [
		"man",
		"male"
	],
	char: "🧞‍♂️",
	fitzpatrick_scale: false,
	category: "people"
};
var mermaid = {
	keywords: [
		"woman",
		"female",
		"merwoman",
		"ariel"
	],
	char: "🧜‍♀️",
	fitzpatrick_scale: true,
	category: "people"
};
var merman = {
	keywords: [
		"man",
		"male",
		"triton"
	],
	char: "🧜‍♂️",
	fitzpatrick_scale: true,
	category: "people"
};
var woman_fairy = {
	keywords: [
		"woman",
		"female"
	],
	char: "🧚‍♀️",
	fitzpatrick_scale: true,
	category: "people"
};
var man_fairy = {
	keywords: [
		"man",
		"male"
	],
	char: "🧚‍♂️",
	fitzpatrick_scale: true,
	category: "people"
};
var angel = {
	keywords: [
		"heaven",
		"wings",
		"halo"
	],
	char: "👼",
	fitzpatrick_scale: true,
	category: "people"
};
var pregnant_woman = {
	keywords: [
		"baby"
	],
	char: "🤰",
	fitzpatrick_scale: true,
	category: "people"
};
var breastfeeding = {
	keywords: [
		"nursing",
		"baby"
	],
	char: "🤱",
	fitzpatrick_scale: true,
	category: "people"
};
var princess = {
	keywords: [
		"girl",
		"woman",
		"female",
		"blond",
		"crown",
		"royal",
		"queen"
	],
	char: "👸",
	fitzpatrick_scale: true,
	category: "people"
};
var prince = {
	keywords: [
		"boy",
		"man",
		"male",
		"crown",
		"royal",
		"king"
	],
	char: "🤴",
	fitzpatrick_scale: true,
	category: "people"
};
var bride_with_veil = {
	keywords: [
		"couple",
		"marriage",
		"wedding",
		"woman",
		"bride"
	],
	char: "👰",
	fitzpatrick_scale: true,
	category: "people"
};
var man_in_tuxedo = {
	keywords: [
		"couple",
		"marriage",
		"wedding",
		"groom"
	],
	char: "🤵",
	fitzpatrick_scale: true,
	category: "people"
};
var running_woman = {
	keywords: [
		"woman",
		"walking",
		"exercise",
		"race",
		"running",
		"female"
	],
	char: "🏃‍♀️",
	fitzpatrick_scale: true,
	category: "people"
};
var running_man = {
	keywords: [
		"man",
		"walking",
		"exercise",
		"race",
		"running"
	],
	char: "🏃",
	fitzpatrick_scale: true,
	category: "people"
};
var walking_woman = {
	keywords: [
		"human",
		"feet",
		"steps",
		"woman",
		"female"
	],
	char: "🚶‍♀️",
	fitzpatrick_scale: true,
	category: "people"
};
var walking_man = {
	keywords: [
		"human",
		"feet",
		"steps"
	],
	char: "🚶",
	fitzpatrick_scale: true,
	category: "people"
};
var dancer = {
	keywords: [
		"female",
		"girl",
		"woman",
		"fun"
	],
	char: "💃",
	fitzpatrick_scale: true,
	category: "people"
};
var man_dancing = {
	keywords: [
		"male",
		"boy",
		"fun",
		"dancer"
	],
	char: "🕺",
	fitzpatrick_scale: true,
	category: "people"
};
var dancing_women = {
	keywords: [
		"female",
		"bunny",
		"women",
		"girls"
	],
	char: "👯",
	fitzpatrick_scale: false,
	category: "people"
};
var dancing_men = {
	keywords: [
		"male",
		"bunny",
		"men",
		"boys"
	],
	char: "👯‍♂️",
	fitzpatrick_scale: false,
	category: "people"
};
var couple = {
	keywords: [
		"pair",
		"people",
		"human",
		"love",
		"date",
		"dating",
		"like",
		"affection",
		"valentines",
		"marriage"
	],
	char: "👫",
	fitzpatrick_scale: false,
	category: "people"
};
var two_men_holding_hands = {
	keywords: [
		"pair",
		"couple",
		"love",
		"like",
		"bromance",
		"friendship",
		"people",
		"human"
	],
	char: "👬",
	fitzpatrick_scale: false,
	category: "people"
};
var two_women_holding_hands = {
	keywords: [
		"pair",
		"friendship",
		"couple",
		"love",
		"like",
		"female",
		"people",
		"human"
	],
	char: "👭",
	fitzpatrick_scale: false,
	category: "people"
};
var bowing_woman = {
	keywords: [
		"woman",
		"female",
		"girl"
	],
	char: "🙇‍♀️",
	fitzpatrick_scale: true,
	category: "people"
};
var bowing_man = {
	keywords: [
		"man",
		"male",
		"boy"
	],
	char: "🙇",
	fitzpatrick_scale: true,
	category: "people"
};
var man_facepalming = {
	keywords: [
		"man",
		"male",
		"boy",
		"disbelief"
	],
	char: "🤦‍♂️",
	fitzpatrick_scale: true,
	category: "people"
};
var woman_facepalming = {
	keywords: [
		"woman",
		"female",
		"girl",
		"disbelief"
	],
	char: "🤦‍♀️",
	fitzpatrick_scale: true,
	category: "people"
};
var woman_shrugging = {
	keywords: [
		"woman",
		"female",
		"girl",
		"confused",
		"indifferent",
		"doubt"
	],
	char: "🤷",
	fitzpatrick_scale: true,
	category: "people"
};
var man_shrugging = {
	keywords: [
		"man",
		"male",
		"boy",
		"confused",
		"indifferent",
		"doubt"
	],
	char: "🤷‍♂️",
	fitzpatrick_scale: true,
	category: "people"
};
var tipping_hand_woman = {
	keywords: [
		"female",
		"girl",
		"woman",
		"human",
		"information"
	],
	char: "💁",
	fitzpatrick_scale: true,
	category: "people"
};
var tipping_hand_man = {
	keywords: [
		"male",
		"boy",
		"man",
		"human",
		"information"
	],
	char: "💁‍♂️",
	fitzpatrick_scale: true,
	category: "people"
};
var no_good_woman = {
	keywords: [
		"female",
		"girl",
		"woman",
		"nope"
	],
	char: "🙅",
	fitzpatrick_scale: true,
	category: "people"
};
var no_good_man = {
	keywords: [
		"male",
		"boy",
		"man",
		"nope"
	],
	char: "🙅‍♂️",
	fitzpatrick_scale: true,
	category: "people"
};
var ok_woman = {
	keywords: [
		"women",
		"girl",
		"female",
		"pink",
		"human",
		"woman"
	],
	char: "🙆",
	fitzpatrick_scale: true,
	category: "people"
};
var ok_man = {
	keywords: [
		"men",
		"boy",
		"male",
		"blue",
		"human",
		"man"
	],
	char: "🙆‍♂️",
	fitzpatrick_scale: true,
	category: "people"
};
var raising_hand_woman = {
	keywords: [
		"female",
		"girl",
		"woman"
	],
	char: "🙋",
	fitzpatrick_scale: true,
	category: "people"
};
var raising_hand_man = {
	keywords: [
		"male",
		"boy",
		"man"
	],
	char: "🙋‍♂️",
	fitzpatrick_scale: true,
	category: "people"
};
var pouting_woman = {
	keywords: [
		"female",
		"girl",
		"woman"
	],
	char: "🙎",
	fitzpatrick_scale: true,
	category: "people"
};
var pouting_man = {
	keywords: [
		"male",
		"boy",
		"man"
	],
	char: "🙎‍♂️",
	fitzpatrick_scale: true,
	category: "people"
};
var frowning_woman = {
	keywords: [
		"female",
		"girl",
		"woman",
		"sad",
		"depressed",
		"discouraged",
		"unhappy"
	],
	char: "🙍",
	fitzpatrick_scale: true,
	category: "people"
};
var frowning_man = {
	keywords: [
		"male",
		"boy",
		"man",
		"sad",
		"depressed",
		"discouraged",
		"unhappy"
	],
	char: "🙍‍♂️",
	fitzpatrick_scale: true,
	category: "people"
};
var haircut_woman = {
	keywords: [
		"female",
		"girl",
		"woman"
	],
	char: "💇",
	fitzpatrick_scale: true,
	category: "people"
};
var haircut_man = {
	keywords: [
		"male",
		"boy",
		"man"
	],
	char: "💇‍♂️",
	fitzpatrick_scale: true,
	category: "people"
};
var massage_woman = {
	keywords: [
		"female",
		"girl",
		"woman",
		"head"
	],
	char: "💆",
	fitzpatrick_scale: true,
	category: "people"
};
var massage_man = {
	keywords: [
		"male",
		"boy",
		"man",
		"head"
	],
	char: "💆‍♂️",
	fitzpatrick_scale: true,
	category: "people"
};
var woman_in_steamy_room = {
	keywords: [
		"female",
		"woman",
		"spa",
		"steamroom",
		"sauna"
	],
	char: "🧖‍♀️",
	fitzpatrick_scale: true,
	category: "people"
};
var man_in_steamy_room = {
	keywords: [
		"male",
		"man",
		"spa",
		"steamroom",
		"sauna"
	],
	char: "🧖‍♂️",
	fitzpatrick_scale: true,
	category: "people"
};
var couple_with_heart_woman_man = {
	keywords: [
		"pair",
		"love",
		"like",
		"affection",
		"human",
		"dating",
		"valentines",
		"marriage"
	],
	char: "💑",
	fitzpatrick_scale: false,
	category: "people"
};
var couple_with_heart_woman_woman = {
	keywords: [
		"pair",
		"love",
		"like",
		"affection",
		"human",
		"dating",
		"valentines",
		"marriage"
	],
	char: "👩‍❤️‍👩",
	fitzpatrick_scale: false,
	category: "people"
};
var couple_with_heart_man_man = {
	keywords: [
		"pair",
		"love",
		"like",
		"affection",
		"human",
		"dating",
		"valentines",
		"marriage"
	],
	char: "👨‍❤️‍👨",
	fitzpatrick_scale: false,
	category: "people"
};
var couplekiss_man_woman = {
	keywords: [
		"pair",
		"valentines",
		"love",
		"like",
		"dating",
		"marriage"
	],
	char: "💏",
	fitzpatrick_scale: false,
	category: "people"
};
var couplekiss_woman_woman = {
	keywords: [
		"pair",
		"valentines",
		"love",
		"like",
		"dating",
		"marriage"
	],
	char: "👩‍❤️‍💋‍👩",
	fitzpatrick_scale: false,
	category: "people"
};
var couplekiss_man_man = {
	keywords: [
		"pair",
		"valentines",
		"love",
		"like",
		"dating",
		"marriage"
	],
	char: "👨‍❤️‍💋‍👨",
	fitzpatrick_scale: false,
	category: "people"
};
var family_man_woman_boy = {
	keywords: [
		"home",
		"parents",
		"child",
		"mom",
		"dad",
		"father",
		"mother",
		"people",
		"human"
	],
	char: "👪",
	fitzpatrick_scale: false,
	category: "people"
};
var family_man_woman_girl = {
	keywords: [
		"home",
		"parents",
		"people",
		"human",
		"child"
	],
	char: "👨‍👩‍👧",
	fitzpatrick_scale: false,
	category: "people"
};
var family_man_woman_girl_boy = {
	keywords: [
		"home",
		"parents",
		"people",
		"human",
		"children"
	],
	char: "👨‍👩‍👧‍👦",
	fitzpatrick_scale: false,
	category: "people"
};
var family_man_woman_boy_boy = {
	keywords: [
		"home",
		"parents",
		"people",
		"human",
		"children"
	],
	char: "👨‍👩‍👦‍👦",
	fitzpatrick_scale: false,
	category: "people"
};
var family_man_woman_girl_girl = {
	keywords: [
		"home",
		"parents",
		"people",
		"human",
		"children"
	],
	char: "👨‍👩‍👧‍👧",
	fitzpatrick_scale: false,
	category: "people"
};
var family_woman_woman_boy = {
	keywords: [
		"home",
		"parents",
		"people",
		"human",
		"children"
	],
	char: "👩‍👩‍👦",
	fitzpatrick_scale: false,
	category: "people"
};
var family_woman_woman_girl = {
	keywords: [
		"home",
		"parents",
		"people",
		"human",
		"children"
	],
	char: "👩‍👩‍👧",
	fitzpatrick_scale: false,
	category: "people"
};
var family_woman_woman_girl_boy = {
	keywords: [
		"home",
		"parents",
		"people",
		"human",
		"children"
	],
	char: "👩‍👩‍👧‍👦",
	fitzpatrick_scale: false,
	category: "people"
};
var family_woman_woman_boy_boy = {
	keywords: [
		"home",
		"parents",
		"people",
		"human",
		"children"
	],
	char: "👩‍👩‍👦‍👦",
	fitzpatrick_scale: false,
	category: "people"
};
var family_woman_woman_girl_girl = {
	keywords: [
		"home",
		"parents",
		"people",
		"human",
		"children"
	],
	char: "👩‍👩‍👧‍👧",
	fitzpatrick_scale: false,
	category: "people"
};
var family_man_man_boy = {
	keywords: [
		"home",
		"parents",
		"people",
		"human",
		"children"
	],
	char: "👨‍👨‍👦",
	fitzpatrick_scale: false,
	category: "people"
};
var family_man_man_girl = {
	keywords: [
		"home",
		"parents",
		"people",
		"human",
		"children"
	],
	char: "👨‍👨‍👧",
	fitzpatrick_scale: false,
	category: "people"
};
var family_man_man_girl_boy = {
	keywords: [
		"home",
		"parents",
		"people",
		"human",
		"children"
	],
	char: "👨‍👨‍👧‍👦",
	fitzpatrick_scale: false,
	category: "people"
};
var family_man_man_boy_boy = {
	keywords: [
		"home",
		"parents",
		"people",
		"human",
		"children"
	],
	char: "👨‍👨‍👦‍👦",
	fitzpatrick_scale: false,
	category: "people"
};
var family_man_man_girl_girl = {
	keywords: [
		"home",
		"parents",
		"people",
		"human",
		"children"
	],
	char: "👨‍👨‍👧‍👧",
	fitzpatrick_scale: false,
	category: "people"
};
var family_woman_boy = {
	keywords: [
		"home",
		"parent",
		"people",
		"human",
		"child"
	],
	char: "👩‍👦",
	fitzpatrick_scale: false,
	category: "people"
};
var family_woman_girl = {
	keywords: [
		"home",
		"parent",
		"people",
		"human",
		"child"
	],
	char: "👩‍👧",
	fitzpatrick_scale: false,
	category: "people"
};
var family_woman_girl_boy = {
	keywords: [
		"home",
		"parent",
		"people",
		"human",
		"children"
	],
	char: "👩‍👧‍👦",
	fitzpatrick_scale: false,
	category: "people"
};
var family_woman_boy_boy = {
	keywords: [
		"home",
		"parent",
		"people",
		"human",
		"children"
	],
	char: "👩‍👦‍👦",
	fitzpatrick_scale: false,
	category: "people"
};
var family_woman_girl_girl = {
	keywords: [
		"home",
		"parent",
		"people",
		"human",
		"children"
	],
	char: "👩‍👧‍👧",
	fitzpatrick_scale: false,
	category: "people"
};
var family_man_boy = {
	keywords: [
		"home",
		"parent",
		"people",
		"human",
		"child"
	],
	char: "👨‍👦",
	fitzpatrick_scale: false,
	category: "people"
};
var family_man_girl = {
	keywords: [
		"home",
		"parent",
		"people",
		"human",
		"child"
	],
	char: "👨‍👧",
	fitzpatrick_scale: false,
	category: "people"
};
var family_man_girl_boy = {
	keywords: [
		"home",
		"parent",
		"people",
		"human",
		"children"
	],
	char: "👨‍👧‍👦",
	fitzpatrick_scale: false,
	category: "people"
};
var family_man_boy_boy = {
	keywords: [
		"home",
		"parent",
		"people",
		"human",
		"children"
	],
	char: "👨‍👦‍👦",
	fitzpatrick_scale: false,
	category: "people"
};
var family_man_girl_girl = {
	keywords: [
		"home",
		"parent",
		"people",
		"human",
		"children"
	],
	char: "👨‍👧‍👧",
	fitzpatrick_scale: false,
	category: "people"
};
var yarn = {
	keywords: [
		"ball",
		"crochet",
		"knit"
	],
	char: "🧶",
	fitzpatrick_scale: false,
	category: "people"
};
var thread = {
	keywords: [
		"needle",
		"sewing",
		"spool",
		"string"
	],
	char: "🧵",
	fitzpatrick_scale: false,
	category: "people"
};
var coat = {
	keywords: [
		"jacket"
	],
	char: "🧥",
	fitzpatrick_scale: false,
	category: "people"
};
var labcoat = {
	keywords: [
		"doctor",
		"experiment",
		"scientist",
		"chemist"
	],
	char: "🥼",
	fitzpatrick_scale: false,
	category: "people"
};
var womans_clothes = {
	keywords: [
		"fashion",
		"shopping_bags",
		"female"
	],
	char: "👚",
	fitzpatrick_scale: false,
	category: "people"
};
var tshirt = {
	keywords: [
		"fashion",
		"cloth",
		"casual",
		"shirt",
		"tee"
	],
	char: "👕",
	fitzpatrick_scale: false,
	category: "people"
};
var jeans = {
	keywords: [
		"fashion",
		"shopping"
	],
	char: "👖",
	fitzpatrick_scale: false,
	category: "people"
};
var necktie = {
	keywords: [
		"shirt",
		"suitup",
		"formal",
		"fashion",
		"cloth",
		"business"
	],
	char: "👔",
	fitzpatrick_scale: false,
	category: "people"
};
var dress = {
	keywords: [
		"clothes",
		"fashion",
		"shopping"
	],
	char: "👗",
	fitzpatrick_scale: false,
	category: "people"
};
var bikini = {
	keywords: [
		"swimming",
		"female",
		"woman",
		"girl",
		"fashion",
		"beach",
		"summer"
	],
	char: "👙",
	fitzpatrick_scale: false,
	category: "people"
};
var kimono = {
	keywords: [
		"dress",
		"fashion",
		"women",
		"female",
		"japanese"
	],
	char: "👘",
	fitzpatrick_scale: false,
	category: "people"
};
var lipstick = {
	keywords: [
		"female",
		"girl",
		"fashion",
		"woman"
	],
	char: "💄",
	fitzpatrick_scale: false,
	category: "people"
};
var kiss = {
	keywords: [
		"face",
		"lips",
		"love",
		"like",
		"affection",
		"valentines"
	],
	char: "💋",
	fitzpatrick_scale: false,
	category: "people"
};
var footprints = {
	keywords: [
		"feet",
		"tracking",
		"walking",
		"beach"
	],
	char: "👣",
	fitzpatrick_scale: false,
	category: "people"
};
var flat_shoe = {
	keywords: [
		"ballet",
		"slip-on",
		"slipper"
	],
	char: "🥿",
	fitzpatrick_scale: false,
	category: "people"
};
var high_heel = {
	keywords: [
		"fashion",
		"shoes",
		"female",
		"pumps",
		"stiletto"
	],
	char: "👠",
	fitzpatrick_scale: false,
	category: "people"
};
var sandal = {
	keywords: [
		"shoes",
		"fashion",
		"flip flops"
	],
	char: "👡",
	fitzpatrick_scale: false,
	category: "people"
};
var boot = {
	keywords: [
		"shoes",
		"fashion"
	],
	char: "👢",
	fitzpatrick_scale: false,
	category: "people"
};
var mans_shoe = {
	keywords: [
		"fashion",
		"male"
	],
	char: "👞",
	fitzpatrick_scale: false,
	category: "people"
};
var athletic_shoe = {
	keywords: [
		"shoes",
		"sports",
		"sneakers"
	],
	char: "👟",
	fitzpatrick_scale: false,
	category: "people"
};
var hiking_boot = {
	keywords: [
		"backpacking",
		"camping",
		"hiking"
	],
	char: "🥾",
	fitzpatrick_scale: false,
	category: "people"
};
var socks = {
	keywords: [
		"stockings",
		"clothes"
	],
	char: "🧦",
	fitzpatrick_scale: false,
	category: "people"
};
var gloves = {
	keywords: [
		"hands",
		"winter",
		"clothes"
	],
	char: "🧤",
	fitzpatrick_scale: false,
	category: "people"
};
var scarf = {
	keywords: [
		"neck",
		"winter",
		"clothes"
	],
	char: "🧣",
	fitzpatrick_scale: false,
	category: "people"
};
var womans_hat = {
	keywords: [
		"fashion",
		"accessories",
		"female",
		"lady",
		"spring"
	],
	char: "👒",
	fitzpatrick_scale: false,
	category: "people"
};
var tophat = {
	keywords: [
		"magic",
		"gentleman",
		"classy",
		"circus"
	],
	char: "🎩",
	fitzpatrick_scale: false,
	category: "people"
};
var billed_hat = {
	keywords: [
		"cap",
		"baseball"
	],
	char: "🧢",
	fitzpatrick_scale: false,
	category: "people"
};
var rescue_worker_helmet = {
	keywords: [
		"construction",
		"build"
	],
	char: "⛑",
	fitzpatrick_scale: false,
	category: "people"
};
var mortar_board = {
	keywords: [
		"school",
		"college",
		"degree",
		"university",
		"graduation",
		"cap",
		"hat",
		"legal",
		"learn",
		"education"
	],
	char: "🎓",
	fitzpatrick_scale: false,
	category: "people"
};
var crown = {
	keywords: [
		"king",
		"kod",
		"leader",
		"royalty",
		"lord"
	],
	char: "👑",
	fitzpatrick_scale: false,
	category: "people"
};
var school_satchel = {
	keywords: [
		"student",
		"education",
		"bag",
		"backpack"
	],
	char: "🎒",
	fitzpatrick_scale: false,
	category: "people"
};
var luggage = {
	keywords: [
		"packing",
		"travel"
	],
	char: "🧳",
	fitzpatrick_scale: false,
	category: "people"
};
var pouch = {
	keywords: [
		"bag",
		"accessories",
		"shopping"
	],
	char: "👝",
	fitzpatrick_scale: false,
	category: "people"
};
var purse = {
	keywords: [
		"fashion",
		"accessories",
		"money",
		"sales",
		"shopping"
	],
	char: "👛",
	fitzpatrick_scale: false,
	category: "people"
};
var handbag = {
	keywords: [
		"fashion",
		"accessory",
		"accessories",
		"shopping"
	],
	char: "👜",
	fitzpatrick_scale: false,
	category: "people"
};
var briefcase = {
	keywords: [
		"business",
		"documents",
		"work",
		"law",
		"legal",
		"job",
		"career"
	],
	char: "💼",
	fitzpatrick_scale: false,
	category: "people"
};
var eyeglasses = {
	keywords: [
		"fashion",
		"accessories",
		"eyesight",
		"nerdy",
		"dork",
		"geek"
	],
	char: "👓",
	fitzpatrick_scale: false,
	category: "people"
};
var dark_sunglasses = {
	keywords: [
		"face",
		"cool",
		"accessories"
	],
	char: "🕶",
	fitzpatrick_scale: false,
	category: "people"
};
var goggles = {
	keywords: [
		"eyes",
		"protection",
		"safety"
	],
	char: "🥽",
	fitzpatrick_scale: false,
	category: "people"
};
var ring$1 = {
	keywords: [
		"wedding",
		"propose",
		"marriage",
		"valentines",
		"diamond",
		"fashion",
		"jewelry",
		"gem",
		"engagement"
	],
	char: "💍",
	fitzpatrick_scale: false,
	category: "people"
};
var closed_umbrella = {
	keywords: [
		"weather",
		"rain",
		"drizzle"
	],
	char: "🌂",
	fitzpatrick_scale: false,
	category: "people"
};
var dog = {
	keywords: [
		"animal",
		"friend",
		"nature",
		"woof",
		"puppy",
		"pet",
		"faithful"
	],
	char: "🐶",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var cat = {
	keywords: [
		"animal",
		"meow",
		"nature",
		"pet",
		"kitten"
	],
	char: "🐱",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var mouse = {
	keywords: [
		"animal",
		"nature",
		"cheese_wedge",
		"rodent"
	],
	char: "🐭",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var hamster = {
	keywords: [
		"animal",
		"nature"
	],
	char: "🐹",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var rabbit = {
	keywords: [
		"animal",
		"nature",
		"pet",
		"spring",
		"magic",
		"bunny"
	],
	char: "🐰",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var fox_face = {
	keywords: [
		"animal",
		"nature",
		"face"
	],
	char: "🦊",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var bear = {
	keywords: [
		"animal",
		"nature",
		"wild"
	],
	char: "🐻",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var panda_face = {
	keywords: [
		"animal",
		"nature",
		"panda"
	],
	char: "🐼",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var koala = {
	keywords: [
		"animal",
		"nature"
	],
	char: "🐨",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var tiger = {
	keywords: [
		"animal",
		"cat",
		"danger",
		"wild",
		"nature",
		"roar"
	],
	char: "🐯",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var lion = {
	keywords: [
		"animal",
		"nature"
	],
	char: "🦁",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var cow = {
	keywords: [
		"beef",
		"ox",
		"animal",
		"nature",
		"moo",
		"milk"
	],
	char: "🐮",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var pig = {
	keywords: [
		"animal",
		"oink",
		"nature"
	],
	char: "🐷",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var pig_nose = {
	keywords: [
		"animal",
		"oink"
	],
	char: "🐽",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var frog = {
	keywords: [
		"animal",
		"nature",
		"croak",
		"toad"
	],
	char: "🐸",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var squid = {
	keywords: [
		"animal",
		"nature",
		"ocean",
		"sea"
	],
	char: "🦑",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var octopus = {
	keywords: [
		"animal",
		"creature",
		"ocean",
		"sea",
		"nature",
		"beach"
	],
	char: "🐙",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var shrimp = {
	keywords: [
		"animal",
		"ocean",
		"nature",
		"seafood"
	],
	char: "🦐",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var monkey_face = {
	keywords: [
		"animal",
		"nature",
		"circus"
	],
	char: "🐵",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var gorilla = {
	keywords: [
		"animal",
		"nature",
		"circus"
	],
	char: "🦍",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var see_no_evil = {
	keywords: [
		"monkey",
		"animal",
		"nature",
		"haha"
	],
	char: "🙈",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var hear_no_evil = {
	keywords: [
		"animal",
		"monkey",
		"nature"
	],
	char: "🙉",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var speak_no_evil = {
	keywords: [
		"monkey",
		"animal",
		"nature",
		"omg"
	],
	char: "🙊",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var monkey = {
	keywords: [
		"animal",
		"nature",
		"banana",
		"circus"
	],
	char: "🐒",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var chicken = {
	keywords: [
		"animal",
		"cluck",
		"nature",
		"bird"
	],
	char: "🐔",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var penguin = {
	keywords: [
		"animal",
		"nature"
	],
	char: "🐧",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var bird = {
	keywords: [
		"animal",
		"nature",
		"fly",
		"tweet",
		"spring"
	],
	char: "🐦",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var baby_chick = {
	keywords: [
		"animal",
		"chicken",
		"bird"
	],
	char: "🐤",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var hatching_chick = {
	keywords: [
		"animal",
		"chicken",
		"egg",
		"born",
		"baby",
		"bird"
	],
	char: "🐣",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var hatched_chick = {
	keywords: [
		"animal",
		"chicken",
		"baby",
		"bird"
	],
	char: "🐥",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var duck = {
	keywords: [
		"animal",
		"nature",
		"bird",
		"mallard"
	],
	char: "🦆",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var eagle = {
	keywords: [
		"animal",
		"nature",
		"bird"
	],
	char: "🦅",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var owl = {
	keywords: [
		"animal",
		"nature",
		"bird",
		"hoot"
	],
	char: "🦉",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var bat = {
	keywords: [
		"animal",
		"nature",
		"blind",
		"vampire"
	],
	char: "🦇",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var wolf = {
	keywords: [
		"animal",
		"nature",
		"wild"
	],
	char: "🐺",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var boar = {
	keywords: [
		"animal",
		"nature"
	],
	char: "🐗",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var horse = {
	keywords: [
		"animal",
		"brown",
		"nature"
	],
	char: "🐴",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var unicorn = {
	keywords: [
		"animal",
		"nature",
		"mystical"
	],
	char: "🦄",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var honeybee = {
	keywords: [
		"animal",
		"insect",
		"nature",
		"bug",
		"spring",
		"honey"
	],
	char: "🐝",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var bug = {
	keywords: [
		"animal",
		"insect",
		"nature",
		"worm"
	],
	char: "🐛",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var butterfly = {
	keywords: [
		"animal",
		"insect",
		"nature",
		"caterpillar"
	],
	char: "🦋",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var snail = {
	keywords: [
		"slow",
		"animal",
		"shell"
	],
	char: "🐌",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var beetle = {
	keywords: [
		"animal",
		"insect",
		"nature",
		"ladybug"
	],
	char: "🐞",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var ant = {
	keywords: [
		"animal",
		"insect",
		"nature",
		"bug"
	],
	char: "🐜",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var grasshopper = {
	keywords: [
		"animal",
		"cricket",
		"chirp"
	],
	char: "🦗",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var spider = {
	keywords: [
		"animal",
		"arachnid"
	],
	char: "🕷",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var scorpion = {
	keywords: [
		"animal",
		"arachnid"
	],
	char: "🦂",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var crab = {
	keywords: [
		"animal",
		"crustacean"
	],
	char: "🦀",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var snake = {
	keywords: [
		"animal",
		"evil",
		"nature",
		"hiss",
		"python"
	],
	char: "🐍",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var lizard = {
	keywords: [
		"animal",
		"nature",
		"reptile"
	],
	char: "🦎",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var sauropod = {
	keywords: [
		"animal",
		"nature",
		"dinosaur",
		"brachiosaurus",
		"brontosaurus",
		"diplodocus",
		"extinct"
	],
	char: "🦕",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var turtle = {
	keywords: [
		"animal",
		"slow",
		"nature",
		"tortoise"
	],
	char: "🐢",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var tropical_fish = {
	keywords: [
		"animal",
		"swim",
		"ocean",
		"beach",
		"nemo"
	],
	char: "🐠",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var fish = {
	keywords: [
		"animal",
		"food",
		"nature"
	],
	char: "🐟",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var blowfish = {
	keywords: [
		"animal",
		"nature",
		"food",
		"sea",
		"ocean"
	],
	char: "🐡",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var dolphin = {
	keywords: [
		"animal",
		"nature",
		"fish",
		"sea",
		"ocean",
		"flipper",
		"fins",
		"beach"
	],
	char: "🐬",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var shark = {
	keywords: [
		"animal",
		"nature",
		"fish",
		"sea",
		"ocean",
		"jaws",
		"fins",
		"beach"
	],
	char: "🦈",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var whale = {
	keywords: [
		"animal",
		"nature",
		"sea",
		"ocean"
	],
	char: "🐳",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var whale2 = {
	keywords: [
		"animal",
		"nature",
		"sea",
		"ocean"
	],
	char: "🐋",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var crocodile = {
	keywords: [
		"animal",
		"nature",
		"reptile",
		"lizard",
		"alligator"
	],
	char: "🐊",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var leopard = {
	keywords: [
		"animal",
		"nature"
	],
	char: "🐆",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var zebra = {
	keywords: [
		"animal",
		"nature",
		"stripes",
		"safari"
	],
	char: "🦓",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var tiger2 = {
	keywords: [
		"animal",
		"nature",
		"roar"
	],
	char: "🐅",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var water_buffalo = {
	keywords: [
		"animal",
		"nature",
		"ox",
		"cow"
	],
	char: "🐃",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var ox = {
	keywords: [
		"animal",
		"cow",
		"beef"
	],
	char: "🐂",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var cow2 = {
	keywords: [
		"beef",
		"ox",
		"animal",
		"nature",
		"moo",
		"milk"
	],
	char: "🐄",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var deer = {
	keywords: [
		"animal",
		"nature",
		"horns",
		"venison"
	],
	char: "🦌",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var dromedary_camel = {
	keywords: [
		"animal",
		"hot",
		"desert",
		"hump"
	],
	char: "🐪",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var camel = {
	keywords: [
		"animal",
		"nature",
		"hot",
		"desert",
		"hump"
	],
	char: "🐫",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var giraffe = {
	keywords: [
		"animal",
		"nature",
		"spots",
		"safari"
	],
	char: "🦒",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var elephant = {
	keywords: [
		"animal",
		"nature",
		"nose",
		"th",
		"circus"
	],
	char: "🐘",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var rhinoceros = {
	keywords: [
		"animal",
		"nature",
		"horn"
	],
	char: "🦏",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var goat = {
	keywords: [
		"animal",
		"nature"
	],
	char: "🐐",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var ram = {
	keywords: [
		"animal",
		"sheep",
		"nature"
	],
	char: "🐏",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var sheep = {
	keywords: [
		"animal",
		"nature",
		"wool",
		"shipit"
	],
	char: "🐑",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var racehorse = {
	keywords: [
		"animal",
		"gamble",
		"luck"
	],
	char: "🐎",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var pig2 = {
	keywords: [
		"animal",
		"nature"
	],
	char: "🐖",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var rat = {
	keywords: [
		"animal",
		"mouse",
		"rodent"
	],
	char: "🐀",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var mouse2 = {
	keywords: [
		"animal",
		"nature",
		"rodent"
	],
	char: "🐁",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var rooster = {
	keywords: [
		"animal",
		"nature",
		"chicken"
	],
	char: "🐓",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var turkey = {
	keywords: [
		"animal",
		"bird"
	],
	char: "🦃",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var dove = {
	keywords: [
		"animal",
		"bird"
	],
	char: "🕊",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var dog2 = {
	keywords: [
		"animal",
		"nature",
		"friend",
		"doge",
		"pet",
		"faithful"
	],
	char: "🐕",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var poodle = {
	keywords: [
		"dog",
		"animal",
		"101",
		"nature",
		"pet"
	],
	char: "🐩",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var cat2 = {
	keywords: [
		"animal",
		"meow",
		"pet",
		"cats"
	],
	char: "🐈",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var rabbit2 = {
	keywords: [
		"animal",
		"nature",
		"pet",
		"magic",
		"spring"
	],
	char: "🐇",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var chipmunk = {
	keywords: [
		"animal",
		"nature",
		"rodent",
		"squirrel"
	],
	char: "🐿",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var hedgehog = {
	keywords: [
		"animal",
		"nature",
		"spiny"
	],
	char: "🦔",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var raccoon = {
	keywords: [
		"animal",
		"nature"
	],
	char: "🦝",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var llama = {
	keywords: [
		"animal",
		"nature",
		"alpaca"
	],
	char: "🦙",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var hippopotamus = {
	keywords: [
		"animal",
		"nature"
	],
	char: "🦛",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var kangaroo = {
	keywords: [
		"animal",
		"nature",
		"australia",
		"joey",
		"hop",
		"marsupial"
	],
	char: "🦘",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var badger = {
	keywords: [
		"animal",
		"nature",
		"honey"
	],
	char: "🦡",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var swan = {
	keywords: [
		"animal",
		"nature",
		"bird"
	],
	char: "🦢",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var peacock = {
	keywords: [
		"animal",
		"nature",
		"peahen",
		"bird"
	],
	char: "🦚",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var parrot = {
	keywords: [
		"animal",
		"nature",
		"bird",
		"pirate",
		"talk"
	],
	char: "🦜",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var lobster = {
	keywords: [
		"animal",
		"nature",
		"bisque",
		"claws",
		"seafood"
	],
	char: "🦞",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var mosquito = {
	keywords: [
		"animal",
		"nature",
		"insect",
		"malaria"
	],
	char: "🦟",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var paw_prints = {
	keywords: [
		"animal",
		"tracking",
		"footprints",
		"dog",
		"cat",
		"pet",
		"feet"
	],
	char: "🐾",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var dragon = {
	keywords: [
		"animal",
		"myth",
		"nature",
		"chinese",
		"green"
	],
	char: "🐉",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var dragon_face = {
	keywords: [
		"animal",
		"myth",
		"nature",
		"chinese",
		"green"
	],
	char: "🐲",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var cactus = {
	keywords: [
		"vegetable",
		"plant",
		"nature"
	],
	char: "🌵",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var christmas_tree = {
	keywords: [
		"festival",
		"vacation",
		"december",
		"xmas",
		"celebration"
	],
	char: "🎄",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var evergreen_tree = {
	keywords: [
		"plant",
		"nature"
	],
	char: "🌲",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var deciduous_tree = {
	keywords: [
		"plant",
		"nature"
	],
	char: "🌳",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var palm_tree = {
	keywords: [
		"plant",
		"vegetable",
		"nature",
		"summer",
		"beach",
		"mojito",
		"tropical"
	],
	char: "🌴",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var seedling = {
	keywords: [
		"plant",
		"nature",
		"grass",
		"lawn",
		"spring"
	],
	char: "🌱",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var herb = {
	keywords: [
		"vegetable",
		"plant",
		"medicine",
		"weed",
		"grass",
		"lawn"
	],
	char: "🌿",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var shamrock = {
	keywords: [
		"vegetable",
		"plant",
		"nature",
		"irish",
		"clover"
	],
	char: "☘",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var four_leaf_clover = {
	keywords: [
		"vegetable",
		"plant",
		"nature",
		"lucky",
		"irish"
	],
	char: "🍀",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var bamboo = {
	keywords: [
		"plant",
		"nature",
		"vegetable",
		"panda",
		"pine_decoration"
	],
	char: "🎍",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var tanabata_tree = {
	keywords: [
		"plant",
		"nature",
		"branch",
		"summer"
	],
	char: "🎋",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var leaves = {
	keywords: [
		"nature",
		"plant",
		"tree",
		"vegetable",
		"grass",
		"lawn",
		"spring"
	],
	char: "🍃",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var fallen_leaf = {
	keywords: [
		"nature",
		"plant",
		"vegetable",
		"leaves"
	],
	char: "🍂",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var maple_leaf = {
	keywords: [
		"nature",
		"plant",
		"vegetable",
		"ca",
		"fall"
	],
	char: "🍁",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var ear_of_rice = {
	keywords: [
		"nature",
		"plant"
	],
	char: "🌾",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var hibiscus = {
	keywords: [
		"plant",
		"vegetable",
		"flowers",
		"beach"
	],
	char: "🌺",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var sunflower = {
	keywords: [
		"nature",
		"plant",
		"fall"
	],
	char: "🌻",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var rose = {
	keywords: [
		"flowers",
		"valentines",
		"love",
		"spring"
	],
	char: "🌹",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var wilted_flower = {
	keywords: [
		"plant",
		"nature",
		"flower"
	],
	char: "🥀",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var tulip = {
	keywords: [
		"flowers",
		"plant",
		"nature",
		"summer",
		"spring"
	],
	char: "🌷",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var blossom = {
	keywords: [
		"nature",
		"flowers",
		"yellow"
	],
	char: "🌼",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var cherry_blossom = {
	keywords: [
		"nature",
		"plant",
		"spring",
		"flower"
	],
	char: "🌸",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var bouquet = {
	keywords: [
		"flowers",
		"nature",
		"spring"
	],
	char: "💐",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var mushroom = {
	keywords: [
		"plant",
		"vegetable"
	],
	char: "🍄",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var chestnut = {
	keywords: [
		"food",
		"squirrel"
	],
	char: "🌰",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var jack_o_lantern = {
	keywords: [
		"halloween",
		"light",
		"pumpkin",
		"creepy",
		"fall"
	],
	char: "🎃",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var shell = {
	keywords: [
		"nature",
		"sea",
		"beach"
	],
	char: "🐚",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var spider_web = {
	keywords: [
		"animal",
		"insect",
		"arachnid",
		"silk"
	],
	char: "🕸",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var earth_americas = {
	keywords: [
		"globe",
		"world",
		"USA",
		"international"
	],
	char: "🌎",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var earth_africa = {
	keywords: [
		"globe",
		"world",
		"international"
	],
	char: "🌍",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var earth_asia = {
	keywords: [
		"globe",
		"world",
		"east",
		"international"
	],
	char: "🌏",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var full_moon = {
	keywords: [
		"nature",
		"yellow",
		"twilight",
		"planet",
		"space",
		"night",
		"evening",
		"sleep"
	],
	char: "🌕",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var waning_gibbous_moon = {
	keywords: [
		"nature",
		"twilight",
		"planet",
		"space",
		"night",
		"evening",
		"sleep",
		"waxing_gibbous_moon"
	],
	char: "🌖",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var last_quarter_moon = {
	keywords: [
		"nature",
		"twilight",
		"planet",
		"space",
		"night",
		"evening",
		"sleep"
	],
	char: "🌗",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var waning_crescent_moon = {
	keywords: [
		"nature",
		"twilight",
		"planet",
		"space",
		"night",
		"evening",
		"sleep"
	],
	char: "🌘",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var new_moon = {
	keywords: [
		"nature",
		"twilight",
		"planet",
		"space",
		"night",
		"evening",
		"sleep"
	],
	char: "🌑",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var waxing_crescent_moon = {
	keywords: [
		"nature",
		"twilight",
		"planet",
		"space",
		"night",
		"evening",
		"sleep"
	],
	char: "🌒",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var first_quarter_moon = {
	keywords: [
		"nature",
		"twilight",
		"planet",
		"space",
		"night",
		"evening",
		"sleep"
	],
	char: "🌓",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var waxing_gibbous_moon = {
	keywords: [
		"nature",
		"night",
		"sky",
		"gray",
		"twilight",
		"planet",
		"space",
		"evening",
		"sleep"
	],
	char: "🌔",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var new_moon_with_face = {
	keywords: [
		"nature",
		"twilight",
		"planet",
		"space",
		"night",
		"evening",
		"sleep"
	],
	char: "🌚",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var full_moon_with_face = {
	keywords: [
		"nature",
		"twilight",
		"planet",
		"space",
		"night",
		"evening",
		"sleep"
	],
	char: "🌝",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var first_quarter_moon_with_face = {
	keywords: [
		"nature",
		"twilight",
		"planet",
		"space",
		"night",
		"evening",
		"sleep"
	],
	char: "🌛",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var last_quarter_moon_with_face = {
	keywords: [
		"nature",
		"twilight",
		"planet",
		"space",
		"night",
		"evening",
		"sleep"
	],
	char: "🌜",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var sun_with_face = {
	keywords: [
		"nature",
		"morning",
		"sky"
	],
	char: "🌞",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var crescent_moon = {
	keywords: [
		"night",
		"sleep",
		"sky",
		"evening",
		"magic"
	],
	char: "🌙",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var star$1 = {
	keywords: [
		"night",
		"yellow"
	],
	char: "⭐",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var star2 = {
	keywords: [
		"night",
		"sparkle",
		"awesome",
		"good",
		"magic"
	],
	char: "🌟",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var dizzy = {
	keywords: [
		"star",
		"sparkle",
		"shoot",
		"magic"
	],
	char: "💫",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var sparkles = {
	keywords: [
		"stars",
		"shine",
		"shiny",
		"cool",
		"awesome",
		"good",
		"magic"
	],
	char: "✨",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var comet = {
	keywords: [
		"space"
	],
	char: "☄",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var sunny = {
	keywords: [
		"weather",
		"nature",
		"brightness",
		"summer",
		"beach",
		"spring"
	],
	char: "☀️",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var sun_behind_small_cloud = {
	keywords: [
		"weather"
	],
	char: "🌤",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var partly_sunny = {
	keywords: [
		"weather",
		"nature",
		"cloudy",
		"morning",
		"fall",
		"spring"
	],
	char: "⛅",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var sun_behind_large_cloud = {
	keywords: [
		"weather"
	],
	char: "🌥",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var sun_behind_rain_cloud = {
	keywords: [
		"weather"
	],
	char: "🌦",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var cloud = {
	keywords: [
		"weather",
		"sky"
	],
	char: "☁️",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var cloud_with_rain = {
	keywords: [
		"weather"
	],
	char: "🌧",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var cloud_with_lightning_and_rain = {
	keywords: [
		"weather",
		"lightning"
	],
	char: "⛈",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var cloud_with_lightning = {
	keywords: [
		"weather",
		"thunder"
	],
	char: "🌩",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var zap = {
	keywords: [
		"thunder",
		"weather",
		"lightning bolt",
		"fast"
	],
	char: "⚡",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var fire = {
	keywords: [
		"hot",
		"cook",
		"flame"
	],
	char: "🔥",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var boom = {
	keywords: [
		"bomb",
		"explode",
		"explosion",
		"collision",
		"blown"
	],
	char: "💥",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var snowflake = {
	keywords: [
		"winter",
		"season",
		"cold",
		"weather",
		"christmas",
		"xmas"
	],
	char: "❄️",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var cloud_with_snow = {
	keywords: [
		"weather"
	],
	char: "🌨",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var snowman = {
	keywords: [
		"winter",
		"season",
		"cold",
		"weather",
		"christmas",
		"xmas",
		"frozen",
		"without_snow"
	],
	char: "⛄",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var snowman_with_snow = {
	keywords: [
		"winter",
		"season",
		"cold",
		"weather",
		"christmas",
		"xmas",
		"frozen"
	],
	char: "☃",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var wind_face = {
	keywords: [
		"gust",
		"air"
	],
	char: "🌬",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var dash$1 = {
	keywords: [
		"wind",
		"air",
		"fast",
		"shoo",
		"fart",
		"smoke",
		"puff"
	],
	char: "💨",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var tornado = {
	keywords: [
		"weather",
		"cyclone",
		"twister"
	],
	char: "🌪",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var fog = {
	keywords: [
		"weather"
	],
	char: "🌫",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var open_umbrella = {
	keywords: [
		"weather",
		"spring"
	],
	char: "☂",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var umbrella = {
	keywords: [
		"rainy",
		"weather",
		"spring"
	],
	char: "☔",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var droplet = {
	keywords: [
		"water",
		"drip",
		"faucet",
		"spring"
	],
	char: "💧",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var sweat_drops = {
	keywords: [
		"water",
		"drip",
		"oops"
	],
	char: "💦",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var ocean = {
	keywords: [
		"sea",
		"water",
		"wave",
		"nature",
		"tsunami",
		"disaster"
	],
	char: "🌊",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
};
var green_apple = {
	keywords: [
		"fruit",
		"nature"
	],
	char: "🍏",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var apple = {
	keywords: [
		"fruit",
		"mac",
		"school"
	],
	char: "🍎",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var pear = {
	keywords: [
		"fruit",
		"nature",
		"food"
	],
	char: "🍐",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var tangerine = {
	keywords: [
		"food",
		"fruit",
		"nature",
		"orange"
	],
	char: "🍊",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var lemon = {
	keywords: [
		"fruit",
		"nature"
	],
	char: "🍋",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var banana = {
	keywords: [
		"fruit",
		"food",
		"monkey"
	],
	char: "🍌",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var watermelon = {
	keywords: [
		"fruit",
		"food",
		"picnic",
		"summer"
	],
	char: "🍉",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var grapes = {
	keywords: [
		"fruit",
		"food",
		"wine"
	],
	char: "🍇",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var strawberry = {
	keywords: [
		"fruit",
		"food",
		"nature"
	],
	char: "🍓",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var melon = {
	keywords: [
		"fruit",
		"nature",
		"food"
	],
	char: "🍈",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var cherries = {
	keywords: [
		"food",
		"fruit"
	],
	char: "🍒",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var peach = {
	keywords: [
		"fruit",
		"nature",
		"food"
	],
	char: "🍑",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var pineapple = {
	keywords: [
		"fruit",
		"nature",
		"food"
	],
	char: "🍍",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var coconut = {
	keywords: [
		"fruit",
		"nature",
		"food",
		"palm"
	],
	char: "🥥",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var kiwi_fruit = {
	keywords: [
		"fruit",
		"food"
	],
	char: "🥝",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var mango = {
	keywords: [
		"fruit",
		"food",
		"tropical"
	],
	char: "🥭",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var avocado = {
	keywords: [
		"fruit",
		"food"
	],
	char: "🥑",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var broccoli = {
	keywords: [
		"fruit",
		"food",
		"vegetable"
	],
	char: "🥦",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var tomato = {
	keywords: [
		"fruit",
		"vegetable",
		"nature",
		"food"
	],
	char: "🍅",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var eggplant = {
	keywords: [
		"vegetable",
		"nature",
		"food",
		"aubergine"
	],
	char: "🍆",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var cucumber = {
	keywords: [
		"fruit",
		"food",
		"pickle"
	],
	char: "🥒",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var carrot = {
	keywords: [
		"vegetable",
		"food",
		"orange"
	],
	char: "🥕",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var hot_pepper = {
	keywords: [
		"food",
		"spicy",
		"chilli",
		"chili"
	],
	char: "🌶",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var potato = {
	keywords: [
		"food",
		"tuber",
		"vegatable",
		"starch"
	],
	char: "🥔",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var corn = {
	keywords: [
		"food",
		"vegetable",
		"plant"
	],
	char: "🌽",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var leafy_greens = {
	keywords: [
		"food",
		"vegetable",
		"plant",
		"bok choy",
		"cabbage",
		"kale",
		"lettuce"
	],
	char: "🥬",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var sweet_potato = {
	keywords: [
		"food",
		"nature"
	],
	char: "🍠",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var peanuts = {
	keywords: [
		"food",
		"nut"
	],
	char: "🥜",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var honey_pot = {
	keywords: [
		"bees",
		"sweet",
		"kitchen"
	],
	char: "🍯",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var croissant = {
	keywords: [
		"food",
		"bread",
		"french"
	],
	char: "🥐",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var bread = {
	keywords: [
		"food",
		"wheat",
		"breakfast",
		"toast"
	],
	char: "🍞",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var baguette_bread = {
	keywords: [
		"food",
		"bread",
		"french"
	],
	char: "🥖",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var bagel = {
	keywords: [
		"food",
		"bread",
		"bakery",
		"schmear"
	],
	char: "🥯",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var pretzel = {
	keywords: [
		"food",
		"bread",
		"twisted"
	],
	char: "🥨",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var cheese = {
	keywords: [
		"food",
		"chadder"
	],
	char: "🧀",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var egg = {
	keywords: [
		"food",
		"chicken",
		"breakfast"
	],
	char: "🥚",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var bacon = {
	keywords: [
		"food",
		"breakfast",
		"pork",
		"pig",
		"meat"
	],
	char: "🥓",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var steak = {
	keywords: [
		"food",
		"cow",
		"meat",
		"cut",
		"chop",
		"lambchop",
		"porkchop"
	],
	char: "🥩",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var pancakes = {
	keywords: [
		"food",
		"breakfast",
		"flapjacks",
		"hotcakes"
	],
	char: "🥞",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var poultry_leg = {
	keywords: [
		"food",
		"meat",
		"drumstick",
		"bird",
		"chicken",
		"turkey"
	],
	char: "🍗",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var meat_on_bone = {
	keywords: [
		"good",
		"food",
		"drumstick"
	],
	char: "🍖",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var bone = {
	keywords: [
		"skeleton"
	],
	char: "🦴",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var fried_shrimp = {
	keywords: [
		"food",
		"animal",
		"appetizer",
		"summer"
	],
	char: "🍤",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var fried_egg = {
	keywords: [
		"food",
		"breakfast",
		"kitchen",
		"egg"
	],
	char: "🍳",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var hamburger = {
	keywords: [
		"meat",
		"fast food",
		"beef",
		"cheeseburger",
		"mcdonalds",
		"burger king"
	],
	char: "🍔",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var fries = {
	keywords: [
		"chips",
		"snack",
		"fast food"
	],
	char: "🍟",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var stuffed_flatbread = {
	keywords: [
		"food",
		"flatbread",
		"stuffed",
		"gyro"
	],
	char: "🥙",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var hotdog = {
	keywords: [
		"food",
		"frankfurter"
	],
	char: "🌭",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var pizza = {
	keywords: [
		"food",
		"party"
	],
	char: "🍕",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var sandwich = {
	keywords: [
		"food",
		"lunch",
		"bread"
	],
	char: "🥪",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var canned_food = {
	keywords: [
		"food",
		"soup"
	],
	char: "🥫",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var spaghetti = {
	keywords: [
		"food",
		"italian",
		"noodle"
	],
	char: "🍝",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var taco = {
	keywords: [
		"food",
		"mexican"
	],
	char: "🌮",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var burrito = {
	keywords: [
		"food",
		"mexican"
	],
	char: "🌯",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var green_salad = {
	keywords: [
		"food",
		"healthy",
		"lettuce"
	],
	char: "🥗",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var shallow_pan_of_food = {
	keywords: [
		"food",
		"cooking",
		"casserole",
		"paella"
	],
	char: "🥘",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var ramen = {
	keywords: [
		"food",
		"japanese",
		"noodle",
		"chopsticks"
	],
	char: "🍜",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var stew = {
	keywords: [
		"food",
		"meat",
		"soup"
	],
	char: "🍲",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var fish_cake = {
	keywords: [
		"food",
		"japan",
		"sea",
		"beach",
		"narutomaki",
		"pink",
		"swirl",
		"kamaboko",
		"surimi",
		"ramen"
	],
	char: "🍥",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var fortune_cookie = {
	keywords: [
		"food",
		"prophecy"
	],
	char: "🥠",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var sushi = {
	keywords: [
		"food",
		"fish",
		"japanese",
		"rice"
	],
	char: "🍣",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var bento = {
	keywords: [
		"food",
		"japanese",
		"box"
	],
	char: "🍱",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var curry = {
	keywords: [
		"food",
		"spicy",
		"hot",
		"indian"
	],
	char: "🍛",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var rice_ball = {
	keywords: [
		"food",
		"japanese"
	],
	char: "🍙",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var rice = {
	keywords: [
		"food",
		"china",
		"asian"
	],
	char: "🍚",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var rice_cracker = {
	keywords: [
		"food",
		"japanese"
	],
	char: "🍘",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var oden = {
	keywords: [
		"food",
		"japanese"
	],
	char: "🍢",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var dango = {
	keywords: [
		"food",
		"dessert",
		"sweet",
		"japanese",
		"barbecue",
		"meat"
	],
	char: "🍡",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var shaved_ice = {
	keywords: [
		"hot",
		"dessert",
		"summer"
	],
	char: "🍧",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var ice_cream = {
	keywords: [
		"food",
		"hot",
		"dessert"
	],
	char: "🍨",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var icecream = {
	keywords: [
		"food",
		"hot",
		"dessert",
		"summer"
	],
	char: "🍦",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var pie = {
	keywords: [
		"food",
		"dessert",
		"pastry"
	],
	char: "🥧",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var cake = {
	keywords: [
		"food",
		"dessert"
	],
	char: "🍰",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var cupcake = {
	keywords: [
		"food",
		"dessert",
		"bakery",
		"sweet"
	],
	char: "🧁",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var moon_cake = {
	keywords: [
		"food",
		"autumn"
	],
	char: "🥮",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var birthday = {
	keywords: [
		"food",
		"dessert",
		"cake"
	],
	char: "🎂",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var custard = {
	keywords: [
		"dessert",
		"food"
	],
	char: "🍮",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var candy = {
	keywords: [
		"snack",
		"dessert",
		"sweet",
		"lolly"
	],
	char: "🍬",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var lollipop = {
	keywords: [
		"food",
		"snack",
		"candy",
		"sweet"
	],
	char: "🍭",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var chocolate_bar = {
	keywords: [
		"food",
		"snack",
		"dessert",
		"sweet"
	],
	char: "🍫",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var popcorn = {
	keywords: [
		"food",
		"movie theater",
		"films",
		"snack"
	],
	char: "🍿",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var dumpling = {
	keywords: [
		"food",
		"empanada",
		"pierogi",
		"potsticker"
	],
	char: "🥟",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var doughnut = {
	keywords: [
		"food",
		"dessert",
		"snack",
		"sweet",
		"donut"
	],
	char: "🍩",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var cookie = {
	keywords: [
		"food",
		"snack",
		"oreo",
		"chocolate",
		"sweet",
		"dessert"
	],
	char: "🍪",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var milk_glass = {
	keywords: [
		"beverage",
		"drink",
		"cow"
	],
	char: "🥛",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var beer = {
	keywords: [
		"relax",
		"beverage",
		"drink",
		"drunk",
		"party",
		"pub",
		"summer",
		"alcohol",
		"booze"
	],
	char: "🍺",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var beers = {
	keywords: [
		"relax",
		"beverage",
		"drink",
		"drunk",
		"party",
		"pub",
		"summer",
		"alcohol",
		"booze"
	],
	char: "🍻",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var clinking_glasses = {
	keywords: [
		"beverage",
		"drink",
		"party",
		"alcohol",
		"celebrate",
		"cheers",
		"wine",
		"champagne",
		"toast"
	],
	char: "🥂",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var wine_glass = {
	keywords: [
		"drink",
		"beverage",
		"drunk",
		"alcohol",
		"booze"
	],
	char: "🍷",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var tumbler_glass = {
	keywords: [
		"drink",
		"beverage",
		"drunk",
		"alcohol",
		"liquor",
		"booze",
		"bourbon",
		"scotch",
		"whisky",
		"glass",
		"shot"
	],
	char: "🥃",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var cocktail = {
	keywords: [
		"drink",
		"drunk",
		"alcohol",
		"beverage",
		"booze",
		"mojito"
	],
	char: "🍸",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var tropical_drink = {
	keywords: [
		"beverage",
		"cocktail",
		"summer",
		"beach",
		"alcohol",
		"booze",
		"mojito"
	],
	char: "🍹",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var champagne = {
	keywords: [
		"drink",
		"wine",
		"bottle",
		"celebration"
	],
	char: "🍾",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var sake = {
	keywords: [
		"wine",
		"drink",
		"drunk",
		"beverage",
		"japanese",
		"alcohol",
		"booze"
	],
	char: "🍶",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var tea = {
	keywords: [
		"drink",
		"bowl",
		"breakfast",
		"green",
		"british"
	],
	char: "🍵",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var cup_with_straw = {
	keywords: [
		"drink",
		"soda"
	],
	char: "🥤",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var coffee = {
	keywords: [
		"beverage",
		"caffeine",
		"latte",
		"espresso"
	],
	char: "☕",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var baby_bottle = {
	keywords: [
		"food",
		"container",
		"milk"
	],
	char: "🍼",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var salt = {
	keywords: [
		"condiment",
		"shaker"
	],
	char: "🧂",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var spoon = {
	keywords: [
		"cutlery",
		"kitchen",
		"tableware"
	],
	char: "🥄",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var fork_and_knife = {
	keywords: [
		"cutlery",
		"kitchen"
	],
	char: "🍴",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var plate_with_cutlery = {
	keywords: [
		"food",
		"eat",
		"meal",
		"lunch",
		"dinner",
		"restaurant"
	],
	char: "🍽",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var bowl_with_spoon = {
	keywords: [
		"food",
		"breakfast",
		"cereal",
		"oatmeal",
		"porridge"
	],
	char: "🥣",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var takeout_box = {
	keywords: [
		"food",
		"leftovers"
	],
	char: "🥡",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var chopsticks = {
	keywords: [
		"food"
	],
	char: "🥢",
	fitzpatrick_scale: false,
	category: "food_and_drink"
};
var soccer = {
	keywords: [
		"sports",
		"football"
	],
	char: "⚽",
	fitzpatrick_scale: false,
	category: "activity"
};
var basketball = {
	keywords: [
		"sports",
		"balls",
		"NBA"
	],
	char: "🏀",
	fitzpatrick_scale: false,
	category: "activity"
};
var football = {
	keywords: [
		"sports",
		"balls",
		"NFL"
	],
	char: "🏈",
	fitzpatrick_scale: false,
	category: "activity"
};
var baseball = {
	keywords: [
		"sports",
		"balls"
	],
	char: "⚾",
	fitzpatrick_scale: false,
	category: "activity"
};
var softball = {
	keywords: [
		"sports",
		"balls"
	],
	char: "🥎",
	fitzpatrick_scale: false,
	category: "activity"
};
var tennis = {
	keywords: [
		"sports",
		"balls",
		"green"
	],
	char: "🎾",
	fitzpatrick_scale: false,
	category: "activity"
};
var volleyball = {
	keywords: [
		"sports",
		"balls"
	],
	char: "🏐",
	fitzpatrick_scale: false,
	category: "activity"
};
var rugby_football = {
	keywords: [
		"sports",
		"team"
	],
	char: "🏉",
	fitzpatrick_scale: false,
	category: "activity"
};
var flying_disc = {
	keywords: [
		"sports",
		"frisbee",
		"ultimate"
	],
	char: "🥏",
	fitzpatrick_scale: false,
	category: "activity"
};
var golf = {
	keywords: [
		"sports",
		"business",
		"flag",
		"hole",
		"summer"
	],
	char: "⛳",
	fitzpatrick_scale: false,
	category: "activity"
};
var golfing_woman = {
	keywords: [
		"sports",
		"business",
		"woman",
		"female"
	],
	char: "🏌️‍♀️",
	fitzpatrick_scale: false,
	category: "activity"
};
var golfing_man = {
	keywords: [
		"sports",
		"business"
	],
	char: "🏌",
	fitzpatrick_scale: true,
	category: "activity"
};
var ping_pong = {
	keywords: [
		"sports",
		"pingpong"
	],
	char: "🏓",
	fitzpatrick_scale: false,
	category: "activity"
};
var badminton = {
	keywords: [
		"sports"
	],
	char: "🏸",
	fitzpatrick_scale: false,
	category: "activity"
};
var goal_net = {
	keywords: [
		"sports"
	],
	char: "🥅",
	fitzpatrick_scale: false,
	category: "activity"
};
var ice_hockey = {
	keywords: [
		"sports"
	],
	char: "🏒",
	fitzpatrick_scale: false,
	category: "activity"
};
var field_hockey = {
	keywords: [
		"sports"
	],
	char: "🏑",
	fitzpatrick_scale: false,
	category: "activity"
};
var lacrosse = {
	keywords: [
		"sports",
		"ball",
		"stick"
	],
	char: "🥍",
	fitzpatrick_scale: false,
	category: "activity"
};
var cricket = {
	keywords: [
		"sports"
	],
	char: "🏏",
	fitzpatrick_scale: false,
	category: "activity"
};
var ski = {
	keywords: [
		"sports",
		"winter",
		"cold",
		"snow"
	],
	char: "🎿",
	fitzpatrick_scale: false,
	category: "activity"
};
var skier = {
	keywords: [
		"sports",
		"winter",
		"snow"
	],
	char: "⛷",
	fitzpatrick_scale: false,
	category: "activity"
};
var snowboarder = {
	keywords: [
		"sports",
		"winter"
	],
	char: "🏂",
	fitzpatrick_scale: true,
	category: "activity"
};
var person_fencing = {
	keywords: [
		"sports",
		"fencing",
		"sword"
	],
	char: "🤺",
	fitzpatrick_scale: false,
	category: "activity"
};
var women_wrestling = {
	keywords: [
		"sports",
		"wrestlers"
	],
	char: "🤼‍♀️",
	fitzpatrick_scale: false,
	category: "activity"
};
var men_wrestling = {
	keywords: [
		"sports",
		"wrestlers"
	],
	char: "🤼‍♂️",
	fitzpatrick_scale: false,
	category: "activity"
};
var woman_cartwheeling = {
	keywords: [
		"gymnastics"
	],
	char: "🤸‍♀️",
	fitzpatrick_scale: true,
	category: "activity"
};
var man_cartwheeling = {
	keywords: [
		"gymnastics"
	],
	char: "🤸‍♂️",
	fitzpatrick_scale: true,
	category: "activity"
};
var woman_playing_handball = {
	keywords: [
		"sports"
	],
	char: "🤾‍♀️",
	fitzpatrick_scale: true,
	category: "activity"
};
var man_playing_handball = {
	keywords: [
		"sports"
	],
	char: "🤾‍♂️",
	fitzpatrick_scale: true,
	category: "activity"
};
var ice_skate = {
	keywords: [
		"sports"
	],
	char: "⛸",
	fitzpatrick_scale: false,
	category: "activity"
};
var curling_stone = {
	keywords: [
		"sports"
	],
	char: "🥌",
	fitzpatrick_scale: false,
	category: "activity"
};
var skateboard = {
	keywords: [
		"board"
	],
	char: "🛹",
	fitzpatrick_scale: false,
	category: "activity"
};
var sled = {
	keywords: [
		"sleigh",
		"luge",
		"toboggan"
	],
	char: "🛷",
	fitzpatrick_scale: false,
	category: "activity"
};
var bow_and_arrow = {
	keywords: [
		"sports"
	],
	char: "🏹",
	fitzpatrick_scale: false,
	category: "activity"
};
var fishing_pole_and_fish = {
	keywords: [
		"food",
		"hobby",
		"summer"
	],
	char: "🎣",
	fitzpatrick_scale: false,
	category: "activity"
};
var boxing_glove = {
	keywords: [
		"sports",
		"fighting"
	],
	char: "🥊",
	fitzpatrick_scale: false,
	category: "activity"
};
var martial_arts_uniform = {
	keywords: [
		"judo",
		"karate",
		"taekwondo"
	],
	char: "🥋",
	fitzpatrick_scale: false,
	category: "activity"
};
var rowing_woman = {
	keywords: [
		"sports",
		"hobby",
		"water",
		"ship",
		"woman",
		"female"
	],
	char: "🚣‍♀️",
	fitzpatrick_scale: true,
	category: "activity"
};
var rowing_man = {
	keywords: [
		"sports",
		"hobby",
		"water",
		"ship"
	],
	char: "🚣",
	fitzpatrick_scale: true,
	category: "activity"
};
var climbing_woman = {
	keywords: [
		"sports",
		"hobby",
		"woman",
		"female",
		"rock"
	],
	char: "🧗‍♀️",
	fitzpatrick_scale: true,
	category: "activity"
};
var climbing_man = {
	keywords: [
		"sports",
		"hobby",
		"man",
		"male",
		"rock"
	],
	char: "🧗‍♂️",
	fitzpatrick_scale: true,
	category: "activity"
};
var swimming_woman = {
	keywords: [
		"sports",
		"exercise",
		"human",
		"athlete",
		"water",
		"summer",
		"woman",
		"female"
	],
	char: "🏊‍♀️",
	fitzpatrick_scale: true,
	category: "activity"
};
var swimming_man = {
	keywords: [
		"sports",
		"exercise",
		"human",
		"athlete",
		"water",
		"summer"
	],
	char: "🏊",
	fitzpatrick_scale: true,
	category: "activity"
};
var woman_playing_water_polo = {
	keywords: [
		"sports",
		"pool"
	],
	char: "🤽‍♀️",
	fitzpatrick_scale: true,
	category: "activity"
};
var man_playing_water_polo = {
	keywords: [
		"sports",
		"pool"
	],
	char: "🤽‍♂️",
	fitzpatrick_scale: true,
	category: "activity"
};
var woman_in_lotus_position = {
	keywords: [
		"woman",
		"female",
		"meditation",
		"yoga",
		"serenity",
		"zen",
		"mindfulness"
	],
	char: "🧘‍♀️",
	fitzpatrick_scale: true,
	category: "activity"
};
var man_in_lotus_position = {
	keywords: [
		"man",
		"male",
		"meditation",
		"yoga",
		"serenity",
		"zen",
		"mindfulness"
	],
	char: "🧘‍♂️",
	fitzpatrick_scale: true,
	category: "activity"
};
var surfing_woman = {
	keywords: [
		"sports",
		"ocean",
		"sea",
		"summer",
		"beach",
		"woman",
		"female"
	],
	char: "🏄‍♀️",
	fitzpatrick_scale: true,
	category: "activity"
};
var surfing_man = {
	keywords: [
		"sports",
		"ocean",
		"sea",
		"summer",
		"beach"
	],
	char: "🏄",
	fitzpatrick_scale: true,
	category: "activity"
};
var bath = {
	keywords: [
		"clean",
		"shower",
		"bathroom"
	],
	char: "🛀",
	fitzpatrick_scale: true,
	category: "activity"
};
var basketball_woman = {
	keywords: [
		"sports",
		"human",
		"woman",
		"female"
	],
	char: "⛹️‍♀️",
	fitzpatrick_scale: true,
	category: "activity"
};
var basketball_man = {
	keywords: [
		"sports",
		"human"
	],
	char: "⛹",
	fitzpatrick_scale: true,
	category: "activity"
};
var weight_lifting_woman = {
	keywords: [
		"sports",
		"training",
		"exercise",
		"woman",
		"female"
	],
	char: "🏋️‍♀️",
	fitzpatrick_scale: true,
	category: "activity"
};
var weight_lifting_man = {
	keywords: [
		"sports",
		"training",
		"exercise"
	],
	char: "🏋",
	fitzpatrick_scale: true,
	category: "activity"
};
var biking_woman = {
	keywords: [
		"sports",
		"bike",
		"exercise",
		"hipster",
		"woman",
		"female"
	],
	char: "🚴‍♀️",
	fitzpatrick_scale: true,
	category: "activity"
};
var biking_man = {
	keywords: [
		"sports",
		"bike",
		"exercise",
		"hipster"
	],
	char: "🚴",
	fitzpatrick_scale: true,
	category: "activity"
};
var mountain_biking_woman = {
	keywords: [
		"transportation",
		"sports",
		"human",
		"race",
		"bike",
		"woman",
		"female"
	],
	char: "🚵‍♀️",
	fitzpatrick_scale: true,
	category: "activity"
};
var mountain_biking_man = {
	keywords: [
		"transportation",
		"sports",
		"human",
		"race",
		"bike"
	],
	char: "🚵",
	fitzpatrick_scale: true,
	category: "activity"
};
var horse_racing = {
	keywords: [
		"animal",
		"betting",
		"competition",
		"gambling",
		"luck"
	],
	char: "🏇",
	fitzpatrick_scale: true,
	category: "activity"
};
var business_suit_levitating = {
	keywords: [
		"suit",
		"business",
		"levitate",
		"hover",
		"jump"
	],
	char: "🕴",
	fitzpatrick_scale: true,
	category: "activity"
};
var trophy = {
	keywords: [
		"win",
		"award",
		"contest",
		"place",
		"ftw",
		"ceremony"
	],
	char: "🏆",
	fitzpatrick_scale: false,
	category: "activity"
};
var running_shirt_with_sash = {
	keywords: [
		"play",
		"pageant"
	],
	char: "🎽",
	fitzpatrick_scale: false,
	category: "activity"
};
var medal_sports = {
	keywords: [
		"award",
		"winning"
	],
	char: "🏅",
	fitzpatrick_scale: false,
	category: "activity"
};
var medal_military = {
	keywords: [
		"award",
		"winning",
		"army"
	],
	char: "🎖",
	fitzpatrick_scale: false,
	category: "activity"
};
var reminder_ribbon = {
	keywords: [
		"sports",
		"cause",
		"support",
		"awareness"
	],
	char: "🎗",
	fitzpatrick_scale: false,
	category: "activity"
};
var rosette = {
	keywords: [
		"flower",
		"decoration",
		"military"
	],
	char: "🏵",
	fitzpatrick_scale: false,
	category: "activity"
};
var ticket = {
	keywords: [
		"event",
		"concert",
		"pass"
	],
	char: "🎫",
	fitzpatrick_scale: false,
	category: "activity"
};
var tickets = {
	keywords: [
		"sports",
		"concert",
		"entrance"
	],
	char: "🎟",
	fitzpatrick_scale: false,
	category: "activity"
};
var performing_arts = {
	keywords: [
		"acting",
		"theater",
		"drama"
	],
	char: "🎭",
	fitzpatrick_scale: false,
	category: "activity"
};
var art = {
	keywords: [
		"design",
		"paint",
		"draw",
		"colors"
	],
	char: "🎨",
	fitzpatrick_scale: false,
	category: "activity"
};
var circus_tent = {
	keywords: [
		"festival",
		"carnival",
		"party"
	],
	char: "🎪",
	fitzpatrick_scale: false,
	category: "activity"
};
var woman_juggling = {
	keywords: [
		"juggle",
		"balance",
		"skill",
		"multitask"
	],
	char: "🤹‍♀️",
	fitzpatrick_scale: true,
	category: "activity"
};
var man_juggling = {
	keywords: [
		"juggle",
		"balance",
		"skill",
		"multitask"
	],
	char: "🤹‍♂️",
	fitzpatrick_scale: true,
	category: "activity"
};
var microphone = {
	keywords: [
		"sound",
		"music",
		"PA",
		"sing",
		"talkshow"
	],
	char: "🎤",
	fitzpatrick_scale: false,
	category: "activity"
};
var headphones = {
	keywords: [
		"music",
		"score",
		"gadgets"
	],
	char: "🎧",
	fitzpatrick_scale: false,
	category: "activity"
};
var musical_score = {
	keywords: [
		"treble",
		"clef",
		"compose"
	],
	char: "🎼",
	fitzpatrick_scale: false,
	category: "activity"
};
var musical_keyboard = {
	keywords: [
		"piano",
		"instrument",
		"compose"
	],
	char: "🎹",
	fitzpatrick_scale: false,
	category: "activity"
};
var drum = {
	keywords: [
		"music",
		"instrument",
		"drumsticks",
		"snare"
	],
	char: "🥁",
	fitzpatrick_scale: false,
	category: "activity"
};
var saxophone = {
	keywords: [
		"music",
		"instrument",
		"jazz",
		"blues"
	],
	char: "🎷",
	fitzpatrick_scale: false,
	category: "activity"
};
var trumpet = {
	keywords: [
		"music",
		"brass"
	],
	char: "🎺",
	fitzpatrick_scale: false,
	category: "activity"
};
var guitar = {
	keywords: [
		"music",
		"instrument"
	],
	char: "🎸",
	fitzpatrick_scale: false,
	category: "activity"
};
var violin = {
	keywords: [
		"music",
		"instrument",
		"orchestra",
		"symphony"
	],
	char: "🎻",
	fitzpatrick_scale: false,
	category: "activity"
};
var clapper = {
	keywords: [
		"movie",
		"film",
		"record"
	],
	char: "🎬",
	fitzpatrick_scale: false,
	category: "activity"
};
var video_game = {
	keywords: [
		"play",
		"console",
		"PS4",
		"controller"
	],
	char: "🎮",
	fitzpatrick_scale: false,
	category: "activity"
};
var space_invader = {
	keywords: [
		"game",
		"arcade",
		"play"
	],
	char: "👾",
	fitzpatrick_scale: false,
	category: "activity"
};
var dart = {
	keywords: [
		"game",
		"play",
		"bar",
		"target",
		"bullseye"
	],
	char: "🎯",
	fitzpatrick_scale: false,
	category: "activity"
};
var game_die = {
	keywords: [
		"dice",
		"random",
		"tabletop",
		"play",
		"luck"
	],
	char: "🎲",
	fitzpatrick_scale: false,
	category: "activity"
};
var chess_pawn = {
	keywords: [
		"expendable"
	],
	char: "♟",
	fitzpatrick_scale: false,
	category: "activity"
};
var slot_machine = {
	keywords: [
		"bet",
		"gamble",
		"vegas",
		"fruit machine",
		"luck",
		"casino"
	],
	char: "🎰",
	fitzpatrick_scale: false,
	category: "activity"
};
var jigsaw = {
	keywords: [
		"interlocking",
		"puzzle",
		"piece"
	],
	char: "🧩",
	fitzpatrick_scale: false,
	category: "activity"
};
var bowling = {
	keywords: [
		"sports",
		"fun",
		"play"
	],
	char: "🎳",
	fitzpatrick_scale: false,
	category: "activity"
};
var red_car = {
	keywords: [
		"red",
		"transportation",
		"vehicle"
	],
	char: "🚗",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var taxi = {
	keywords: [
		"uber",
		"vehicle",
		"cars",
		"transportation"
	],
	char: "🚕",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var blue_car = {
	keywords: [
		"transportation",
		"vehicle"
	],
	char: "🚙",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var bus = {
	keywords: [
		"car",
		"vehicle",
		"transportation"
	],
	char: "🚌",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var trolleybus = {
	keywords: [
		"bart",
		"transportation",
		"vehicle"
	],
	char: "🚎",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var racing_car = {
	keywords: [
		"sports",
		"race",
		"fast",
		"formula",
		"f1"
	],
	char: "🏎",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var police_car = {
	keywords: [
		"vehicle",
		"cars",
		"transportation",
		"law",
		"legal",
		"enforcement"
	],
	char: "🚓",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var ambulance = {
	keywords: [
		"health",
		"911",
		"hospital"
	],
	char: "🚑",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var fire_engine = {
	keywords: [
		"transportation",
		"cars",
		"vehicle"
	],
	char: "🚒",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var minibus = {
	keywords: [
		"vehicle",
		"car",
		"transportation"
	],
	char: "🚐",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var truck = {
	keywords: [
		"cars",
		"transportation"
	],
	char: "🚚",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var articulated_lorry = {
	keywords: [
		"vehicle",
		"cars",
		"transportation",
		"express"
	],
	char: "🚛",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var tractor = {
	keywords: [
		"vehicle",
		"car",
		"farming",
		"agriculture"
	],
	char: "🚜",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var kick_scooter = {
	keywords: [
		"vehicle",
		"kick",
		"razor"
	],
	char: "🛴",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var motorcycle = {
	keywords: [
		"race",
		"sports",
		"fast"
	],
	char: "🏍",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var bike = {
	keywords: [
		"sports",
		"bicycle",
		"exercise",
		"hipster"
	],
	char: "🚲",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var motor_scooter = {
	keywords: [
		"vehicle",
		"vespa",
		"sasha"
	],
	char: "🛵",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var rotating_light = {
	keywords: [
		"police",
		"ambulance",
		"911",
		"emergency",
		"alert",
		"error",
		"pinged",
		"law",
		"legal"
	],
	char: "🚨",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var oncoming_police_car = {
	keywords: [
		"vehicle",
		"law",
		"legal",
		"enforcement",
		"911"
	],
	char: "🚔",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var oncoming_bus = {
	keywords: [
		"vehicle",
		"transportation"
	],
	char: "🚍",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var oncoming_automobile = {
	keywords: [
		"car",
		"vehicle",
		"transportation"
	],
	char: "🚘",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var oncoming_taxi = {
	keywords: [
		"vehicle",
		"cars",
		"uber"
	],
	char: "🚖",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var aerial_tramway = {
	keywords: [
		"transportation",
		"vehicle",
		"ski"
	],
	char: "🚡",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var mountain_cableway = {
	keywords: [
		"transportation",
		"vehicle",
		"ski"
	],
	char: "🚠",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var suspension_railway = {
	keywords: [
		"vehicle",
		"transportation"
	],
	char: "🚟",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var railway_car = {
	keywords: [
		"transportation",
		"vehicle"
	],
	char: "🚃",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var train = {
	keywords: [
		"transportation",
		"vehicle",
		"carriage",
		"public",
		"travel"
	],
	char: "🚋",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var monorail = {
	keywords: [
		"transportation",
		"vehicle"
	],
	char: "🚝",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var bullettrain_side = {
	keywords: [
		"transportation",
		"vehicle"
	],
	char: "🚄",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var bullettrain_front = {
	keywords: [
		"transportation",
		"vehicle",
		"speed",
		"fast",
		"public",
		"travel"
	],
	char: "🚅",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var light_rail = {
	keywords: [
		"transportation",
		"vehicle"
	],
	char: "🚈",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var mountain_railway = {
	keywords: [
		"transportation",
		"vehicle"
	],
	char: "🚞",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var steam_locomotive = {
	keywords: [
		"transportation",
		"vehicle",
		"train"
	],
	char: "🚂",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var train2 = {
	keywords: [
		"transportation",
		"vehicle"
	],
	char: "🚆",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var metro = {
	keywords: [
		"transportation",
		"blue-square",
		"mrt",
		"underground",
		"tube"
	],
	char: "🚇",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var tram = {
	keywords: [
		"transportation",
		"vehicle"
	],
	char: "🚊",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var station = {
	keywords: [
		"transportation",
		"vehicle",
		"public"
	],
	char: "🚉",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var flying_saucer = {
	keywords: [
		"transportation",
		"vehicle",
		"ufo"
	],
	char: "🛸",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var helicopter = {
	keywords: [
		"transportation",
		"vehicle",
		"fly"
	],
	char: "🚁",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var small_airplane = {
	keywords: [
		"flight",
		"transportation",
		"fly",
		"vehicle"
	],
	char: "🛩",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var airplane = {
	keywords: [
		"vehicle",
		"transportation",
		"flight",
		"fly"
	],
	char: "✈️",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var flight_departure = {
	keywords: [
		"airport",
		"flight",
		"landing"
	],
	char: "🛫",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var flight_arrival = {
	keywords: [
		"airport",
		"flight",
		"boarding"
	],
	char: "🛬",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var sailboat = {
	keywords: [
		"ship",
		"summer",
		"transportation",
		"water",
		"sailing"
	],
	char: "⛵",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var motor_boat = {
	keywords: [
		"ship"
	],
	char: "🛥",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var speedboat = {
	keywords: [
		"ship",
		"transportation",
		"vehicle",
		"summer"
	],
	char: "🚤",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var ferry = {
	keywords: [
		"boat",
		"ship",
		"yacht"
	],
	char: "⛴",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var passenger_ship = {
	keywords: [
		"yacht",
		"cruise",
		"ferry"
	],
	char: "🛳",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var rocket = {
	keywords: [
		"launch",
		"ship",
		"staffmode",
		"NASA",
		"outer space",
		"outer_space",
		"fly"
	],
	char: "🚀",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var artificial_satellite = {
	keywords: [
		"communication",
		"gps",
		"orbit",
		"spaceflight",
		"NASA",
		"ISS"
	],
	char: "🛰",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var seat = {
	keywords: [
		"sit",
		"airplane",
		"transport",
		"bus",
		"flight",
		"fly"
	],
	char: "💺",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var canoe = {
	keywords: [
		"boat",
		"paddle",
		"water",
		"ship"
	],
	char: "🛶",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var anchor = {
	keywords: [
		"ship",
		"ferry",
		"sea",
		"boat"
	],
	char: "⚓",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var construction = {
	keywords: [
		"wip",
		"progress",
		"caution",
		"warning"
	],
	char: "🚧",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var fuelpump = {
	keywords: [
		"gas station",
		"petroleum"
	],
	char: "⛽",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var busstop = {
	keywords: [
		"transportation",
		"wait"
	],
	char: "🚏",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var vertical_traffic_light = {
	keywords: [
		"transportation",
		"driving"
	],
	char: "🚦",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var traffic_light = {
	keywords: [
		"transportation",
		"signal"
	],
	char: "🚥",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var checkered_flag = {
	keywords: [
		"contest",
		"finishline",
		"race",
		"gokart"
	],
	char: "🏁",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var ship = {
	keywords: [
		"transportation",
		"titanic",
		"deploy"
	],
	char: "🚢",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var ferris_wheel = {
	keywords: [
		"photo",
		"carnival",
		"londoneye"
	],
	char: "🎡",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var roller_coaster = {
	keywords: [
		"carnival",
		"playground",
		"photo",
		"fun"
	],
	char: "🎢",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var carousel_horse = {
	keywords: [
		"photo",
		"carnival"
	],
	char: "🎠",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var building_construction = {
	keywords: [
		"wip",
		"working",
		"progress"
	],
	char: "🏗",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var foggy = {
	keywords: [
		"photo",
		"mountain"
	],
	char: "🌁",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var tokyo_tower = {
	keywords: [
		"photo",
		"japanese"
	],
	char: "🗼",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var factory = {
	keywords: [
		"building",
		"industry",
		"pollution",
		"smoke"
	],
	char: "🏭",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var fountain = {
	keywords: [
		"photo",
		"summer",
		"water",
		"fresh"
	],
	char: "⛲",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var rice_scene = {
	keywords: [
		"photo",
		"japan",
		"asia",
		"tsukimi"
	],
	char: "🎑",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var mountain = {
	keywords: [
		"photo",
		"nature",
		"environment"
	],
	char: "⛰",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var mountain_snow = {
	keywords: [
		"photo",
		"nature",
		"environment",
		"winter",
		"cold"
	],
	char: "🏔",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var mount_fuji = {
	keywords: [
		"photo",
		"mountain",
		"nature",
		"japanese"
	],
	char: "🗻",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var volcano = {
	keywords: [
		"photo",
		"nature",
		"disaster"
	],
	char: "🌋",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var japan = {
	keywords: [
		"nation",
		"country",
		"japanese",
		"asia"
	],
	char: "🗾",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var camping = {
	keywords: [
		"photo",
		"outdoors",
		"tent"
	],
	char: "🏕",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var tent = {
	keywords: [
		"photo",
		"camping",
		"outdoors"
	],
	char: "⛺",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var national_park = {
	keywords: [
		"photo",
		"environment",
		"nature"
	],
	char: "🏞",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var motorway = {
	keywords: [
		"road",
		"cupertino",
		"interstate",
		"highway"
	],
	char: "🛣",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var railway_track = {
	keywords: [
		"train",
		"transportation"
	],
	char: "🛤",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var sunrise = {
	keywords: [
		"morning",
		"view",
		"vacation",
		"photo"
	],
	char: "🌅",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var sunrise_over_mountains = {
	keywords: [
		"view",
		"vacation",
		"photo"
	],
	char: "🌄",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var desert = {
	keywords: [
		"photo",
		"warm",
		"saharah"
	],
	char: "🏜",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var beach_umbrella = {
	keywords: [
		"weather",
		"summer",
		"sunny",
		"sand",
		"mojito"
	],
	char: "🏖",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var desert_island = {
	keywords: [
		"photo",
		"tropical",
		"mojito"
	],
	char: "🏝",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var city_sunrise = {
	keywords: [
		"photo",
		"good morning",
		"dawn"
	],
	char: "🌇",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var city_sunset = {
	keywords: [
		"photo",
		"evening",
		"sky",
		"buildings"
	],
	char: "🌆",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var cityscape = {
	keywords: [
		"photo",
		"night life",
		"urban"
	],
	char: "🏙",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var night_with_stars = {
	keywords: [
		"evening",
		"city",
		"downtown"
	],
	char: "🌃",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var bridge_at_night = {
	keywords: [
		"photo",
		"sanfrancisco"
	],
	char: "🌉",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var milky_way = {
	keywords: [
		"photo",
		"space",
		"stars"
	],
	char: "🌌",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var stars = {
	keywords: [
		"night",
		"photo"
	],
	char: "🌠",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var sparkler = {
	keywords: [
		"stars",
		"night",
		"shine"
	],
	char: "🎇",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var fireworks = {
	keywords: [
		"photo",
		"festival",
		"carnival",
		"congratulations"
	],
	char: "🎆",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var rainbow = {
	keywords: [
		"nature",
		"happy",
		"unicorn_face",
		"photo",
		"sky",
		"spring"
	],
	char: "🌈",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var houses = {
	keywords: [
		"buildings",
		"photo"
	],
	char: "🏘",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var european_castle = {
	keywords: [
		"building",
		"royalty",
		"history"
	],
	char: "🏰",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var japanese_castle = {
	keywords: [
		"photo",
		"building"
	],
	char: "🏯",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var stadium = {
	keywords: [
		"photo",
		"place",
		"sports",
		"concert",
		"venue"
	],
	char: "🏟",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var statue_of_liberty = {
	keywords: [
		"american",
		"newyork"
	],
	char: "🗽",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var house = {
	keywords: [
		"building",
		"home"
	],
	char: "🏠",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var house_with_garden = {
	keywords: [
		"home",
		"plant",
		"nature"
	],
	char: "🏡",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var derelict_house = {
	keywords: [
		"abandon",
		"evict",
		"broken",
		"building"
	],
	char: "🏚",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var office = {
	keywords: [
		"building",
		"bureau",
		"work"
	],
	char: "🏢",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var department_store = {
	keywords: [
		"building",
		"shopping",
		"mall"
	],
	char: "🏬",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var post_office = {
	keywords: [
		"building",
		"envelope",
		"communication"
	],
	char: "🏣",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var european_post_office = {
	keywords: [
		"building",
		"email"
	],
	char: "🏤",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var hospital = {
	keywords: [
		"building",
		"health",
		"surgery",
		"doctor"
	],
	char: "🏥",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var bank = {
	keywords: [
		"building",
		"money",
		"sales",
		"cash",
		"business",
		"enterprise"
	],
	char: "🏦",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var hotel = {
	keywords: [
		"building",
		"accomodation",
		"checkin"
	],
	char: "🏨",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var convenience_store = {
	keywords: [
		"building",
		"shopping",
		"groceries"
	],
	char: "🏪",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var school = {
	keywords: [
		"building",
		"student",
		"education",
		"learn",
		"teach"
	],
	char: "🏫",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var love_hotel = {
	keywords: [
		"like",
		"affection",
		"dating"
	],
	char: "🏩",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var wedding = {
	keywords: [
		"love",
		"like",
		"affection",
		"couple",
		"marriage",
		"bride",
		"groom"
	],
	char: "💒",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var classical_building = {
	keywords: [
		"art",
		"culture",
		"history"
	],
	char: "🏛",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var church = {
	keywords: [
		"building",
		"religion",
		"christ"
	],
	char: "⛪",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var mosque = {
	keywords: [
		"islam",
		"worship",
		"minaret"
	],
	char: "🕌",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var synagogue = {
	keywords: [
		"judaism",
		"worship",
		"temple",
		"jewish"
	],
	char: "🕍",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var kaaba = {
	keywords: [
		"mecca",
		"mosque",
		"islam"
	],
	char: "🕋",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var shinto_shrine = {
	keywords: [
		"temple",
		"japan",
		"kyoto"
	],
	char: "⛩",
	fitzpatrick_scale: false,
	category: "travel_and_places"
};
var watch = {
	keywords: [
		"time",
		"accessories"
	],
	char: "⌚",
	fitzpatrick_scale: false,
	category: "objects"
};
var iphone = {
	keywords: [
		"technology",
		"apple",
		"gadgets",
		"dial"
	],
	char: "📱",
	fitzpatrick_scale: false,
	category: "objects"
};
var calling = {
	keywords: [
		"iphone",
		"incoming"
	],
	char: "📲",
	fitzpatrick_scale: false,
	category: "objects"
};
var computer = {
	keywords: [
		"technology",
		"laptop",
		"screen",
		"display",
		"monitor"
	],
	char: "💻",
	fitzpatrick_scale: false,
	category: "objects"
};
var keyboard = {
	keywords: [
		"technology",
		"computer",
		"type",
		"input",
		"text"
	],
	char: "⌨",
	fitzpatrick_scale: false,
	category: "objects"
};
var desktop_computer = {
	keywords: [
		"technology",
		"computing",
		"screen"
	],
	char: "🖥",
	fitzpatrick_scale: false,
	category: "objects"
};
var printer = {
	keywords: [
		"paper",
		"ink"
	],
	char: "🖨",
	fitzpatrick_scale: false,
	category: "objects"
};
var computer_mouse = {
	keywords: [
		"click"
	],
	char: "🖱",
	fitzpatrick_scale: false,
	category: "objects"
};
var trackball = {
	keywords: [
		"technology",
		"trackpad"
	],
	char: "🖲",
	fitzpatrick_scale: false,
	category: "objects"
};
var joystick = {
	keywords: [
		"game",
		"play"
	],
	char: "🕹",
	fitzpatrick_scale: false,
	category: "objects"
};
var clamp = {
	keywords: [
		"tool"
	],
	char: "🗜",
	fitzpatrick_scale: false,
	category: "objects"
};
var minidisc = {
	keywords: [
		"technology",
		"record",
		"data",
		"disk",
		"90s"
	],
	char: "💽",
	fitzpatrick_scale: false,
	category: "objects"
};
var floppy_disk = {
	keywords: [
		"oldschool",
		"technology",
		"save",
		"90s",
		"80s"
	],
	char: "💾",
	fitzpatrick_scale: false,
	category: "objects"
};
var cd = {
	keywords: [
		"technology",
		"dvd",
		"disk",
		"disc",
		"90s"
	],
	char: "💿",
	fitzpatrick_scale: false,
	category: "objects"
};
var dvd = {
	keywords: [
		"cd",
		"disk",
		"disc"
	],
	char: "📀",
	fitzpatrick_scale: false,
	category: "objects"
};
var vhs = {
	keywords: [
		"record",
		"video",
		"oldschool",
		"90s",
		"80s"
	],
	char: "📼",
	fitzpatrick_scale: false,
	category: "objects"
};
var camera = {
	keywords: [
		"gadgets",
		"photography"
	],
	char: "📷",
	fitzpatrick_scale: false,
	category: "objects"
};
var camera_flash = {
	keywords: [
		"photography",
		"gadgets"
	],
	char: "📸",
	fitzpatrick_scale: false,
	category: "objects"
};
var video_camera = {
	keywords: [
		"film",
		"record"
	],
	char: "📹",
	fitzpatrick_scale: false,
	category: "objects"
};
var movie_camera = {
	keywords: [
		"film",
		"record"
	],
	char: "🎥",
	fitzpatrick_scale: false,
	category: "objects"
};
var film_projector = {
	keywords: [
		"video",
		"tape",
		"record",
		"movie"
	],
	char: "📽",
	fitzpatrick_scale: false,
	category: "objects"
};
var film_strip = {
	keywords: [
		"movie"
	],
	char: "🎞",
	fitzpatrick_scale: false,
	category: "objects"
};
var telephone_receiver = {
	keywords: [
		"technology",
		"communication",
		"dial"
	],
	char: "📞",
	fitzpatrick_scale: false,
	category: "objects"
};
var phone$1 = {
	keywords: [
		"technology",
		"communication",
		"dial",
		"telephone"
	],
	char: "☎️",
	fitzpatrick_scale: false,
	category: "objects"
};
var pager = {
	keywords: [
		"bbcall",
		"oldschool",
		"90s"
	],
	char: "📟",
	fitzpatrick_scale: false,
	category: "objects"
};
var fax = {
	keywords: [
		"communication",
		"technology"
	],
	char: "📠",
	fitzpatrick_scale: false,
	category: "objects"
};
var tv = {
	keywords: [
		"technology",
		"program",
		"oldschool",
		"show",
		"television"
	],
	char: "📺",
	fitzpatrick_scale: false,
	category: "objects"
};
var radio = {
	keywords: [
		"communication",
		"music",
		"podcast",
		"program"
	],
	char: "📻",
	fitzpatrick_scale: false,
	category: "objects"
};
var studio_microphone = {
	keywords: [
		"sing",
		"recording",
		"artist",
		"talkshow"
	],
	char: "🎙",
	fitzpatrick_scale: false,
	category: "objects"
};
var level_slider = {
	keywords: [
		"scale"
	],
	char: "🎚",
	fitzpatrick_scale: false,
	category: "objects"
};
var control_knobs = {
	keywords: [
		"dial"
	],
	char: "🎛",
	fitzpatrick_scale: false,
	category: "objects"
};
var compass = {
	keywords: [
		"magnetic",
		"navigation",
		"orienteering"
	],
	char: "🧭",
	fitzpatrick_scale: false,
	category: "objects"
};
var stopwatch = {
	keywords: [
		"time",
		"deadline"
	],
	char: "⏱",
	fitzpatrick_scale: false,
	category: "objects"
};
var timer_clock = {
	keywords: [
		"alarm"
	],
	char: "⏲",
	fitzpatrick_scale: false,
	category: "objects"
};
var alarm_clock = {
	keywords: [
		"time",
		"wake"
	],
	char: "⏰",
	fitzpatrick_scale: false,
	category: "objects"
};
var mantelpiece_clock = {
	keywords: [
		"time"
	],
	char: "🕰",
	fitzpatrick_scale: false,
	category: "objects"
};
var hourglass_flowing_sand = {
	keywords: [
		"oldschool",
		"time",
		"countdown"
	],
	char: "⏳",
	fitzpatrick_scale: false,
	category: "objects"
};
var hourglass = {
	keywords: [
		"time",
		"clock",
		"oldschool",
		"limit",
		"exam",
		"quiz",
		"test"
	],
	char: "⌛",
	fitzpatrick_scale: false,
	category: "objects"
};
var satellite = {
	keywords: [
		"communication",
		"future",
		"radio",
		"space"
	],
	char: "📡",
	fitzpatrick_scale: false,
	category: "objects"
};
var battery = {
	keywords: [
		"power",
		"energy",
		"sustain"
	],
	char: "🔋",
	fitzpatrick_scale: false,
	category: "objects"
};
var electric_plug = {
	keywords: [
		"charger",
		"power"
	],
	char: "🔌",
	fitzpatrick_scale: false,
	category: "objects"
};
var bulb = {
	keywords: [
		"light",
		"electricity",
		"idea"
	],
	char: "💡",
	fitzpatrick_scale: false,
	category: "objects"
};
var flashlight = {
	keywords: [
		"dark",
		"camping",
		"sight",
		"night"
	],
	char: "🔦",
	fitzpatrick_scale: false,
	category: "objects"
};
var candle = {
	keywords: [
		"fire",
		"wax"
	],
	char: "🕯",
	fitzpatrick_scale: false,
	category: "objects"
};
var fire_extinguisher = {
	keywords: [
		"quench"
	],
	char: "🧯",
	fitzpatrick_scale: false,
	category: "objects"
};
var wastebasket = {
	keywords: [
		"bin",
		"trash",
		"rubbish",
		"garbage",
		"toss"
	],
	char: "🗑",
	fitzpatrick_scale: false,
	category: "objects"
};
var oil_drum = {
	keywords: [
		"barrell"
	],
	char: "🛢",
	fitzpatrick_scale: false,
	category: "objects"
};
var money_with_wings = {
	keywords: [
		"dollar",
		"bills",
		"payment",
		"sale"
	],
	char: "💸",
	fitzpatrick_scale: false,
	category: "objects"
};
var dollar$1 = {
	keywords: [
		"money",
		"sales",
		"bill",
		"currency"
	],
	char: "💵",
	fitzpatrick_scale: false,
	category: "objects"
};
var yen$1 = {
	keywords: [
		"money",
		"sales",
		"japanese",
		"dollar",
		"currency"
	],
	char: "💴",
	fitzpatrick_scale: false,
	category: "objects"
};
var euro$1 = {
	keywords: [
		"money",
		"sales",
		"dollar",
		"currency"
	],
	char: "💶",
	fitzpatrick_scale: false,
	category: "objects"
};
var pound$1 = {
	keywords: [
		"british",
		"sterling",
		"money",
		"sales",
		"bills",
		"uk",
		"england",
		"currency"
	],
	char: "💷",
	fitzpatrick_scale: false,
	category: "objects"
};
var moneybag = {
	keywords: [
		"dollar",
		"payment",
		"coins",
		"sale"
	],
	char: "💰",
	fitzpatrick_scale: false,
	category: "objects"
};
var credit_card = {
	keywords: [
		"money",
		"sales",
		"dollar",
		"bill",
		"payment",
		"shopping"
	],
	char: "💳",
	fitzpatrick_scale: false,
	category: "objects"
};
var gem = {
	keywords: [
		"blue",
		"ruby",
		"diamond",
		"jewelry"
	],
	char: "💎",
	fitzpatrick_scale: false,
	category: "objects"
};
var balance_scale = {
	keywords: [
		"law",
		"fairness",
		"weight"
	],
	char: "⚖",
	fitzpatrick_scale: false,
	category: "objects"
};
var toolbox = {
	keywords: [
		"tools",
		"diy",
		"fix",
		"maintainer",
		"mechanic"
	],
	char: "🧰",
	fitzpatrick_scale: false,
	category: "objects"
};
var wrench = {
	keywords: [
		"tools",
		"diy",
		"ikea",
		"fix",
		"maintainer"
	],
	char: "🔧",
	fitzpatrick_scale: false,
	category: "objects"
};
var hammer = {
	keywords: [
		"tools",
		"build",
		"create"
	],
	char: "🔨",
	fitzpatrick_scale: false,
	category: "objects"
};
var hammer_and_pick = {
	keywords: [
		"tools",
		"build",
		"create"
	],
	char: "⚒",
	fitzpatrick_scale: false,
	category: "objects"
};
var hammer_and_wrench = {
	keywords: [
		"tools",
		"build",
		"create"
	],
	char: "🛠",
	fitzpatrick_scale: false,
	category: "objects"
};
var pick = {
	keywords: [
		"tools",
		"dig"
	],
	char: "⛏",
	fitzpatrick_scale: false,
	category: "objects"
};
var nut_and_bolt = {
	keywords: [
		"handy",
		"tools",
		"fix"
	],
	char: "🔩",
	fitzpatrick_scale: false,
	category: "objects"
};
var gear = {
	keywords: [
		"cog"
	],
	char: "⚙",
	fitzpatrick_scale: false,
	category: "objects"
};
var brick = {
	keywords: [
		"bricks"
	],
	char: "🧱",
	fitzpatrick_scale: false,
	category: "objects"
};
var chains = {
	keywords: [
		"lock",
		"arrest"
	],
	char: "⛓",
	fitzpatrick_scale: false,
	category: "objects"
};
var magnet = {
	keywords: [
		"attraction",
		"magnetic"
	],
	char: "🧲",
	fitzpatrick_scale: false,
	category: "objects"
};
var gun = {
	keywords: [
		"violence",
		"weapon",
		"pistol",
		"revolver"
	],
	char: "🔫",
	fitzpatrick_scale: false,
	category: "objects"
};
var bomb = {
	keywords: [
		"boom",
		"explode",
		"explosion",
		"terrorism"
	],
	char: "💣",
	fitzpatrick_scale: false,
	category: "objects"
};
var firecracker = {
	keywords: [
		"dynamite",
		"boom",
		"explode",
		"explosion",
		"explosive"
	],
	char: "🧨",
	fitzpatrick_scale: false,
	category: "objects"
};
var hocho = {
	keywords: [
		"knife",
		"blade",
		"cutlery",
		"kitchen",
		"weapon"
	],
	char: "🔪",
	fitzpatrick_scale: false,
	category: "objects"
};
var dagger$1 = {
	keywords: [
		"weapon"
	],
	char: "🗡",
	fitzpatrick_scale: false,
	category: "objects"
};
var crossed_swords = {
	keywords: [
		"weapon"
	],
	char: "⚔",
	fitzpatrick_scale: false,
	category: "objects"
};
var shield = {
	keywords: [
		"protection",
		"security"
	],
	char: "🛡",
	fitzpatrick_scale: false,
	category: "objects"
};
var smoking = {
	keywords: [
		"kills",
		"tobacco",
		"cigarette",
		"joint",
		"smoke"
	],
	char: "🚬",
	fitzpatrick_scale: false,
	category: "objects"
};
var skull_and_crossbones = {
	keywords: [
		"poison",
		"danger",
		"deadly",
		"scary",
		"death",
		"pirate",
		"evil"
	],
	char: "☠",
	fitzpatrick_scale: false,
	category: "objects"
};
var coffin = {
	keywords: [
		"vampire",
		"dead",
		"die",
		"death",
		"rip",
		"graveyard",
		"cemetery",
		"casket",
		"funeral",
		"box"
	],
	char: "⚰",
	fitzpatrick_scale: false,
	category: "objects"
};
var funeral_urn = {
	keywords: [
		"dead",
		"die",
		"death",
		"rip",
		"ashes"
	],
	char: "⚱",
	fitzpatrick_scale: false,
	category: "objects"
};
var amphora = {
	keywords: [
		"vase",
		"jar"
	],
	char: "🏺",
	fitzpatrick_scale: false,
	category: "objects"
};
var crystal_ball = {
	keywords: [
		"disco",
		"party",
		"magic",
		"circus",
		"fortune_teller"
	],
	char: "🔮",
	fitzpatrick_scale: false,
	category: "objects"
};
var prayer_beads = {
	keywords: [
		"dhikr",
		"religious"
	],
	char: "📿",
	fitzpatrick_scale: false,
	category: "objects"
};
var nazar_amulet = {
	keywords: [
		"bead",
		"charm"
	],
	char: "🧿",
	fitzpatrick_scale: false,
	category: "objects"
};
var barber = {
	keywords: [
		"hair",
		"salon",
		"style"
	],
	char: "💈",
	fitzpatrick_scale: false,
	category: "objects"
};
var alembic = {
	keywords: [
		"distilling",
		"science",
		"experiment",
		"chemistry"
	],
	char: "⚗",
	fitzpatrick_scale: false,
	category: "objects"
};
var telescope = {
	keywords: [
		"stars",
		"space",
		"zoom",
		"science",
		"astronomy"
	],
	char: "🔭",
	fitzpatrick_scale: false,
	category: "objects"
};
var microscope = {
	keywords: [
		"laboratory",
		"experiment",
		"zoomin",
		"science",
		"study"
	],
	char: "🔬",
	fitzpatrick_scale: false,
	category: "objects"
};
var hole = {
	keywords: [
		"embarrassing"
	],
	char: "🕳",
	fitzpatrick_scale: false,
	category: "objects"
};
var pill = {
	keywords: [
		"health",
		"medicine",
		"doctor",
		"pharmacy",
		"drug"
	],
	char: "💊",
	fitzpatrick_scale: false,
	category: "objects"
};
var syringe = {
	keywords: [
		"health",
		"hospital",
		"drugs",
		"blood",
		"medicine",
		"needle",
		"doctor",
		"nurse"
	],
	char: "💉",
	fitzpatrick_scale: false,
	category: "objects"
};
var dna = {
	keywords: [
		"biologist",
		"genetics",
		"life"
	],
	char: "🧬",
	fitzpatrick_scale: false,
	category: "objects"
};
var microbe = {
	keywords: [
		"amoeba",
		"bacteria",
		"germs"
	],
	char: "🦠",
	fitzpatrick_scale: false,
	category: "objects"
};
var petri_dish = {
	keywords: [
		"bacteria",
		"biology",
		"culture",
		"lab"
	],
	char: "🧫",
	fitzpatrick_scale: false,
	category: "objects"
};
var test_tube = {
	keywords: [
		"chemistry",
		"experiment",
		"lab",
		"science"
	],
	char: "🧪",
	fitzpatrick_scale: false,
	category: "objects"
};
var thermometer = {
	keywords: [
		"weather",
		"temperature",
		"hot",
		"cold"
	],
	char: "🌡",
	fitzpatrick_scale: false,
	category: "objects"
};
var broom = {
	keywords: [
		"cleaning",
		"sweeping",
		"witch"
	],
	char: "🧹",
	fitzpatrick_scale: false,
	category: "objects"
};
var basket = {
	keywords: [
		"laundry"
	],
	char: "🧺",
	fitzpatrick_scale: false,
	category: "objects"
};
var toilet_paper = {
	keywords: [
		"roll"
	],
	char: "🧻",
	fitzpatrick_scale: false,
	category: "objects"
};
var label = {
	keywords: [
		"sale",
		"tag"
	],
	char: "🏷",
	fitzpatrick_scale: false,
	category: "objects"
};
var bookmark = {
	keywords: [
		"favorite",
		"label",
		"save"
	],
	char: "🔖",
	fitzpatrick_scale: false,
	category: "objects"
};
var toilet = {
	keywords: [
		"restroom",
		"wc",
		"washroom",
		"bathroom",
		"potty"
	],
	char: "🚽",
	fitzpatrick_scale: false,
	category: "objects"
};
var shower = {
	keywords: [
		"clean",
		"water",
		"bathroom"
	],
	char: "🚿",
	fitzpatrick_scale: false,
	category: "objects"
};
var bathtub = {
	keywords: [
		"clean",
		"shower",
		"bathroom"
	],
	char: "🛁",
	fitzpatrick_scale: false,
	category: "objects"
};
var soap = {
	keywords: [
		"bar",
		"bathing",
		"cleaning",
		"lather"
	],
	char: "🧼",
	fitzpatrick_scale: false,
	category: "objects"
};
var sponge = {
	keywords: [
		"absorbing",
		"cleaning",
		"porous"
	],
	char: "🧽",
	fitzpatrick_scale: false,
	category: "objects"
};
var lotion_bottle = {
	keywords: [
		"moisturizer",
		"sunscreen"
	],
	char: "🧴",
	fitzpatrick_scale: false,
	category: "objects"
};
var key = {
	keywords: [
		"lock",
		"door",
		"password"
	],
	char: "🔑",
	fitzpatrick_scale: false,
	category: "objects"
};
var old_key = {
	keywords: [
		"lock",
		"door",
		"password"
	],
	char: "🗝",
	fitzpatrick_scale: false,
	category: "objects"
};
var couch_and_lamp = {
	keywords: [
		"read",
		"chill"
	],
	char: "🛋",
	fitzpatrick_scale: false,
	category: "objects"
};
var sleeping_bed = {
	keywords: [
		"bed",
		"rest"
	],
	char: "🛌",
	fitzpatrick_scale: true,
	category: "objects"
};
var bed = {
	keywords: [
		"sleep",
		"rest"
	],
	char: "🛏",
	fitzpatrick_scale: false,
	category: "objects"
};
var door = {
	keywords: [
		"house",
		"entry",
		"exit"
	],
	char: "🚪",
	fitzpatrick_scale: false,
	category: "objects"
};
var bellhop_bell = {
	keywords: [
		"service"
	],
	char: "🛎",
	fitzpatrick_scale: false,
	category: "objects"
};
var teddy_bear = {
	keywords: [
		"plush",
		"stuffed"
	],
	char: "🧸",
	fitzpatrick_scale: false,
	category: "objects"
};
var framed_picture = {
	keywords: [
		"photography"
	],
	char: "🖼",
	fitzpatrick_scale: false,
	category: "objects"
};
var world_map = {
	keywords: [
		"location",
		"direction"
	],
	char: "🗺",
	fitzpatrick_scale: false,
	category: "objects"
};
var parasol_on_ground = {
	keywords: [
		"weather",
		"summer"
	],
	char: "⛱",
	fitzpatrick_scale: false,
	category: "objects"
};
var moyai = {
	keywords: [
		"rock",
		"easter island",
		"moai"
	],
	char: "🗿",
	fitzpatrick_scale: false,
	category: "objects"
};
var shopping = {
	keywords: [
		"mall",
		"buy",
		"purchase"
	],
	char: "🛍",
	fitzpatrick_scale: false,
	category: "objects"
};
var shopping_cart = {
	keywords: [
		"trolley"
	],
	char: "🛒",
	fitzpatrick_scale: false,
	category: "objects"
};
var balloon = {
	keywords: [
		"party",
		"celebration",
		"birthday",
		"circus"
	],
	char: "🎈",
	fitzpatrick_scale: false,
	category: "objects"
};
var flags = {
	keywords: [
		"fish",
		"japanese",
		"koinobori",
		"carp",
		"banner"
	],
	char: "🎏",
	fitzpatrick_scale: false,
	category: "objects"
};
var ribbon = {
	keywords: [
		"decoration",
		"pink",
		"girl",
		"bowtie"
	],
	char: "🎀",
	fitzpatrick_scale: false,
	category: "objects"
};
var gift = {
	keywords: [
		"present",
		"birthday",
		"christmas",
		"xmas"
	],
	char: "🎁",
	fitzpatrick_scale: false,
	category: "objects"
};
var confetti_ball = {
	keywords: [
		"festival",
		"party",
		"birthday",
		"circus"
	],
	char: "🎊",
	fitzpatrick_scale: false,
	category: "objects"
};
var tada = {
	keywords: [
		"party",
		"congratulations",
		"birthday",
		"magic",
		"circus",
		"celebration"
	],
	char: "🎉",
	fitzpatrick_scale: false,
	category: "objects"
};
var dolls = {
	keywords: [
		"japanese",
		"toy",
		"kimono"
	],
	char: "🎎",
	fitzpatrick_scale: false,
	category: "objects"
};
var wind_chime = {
	keywords: [
		"nature",
		"ding",
		"spring",
		"bell"
	],
	char: "🎐",
	fitzpatrick_scale: false,
	category: "objects"
};
var crossed_flags = {
	keywords: [
		"japanese",
		"nation",
		"country",
		"border"
	],
	char: "🎌",
	fitzpatrick_scale: false,
	category: "objects"
};
var izakaya_lantern = {
	keywords: [
		"light",
		"paper",
		"halloween",
		"spooky"
	],
	char: "🏮",
	fitzpatrick_scale: false,
	category: "objects"
};
var red_envelope = {
	keywords: [
		"gift"
	],
	char: "🧧",
	fitzpatrick_scale: false,
	category: "objects"
};
var email = {
	keywords: [
		"letter",
		"postal",
		"inbox",
		"communication"
	],
	char: "✉️",
	fitzpatrick_scale: false,
	category: "objects"
};
var envelope_with_arrow = {
	keywords: [
		"email",
		"communication"
	],
	char: "📩",
	fitzpatrick_scale: false,
	category: "objects"
};
var incoming_envelope = {
	keywords: [
		"email",
		"inbox"
	],
	char: "📨",
	fitzpatrick_scale: false,
	category: "objects"
};
var love_letter = {
	keywords: [
		"email",
		"like",
		"affection",
		"envelope",
		"valentines"
	],
	char: "💌",
	fitzpatrick_scale: false,
	category: "objects"
};
var postbox = {
	keywords: [
		"email",
		"letter",
		"envelope"
	],
	char: "📮",
	fitzpatrick_scale: false,
	category: "objects"
};
var mailbox_closed = {
	keywords: [
		"email",
		"communication",
		"inbox"
	],
	char: "📪",
	fitzpatrick_scale: false,
	category: "objects"
};
var mailbox = {
	keywords: [
		"email",
		"inbox",
		"communication"
	],
	char: "📫",
	fitzpatrick_scale: false,
	category: "objects"
};
var mailbox_with_mail = {
	keywords: [
		"email",
		"inbox",
		"communication"
	],
	char: "📬",
	fitzpatrick_scale: false,
	category: "objects"
};
var mailbox_with_no_mail = {
	keywords: [
		"email",
		"inbox"
	],
	char: "📭",
	fitzpatrick_scale: false,
	category: "objects"
};
var postal_horn = {
	keywords: [
		"instrument",
		"music"
	],
	char: "📯",
	fitzpatrick_scale: false,
	category: "objects"
};
var inbox_tray = {
	keywords: [
		"email",
		"documents"
	],
	char: "📥",
	fitzpatrick_scale: false,
	category: "objects"
};
var outbox_tray = {
	keywords: [
		"inbox",
		"email"
	],
	char: "📤",
	fitzpatrick_scale: false,
	category: "objects"
};
var scroll = {
	keywords: [
		"documents",
		"ancient",
		"history",
		"paper"
	],
	char: "📜",
	fitzpatrick_scale: false,
	category: "objects"
};
var page_with_curl = {
	keywords: [
		"documents",
		"office",
		"paper"
	],
	char: "📃",
	fitzpatrick_scale: false,
	category: "objects"
};
var bookmark_tabs = {
	keywords: [
		"favorite",
		"save",
		"order",
		"tidy"
	],
	char: "📑",
	fitzpatrick_scale: false,
	category: "objects"
};
var receipt = {
	keywords: [
		"accounting",
		"expenses"
	],
	char: "🧾",
	fitzpatrick_scale: false,
	category: "objects"
};
var bar_chart = {
	keywords: [
		"graph",
		"presentation",
		"stats"
	],
	char: "📊",
	fitzpatrick_scale: false,
	category: "objects"
};
var chart_with_upwards_trend = {
	keywords: [
		"graph",
		"presentation",
		"stats",
		"recovery",
		"business",
		"economics",
		"money",
		"sales",
		"good",
		"success"
	],
	char: "📈",
	fitzpatrick_scale: false,
	category: "objects"
};
var chart_with_downwards_trend = {
	keywords: [
		"graph",
		"presentation",
		"stats",
		"recession",
		"business",
		"economics",
		"money",
		"sales",
		"bad",
		"failure"
	],
	char: "📉",
	fitzpatrick_scale: false,
	category: "objects"
};
var page_facing_up = {
	keywords: [
		"documents",
		"office",
		"paper",
		"information"
	],
	char: "📄",
	fitzpatrick_scale: false,
	category: "objects"
};
var date = {
	keywords: [
		"calendar",
		"schedule"
	],
	char: "📅",
	fitzpatrick_scale: false,
	category: "objects"
};
var calendar = {
	keywords: [
		"schedule",
		"date",
		"planning"
	],
	char: "📆",
	fitzpatrick_scale: false,
	category: "objects"
};
var spiral_calendar = {
	keywords: [
		"date",
		"schedule",
		"planning"
	],
	char: "🗓",
	fitzpatrick_scale: false,
	category: "objects"
};
var card_index = {
	keywords: [
		"business",
		"stationery"
	],
	char: "📇",
	fitzpatrick_scale: false,
	category: "objects"
};
var card_file_box = {
	keywords: [
		"business",
		"stationery"
	],
	char: "🗃",
	fitzpatrick_scale: false,
	category: "objects"
};
var ballot_box = {
	keywords: [
		"election",
		"vote"
	],
	char: "🗳",
	fitzpatrick_scale: false,
	category: "objects"
};
var file_cabinet = {
	keywords: [
		"filing",
		"organizing"
	],
	char: "🗄",
	fitzpatrick_scale: false,
	category: "objects"
};
var clipboard$1 = {
	keywords: [
		"stationery",
		"documents"
	],
	char: "📋",
	fitzpatrick_scale: false,
	category: "objects"
};
var spiral_notepad = {
	keywords: [
		"memo",
		"stationery"
	],
	char: "🗒",
	fitzpatrick_scale: false,
	category: "objects"
};
var file_folder = {
	keywords: [
		"documents",
		"business",
		"office"
	],
	char: "📁",
	fitzpatrick_scale: false,
	category: "objects"
};
var open_file_folder = {
	keywords: [
		"documents",
		"load"
	],
	char: "📂",
	fitzpatrick_scale: false,
	category: "objects"
};
var card_index_dividers = {
	keywords: [
		"organizing",
		"business",
		"stationery"
	],
	char: "🗂",
	fitzpatrick_scale: false,
	category: "objects"
};
var newspaper_roll = {
	keywords: [
		"press",
		"headline"
	],
	char: "🗞",
	fitzpatrick_scale: false,
	category: "objects"
};
var newspaper = {
	keywords: [
		"press",
		"headline"
	],
	char: "📰",
	fitzpatrick_scale: false,
	category: "objects"
};
var notebook = {
	keywords: [
		"stationery",
		"record",
		"notes",
		"paper",
		"study"
	],
	char: "📓",
	fitzpatrick_scale: false,
	category: "objects"
};
var closed_book = {
	keywords: [
		"read",
		"library",
		"knowledge",
		"textbook",
		"learn"
	],
	char: "📕",
	fitzpatrick_scale: false,
	category: "objects"
};
var green_book = {
	keywords: [
		"read",
		"library",
		"knowledge",
		"study"
	],
	char: "📗",
	fitzpatrick_scale: false,
	category: "objects"
};
var blue_book = {
	keywords: [
		"read",
		"library",
		"knowledge",
		"learn",
		"study"
	],
	char: "📘",
	fitzpatrick_scale: false,
	category: "objects"
};
var orange_book = {
	keywords: [
		"read",
		"library",
		"knowledge",
		"textbook",
		"study"
	],
	char: "📙",
	fitzpatrick_scale: false,
	category: "objects"
};
var notebook_with_decorative_cover = {
	keywords: [
		"classroom",
		"notes",
		"record",
		"paper",
		"study"
	],
	char: "📔",
	fitzpatrick_scale: false,
	category: "objects"
};
var ledger = {
	keywords: [
		"notes",
		"paper"
	],
	char: "📒",
	fitzpatrick_scale: false,
	category: "objects"
};
var books = {
	keywords: [
		"literature",
		"library",
		"study"
	],
	char: "📚",
	fitzpatrick_scale: false,
	category: "objects"
};
var open_book = {
	keywords: [
		"book",
		"read",
		"library",
		"knowledge",
		"literature",
		"learn",
		"study"
	],
	char: "📖",
	fitzpatrick_scale: false,
	category: "objects"
};
var safety_pin = {
	keywords: [
		"diaper"
	],
	char: "🧷",
	fitzpatrick_scale: false,
	category: "objects"
};
var link$2 = {
	keywords: [
		"rings",
		"url"
	],
	char: "🔗",
	fitzpatrick_scale: false,
	category: "objects"
};
var paperclip = {
	keywords: [
		"documents",
		"stationery"
	],
	char: "📎",
	fitzpatrick_scale: false,
	category: "objects"
};
var paperclips = {
	keywords: [
		"documents",
		"stationery"
	],
	char: "🖇",
	fitzpatrick_scale: false,
	category: "objects"
};
var scissors = {
	keywords: [
		"stationery",
		"cut"
	],
	char: "✂️",
	fitzpatrick_scale: false,
	category: "objects"
};
var triangular_ruler = {
	keywords: [
		"stationery",
		"math",
		"architect",
		"sketch"
	],
	char: "📐",
	fitzpatrick_scale: false,
	category: "objects"
};
var straight_ruler = {
	keywords: [
		"stationery",
		"calculate",
		"length",
		"math",
		"school",
		"drawing",
		"architect",
		"sketch"
	],
	char: "📏",
	fitzpatrick_scale: false,
	category: "objects"
};
var abacus = {
	keywords: [
		"calculation"
	],
	char: "🧮",
	fitzpatrick_scale: false,
	category: "objects"
};
var pushpin = {
	keywords: [
		"stationery",
		"mark",
		"here"
	],
	char: "📌",
	fitzpatrick_scale: false,
	category: "objects"
};
var round_pushpin = {
	keywords: [
		"stationery",
		"location",
		"map",
		"here"
	],
	char: "📍",
	fitzpatrick_scale: false,
	category: "objects"
};
var triangular_flag_on_post = {
	keywords: [
		"mark",
		"milestone",
		"place"
	],
	char: "🚩",
	fitzpatrick_scale: false,
	category: "objects"
};
var white_flag = {
	keywords: [
		"losing",
		"loser",
		"lost",
		"surrender",
		"give up",
		"fail"
	],
	char: "🏳",
	fitzpatrick_scale: false,
	category: "objects"
};
var black_flag = {
	keywords: [
		"pirate"
	],
	char: "🏴",
	fitzpatrick_scale: false,
	category: "objects"
};
var rainbow_flag = {
	keywords: [
		"flag",
		"rainbow",
		"pride",
		"gay",
		"lgbt",
		"glbt",
		"queer",
		"homosexual",
		"lesbian",
		"bisexual",
		"transgender"
	],
	char: "🏳️‍🌈",
	fitzpatrick_scale: false,
	category: "objects"
};
var closed_lock_with_key = {
	keywords: [
		"security",
		"privacy"
	],
	char: "🔐",
	fitzpatrick_scale: false,
	category: "objects"
};
var lock = {
	keywords: [
		"security",
		"password",
		"padlock"
	],
	char: "🔒",
	fitzpatrick_scale: false,
	category: "objects"
};
var unlock = {
	keywords: [
		"privacy",
		"security"
	],
	char: "🔓",
	fitzpatrick_scale: false,
	category: "objects"
};
var lock_with_ink_pen = {
	keywords: [
		"security",
		"secret"
	],
	char: "🔏",
	fitzpatrick_scale: false,
	category: "objects"
};
var pen = {
	keywords: [
		"stationery",
		"writing",
		"write"
	],
	char: "🖊",
	fitzpatrick_scale: false,
	category: "objects"
};
var fountain_pen = {
	keywords: [
		"stationery",
		"writing",
		"write"
	],
	char: "🖋",
	fitzpatrick_scale: false,
	category: "objects"
};
var black_nib = {
	keywords: [
		"pen",
		"stationery",
		"writing",
		"write"
	],
	char: "✒️",
	fitzpatrick_scale: false,
	category: "objects"
};
var memo = {
	keywords: [
		"write",
		"documents",
		"stationery",
		"pencil",
		"paper",
		"writing",
		"legal",
		"exam",
		"quiz",
		"test",
		"study",
		"compose"
	],
	char: "📝",
	fitzpatrick_scale: false,
	category: "objects"
};
var pencil2 = {
	keywords: [
		"stationery",
		"write",
		"paper",
		"writing",
		"school",
		"study"
	],
	char: "✏️",
	fitzpatrick_scale: false,
	category: "objects"
};
var crayon = {
	keywords: [
		"drawing",
		"creativity"
	],
	char: "🖍",
	fitzpatrick_scale: false,
	category: "objects"
};
var paintbrush = {
	keywords: [
		"drawing",
		"creativity",
		"art"
	],
	char: "🖌",
	fitzpatrick_scale: false,
	category: "objects"
};
var mag = {
	keywords: [
		"search",
		"zoom",
		"find",
		"detective"
	],
	char: "🔍",
	fitzpatrick_scale: false,
	category: "objects"
};
var mag_right = {
	keywords: [
		"search",
		"zoom",
		"find",
		"detective"
	],
	char: "🔎",
	fitzpatrick_scale: false,
	category: "objects"
};
var heart = {
	keywords: [
		"love",
		"like",
		"valentines"
	],
	char: "❤️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var orange_heart = {
	keywords: [
		"love",
		"like",
		"affection",
		"valentines"
	],
	char: "🧡",
	fitzpatrick_scale: false,
	category: "symbols"
};
var yellow_heart = {
	keywords: [
		"love",
		"like",
		"affection",
		"valentines"
	],
	char: "💛",
	fitzpatrick_scale: false,
	category: "symbols"
};
var green_heart = {
	keywords: [
		"love",
		"like",
		"affection",
		"valentines"
	],
	char: "💚",
	fitzpatrick_scale: false,
	category: "symbols"
};
var blue_heart = {
	keywords: [
		"love",
		"like",
		"affection",
		"valentines"
	],
	char: "💙",
	fitzpatrick_scale: false,
	category: "symbols"
};
var purple_heart = {
	keywords: [
		"love",
		"like",
		"affection",
		"valentines"
	],
	char: "💜",
	fitzpatrick_scale: false,
	category: "symbols"
};
var black_heart = {
	keywords: [
		"evil"
	],
	char: "🖤",
	fitzpatrick_scale: false,
	category: "symbols"
};
var broken_heart = {
	keywords: [
		"sad",
		"sorry",
		"break",
		"heart",
		"heartbreak"
	],
	char: "💔",
	fitzpatrick_scale: false,
	category: "symbols"
};
var heavy_heart_exclamation = {
	keywords: [
		"decoration",
		"love"
	],
	char: "❣",
	fitzpatrick_scale: false,
	category: "symbols"
};
var two_hearts = {
	keywords: [
		"love",
		"like",
		"affection",
		"valentines",
		"heart"
	],
	char: "💕",
	fitzpatrick_scale: false,
	category: "symbols"
};
var revolving_hearts = {
	keywords: [
		"love",
		"like",
		"affection",
		"valentines"
	],
	char: "💞",
	fitzpatrick_scale: false,
	category: "symbols"
};
var heartbeat = {
	keywords: [
		"love",
		"like",
		"affection",
		"valentines",
		"pink",
		"heart"
	],
	char: "💓",
	fitzpatrick_scale: false,
	category: "symbols"
};
var heartpulse = {
	keywords: [
		"like",
		"love",
		"affection",
		"valentines",
		"pink"
	],
	char: "💗",
	fitzpatrick_scale: false,
	category: "symbols"
};
var sparkling_heart = {
	keywords: [
		"love",
		"like",
		"affection",
		"valentines"
	],
	char: "💖",
	fitzpatrick_scale: false,
	category: "symbols"
};
var cupid = {
	keywords: [
		"love",
		"like",
		"heart",
		"affection",
		"valentines"
	],
	char: "💘",
	fitzpatrick_scale: false,
	category: "symbols"
};
var gift_heart = {
	keywords: [
		"love",
		"valentines"
	],
	char: "💝",
	fitzpatrick_scale: false,
	category: "symbols"
};
var heart_decoration = {
	keywords: [
		"purple-square",
		"love",
		"like"
	],
	char: "💟",
	fitzpatrick_scale: false,
	category: "symbols"
};
var peace_symbol = {
	keywords: [
		"hippie"
	],
	char: "☮",
	fitzpatrick_scale: false,
	category: "symbols"
};
var latin_cross = {
	keywords: [
		"christianity"
	],
	char: "✝",
	fitzpatrick_scale: false,
	category: "symbols"
};
var star_and_crescent = {
	keywords: [
		"islam"
	],
	char: "☪",
	fitzpatrick_scale: false,
	category: "symbols"
};
var om = {
	keywords: [
		"hinduism",
		"buddhism",
		"sikhism",
		"jainism"
	],
	char: "🕉",
	fitzpatrick_scale: false,
	category: "symbols"
};
var wheel_of_dharma = {
	keywords: [
		"hinduism",
		"buddhism",
		"sikhism",
		"jainism"
	],
	char: "☸",
	fitzpatrick_scale: false,
	category: "symbols"
};
var star_of_david = {
	keywords: [
		"judaism"
	],
	char: "✡",
	fitzpatrick_scale: false,
	category: "symbols"
};
var six_pointed_star = {
	keywords: [
		"purple-square",
		"religion",
		"jewish",
		"hexagram"
	],
	char: "🔯",
	fitzpatrick_scale: false,
	category: "symbols"
};
var menorah = {
	keywords: [
		"hanukkah",
		"candles",
		"jewish"
	],
	char: "🕎",
	fitzpatrick_scale: false,
	category: "symbols"
};
var yin_yang = {
	keywords: [
		"balance"
	],
	char: "☯",
	fitzpatrick_scale: false,
	category: "symbols"
};
var orthodox_cross = {
	keywords: [
		"suppedaneum",
		"religion"
	],
	char: "☦",
	fitzpatrick_scale: false,
	category: "symbols"
};
var place_of_worship = {
	keywords: [
		"religion",
		"church",
		"temple",
		"prayer"
	],
	char: "🛐",
	fitzpatrick_scale: false,
	category: "symbols"
};
var ophiuchus = {
	keywords: [
		"sign",
		"purple-square",
		"constellation",
		"astrology"
	],
	char: "⛎",
	fitzpatrick_scale: false,
	category: "symbols"
};
var aries = {
	keywords: [
		"sign",
		"purple-square",
		"zodiac",
		"astrology"
	],
	char: "♈",
	fitzpatrick_scale: false,
	category: "symbols"
};
var taurus = {
	keywords: [
		"purple-square",
		"sign",
		"zodiac",
		"astrology"
	],
	char: "♉",
	fitzpatrick_scale: false,
	category: "symbols"
};
var gemini = {
	keywords: [
		"sign",
		"zodiac",
		"purple-square",
		"astrology"
	],
	char: "♊",
	fitzpatrick_scale: false,
	category: "symbols"
};
var cancer = {
	keywords: [
		"sign",
		"zodiac",
		"purple-square",
		"astrology"
	],
	char: "♋",
	fitzpatrick_scale: false,
	category: "symbols"
};
var leo = {
	keywords: [
		"sign",
		"purple-square",
		"zodiac",
		"astrology"
	],
	char: "♌",
	fitzpatrick_scale: false,
	category: "symbols"
};
var virgo = {
	keywords: [
		"sign",
		"zodiac",
		"purple-square",
		"astrology"
	],
	char: "♍",
	fitzpatrick_scale: false,
	category: "symbols"
};
var libra = {
	keywords: [
		"sign",
		"purple-square",
		"zodiac",
		"astrology"
	],
	char: "♎",
	fitzpatrick_scale: false,
	category: "symbols"
};
var scorpius = {
	keywords: [
		"sign",
		"zodiac",
		"purple-square",
		"astrology",
		"scorpio"
	],
	char: "♏",
	fitzpatrick_scale: false,
	category: "symbols"
};
var sagittarius = {
	keywords: [
		"sign",
		"zodiac",
		"purple-square",
		"astrology"
	],
	char: "♐",
	fitzpatrick_scale: false,
	category: "symbols"
};
var capricorn = {
	keywords: [
		"sign",
		"zodiac",
		"purple-square",
		"astrology"
	],
	char: "♑",
	fitzpatrick_scale: false,
	category: "symbols"
};
var aquarius = {
	keywords: [
		"sign",
		"purple-square",
		"zodiac",
		"astrology"
	],
	char: "♒",
	fitzpatrick_scale: false,
	category: "symbols"
};
var pisces = {
	keywords: [
		"purple-square",
		"sign",
		"zodiac",
		"astrology"
	],
	char: "♓",
	fitzpatrick_scale: false,
	category: "symbols"
};
var id = {
	keywords: [
		"purple-square",
		"words"
	],
	char: "🆔",
	fitzpatrick_scale: false,
	category: "symbols"
};
var atom_symbol = {
	keywords: [
		"science",
		"physics",
		"chemistry"
	],
	char: "⚛",
	fitzpatrick_scale: false,
	category: "symbols"
};
var u7a7a = {
	keywords: [
		"kanji",
		"japanese",
		"chinese",
		"empty",
		"sky",
		"blue-square"
	],
	char: "🈳",
	fitzpatrick_scale: false,
	category: "symbols"
};
var u5272 = {
	keywords: [
		"cut",
		"divide",
		"chinese",
		"kanji",
		"pink-square"
	],
	char: "🈹",
	fitzpatrick_scale: false,
	category: "symbols"
};
var radioactive = {
	keywords: [
		"nuclear",
		"danger"
	],
	char: "☢",
	fitzpatrick_scale: false,
	category: "symbols"
};
var biohazard = {
	keywords: [
		"danger"
	],
	char: "☣",
	fitzpatrick_scale: false,
	category: "symbols"
};
var mobile_phone_off = {
	keywords: [
		"mute",
		"orange-square",
		"silence",
		"quiet"
	],
	char: "📴",
	fitzpatrick_scale: false,
	category: "symbols"
};
var vibration_mode = {
	keywords: [
		"orange-square",
		"phone"
	],
	char: "📳",
	fitzpatrick_scale: false,
	category: "symbols"
};
var u6709 = {
	keywords: [
		"orange-square",
		"chinese",
		"have",
		"kanji"
	],
	char: "🈶",
	fitzpatrick_scale: false,
	category: "symbols"
};
var u7121 = {
	keywords: [
		"nothing",
		"chinese",
		"kanji",
		"japanese",
		"orange-square"
	],
	char: "🈚",
	fitzpatrick_scale: false,
	category: "symbols"
};
var u7533 = {
	keywords: [
		"chinese",
		"japanese",
		"kanji",
		"orange-square"
	],
	char: "🈸",
	fitzpatrick_scale: false,
	category: "symbols"
};
var u55b6 = {
	keywords: [
		"japanese",
		"opening hours",
		"orange-square"
	],
	char: "🈺",
	fitzpatrick_scale: false,
	category: "symbols"
};
var u6708 = {
	keywords: [
		"chinese",
		"month",
		"moon",
		"japanese",
		"orange-square",
		"kanji"
	],
	char: "🈷️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var eight_pointed_black_star = {
	keywords: [
		"orange-square",
		"shape",
		"polygon"
	],
	char: "✴️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var vs = {
	keywords: [
		"words",
		"orange-square"
	],
	char: "🆚",
	fitzpatrick_scale: false,
	category: "symbols"
};
var accept = {
	keywords: [
		"ok",
		"good",
		"chinese",
		"kanji",
		"agree",
		"yes",
		"orange-circle"
	],
	char: "🉑",
	fitzpatrick_scale: false,
	category: "symbols"
};
var white_flower = {
	keywords: [
		"japanese",
		"spring"
	],
	char: "💮",
	fitzpatrick_scale: false,
	category: "symbols"
};
var ideograph_advantage = {
	keywords: [
		"chinese",
		"kanji",
		"obtain",
		"get",
		"circle"
	],
	char: "🉐",
	fitzpatrick_scale: false,
	category: "symbols"
};
var secret = {
	keywords: [
		"privacy",
		"chinese",
		"sshh",
		"kanji",
		"red-circle"
	],
	char: "㊙️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var congratulations = {
	keywords: [
		"chinese",
		"kanji",
		"japanese",
		"red-circle"
	],
	char: "㊗️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var u5408 = {
	keywords: [
		"japanese",
		"chinese",
		"join",
		"kanji",
		"red-square"
	],
	char: "🈴",
	fitzpatrick_scale: false,
	category: "symbols"
};
var u6e80 = {
	keywords: [
		"full",
		"chinese",
		"japanese",
		"red-square",
		"kanji"
	],
	char: "🈵",
	fitzpatrick_scale: false,
	category: "symbols"
};
var u7981 = {
	keywords: [
		"kanji",
		"japanese",
		"chinese",
		"forbidden",
		"limit",
		"restricted",
		"red-square"
	],
	char: "🈲",
	fitzpatrick_scale: false,
	category: "symbols"
};
var a$1 = {
	keywords: [
		"red-square",
		"alphabet",
		"letter"
	],
	char: "🅰️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var b = {
	keywords: [
		"red-square",
		"alphabet",
		"letter"
	],
	char: "🅱️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var ab = {
	keywords: [
		"red-square",
		"alphabet"
	],
	char: "🆎",
	fitzpatrick_scale: false,
	category: "symbols"
};
var cl = {
	keywords: [
		"alphabet",
		"words",
		"red-square"
	],
	char: "🆑",
	fitzpatrick_scale: false,
	category: "symbols"
};
var o2 = {
	keywords: [
		"alphabet",
		"red-square",
		"letter"
	],
	char: "🅾️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var sos = {
	keywords: [
		"help",
		"red-square",
		"words",
		"emergency",
		"911"
	],
	char: "🆘",
	fitzpatrick_scale: false,
	category: "symbols"
};
var no_entry = {
	keywords: [
		"limit",
		"security",
		"privacy",
		"bad",
		"denied",
		"stop",
		"circle"
	],
	char: "⛔",
	fitzpatrick_scale: false,
	category: "symbols"
};
var name_badge = {
	keywords: [
		"fire",
		"forbid"
	],
	char: "📛",
	fitzpatrick_scale: false,
	category: "symbols"
};
var no_entry_sign = {
	keywords: [
		"forbid",
		"stop",
		"limit",
		"denied",
		"disallow",
		"circle"
	],
	char: "🚫",
	fitzpatrick_scale: false,
	category: "symbols"
};
var x = {
	keywords: [
		"no",
		"delete",
		"remove",
		"cancel",
		"red"
	],
	char: "❌",
	fitzpatrick_scale: false,
	category: "symbols"
};
var o$1 = {
	keywords: [
		"circle",
		"round"
	],
	char: "⭕",
	fitzpatrick_scale: false,
	category: "symbols"
};
var stop_sign = {
	keywords: [
		"stop"
	],
	char: "🛑",
	fitzpatrick_scale: false,
	category: "symbols"
};
var anger = {
	keywords: [
		"angry",
		"mad"
	],
	char: "💢",
	fitzpatrick_scale: false,
	category: "symbols"
};
var hotsprings = {
	keywords: [
		"bath",
		"warm",
		"relax"
	],
	char: "♨️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var no_pedestrians = {
	keywords: [
		"rules",
		"crossing",
		"walking",
		"circle"
	],
	char: "🚷",
	fitzpatrick_scale: false,
	category: "symbols"
};
var do_not_litter = {
	keywords: [
		"trash",
		"bin",
		"garbage",
		"circle"
	],
	char: "🚯",
	fitzpatrick_scale: false,
	category: "symbols"
};
var no_bicycles = {
	keywords: [
		"cyclist",
		"prohibited",
		"circle"
	],
	char: "🚳",
	fitzpatrick_scale: false,
	category: "symbols"
};
var underage = {
	keywords: [
		"18",
		"drink",
		"pub",
		"night",
		"minor",
		"circle"
	],
	char: "🔞",
	fitzpatrick_scale: false,
	category: "symbols"
};
var no_mobile_phones = {
	keywords: [
		"iphone",
		"mute",
		"circle"
	],
	char: "📵",
	fitzpatrick_scale: false,
	category: "symbols"
};
var exclamation = {
	keywords: [
		"heavy_exclamation_mark",
		"danger",
		"surprise",
		"punctuation",
		"wow",
		"warning"
	],
	char: "❗",
	fitzpatrick_scale: false,
	category: "symbols"
};
var grey_exclamation = {
	keywords: [
		"surprise",
		"punctuation",
		"gray",
		"wow",
		"warning"
	],
	char: "❕",
	fitzpatrick_scale: false,
	category: "symbols"
};
var question = {
	keywords: [
		"doubt",
		"confused"
	],
	char: "❓",
	fitzpatrick_scale: false,
	category: "symbols"
};
var grey_question = {
	keywords: [
		"doubts",
		"gray",
		"huh",
		"confused"
	],
	char: "❔",
	fitzpatrick_scale: false,
	category: "symbols"
};
var bangbang = {
	keywords: [
		"exclamation",
		"surprise"
	],
	char: "‼️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var interrobang = {
	keywords: [
		"wat",
		"punctuation",
		"surprise"
	],
	char: "⁉️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var low_brightness = {
	keywords: [
		"sun",
		"afternoon",
		"warm",
		"summer"
	],
	char: "🔅",
	fitzpatrick_scale: false,
	category: "symbols"
};
var high_brightness = {
	keywords: [
		"sun",
		"light"
	],
	char: "🔆",
	fitzpatrick_scale: false,
	category: "symbols"
};
var trident = {
	keywords: [
		"weapon",
		"spear"
	],
	char: "🔱",
	fitzpatrick_scale: false,
	category: "symbols"
};
var fleur_de_lis = {
	keywords: [
		"decorative",
		"scout"
	],
	char: "⚜",
	fitzpatrick_scale: false,
	category: "symbols"
};
var part_alternation_mark = {
	keywords: [
		"graph",
		"presentation",
		"stats",
		"business",
		"economics",
		"bad"
	],
	char: "〽️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var warning = {
	keywords: [
		"exclamation",
		"wip",
		"alert",
		"error",
		"problem",
		"issue"
	],
	char: "⚠️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var children_crossing = {
	keywords: [
		"school",
		"warning",
		"danger",
		"sign",
		"driving",
		"yellow-diamond"
	],
	char: "🚸",
	fitzpatrick_scale: false,
	category: "symbols"
};
var beginner = {
	keywords: [
		"badge",
		"shield"
	],
	char: "🔰",
	fitzpatrick_scale: false,
	category: "symbols"
};
var recycle = {
	keywords: [
		"arrow",
		"environment",
		"garbage",
		"trash"
	],
	char: "♻️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var u6307 = {
	keywords: [
		"chinese",
		"point",
		"green-square",
		"kanji"
	],
	char: "🈯",
	fitzpatrick_scale: false,
	category: "symbols"
};
var chart = {
	keywords: [
		"green-square",
		"graph",
		"presentation",
		"stats"
	],
	char: "💹",
	fitzpatrick_scale: false,
	category: "symbols"
};
var sparkle = {
	keywords: [
		"stars",
		"green-square",
		"awesome",
		"good",
		"fireworks"
	],
	char: "❇️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var eight_spoked_asterisk = {
	keywords: [
		"star",
		"sparkle",
		"green-square"
	],
	char: "✳️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var negative_squared_cross_mark = {
	keywords: [
		"x",
		"green-square",
		"no",
		"deny"
	],
	char: "❎",
	fitzpatrick_scale: false,
	category: "symbols"
};
var white_check_mark = {
	keywords: [
		"green-square",
		"ok",
		"agree",
		"vote",
		"election",
		"answer",
		"tick"
	],
	char: "✅",
	fitzpatrick_scale: false,
	category: "symbols"
};
var diamond_shape_with_a_dot_inside = {
	keywords: [
		"jewel",
		"blue",
		"gem",
		"crystal",
		"fancy"
	],
	char: "💠",
	fitzpatrick_scale: false,
	category: "symbols"
};
var cyclone = {
	keywords: [
		"weather",
		"swirl",
		"blue",
		"cloud",
		"vortex",
		"spiral",
		"whirlpool",
		"spin",
		"tornado",
		"hurricane",
		"typhoon"
	],
	char: "🌀",
	fitzpatrick_scale: false,
	category: "symbols"
};
var loop = {
	keywords: [
		"tape",
		"cassette"
	],
	char: "➿",
	fitzpatrick_scale: false,
	category: "symbols"
};
var globe_with_meridians = {
	keywords: [
		"earth",
		"international",
		"world",
		"internet",
		"interweb",
		"i18n"
	],
	char: "🌐",
	fitzpatrick_scale: false,
	category: "symbols"
};
var m = {
	keywords: [
		"alphabet",
		"blue-circle",
		"letter"
	],
	char: "Ⓜ️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var atm = {
	keywords: [
		"money",
		"sales",
		"cash",
		"blue-square",
		"payment",
		"bank"
	],
	char: "🏧",
	fitzpatrick_scale: false,
	category: "symbols"
};
var sa = {
	keywords: [
		"japanese",
		"blue-square",
		"katakana"
	],
	char: "🈂️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var passport_control = {
	keywords: [
		"custom",
		"blue-square"
	],
	char: "🛂",
	fitzpatrick_scale: false,
	category: "symbols"
};
var customs = {
	keywords: [
		"passport",
		"border",
		"blue-square"
	],
	char: "🛃",
	fitzpatrick_scale: false,
	category: "symbols"
};
var baggage_claim = {
	keywords: [
		"blue-square",
		"airport",
		"transport"
	],
	char: "🛄",
	fitzpatrick_scale: false,
	category: "symbols"
};
var left_luggage = {
	keywords: [
		"blue-square",
		"travel"
	],
	char: "🛅",
	fitzpatrick_scale: false,
	category: "symbols"
};
var wheelchair = {
	keywords: [
		"blue-square",
		"disabled",
		"a11y",
		"accessibility"
	],
	char: "♿",
	fitzpatrick_scale: false,
	category: "symbols"
};
var no_smoking = {
	keywords: [
		"cigarette",
		"blue-square",
		"smell",
		"smoke"
	],
	char: "🚭",
	fitzpatrick_scale: false,
	category: "symbols"
};
var wc = {
	keywords: [
		"toilet",
		"restroom",
		"blue-square"
	],
	char: "🚾",
	fitzpatrick_scale: false,
	category: "symbols"
};
var parking = {
	keywords: [
		"cars",
		"blue-square",
		"alphabet",
		"letter"
	],
	char: "🅿️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var potable_water = {
	keywords: [
		"blue-square",
		"liquid",
		"restroom",
		"cleaning",
		"faucet"
	],
	char: "🚰",
	fitzpatrick_scale: false,
	category: "symbols"
};
var mens = {
	keywords: [
		"toilet",
		"restroom",
		"wc",
		"blue-square",
		"gender",
		"male"
	],
	char: "🚹",
	fitzpatrick_scale: false,
	category: "symbols"
};
var womens = {
	keywords: [
		"purple-square",
		"woman",
		"female",
		"toilet",
		"loo",
		"restroom",
		"gender"
	],
	char: "🚺",
	fitzpatrick_scale: false,
	category: "symbols"
};
var baby_symbol = {
	keywords: [
		"orange-square",
		"child"
	],
	char: "🚼",
	fitzpatrick_scale: false,
	category: "symbols"
};
var restroom = {
	keywords: [
		"blue-square",
		"toilet",
		"refresh",
		"wc",
		"gender"
	],
	char: "🚻",
	fitzpatrick_scale: false,
	category: "symbols"
};
var put_litter_in_its_place = {
	keywords: [
		"blue-square",
		"sign",
		"human",
		"info"
	],
	char: "🚮",
	fitzpatrick_scale: false,
	category: "symbols"
};
var cinema = {
	keywords: [
		"blue-square",
		"record",
		"film",
		"movie",
		"curtain",
		"stage",
		"theater"
	],
	char: "🎦",
	fitzpatrick_scale: false,
	category: "symbols"
};
var signal_strength = {
	keywords: [
		"blue-square",
		"reception",
		"phone",
		"internet",
		"connection",
		"wifi",
		"bluetooth",
		"bars"
	],
	char: "📶",
	fitzpatrick_scale: false,
	category: "symbols"
};
var koko = {
	keywords: [
		"blue-square",
		"here",
		"katakana",
		"japanese",
		"destination"
	],
	char: "🈁",
	fitzpatrick_scale: false,
	category: "symbols"
};
var ng = {
	keywords: [
		"blue-square",
		"words",
		"shape",
		"icon"
	],
	char: "🆖",
	fitzpatrick_scale: false,
	category: "symbols"
};
var ok = {
	keywords: [
		"good",
		"agree",
		"yes",
		"blue-square"
	],
	char: "🆗",
	fitzpatrick_scale: false,
	category: "symbols"
};
var up = {
	keywords: [
		"blue-square",
		"above",
		"high"
	],
	char: "🆙",
	fitzpatrick_scale: false,
	category: "symbols"
};
var cool = {
	keywords: [
		"words",
		"blue-square"
	],
	char: "🆒",
	fitzpatrick_scale: false,
	category: "symbols"
};
var free = {
	keywords: [
		"blue-square",
		"words"
	],
	char: "🆓",
	fitzpatrick_scale: false,
	category: "symbols"
};
var zero$1 = {
	keywords: [
		"0",
		"numbers",
		"blue-square",
		"null"
	],
	char: "0️⃣",
	fitzpatrick_scale: false,
	category: "symbols"
};
var one = {
	keywords: [
		"blue-square",
		"numbers",
		"1"
	],
	char: "1️⃣",
	fitzpatrick_scale: false,
	category: "symbols"
};
var two = {
	keywords: [
		"numbers",
		"2",
		"prime",
		"blue-square"
	],
	char: "2️⃣",
	fitzpatrick_scale: false,
	category: "symbols"
};
var three = {
	keywords: [
		"3",
		"numbers",
		"prime",
		"blue-square"
	],
	char: "3️⃣",
	fitzpatrick_scale: false,
	category: "symbols"
};
var four = {
	keywords: [
		"4",
		"numbers",
		"blue-square"
	],
	char: "4️⃣",
	fitzpatrick_scale: false,
	category: "symbols"
};
var five = {
	keywords: [
		"5",
		"numbers",
		"blue-square",
		"prime"
	],
	char: "5️⃣",
	fitzpatrick_scale: false,
	category: "symbols"
};
var six = {
	keywords: [
		"6",
		"numbers",
		"blue-square"
	],
	char: "6️⃣",
	fitzpatrick_scale: false,
	category: "symbols"
};
var seven = {
	keywords: [
		"7",
		"numbers",
		"blue-square",
		"prime"
	],
	char: "7️⃣",
	fitzpatrick_scale: false,
	category: "symbols"
};
var eight = {
	keywords: [
		"8",
		"blue-square",
		"numbers"
	],
	char: "8️⃣",
	fitzpatrick_scale: false,
	category: "symbols"
};
var nine = {
	keywords: [
		"blue-square",
		"numbers",
		"9"
	],
	char: "9️⃣",
	fitzpatrick_scale: false,
	category: "symbols"
};
var keycap_ten = {
	keywords: [
		"numbers",
		"10",
		"blue-square"
	],
	char: "🔟",
	fitzpatrick_scale: false,
	category: "symbols"
};
var asterisk = {
	keywords: [
		"star",
		"keycap"
	],
	char: "*⃣",
	fitzpatrick_scale: false,
	category: "symbols"
};
var eject_button = {
	keywords: [
		"blue-square"
	],
	char: "⏏️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var arrow_forward = {
	keywords: [
		"blue-square",
		"right",
		"direction",
		"play"
	],
	char: "▶️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var pause_button = {
	keywords: [
		"pause",
		"blue-square"
	],
	char: "⏸",
	fitzpatrick_scale: false,
	category: "symbols"
};
var next_track_button = {
	keywords: [
		"forward",
		"next",
		"blue-square"
	],
	char: "⏭",
	fitzpatrick_scale: false,
	category: "symbols"
};
var stop_button = {
	keywords: [
		"blue-square"
	],
	char: "⏹",
	fitzpatrick_scale: false,
	category: "symbols"
};
var record_button = {
	keywords: [
		"blue-square"
	],
	char: "⏺",
	fitzpatrick_scale: false,
	category: "symbols"
};
var play_or_pause_button = {
	keywords: [
		"blue-square",
		"play",
		"pause"
	],
	char: "⏯",
	fitzpatrick_scale: false,
	category: "symbols"
};
var previous_track_button = {
	keywords: [
		"backward"
	],
	char: "⏮",
	fitzpatrick_scale: false,
	category: "symbols"
};
var fast_forward = {
	keywords: [
		"blue-square",
		"play",
		"speed",
		"continue"
	],
	char: "⏩",
	fitzpatrick_scale: false,
	category: "symbols"
};
var rewind = {
	keywords: [
		"play",
		"blue-square"
	],
	char: "⏪",
	fitzpatrick_scale: false,
	category: "symbols"
};
var twisted_rightwards_arrows = {
	keywords: [
		"blue-square",
		"shuffle",
		"music",
		"random"
	],
	char: "🔀",
	fitzpatrick_scale: false,
	category: "symbols"
};
var repeat = {
	keywords: [
		"loop",
		"record"
	],
	char: "🔁",
	fitzpatrick_scale: false,
	category: "symbols"
};
var repeat_one = {
	keywords: [
		"blue-square",
		"loop"
	],
	char: "🔂",
	fitzpatrick_scale: false,
	category: "symbols"
};
var arrow_backward = {
	keywords: [
		"blue-square",
		"left",
		"direction"
	],
	char: "◀️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var arrow_up_small = {
	keywords: [
		"blue-square",
		"triangle",
		"direction",
		"point",
		"forward",
		"top"
	],
	char: "🔼",
	fitzpatrick_scale: false,
	category: "symbols"
};
var arrow_down_small = {
	keywords: [
		"blue-square",
		"direction",
		"bottom"
	],
	char: "🔽",
	fitzpatrick_scale: false,
	category: "symbols"
};
var arrow_double_up = {
	keywords: [
		"blue-square",
		"direction",
		"top"
	],
	char: "⏫",
	fitzpatrick_scale: false,
	category: "symbols"
};
var arrow_double_down = {
	keywords: [
		"blue-square",
		"direction",
		"bottom"
	],
	char: "⏬",
	fitzpatrick_scale: false,
	category: "symbols"
};
var arrow_right = {
	keywords: [
		"blue-square",
		"next"
	],
	char: "➡️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var arrow_left = {
	keywords: [
		"blue-square",
		"previous",
		"back"
	],
	char: "⬅️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var arrow_up = {
	keywords: [
		"blue-square",
		"continue",
		"top",
		"direction"
	],
	char: "⬆️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var arrow_down = {
	keywords: [
		"blue-square",
		"direction",
		"bottom"
	],
	char: "⬇️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var arrow_upper_right = {
	keywords: [
		"blue-square",
		"point",
		"direction",
		"diagonal",
		"northeast"
	],
	char: "↗️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var arrow_lower_right = {
	keywords: [
		"blue-square",
		"direction",
		"diagonal",
		"southeast"
	],
	char: "↘️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var arrow_lower_left = {
	keywords: [
		"blue-square",
		"direction",
		"diagonal",
		"southwest"
	],
	char: "↙️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var arrow_upper_left = {
	keywords: [
		"blue-square",
		"point",
		"direction",
		"diagonal",
		"northwest"
	],
	char: "↖️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var arrow_up_down = {
	keywords: [
		"blue-square",
		"direction",
		"way",
		"vertical"
	],
	char: "↕️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var left_right_arrow = {
	keywords: [
		"shape",
		"direction",
		"horizontal",
		"sideways"
	],
	char: "↔️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var arrows_counterclockwise = {
	keywords: [
		"blue-square",
		"sync",
		"cycle"
	],
	char: "🔄",
	fitzpatrick_scale: false,
	category: "symbols"
};
var arrow_right_hook = {
	keywords: [
		"blue-square",
		"return",
		"rotate",
		"direction"
	],
	char: "↪️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var leftwards_arrow_with_hook = {
	keywords: [
		"back",
		"return",
		"blue-square",
		"undo",
		"enter"
	],
	char: "↩️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var arrow_heading_up = {
	keywords: [
		"blue-square",
		"direction",
		"top"
	],
	char: "⤴️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var arrow_heading_down = {
	keywords: [
		"blue-square",
		"direction",
		"bottom"
	],
	char: "⤵️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var hash = {
	keywords: [
		"symbol",
		"blue-square",
		"twitter"
	],
	char: "#️⃣",
	fitzpatrick_scale: false,
	category: "symbols"
};
var information_source = {
	keywords: [
		"blue-square",
		"alphabet",
		"letter"
	],
	char: "ℹ️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var abc = {
	keywords: [
		"blue-square",
		"alphabet"
	],
	char: "🔤",
	fitzpatrick_scale: false,
	category: "symbols"
};
var abcd = {
	keywords: [
		"blue-square",
		"alphabet"
	],
	char: "🔡",
	fitzpatrick_scale: false,
	category: "symbols"
};
var capital_abcd = {
	keywords: [
		"alphabet",
		"words",
		"blue-square"
	],
	char: "🔠",
	fitzpatrick_scale: false,
	category: "symbols"
};
var symbols = {
	keywords: [
		"blue-square",
		"music",
		"note",
		"ampersand",
		"percent",
		"glyphs",
		"characters"
	],
	char: "🔣",
	fitzpatrick_scale: false,
	category: "symbols"
};
var musical_note = {
	keywords: [
		"score",
		"tone",
		"sound"
	],
	char: "🎵",
	fitzpatrick_scale: false,
	category: "symbols"
};
var notes = {
	keywords: [
		"music",
		"score"
	],
	char: "🎶",
	fitzpatrick_scale: false,
	category: "symbols"
};
var wavy_dash = {
	keywords: [
		"draw",
		"line",
		"moustache",
		"mustache",
		"squiggle",
		"scribble"
	],
	char: "〰️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var curly_loop = {
	keywords: [
		"scribble",
		"draw",
		"shape",
		"squiggle"
	],
	char: "➰",
	fitzpatrick_scale: false,
	category: "symbols"
};
var heavy_check_mark = {
	keywords: [
		"ok",
		"nike",
		"answer",
		"yes",
		"tick"
	],
	char: "✔️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var arrows_clockwise = {
	keywords: [
		"sync",
		"cycle",
		"round",
		"repeat"
	],
	char: "🔃",
	fitzpatrick_scale: false,
	category: "symbols"
};
var heavy_plus_sign = {
	keywords: [
		"math",
		"calculation",
		"addition",
		"more",
		"increase"
	],
	char: "➕",
	fitzpatrick_scale: false,
	category: "symbols"
};
var heavy_minus_sign = {
	keywords: [
		"math",
		"calculation",
		"subtract",
		"less"
	],
	char: "➖",
	fitzpatrick_scale: false,
	category: "symbols"
};
var heavy_division_sign = {
	keywords: [
		"divide",
		"math",
		"calculation"
	],
	char: "➗",
	fitzpatrick_scale: false,
	category: "symbols"
};
var heavy_multiplication_x = {
	keywords: [
		"math",
		"calculation"
	],
	char: "✖️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var infinity = {
	keywords: [
		"forever"
	],
	char: "♾",
	fitzpatrick_scale: false,
	category: "symbols"
};
var heavy_dollar_sign = {
	keywords: [
		"money",
		"sales",
		"payment",
		"currency",
		"buck"
	],
	char: "💲",
	fitzpatrick_scale: false,
	category: "symbols"
};
var currency_exchange = {
	keywords: [
		"money",
		"sales",
		"dollar",
		"travel"
	],
	char: "💱",
	fitzpatrick_scale: false,
	category: "symbols"
};
var copyright = {
	keywords: [
		"ip",
		"license",
		"circle",
		"law",
		"legal"
	],
	char: "©️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var registered = {
	keywords: [
		"alphabet",
		"circle"
	],
	char: "®️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var tm = {
	keywords: [
		"trademark",
		"brand",
		"law",
		"legal"
	],
	char: "™️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var end = {
	keywords: [
		"words",
		"arrow"
	],
	char: "🔚",
	fitzpatrick_scale: false,
	category: "symbols"
};
var back = {
	keywords: [
		"arrow",
		"words",
		"return"
	],
	char: "🔙",
	fitzpatrick_scale: false,
	category: "symbols"
};
var on = {
	keywords: [
		"arrow",
		"words"
	],
	char: "🔛",
	fitzpatrick_scale: false,
	category: "symbols"
};
var top$1 = {
	keywords: [
		"words",
		"blue-square"
	],
	char: "🔝",
	fitzpatrick_scale: false,
	category: "symbols"
};
var soon = {
	keywords: [
		"arrow",
		"words"
	],
	char: "🔜",
	fitzpatrick_scale: false,
	category: "symbols"
};
var ballot_box_with_check = {
	keywords: [
		"ok",
		"agree",
		"confirm",
		"black-square",
		"vote",
		"election",
		"yes",
		"tick"
	],
	char: "☑️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var radio_button = {
	keywords: [
		"input",
		"old",
		"music",
		"circle"
	],
	char: "🔘",
	fitzpatrick_scale: false,
	category: "symbols"
};
var white_circle = {
	keywords: [
		"shape",
		"round"
	],
	char: "⚪",
	fitzpatrick_scale: false,
	category: "symbols"
};
var black_circle = {
	keywords: [
		"shape",
		"button",
		"round"
	],
	char: "⚫",
	fitzpatrick_scale: false,
	category: "symbols"
};
var red_circle = {
	keywords: [
		"shape",
		"error",
		"danger"
	],
	char: "🔴",
	fitzpatrick_scale: false,
	category: "symbols"
};
var large_blue_circle = {
	keywords: [
		"shape",
		"icon",
		"button"
	],
	char: "🔵",
	fitzpatrick_scale: false,
	category: "symbols"
};
var small_orange_diamond = {
	keywords: [
		"shape",
		"jewel",
		"gem"
	],
	char: "🔸",
	fitzpatrick_scale: false,
	category: "symbols"
};
var small_blue_diamond = {
	keywords: [
		"shape",
		"jewel",
		"gem"
	],
	char: "🔹",
	fitzpatrick_scale: false,
	category: "symbols"
};
var large_orange_diamond = {
	keywords: [
		"shape",
		"jewel",
		"gem"
	],
	char: "🔶",
	fitzpatrick_scale: false,
	category: "symbols"
};
var large_blue_diamond = {
	keywords: [
		"shape",
		"jewel",
		"gem"
	],
	char: "🔷",
	fitzpatrick_scale: false,
	category: "symbols"
};
var small_red_triangle = {
	keywords: [
		"shape",
		"direction",
		"up",
		"top"
	],
	char: "🔺",
	fitzpatrick_scale: false,
	category: "symbols"
};
var black_small_square = {
	keywords: [
		"shape",
		"icon"
	],
	char: "▪️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var white_small_square = {
	keywords: [
		"shape",
		"icon"
	],
	char: "▫️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var black_large_square = {
	keywords: [
		"shape",
		"icon",
		"button"
	],
	char: "⬛",
	fitzpatrick_scale: false,
	category: "symbols"
};
var white_large_square = {
	keywords: [
		"shape",
		"icon",
		"stone",
		"button"
	],
	char: "⬜",
	fitzpatrick_scale: false,
	category: "symbols"
};
var small_red_triangle_down = {
	keywords: [
		"shape",
		"direction",
		"bottom"
	],
	char: "🔻",
	fitzpatrick_scale: false,
	category: "symbols"
};
var black_medium_square = {
	keywords: [
		"shape",
		"button",
		"icon"
	],
	char: "◼️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var white_medium_square = {
	keywords: [
		"shape",
		"stone",
		"icon"
	],
	char: "◻️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var black_medium_small_square = {
	keywords: [
		"icon",
		"shape",
		"button"
	],
	char: "◾",
	fitzpatrick_scale: false,
	category: "symbols"
};
var white_medium_small_square = {
	keywords: [
		"shape",
		"stone",
		"icon",
		"button"
	],
	char: "◽",
	fitzpatrick_scale: false,
	category: "symbols"
};
var black_square_button = {
	keywords: [
		"shape",
		"input",
		"frame"
	],
	char: "🔲",
	fitzpatrick_scale: false,
	category: "symbols"
};
var white_square_button = {
	keywords: [
		"shape",
		"input"
	],
	char: "🔳",
	fitzpatrick_scale: false,
	category: "symbols"
};
var speaker = {
	keywords: [
		"sound",
		"volume",
		"silence",
		"broadcast"
	],
	char: "🔈",
	fitzpatrick_scale: false,
	category: "symbols"
};
var sound = {
	keywords: [
		"volume",
		"speaker",
		"broadcast"
	],
	char: "🔉",
	fitzpatrick_scale: false,
	category: "symbols"
};
var loud_sound = {
	keywords: [
		"volume",
		"noise",
		"noisy",
		"speaker",
		"broadcast"
	],
	char: "🔊",
	fitzpatrick_scale: false,
	category: "symbols"
};
var mute = {
	keywords: [
		"sound",
		"volume",
		"silence",
		"quiet"
	],
	char: "🔇",
	fitzpatrick_scale: false,
	category: "symbols"
};
var mega = {
	keywords: [
		"sound",
		"speaker",
		"volume"
	],
	char: "📣",
	fitzpatrick_scale: false,
	category: "symbols"
};
var loudspeaker = {
	keywords: [
		"volume",
		"sound"
	],
	char: "📢",
	fitzpatrick_scale: false,
	category: "symbols"
};
var bell = {
	keywords: [
		"sound",
		"notification",
		"christmas",
		"xmas",
		"chime"
	],
	char: "🔔",
	fitzpatrick_scale: false,
	category: "symbols"
};
var no_bell = {
	keywords: [
		"sound",
		"volume",
		"mute",
		"quiet",
		"silent"
	],
	char: "🔕",
	fitzpatrick_scale: false,
	category: "symbols"
};
var black_joker = {
	keywords: [
		"poker",
		"cards",
		"game",
		"play",
		"magic"
	],
	char: "🃏",
	fitzpatrick_scale: false,
	category: "symbols"
};
var mahjong = {
	keywords: [
		"game",
		"play",
		"chinese",
		"kanji"
	],
	char: "🀄",
	fitzpatrick_scale: false,
	category: "symbols"
};
var spades$1 = {
	keywords: [
		"poker",
		"cards",
		"suits",
		"magic"
	],
	char: "♠️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var clubs$1 = {
	keywords: [
		"poker",
		"cards",
		"magic",
		"suits"
	],
	char: "♣️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var hearts$1 = {
	keywords: [
		"poker",
		"cards",
		"magic",
		"suits"
	],
	char: "♥️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var diamonds = {
	keywords: [
		"poker",
		"cards",
		"magic",
		"suits"
	],
	char: "♦️",
	fitzpatrick_scale: false,
	category: "symbols"
};
var flower_playing_cards = {
	keywords: [
		"game",
		"sunset",
		"red"
	],
	char: "🎴",
	fitzpatrick_scale: false,
	category: "symbols"
};
var thought_balloon = {
	keywords: [
		"bubble",
		"cloud",
		"speech",
		"thinking",
		"dream"
	],
	char: "💭",
	fitzpatrick_scale: false,
	category: "symbols"
};
var right_anger_bubble = {
	keywords: [
		"caption",
		"speech",
		"thinking",
		"mad"
	],
	char: "🗯",
	fitzpatrick_scale: false,
	category: "symbols"
};
var speech_balloon = {
	keywords: [
		"bubble",
		"words",
		"message",
		"talk",
		"chatting"
	],
	char: "💬",
	fitzpatrick_scale: false,
	category: "symbols"
};
var left_speech_bubble = {
	keywords: [
		"words",
		"message",
		"talk",
		"chatting"
	],
	char: "🗨",
	fitzpatrick_scale: false,
	category: "symbols"
};
var clock1 = {
	keywords: [
		"time",
		"late",
		"early",
		"schedule"
	],
	char: "🕐",
	fitzpatrick_scale: false,
	category: "symbols"
};
var clock2 = {
	keywords: [
		"time",
		"late",
		"early",
		"schedule"
	],
	char: "🕑",
	fitzpatrick_scale: false,
	category: "symbols"
};
var clock3 = {
	keywords: [
		"time",
		"late",
		"early",
		"schedule"
	],
	char: "🕒",
	fitzpatrick_scale: false,
	category: "symbols"
};
var clock4 = {
	keywords: [
		"time",
		"late",
		"early",
		"schedule"
	],
	char: "🕓",
	fitzpatrick_scale: false,
	category: "symbols"
};
var clock5 = {
	keywords: [
		"time",
		"late",
		"early",
		"schedule"
	],
	char: "🕔",
	fitzpatrick_scale: false,
	category: "symbols"
};
var clock6 = {
	keywords: [
		"time",
		"late",
		"early",
		"schedule",
		"dawn",
		"dusk"
	],
	char: "🕕",
	fitzpatrick_scale: false,
	category: "symbols"
};
var clock7 = {
	keywords: [
		"time",
		"late",
		"early",
		"schedule"
	],
	char: "🕖",
	fitzpatrick_scale: false,
	category: "symbols"
};
var clock8 = {
	keywords: [
		"time",
		"late",
		"early",
		"schedule"
	],
	char: "🕗",
	fitzpatrick_scale: false,
	category: "symbols"
};
var clock9 = {
	keywords: [
		"time",
		"late",
		"early",
		"schedule"
	],
	char: "🕘",
	fitzpatrick_scale: false,
	category: "symbols"
};
var clock10 = {
	keywords: [
		"time",
		"late",
		"early",
		"schedule"
	],
	char: "🕙",
	fitzpatrick_scale: false,
	category: "symbols"
};
var clock11 = {
	keywords: [
		"time",
		"late",
		"early",
		"schedule"
	],
	char: "🕚",
	fitzpatrick_scale: false,
	category: "symbols"
};
var clock12 = {
	keywords: [
		"time",
		"noon",
		"midnight",
		"midday",
		"late",
		"early",
		"schedule"
	],
	char: "🕛",
	fitzpatrick_scale: false,
	category: "symbols"
};
var clock130 = {
	keywords: [
		"time",
		"late",
		"early",
		"schedule"
	],
	char: "🕜",
	fitzpatrick_scale: false,
	category: "symbols"
};
var clock230 = {
	keywords: [
		"time",
		"late",
		"early",
		"schedule"
	],
	char: "🕝",
	fitzpatrick_scale: false,
	category: "symbols"
};
var clock330 = {
	keywords: [
		"time",
		"late",
		"early",
		"schedule"
	],
	char: "🕞",
	fitzpatrick_scale: false,
	category: "symbols"
};
var clock430 = {
	keywords: [
		"time",
		"late",
		"early",
		"schedule"
	],
	char: "🕟",
	fitzpatrick_scale: false,
	category: "symbols"
};
var clock530 = {
	keywords: [
		"time",
		"late",
		"early",
		"schedule"
	],
	char: "🕠",
	fitzpatrick_scale: false,
	category: "symbols"
};
var clock630 = {
	keywords: [
		"time",
		"late",
		"early",
		"schedule"
	],
	char: "🕡",
	fitzpatrick_scale: false,
	category: "symbols"
};
var clock730 = {
	keywords: [
		"time",
		"late",
		"early",
		"schedule"
	],
	char: "🕢",
	fitzpatrick_scale: false,
	category: "symbols"
};
var clock830 = {
	keywords: [
		"time",
		"late",
		"early",
		"schedule"
	],
	char: "🕣",
	fitzpatrick_scale: false,
	category: "symbols"
};
var clock930 = {
	keywords: [
		"time",
		"late",
		"early",
		"schedule"
	],
	char: "🕤",
	fitzpatrick_scale: false,
	category: "symbols"
};
var clock1030 = {
	keywords: [
		"time",
		"late",
		"early",
		"schedule"
	],
	char: "🕥",
	fitzpatrick_scale: false,
	category: "symbols"
};
var clock1130 = {
	keywords: [
		"time",
		"late",
		"early",
		"schedule"
	],
	char: "🕦",
	fitzpatrick_scale: false,
	category: "symbols"
};
var clock1230 = {
	keywords: [
		"time",
		"late",
		"early",
		"schedule"
	],
	char: "🕧",
	fitzpatrick_scale: false,
	category: "symbols"
};
var afghanistan = {
	keywords: [
		"af",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇦🇫",
	fitzpatrick_scale: false,
	category: "flags"
};
var aland_islands = {
	keywords: [
		"Åland",
		"islands",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇦🇽",
	fitzpatrick_scale: false,
	category: "flags"
};
var albania = {
	keywords: [
		"al",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇦🇱",
	fitzpatrick_scale: false,
	category: "flags"
};
var algeria = {
	keywords: [
		"dz",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇩🇿",
	fitzpatrick_scale: false,
	category: "flags"
};
var american_samoa = {
	keywords: [
		"american",
		"ws",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇦🇸",
	fitzpatrick_scale: false,
	category: "flags"
};
var andorra = {
	keywords: [
		"ad",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇦🇩",
	fitzpatrick_scale: false,
	category: "flags"
};
var angola = {
	keywords: [
		"ao",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇦🇴",
	fitzpatrick_scale: false,
	category: "flags"
};
var anguilla = {
	keywords: [
		"ai",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇦🇮",
	fitzpatrick_scale: false,
	category: "flags"
};
var antarctica = {
	keywords: [
		"aq",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇦🇶",
	fitzpatrick_scale: false,
	category: "flags"
};
var antigua_barbuda = {
	keywords: [
		"antigua",
		"barbuda",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇦🇬",
	fitzpatrick_scale: false,
	category: "flags"
};
var argentina = {
	keywords: [
		"ar",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇦🇷",
	fitzpatrick_scale: false,
	category: "flags"
};
var armenia = {
	keywords: [
		"am",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇦🇲",
	fitzpatrick_scale: false,
	category: "flags"
};
var aruba = {
	keywords: [
		"aw",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇦🇼",
	fitzpatrick_scale: false,
	category: "flags"
};
var australia = {
	keywords: [
		"au",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇦🇺",
	fitzpatrick_scale: false,
	category: "flags"
};
var austria = {
	keywords: [
		"at",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇦🇹",
	fitzpatrick_scale: false,
	category: "flags"
};
var azerbaijan = {
	keywords: [
		"az",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇦🇿",
	fitzpatrick_scale: false,
	category: "flags"
};
var bahamas = {
	keywords: [
		"bs",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇧🇸",
	fitzpatrick_scale: false,
	category: "flags"
};
var bahrain = {
	keywords: [
		"bh",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇧🇭",
	fitzpatrick_scale: false,
	category: "flags"
};
var bangladesh = {
	keywords: [
		"bd",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇧🇩",
	fitzpatrick_scale: false,
	category: "flags"
};
var barbados = {
	keywords: [
		"bb",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇧🇧",
	fitzpatrick_scale: false,
	category: "flags"
};
var belarus = {
	keywords: [
		"by",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇧🇾",
	fitzpatrick_scale: false,
	category: "flags"
};
var belgium = {
	keywords: [
		"be",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇧🇪",
	fitzpatrick_scale: false,
	category: "flags"
};
var belize = {
	keywords: [
		"bz",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇧🇿",
	fitzpatrick_scale: false,
	category: "flags"
};
var benin = {
	keywords: [
		"bj",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇧🇯",
	fitzpatrick_scale: false,
	category: "flags"
};
var bermuda = {
	keywords: [
		"bm",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇧🇲",
	fitzpatrick_scale: false,
	category: "flags"
};
var bhutan = {
	keywords: [
		"bt",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇧🇹",
	fitzpatrick_scale: false,
	category: "flags"
};
var bolivia = {
	keywords: [
		"bo",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇧🇴",
	fitzpatrick_scale: false,
	category: "flags"
};
var caribbean_netherlands = {
	keywords: [
		"bonaire",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇧🇶",
	fitzpatrick_scale: false,
	category: "flags"
};
var bosnia_herzegovina = {
	keywords: [
		"bosnia",
		"herzegovina",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇧🇦",
	fitzpatrick_scale: false,
	category: "flags"
};
var botswana = {
	keywords: [
		"bw",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇧🇼",
	fitzpatrick_scale: false,
	category: "flags"
};
var brazil = {
	keywords: [
		"br",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇧🇷",
	fitzpatrick_scale: false,
	category: "flags"
};
var british_indian_ocean_territory = {
	keywords: [
		"british",
		"indian",
		"ocean",
		"territory",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇮🇴",
	fitzpatrick_scale: false,
	category: "flags"
};
var british_virgin_islands = {
	keywords: [
		"british",
		"virgin",
		"islands",
		"bvi",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇻🇬",
	fitzpatrick_scale: false,
	category: "flags"
};
var brunei = {
	keywords: [
		"bn",
		"darussalam",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇧🇳",
	fitzpatrick_scale: false,
	category: "flags"
};
var bulgaria = {
	keywords: [
		"bg",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇧🇬",
	fitzpatrick_scale: false,
	category: "flags"
};
var burkina_faso = {
	keywords: [
		"burkina",
		"faso",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇧🇫",
	fitzpatrick_scale: false,
	category: "flags"
};
var burundi = {
	keywords: [
		"bi",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇧🇮",
	fitzpatrick_scale: false,
	category: "flags"
};
var cape_verde = {
	keywords: [
		"cabo",
		"verde",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇨🇻",
	fitzpatrick_scale: false,
	category: "flags"
};
var cambodia = {
	keywords: [
		"kh",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇰🇭",
	fitzpatrick_scale: false,
	category: "flags"
};
var cameroon = {
	keywords: [
		"cm",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇨🇲",
	fitzpatrick_scale: false,
	category: "flags"
};
var canada = {
	keywords: [
		"ca",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇨🇦",
	fitzpatrick_scale: false,
	category: "flags"
};
var canary_islands = {
	keywords: [
		"canary",
		"islands",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇮🇨",
	fitzpatrick_scale: false,
	category: "flags"
};
var cayman_islands = {
	keywords: [
		"cayman",
		"islands",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇰🇾",
	fitzpatrick_scale: false,
	category: "flags"
};
var central_african_republic = {
	keywords: [
		"central",
		"african",
		"republic",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇨🇫",
	fitzpatrick_scale: false,
	category: "flags"
};
var chad = {
	keywords: [
		"td",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇹🇩",
	fitzpatrick_scale: false,
	category: "flags"
};
var chile = {
	keywords: [
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇨🇱",
	fitzpatrick_scale: false,
	category: "flags"
};
var cn = {
	keywords: [
		"china",
		"chinese",
		"prc",
		"flag",
		"country",
		"nation",
		"banner"
	],
	char: "🇨🇳",
	fitzpatrick_scale: false,
	category: "flags"
};
var christmas_island = {
	keywords: [
		"christmas",
		"island",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇨🇽",
	fitzpatrick_scale: false,
	category: "flags"
};
var cocos_islands = {
	keywords: [
		"cocos",
		"keeling",
		"islands",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇨🇨",
	fitzpatrick_scale: false,
	category: "flags"
};
var colombia = {
	keywords: [
		"co",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇨🇴",
	fitzpatrick_scale: false,
	category: "flags"
};
var comoros = {
	keywords: [
		"km",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇰🇲",
	fitzpatrick_scale: false,
	category: "flags"
};
var congo_brazzaville = {
	keywords: [
		"congo",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇨🇬",
	fitzpatrick_scale: false,
	category: "flags"
};
var congo_kinshasa = {
	keywords: [
		"congo",
		"democratic",
		"republic",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇨🇩",
	fitzpatrick_scale: false,
	category: "flags"
};
var cook_islands = {
	keywords: [
		"cook",
		"islands",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇨🇰",
	fitzpatrick_scale: false,
	category: "flags"
};
var costa_rica = {
	keywords: [
		"costa",
		"rica",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇨🇷",
	fitzpatrick_scale: false,
	category: "flags"
};
var croatia = {
	keywords: [
		"hr",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇭🇷",
	fitzpatrick_scale: false,
	category: "flags"
};
var cuba = {
	keywords: [
		"cu",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇨🇺",
	fitzpatrick_scale: false,
	category: "flags"
};
var curacao = {
	keywords: [
		"curaçao",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇨🇼",
	fitzpatrick_scale: false,
	category: "flags"
};
var cyprus = {
	keywords: [
		"cy",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇨🇾",
	fitzpatrick_scale: false,
	category: "flags"
};
var czech_republic = {
	keywords: [
		"cz",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇨🇿",
	fitzpatrick_scale: false,
	category: "flags"
};
var denmark = {
	keywords: [
		"dk",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇩🇰",
	fitzpatrick_scale: false,
	category: "flags"
};
var djibouti = {
	keywords: [
		"dj",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇩🇯",
	fitzpatrick_scale: false,
	category: "flags"
};
var dominica = {
	keywords: [
		"dm",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇩🇲",
	fitzpatrick_scale: false,
	category: "flags"
};
var dominican_republic = {
	keywords: [
		"dominican",
		"republic",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇩🇴",
	fitzpatrick_scale: false,
	category: "flags"
};
var ecuador = {
	keywords: [
		"ec",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇪🇨",
	fitzpatrick_scale: false,
	category: "flags"
};
var egypt = {
	keywords: [
		"eg",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇪🇬",
	fitzpatrick_scale: false,
	category: "flags"
};
var el_salvador = {
	keywords: [
		"el",
		"salvador",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇸🇻",
	fitzpatrick_scale: false,
	category: "flags"
};
var equatorial_guinea = {
	keywords: [
		"equatorial",
		"gn",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇬🇶",
	fitzpatrick_scale: false,
	category: "flags"
};
var eritrea = {
	keywords: [
		"er",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇪🇷",
	fitzpatrick_scale: false,
	category: "flags"
};
var estonia = {
	keywords: [
		"ee",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇪🇪",
	fitzpatrick_scale: false,
	category: "flags"
};
var ethiopia = {
	keywords: [
		"et",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇪🇹",
	fitzpatrick_scale: false,
	category: "flags"
};
var eu = {
	keywords: [
		"european",
		"union",
		"flag",
		"banner"
	],
	char: "🇪🇺",
	fitzpatrick_scale: false,
	category: "flags"
};
var falkland_islands = {
	keywords: [
		"falkland",
		"islands",
		"malvinas",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇫🇰",
	fitzpatrick_scale: false,
	category: "flags"
};
var faroe_islands = {
	keywords: [
		"faroe",
		"islands",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇫🇴",
	fitzpatrick_scale: false,
	category: "flags"
};
var fiji = {
	keywords: [
		"fj",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇫🇯",
	fitzpatrick_scale: false,
	category: "flags"
};
var finland = {
	keywords: [
		"fi",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇫🇮",
	fitzpatrick_scale: false,
	category: "flags"
};
var fr = {
	keywords: [
		"banner",
		"flag",
		"nation",
		"france",
		"french",
		"country"
	],
	char: "🇫🇷",
	fitzpatrick_scale: false,
	category: "flags"
};
var french_guiana = {
	keywords: [
		"french",
		"guiana",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇬🇫",
	fitzpatrick_scale: false,
	category: "flags"
};
var french_polynesia = {
	keywords: [
		"french",
		"polynesia",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇵🇫",
	fitzpatrick_scale: false,
	category: "flags"
};
var french_southern_territories = {
	keywords: [
		"french",
		"southern",
		"territories",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇹🇫",
	fitzpatrick_scale: false,
	category: "flags"
};
var gabon = {
	keywords: [
		"ga",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇬🇦",
	fitzpatrick_scale: false,
	category: "flags"
};
var gambia = {
	keywords: [
		"gm",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇬🇲",
	fitzpatrick_scale: false,
	category: "flags"
};
var georgia = {
	keywords: [
		"ge",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇬🇪",
	fitzpatrick_scale: false,
	category: "flags"
};
var de = {
	keywords: [
		"german",
		"nation",
		"flag",
		"country",
		"banner"
	],
	char: "🇩🇪",
	fitzpatrick_scale: false,
	category: "flags"
};
var ghana = {
	keywords: [
		"gh",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇬🇭",
	fitzpatrick_scale: false,
	category: "flags"
};
var gibraltar = {
	keywords: [
		"gi",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇬🇮",
	fitzpatrick_scale: false,
	category: "flags"
};
var greece = {
	keywords: [
		"gr",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇬🇷",
	fitzpatrick_scale: false,
	category: "flags"
};
var greenland = {
	keywords: [
		"gl",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇬🇱",
	fitzpatrick_scale: false,
	category: "flags"
};
var grenada = {
	keywords: [
		"gd",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇬🇩",
	fitzpatrick_scale: false,
	category: "flags"
};
var guadeloupe = {
	keywords: [
		"gp",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇬🇵",
	fitzpatrick_scale: false,
	category: "flags"
};
var guam = {
	keywords: [
		"gu",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇬🇺",
	fitzpatrick_scale: false,
	category: "flags"
};
var guatemala = {
	keywords: [
		"gt",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇬🇹",
	fitzpatrick_scale: false,
	category: "flags"
};
var guernsey = {
	keywords: [
		"gg",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇬🇬",
	fitzpatrick_scale: false,
	category: "flags"
};
var guinea = {
	keywords: [
		"gn",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇬🇳",
	fitzpatrick_scale: false,
	category: "flags"
};
var guinea_bissau = {
	keywords: [
		"gw",
		"bissau",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇬🇼",
	fitzpatrick_scale: false,
	category: "flags"
};
var guyana = {
	keywords: [
		"gy",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇬🇾",
	fitzpatrick_scale: false,
	category: "flags"
};
var haiti = {
	keywords: [
		"ht",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇭🇹",
	fitzpatrick_scale: false,
	category: "flags"
};
var honduras = {
	keywords: [
		"hn",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇭🇳",
	fitzpatrick_scale: false,
	category: "flags"
};
var hong_kong = {
	keywords: [
		"hong",
		"kong",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇭🇰",
	fitzpatrick_scale: false,
	category: "flags"
};
var hungary = {
	keywords: [
		"hu",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇭🇺",
	fitzpatrick_scale: false,
	category: "flags"
};
var iceland = {
	keywords: [
		"is",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇮🇸",
	fitzpatrick_scale: false,
	category: "flags"
};
var india = {
	keywords: [
		"in",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇮🇳",
	fitzpatrick_scale: false,
	category: "flags"
};
var indonesia = {
	keywords: [
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇮🇩",
	fitzpatrick_scale: false,
	category: "flags"
};
var iran = {
	keywords: [
		"iran,",
		"islamic",
		"republic",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇮🇷",
	fitzpatrick_scale: false,
	category: "flags"
};
var iraq = {
	keywords: [
		"iq",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇮🇶",
	fitzpatrick_scale: false,
	category: "flags"
};
var ireland = {
	keywords: [
		"ie",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇮🇪",
	fitzpatrick_scale: false,
	category: "flags"
};
var isle_of_man = {
	keywords: [
		"isle",
		"man",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇮🇲",
	fitzpatrick_scale: false,
	category: "flags"
};
var israel = {
	keywords: [
		"il",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇮🇱",
	fitzpatrick_scale: false,
	category: "flags"
};
var it$1 = {
	keywords: [
		"italy",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇮🇹",
	fitzpatrick_scale: false,
	category: "flags"
};
var cote_divoire = {
	keywords: [
		"ivory",
		"coast",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇨🇮",
	fitzpatrick_scale: false,
	category: "flags"
};
var jamaica = {
	keywords: [
		"jm",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇯🇲",
	fitzpatrick_scale: false,
	category: "flags"
};
var jp = {
	keywords: [
		"japanese",
		"nation",
		"flag",
		"country",
		"banner"
	],
	char: "🇯🇵",
	fitzpatrick_scale: false,
	category: "flags"
};
var jersey = {
	keywords: [
		"je",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇯🇪",
	fitzpatrick_scale: false,
	category: "flags"
};
var jordan = {
	keywords: [
		"jo",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇯🇴",
	fitzpatrick_scale: false,
	category: "flags"
};
var kazakhstan = {
	keywords: [
		"kz",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇰🇿",
	fitzpatrick_scale: false,
	category: "flags"
};
var kenya = {
	keywords: [
		"ke",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇰🇪",
	fitzpatrick_scale: false,
	category: "flags"
};
var kiribati = {
	keywords: [
		"ki",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇰🇮",
	fitzpatrick_scale: false,
	category: "flags"
};
var kosovo = {
	keywords: [
		"xk",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇽🇰",
	fitzpatrick_scale: false,
	category: "flags"
};
var kuwait = {
	keywords: [
		"kw",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇰🇼",
	fitzpatrick_scale: false,
	category: "flags"
};
var kyrgyzstan = {
	keywords: [
		"kg",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇰🇬",
	fitzpatrick_scale: false,
	category: "flags"
};
var laos = {
	keywords: [
		"lao",
		"democratic",
		"republic",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇱🇦",
	fitzpatrick_scale: false,
	category: "flags"
};
var latvia = {
	keywords: [
		"lv",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇱🇻",
	fitzpatrick_scale: false,
	category: "flags"
};
var lebanon = {
	keywords: [
		"lb",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇱🇧",
	fitzpatrick_scale: false,
	category: "flags"
};
var lesotho = {
	keywords: [
		"ls",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇱🇸",
	fitzpatrick_scale: false,
	category: "flags"
};
var liberia = {
	keywords: [
		"lr",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇱🇷",
	fitzpatrick_scale: false,
	category: "flags"
};
var libya = {
	keywords: [
		"ly",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇱🇾",
	fitzpatrick_scale: false,
	category: "flags"
};
var liechtenstein = {
	keywords: [
		"li",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇱🇮",
	fitzpatrick_scale: false,
	category: "flags"
};
var lithuania = {
	keywords: [
		"lt",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇱🇹",
	fitzpatrick_scale: false,
	category: "flags"
};
var luxembourg = {
	keywords: [
		"lu",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇱🇺",
	fitzpatrick_scale: false,
	category: "flags"
};
var macau = {
	keywords: [
		"macao",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇲🇴",
	fitzpatrick_scale: false,
	category: "flags"
};
var macedonia = {
	keywords: [
		"macedonia,",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇲🇰",
	fitzpatrick_scale: false,
	category: "flags"
};
var madagascar = {
	keywords: [
		"mg",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇲🇬",
	fitzpatrick_scale: false,
	category: "flags"
};
var malawi = {
	keywords: [
		"mw",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇲🇼",
	fitzpatrick_scale: false,
	category: "flags"
};
var malaysia = {
	keywords: [
		"my",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇲🇾",
	fitzpatrick_scale: false,
	category: "flags"
};
var maldives = {
	keywords: [
		"mv",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇲🇻",
	fitzpatrick_scale: false,
	category: "flags"
};
var mali = {
	keywords: [
		"ml",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇲🇱",
	fitzpatrick_scale: false,
	category: "flags"
};
var malta = {
	keywords: [
		"mt",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇲🇹",
	fitzpatrick_scale: false,
	category: "flags"
};
var marshall_islands = {
	keywords: [
		"marshall",
		"islands",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇲🇭",
	fitzpatrick_scale: false,
	category: "flags"
};
var martinique = {
	keywords: [
		"mq",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇲🇶",
	fitzpatrick_scale: false,
	category: "flags"
};
var mauritania = {
	keywords: [
		"mr",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇲🇷",
	fitzpatrick_scale: false,
	category: "flags"
};
var mauritius = {
	keywords: [
		"mu",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇲🇺",
	fitzpatrick_scale: false,
	category: "flags"
};
var mayotte = {
	keywords: [
		"yt",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇾🇹",
	fitzpatrick_scale: false,
	category: "flags"
};
var mexico = {
	keywords: [
		"mx",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇲🇽",
	fitzpatrick_scale: false,
	category: "flags"
};
var micronesia = {
	keywords: [
		"micronesia,",
		"federated",
		"states",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇫🇲",
	fitzpatrick_scale: false,
	category: "flags"
};
var moldova = {
	keywords: [
		"moldova,",
		"republic",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇲🇩",
	fitzpatrick_scale: false,
	category: "flags"
};
var monaco = {
	keywords: [
		"mc",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇲🇨",
	fitzpatrick_scale: false,
	category: "flags"
};
var mongolia = {
	keywords: [
		"mn",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇲🇳",
	fitzpatrick_scale: false,
	category: "flags"
};
var montenegro = {
	keywords: [
		"me",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇲🇪",
	fitzpatrick_scale: false,
	category: "flags"
};
var montserrat = {
	keywords: [
		"ms",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇲🇸",
	fitzpatrick_scale: false,
	category: "flags"
};
var morocco = {
	keywords: [
		"ma",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇲🇦",
	fitzpatrick_scale: false,
	category: "flags"
};
var mozambique = {
	keywords: [
		"mz",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇲🇿",
	fitzpatrick_scale: false,
	category: "flags"
};
var myanmar = {
	keywords: [
		"mm",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇲🇲",
	fitzpatrick_scale: false,
	category: "flags"
};
var namibia = {
	keywords: [
		"na",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇳🇦",
	fitzpatrick_scale: false,
	category: "flags"
};
var nauru = {
	keywords: [
		"nr",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇳🇷",
	fitzpatrick_scale: false,
	category: "flags"
};
var nepal = {
	keywords: [
		"np",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇳🇵",
	fitzpatrick_scale: false,
	category: "flags"
};
var netherlands = {
	keywords: [
		"nl",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇳🇱",
	fitzpatrick_scale: false,
	category: "flags"
};
var new_caledonia = {
	keywords: [
		"new",
		"caledonia",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇳🇨",
	fitzpatrick_scale: false,
	category: "flags"
};
var new_zealand = {
	keywords: [
		"new",
		"zealand",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇳🇿",
	fitzpatrick_scale: false,
	category: "flags"
};
var nicaragua = {
	keywords: [
		"ni",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇳🇮",
	fitzpatrick_scale: false,
	category: "flags"
};
var niger = {
	keywords: [
		"ne",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇳🇪",
	fitzpatrick_scale: false,
	category: "flags"
};
var nigeria = {
	keywords: [
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇳🇬",
	fitzpatrick_scale: false,
	category: "flags"
};
var niue = {
	keywords: [
		"nu",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇳🇺",
	fitzpatrick_scale: false,
	category: "flags"
};
var norfolk_island = {
	keywords: [
		"norfolk",
		"island",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇳🇫",
	fitzpatrick_scale: false,
	category: "flags"
};
var northern_mariana_islands = {
	keywords: [
		"northern",
		"mariana",
		"islands",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇲🇵",
	fitzpatrick_scale: false,
	category: "flags"
};
var north_korea = {
	keywords: [
		"north",
		"korea",
		"nation",
		"flag",
		"country",
		"banner"
	],
	char: "🇰🇵",
	fitzpatrick_scale: false,
	category: "flags"
};
var norway = {
	keywords: [
		"no",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇳🇴",
	fitzpatrick_scale: false,
	category: "flags"
};
var oman = {
	keywords: [
		"om_symbol",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇴🇲",
	fitzpatrick_scale: false,
	category: "flags"
};
var pakistan = {
	keywords: [
		"pk",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇵🇰",
	fitzpatrick_scale: false,
	category: "flags"
};
var palau = {
	keywords: [
		"pw",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇵🇼",
	fitzpatrick_scale: false,
	category: "flags"
};
var palestinian_territories = {
	keywords: [
		"palestine",
		"palestinian",
		"territories",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇵🇸",
	fitzpatrick_scale: false,
	category: "flags"
};
var panama = {
	keywords: [
		"pa",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇵🇦",
	fitzpatrick_scale: false,
	category: "flags"
};
var papua_new_guinea = {
	keywords: [
		"papua",
		"new",
		"guinea",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇵🇬",
	fitzpatrick_scale: false,
	category: "flags"
};
var paraguay = {
	keywords: [
		"py",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇵🇾",
	fitzpatrick_scale: false,
	category: "flags"
};
var peru = {
	keywords: [
		"pe",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇵🇪",
	fitzpatrick_scale: false,
	category: "flags"
};
var philippines = {
	keywords: [
		"ph",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇵🇭",
	fitzpatrick_scale: false,
	category: "flags"
};
var pitcairn_islands = {
	keywords: [
		"pitcairn",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇵🇳",
	fitzpatrick_scale: false,
	category: "flags"
};
var poland = {
	keywords: [
		"pl",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇵🇱",
	fitzpatrick_scale: false,
	category: "flags"
};
var portugal = {
	keywords: [
		"pt",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇵🇹",
	fitzpatrick_scale: false,
	category: "flags"
};
var puerto_rico = {
	keywords: [
		"puerto",
		"rico",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇵🇷",
	fitzpatrick_scale: false,
	category: "flags"
};
var qatar = {
	keywords: [
		"qa",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇶🇦",
	fitzpatrick_scale: false,
	category: "flags"
};
var reunion = {
	keywords: [
		"réunion",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇷🇪",
	fitzpatrick_scale: false,
	category: "flags"
};
var romania = {
	keywords: [
		"ro",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇷🇴",
	fitzpatrick_scale: false,
	category: "flags"
};
var ru = {
	keywords: [
		"russian",
		"federation",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇷🇺",
	fitzpatrick_scale: false,
	category: "flags"
};
var rwanda = {
	keywords: [
		"rw",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇷🇼",
	fitzpatrick_scale: false,
	category: "flags"
};
var st_barthelemy = {
	keywords: [
		"saint",
		"barthélemy",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇧🇱",
	fitzpatrick_scale: false,
	category: "flags"
};
var st_helena = {
	keywords: [
		"saint",
		"helena",
		"ascension",
		"tristan",
		"cunha",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇸🇭",
	fitzpatrick_scale: false,
	category: "flags"
};
var st_kitts_nevis = {
	keywords: [
		"saint",
		"kitts",
		"nevis",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇰🇳",
	fitzpatrick_scale: false,
	category: "flags"
};
var st_lucia = {
	keywords: [
		"saint",
		"lucia",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇱🇨",
	fitzpatrick_scale: false,
	category: "flags"
};
var st_pierre_miquelon = {
	keywords: [
		"saint",
		"pierre",
		"miquelon",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇵🇲",
	fitzpatrick_scale: false,
	category: "flags"
};
var st_vincent_grenadines = {
	keywords: [
		"saint",
		"vincent",
		"grenadines",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇻🇨",
	fitzpatrick_scale: false,
	category: "flags"
};
var samoa = {
	keywords: [
		"ws",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇼🇸",
	fitzpatrick_scale: false,
	category: "flags"
};
var san_marino = {
	keywords: [
		"san",
		"marino",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇸🇲",
	fitzpatrick_scale: false,
	category: "flags"
};
var sao_tome_principe = {
	keywords: [
		"sao",
		"tome",
		"principe",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇸🇹",
	fitzpatrick_scale: false,
	category: "flags"
};
var saudi_arabia = {
	keywords: [
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇸🇦",
	fitzpatrick_scale: false,
	category: "flags"
};
var senegal = {
	keywords: [
		"sn",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇸🇳",
	fitzpatrick_scale: false,
	category: "flags"
};
var serbia = {
	keywords: [
		"rs",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇷🇸",
	fitzpatrick_scale: false,
	category: "flags"
};
var seychelles = {
	keywords: [
		"sc",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇸🇨",
	fitzpatrick_scale: false,
	category: "flags"
};
var sierra_leone = {
	keywords: [
		"sierra",
		"leone",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇸🇱",
	fitzpatrick_scale: false,
	category: "flags"
};
var singapore = {
	keywords: [
		"sg",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇸🇬",
	fitzpatrick_scale: false,
	category: "flags"
};
var sint_maarten = {
	keywords: [
		"sint",
		"maarten",
		"dutch",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇸🇽",
	fitzpatrick_scale: false,
	category: "flags"
};
var slovakia = {
	keywords: [
		"sk",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇸🇰",
	fitzpatrick_scale: false,
	category: "flags"
};
var slovenia = {
	keywords: [
		"si",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇸🇮",
	fitzpatrick_scale: false,
	category: "flags"
};
var solomon_islands = {
	keywords: [
		"solomon",
		"islands",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇸🇧",
	fitzpatrick_scale: false,
	category: "flags"
};
var somalia = {
	keywords: [
		"so",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇸🇴",
	fitzpatrick_scale: false,
	category: "flags"
};
var south_africa = {
	keywords: [
		"south",
		"africa",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇿🇦",
	fitzpatrick_scale: false,
	category: "flags"
};
var south_georgia_south_sandwich_islands = {
	keywords: [
		"south",
		"georgia",
		"sandwich",
		"islands",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇬🇸",
	fitzpatrick_scale: false,
	category: "flags"
};
var kr = {
	keywords: [
		"south",
		"korea",
		"nation",
		"flag",
		"country",
		"banner"
	],
	char: "🇰🇷",
	fitzpatrick_scale: false,
	category: "flags"
};
var south_sudan = {
	keywords: [
		"south",
		"sd",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇸🇸",
	fitzpatrick_scale: false,
	category: "flags"
};
var es = {
	keywords: [
		"spain",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇪🇸",
	fitzpatrick_scale: false,
	category: "flags"
};
var sri_lanka = {
	keywords: [
		"sri",
		"lanka",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇱🇰",
	fitzpatrick_scale: false,
	category: "flags"
};
var sudan = {
	keywords: [
		"sd",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇸🇩",
	fitzpatrick_scale: false,
	category: "flags"
};
var suriname = {
	keywords: [
		"sr",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇸🇷",
	fitzpatrick_scale: false,
	category: "flags"
};
var swaziland = {
	keywords: [
		"sz",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇸🇿",
	fitzpatrick_scale: false,
	category: "flags"
};
var sweden = {
	keywords: [
		"se",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇸🇪",
	fitzpatrick_scale: false,
	category: "flags"
};
var switzerland = {
	keywords: [
		"ch",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇨🇭",
	fitzpatrick_scale: false,
	category: "flags"
};
var syria = {
	keywords: [
		"syrian",
		"arab",
		"republic",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇸🇾",
	fitzpatrick_scale: false,
	category: "flags"
};
var taiwan = {
	keywords: [
		"tw",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇹🇼",
	fitzpatrick_scale: false,
	category: "flags"
};
var tajikistan = {
	keywords: [
		"tj",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇹🇯",
	fitzpatrick_scale: false,
	category: "flags"
};
var tanzania = {
	keywords: [
		"tanzania,",
		"united",
		"republic",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇹🇿",
	fitzpatrick_scale: false,
	category: "flags"
};
var thailand = {
	keywords: [
		"th",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇹🇭",
	fitzpatrick_scale: false,
	category: "flags"
};
var timor_leste = {
	keywords: [
		"timor",
		"leste",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇹🇱",
	fitzpatrick_scale: false,
	category: "flags"
};
var togo = {
	keywords: [
		"tg",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇹🇬",
	fitzpatrick_scale: false,
	category: "flags"
};
var tokelau = {
	keywords: [
		"tk",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇹🇰",
	fitzpatrick_scale: false,
	category: "flags"
};
var tonga = {
	keywords: [
		"to",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇹🇴",
	fitzpatrick_scale: false,
	category: "flags"
};
var trinidad_tobago = {
	keywords: [
		"trinidad",
		"tobago",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇹🇹",
	fitzpatrick_scale: false,
	category: "flags"
};
var tunisia = {
	keywords: [
		"tn",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇹🇳",
	fitzpatrick_scale: false,
	category: "flags"
};
var tr = {
	keywords: [
		"turkey",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇹🇷",
	fitzpatrick_scale: false,
	category: "flags"
};
var turkmenistan = {
	keywords: [
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇹🇲",
	fitzpatrick_scale: false,
	category: "flags"
};
var turks_caicos_islands = {
	keywords: [
		"turks",
		"caicos",
		"islands",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇹🇨",
	fitzpatrick_scale: false,
	category: "flags"
};
var tuvalu = {
	keywords: [
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇹🇻",
	fitzpatrick_scale: false,
	category: "flags"
};
var uganda = {
	keywords: [
		"ug",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇺🇬",
	fitzpatrick_scale: false,
	category: "flags"
};
var ukraine = {
	keywords: [
		"ua",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇺🇦",
	fitzpatrick_scale: false,
	category: "flags"
};
var united_arab_emirates = {
	keywords: [
		"united",
		"arab",
		"emirates",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇦🇪",
	fitzpatrick_scale: false,
	category: "flags"
};
var uk = {
	keywords: [
		"united",
		"kingdom",
		"great",
		"britain",
		"northern",
		"ireland",
		"flag",
		"nation",
		"country",
		"banner",
		"british",
		"UK",
		"english",
		"england",
		"union jack"
	],
	char: "🇬🇧",
	fitzpatrick_scale: false,
	category: "flags"
};
var england = {
	keywords: [
		"flag",
		"english"
	],
	char: "🏴󠁧󠁢󠁥󠁮󠁧󠁿",
	fitzpatrick_scale: false,
	category: "flags"
};
var scotland = {
	keywords: [
		"flag",
		"scottish"
	],
	char: "🏴󠁧󠁢󠁳󠁣󠁴󠁿",
	fitzpatrick_scale: false,
	category: "flags"
};
var wales = {
	keywords: [
		"flag",
		"welsh"
	],
	char: "🏴󠁧󠁢󠁷󠁬󠁳󠁿",
	fitzpatrick_scale: false,
	category: "flags"
};
var us = {
	keywords: [
		"united",
		"states",
		"america",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇺🇸",
	fitzpatrick_scale: false,
	category: "flags"
};
var us_virgin_islands = {
	keywords: [
		"virgin",
		"islands",
		"us",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇻🇮",
	fitzpatrick_scale: false,
	category: "flags"
};
var uruguay = {
	keywords: [
		"uy",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇺🇾",
	fitzpatrick_scale: false,
	category: "flags"
};
var uzbekistan = {
	keywords: [
		"uz",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇺🇿",
	fitzpatrick_scale: false,
	category: "flags"
};
var vanuatu = {
	keywords: [
		"vu",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇻🇺",
	fitzpatrick_scale: false,
	category: "flags"
};
var vatican_city = {
	keywords: [
		"vatican",
		"city",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇻🇦",
	fitzpatrick_scale: false,
	category: "flags"
};
var venezuela = {
	keywords: [
		"ve",
		"bolivarian",
		"republic",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇻🇪",
	fitzpatrick_scale: false,
	category: "flags"
};
var vietnam = {
	keywords: [
		"viet",
		"nam",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇻🇳",
	fitzpatrick_scale: false,
	category: "flags"
};
var wallis_futuna = {
	keywords: [
		"wallis",
		"futuna",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇼🇫",
	fitzpatrick_scale: false,
	category: "flags"
};
var western_sahara = {
	keywords: [
		"western",
		"sahara",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇪🇭",
	fitzpatrick_scale: false,
	category: "flags"
};
var yemen = {
	keywords: [
		"ye",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇾🇪",
	fitzpatrick_scale: false,
	category: "flags"
};
var zambia = {
	keywords: [
		"zm",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇿🇲",
	fitzpatrick_scale: false,
	category: "flags"
};
var zimbabwe = {
	keywords: [
		"zw",
		"flag",
		"nation",
		"country",
		"banner"
	],
	char: "🇿🇼",
	fitzpatrick_scale: false,
	category: "flags"
};
var united_nations = {
	keywords: [
		"un",
		"flag",
		"banner"
	],
	char: "🇺🇳",
	fitzpatrick_scale: false,
	category: "flags"
};
var pirate_flag = {
	keywords: [
		"skull",
		"crossbones",
		"flag",
		"banner"
	],
	char: "🏴‍☠️",
	fitzpatrick_scale: false,
	category: "flags"
};
var require$$0$2 = {
	"100": {
	keywords: [
		"score",
		"perfect",
		"numbers",
		"century",
		"exam",
		"quiz",
		"test",
		"pass",
		"hundred"
	],
	char: "💯",
	fitzpatrick_scale: false,
	category: "symbols"
},
	"1234": {
	keywords: [
		"numbers",
		"blue-square"
	],
	char: "🔢",
	fitzpatrick_scale: false,
	category: "symbols"
},
	grinning: grinning,
	grimacing: grimacing,
	grin: grin,
	joy: joy,
	rofl: rofl,
	partying: partying,
	smiley: smiley,
	smile: smile$1,
	sweat_smile: sweat_smile,
	laughing: laughing,
	innocent: innocent,
	wink: wink,
	blush: blush,
	slightly_smiling_face: slightly_smiling_face,
	upside_down_face: upside_down_face,
	relaxed: relaxed,
	yum: yum,
	relieved: relieved,
	heart_eyes: heart_eyes,
	smiling_face_with_three_hearts: smiling_face_with_three_hearts,
	kissing_heart: kissing_heart,
	kissing: kissing,
	kissing_smiling_eyes: kissing_smiling_eyes,
	kissing_closed_eyes: kissing_closed_eyes,
	stuck_out_tongue_winking_eye: stuck_out_tongue_winking_eye,
	zany: zany,
	raised_eyebrow: raised_eyebrow,
	monocle: monocle,
	stuck_out_tongue_closed_eyes: stuck_out_tongue_closed_eyes,
	stuck_out_tongue: stuck_out_tongue,
	money_mouth_face: money_mouth_face,
	nerd_face: nerd_face,
	sunglasses: sunglasses,
	star_struck: star_struck,
	clown_face: clown_face,
	cowboy_hat_face: cowboy_hat_face,
	hugs: hugs,
	smirk: smirk,
	no_mouth: no_mouth,
	neutral_face: neutral_face,
	expressionless: expressionless,
	unamused: unamused,
	roll_eyes: roll_eyes,
	thinking: thinking,
	lying_face: lying_face,
	hand_over_mouth: hand_over_mouth,
	shushing: shushing,
	symbols_over_mouth: symbols_over_mouth,
	exploding_head: exploding_head,
	flushed: flushed,
	disappointed: disappointed,
	worried: worried,
	angry: angry,
	rage: rage,
	pensive: pensive,
	confused: confused,
	slightly_frowning_face: slightly_frowning_face,
	frowning_face: frowning_face,
	persevere: persevere,
	confounded: confounded,
	tired_face: tired_face,
	weary: weary,
	pleading: pleading,
	triumph: triumph,
	open_mouth: open_mouth,
	scream: scream,
	fearful: fearful,
	cold_sweat: cold_sweat,
	hushed: hushed,
	frowning: frowning,
	anguished: anguished,
	cry: cry,
	disappointed_relieved: disappointed_relieved,
	drooling_face: drooling_face,
	sleepy: sleepy,
	sweat: sweat,
	hot: hot,
	cold: cold,
	sob: sob,
	dizzy_face: dizzy_face,
	astonished: astonished,
	zipper_mouth_face: zipper_mouth_face,
	nauseated_face: nauseated_face,
	sneezing_face: sneezing_face,
	vomiting: vomiting,
	mask: mask,
	face_with_thermometer: face_with_thermometer,
	face_with_head_bandage: face_with_head_bandage,
	woozy: woozy,
	sleeping: sleeping,
	zzz: zzz,
	poop: poop,
	smiling_imp: smiling_imp,
	imp: imp,
	japanese_ogre: japanese_ogre,
	japanese_goblin: japanese_goblin,
	skull: skull,
	ghost: ghost,
	alien: alien,
	robot: robot,
	smiley_cat: smiley_cat,
	smile_cat: smile_cat,
	joy_cat: joy_cat,
	heart_eyes_cat: heart_eyes_cat,
	smirk_cat: smirk_cat,
	kissing_cat: kissing_cat,
	scream_cat: scream_cat,
	crying_cat_face: crying_cat_face,
	pouting_cat: pouting_cat,
	palms_up: palms_up,
	raised_hands: raised_hands,
	clap: clap,
	wave: wave,
	call_me_hand: call_me_hand,
	"+1": {
	keywords: [
		"thumbsup",
		"yes",
		"awesome",
		"good",
		"agree",
		"accept",
		"cool",
		"hand",
		"like"
	],
	char: "👍",
	fitzpatrick_scale: true,
	category: "people"
},
	"-1": {
	keywords: [
		"thumbsdown",
		"no",
		"dislike",
		"hand"
	],
	char: "👎",
	fitzpatrick_scale: true,
	category: "people"
},
	facepunch: facepunch,
	fist: fist,
	fist_left: fist_left,
	fist_right: fist_right,
	v: v,
	ok_hand: ok_hand,
	raised_hand: raised_hand,
	raised_back_of_hand: raised_back_of_hand,
	open_hands: open_hands,
	muscle: muscle,
	pray: pray,
	foot: foot,
	leg: leg$1,
	handshake: handshake,
	point_up: point_up,
	point_up_2: point_up_2,
	point_down: point_down,
	point_left: point_left,
	point_right: point_right,
	fu: fu,
	raised_hand_with_fingers_splayed: raised_hand_with_fingers_splayed,
	love_you: love_you,
	metal: metal,
	crossed_fingers: crossed_fingers,
	vulcan_salute: vulcan_salute,
	writing_hand: writing_hand,
	selfie: selfie,
	nail_care: nail_care,
	lips: lips,
	tooth: tooth,
	tongue: tongue,
	ear: ear,
	nose: nose,
	eye: eye,
	eyes: eyes,
	brain: brain,
	bust_in_silhouette: bust_in_silhouette,
	busts_in_silhouette: busts_in_silhouette,
	speaking_head: speaking_head,
	baby: baby,
	child: child,
	boy: boy,
	girl: girl,
	adult: adult,
	man: man,
	woman: woman,
	blonde_woman: blonde_woman,
	blonde_man: blonde_man,
	bearded_person: bearded_person,
	older_adult: older_adult,
	older_man: older_man,
	older_woman: older_woman,
	man_with_gua_pi_mao: man_with_gua_pi_mao,
	woman_with_headscarf: woman_with_headscarf,
	woman_with_turban: woman_with_turban,
	man_with_turban: man_with_turban,
	policewoman: policewoman,
	policeman: policeman,
	construction_worker_woman: construction_worker_woman,
	construction_worker_man: construction_worker_man,
	guardswoman: guardswoman,
	guardsman: guardsman,
	female_detective: female_detective,
	male_detective: male_detective,
	woman_health_worker: woman_health_worker,
	man_health_worker: man_health_worker,
	woman_farmer: woman_farmer,
	man_farmer: man_farmer,
	woman_cook: woman_cook,
	man_cook: man_cook,
	woman_student: woman_student,
	man_student: man_student,
	woman_singer: woman_singer,
	man_singer: man_singer,
	woman_teacher: woman_teacher,
	man_teacher: man_teacher,
	woman_factory_worker: woman_factory_worker,
	man_factory_worker: man_factory_worker,
	woman_technologist: woman_technologist,
	man_technologist: man_technologist,
	woman_office_worker: woman_office_worker,
	man_office_worker: man_office_worker,
	woman_mechanic: woman_mechanic,
	man_mechanic: man_mechanic,
	woman_scientist: woman_scientist,
	man_scientist: man_scientist,
	woman_artist: woman_artist,
	man_artist: man_artist,
	woman_firefighter: woman_firefighter,
	man_firefighter: man_firefighter,
	woman_pilot: woman_pilot,
	man_pilot: man_pilot,
	woman_astronaut: woman_astronaut,
	man_astronaut: man_astronaut,
	woman_judge: woman_judge,
	man_judge: man_judge,
	woman_superhero: woman_superhero,
	man_superhero: man_superhero,
	woman_supervillain: woman_supervillain,
	man_supervillain: man_supervillain,
	mrs_claus: mrs_claus,
	santa: santa,
	sorceress: sorceress,
	wizard: wizard,
	woman_elf: woman_elf,
	man_elf: man_elf,
	woman_vampire: woman_vampire,
	man_vampire: man_vampire,
	woman_zombie: woman_zombie,
	man_zombie: man_zombie,
	woman_genie: woman_genie,
	man_genie: man_genie,
	mermaid: mermaid,
	merman: merman,
	woman_fairy: woman_fairy,
	man_fairy: man_fairy,
	angel: angel,
	pregnant_woman: pregnant_woman,
	breastfeeding: breastfeeding,
	princess: princess,
	prince: prince,
	bride_with_veil: bride_with_veil,
	man_in_tuxedo: man_in_tuxedo,
	running_woman: running_woman,
	running_man: running_man,
	walking_woman: walking_woman,
	walking_man: walking_man,
	dancer: dancer,
	man_dancing: man_dancing,
	dancing_women: dancing_women,
	dancing_men: dancing_men,
	couple: couple,
	two_men_holding_hands: two_men_holding_hands,
	two_women_holding_hands: two_women_holding_hands,
	bowing_woman: bowing_woman,
	bowing_man: bowing_man,
	man_facepalming: man_facepalming,
	woman_facepalming: woman_facepalming,
	woman_shrugging: woman_shrugging,
	man_shrugging: man_shrugging,
	tipping_hand_woman: tipping_hand_woman,
	tipping_hand_man: tipping_hand_man,
	no_good_woman: no_good_woman,
	no_good_man: no_good_man,
	ok_woman: ok_woman,
	ok_man: ok_man,
	raising_hand_woman: raising_hand_woman,
	raising_hand_man: raising_hand_man,
	pouting_woman: pouting_woman,
	pouting_man: pouting_man,
	frowning_woman: frowning_woman,
	frowning_man: frowning_man,
	haircut_woman: haircut_woman,
	haircut_man: haircut_man,
	massage_woman: massage_woman,
	massage_man: massage_man,
	woman_in_steamy_room: woman_in_steamy_room,
	man_in_steamy_room: man_in_steamy_room,
	couple_with_heart_woman_man: couple_with_heart_woman_man,
	couple_with_heart_woman_woman: couple_with_heart_woman_woman,
	couple_with_heart_man_man: couple_with_heart_man_man,
	couplekiss_man_woman: couplekiss_man_woman,
	couplekiss_woman_woman: couplekiss_woman_woman,
	couplekiss_man_man: couplekiss_man_man,
	family_man_woman_boy: family_man_woman_boy,
	family_man_woman_girl: family_man_woman_girl,
	family_man_woman_girl_boy: family_man_woman_girl_boy,
	family_man_woman_boy_boy: family_man_woman_boy_boy,
	family_man_woman_girl_girl: family_man_woman_girl_girl,
	family_woman_woman_boy: family_woman_woman_boy,
	family_woman_woman_girl: family_woman_woman_girl,
	family_woman_woman_girl_boy: family_woman_woman_girl_boy,
	family_woman_woman_boy_boy: family_woman_woman_boy_boy,
	family_woman_woman_girl_girl: family_woman_woman_girl_girl,
	family_man_man_boy: family_man_man_boy,
	family_man_man_girl: family_man_man_girl,
	family_man_man_girl_boy: family_man_man_girl_boy,
	family_man_man_boy_boy: family_man_man_boy_boy,
	family_man_man_girl_girl: family_man_man_girl_girl,
	family_woman_boy: family_woman_boy,
	family_woman_girl: family_woman_girl,
	family_woman_girl_boy: family_woman_girl_boy,
	family_woman_boy_boy: family_woman_boy_boy,
	family_woman_girl_girl: family_woman_girl_girl,
	family_man_boy: family_man_boy,
	family_man_girl: family_man_girl,
	family_man_girl_boy: family_man_girl_boy,
	family_man_boy_boy: family_man_boy_boy,
	family_man_girl_girl: family_man_girl_girl,
	yarn: yarn,
	thread: thread,
	coat: coat,
	labcoat: labcoat,
	womans_clothes: womans_clothes,
	tshirt: tshirt,
	jeans: jeans,
	necktie: necktie,
	dress: dress,
	bikini: bikini,
	kimono: kimono,
	lipstick: lipstick,
	kiss: kiss,
	footprints: footprints,
	flat_shoe: flat_shoe,
	high_heel: high_heel,
	sandal: sandal,
	boot: boot,
	mans_shoe: mans_shoe,
	athletic_shoe: athletic_shoe,
	hiking_boot: hiking_boot,
	socks: socks,
	gloves: gloves,
	scarf: scarf,
	womans_hat: womans_hat,
	tophat: tophat,
	billed_hat: billed_hat,
	rescue_worker_helmet: rescue_worker_helmet,
	mortar_board: mortar_board,
	crown: crown,
	school_satchel: school_satchel,
	luggage: luggage,
	pouch: pouch,
	purse: purse,
	handbag: handbag,
	briefcase: briefcase,
	eyeglasses: eyeglasses,
	dark_sunglasses: dark_sunglasses,
	goggles: goggles,
	ring: ring$1,
	closed_umbrella: closed_umbrella,
	dog: dog,
	cat: cat,
	mouse: mouse,
	hamster: hamster,
	rabbit: rabbit,
	fox_face: fox_face,
	bear: bear,
	panda_face: panda_face,
	koala: koala,
	tiger: tiger,
	lion: lion,
	cow: cow,
	pig: pig,
	pig_nose: pig_nose,
	frog: frog,
	squid: squid,
	octopus: octopus,
	shrimp: shrimp,
	monkey_face: monkey_face,
	gorilla: gorilla,
	see_no_evil: see_no_evil,
	hear_no_evil: hear_no_evil,
	speak_no_evil: speak_no_evil,
	monkey: monkey,
	chicken: chicken,
	penguin: penguin,
	bird: bird,
	baby_chick: baby_chick,
	hatching_chick: hatching_chick,
	hatched_chick: hatched_chick,
	duck: duck,
	eagle: eagle,
	owl: owl,
	bat: bat,
	wolf: wolf,
	boar: boar,
	horse: horse,
	unicorn: unicorn,
	honeybee: honeybee,
	bug: bug,
	butterfly: butterfly,
	snail: snail,
	beetle: beetle,
	ant: ant,
	grasshopper: grasshopper,
	spider: spider,
	scorpion: scorpion,
	crab: crab,
	snake: snake,
	lizard: lizard,
	"t-rex": {
	keywords: [
		"animal",
		"nature",
		"dinosaur",
		"tyrannosaurus",
		"extinct"
	],
	char: "🦖",
	fitzpatrick_scale: false,
	category: "animals_and_nature"
},
	sauropod: sauropod,
	turtle: turtle,
	tropical_fish: tropical_fish,
	fish: fish,
	blowfish: blowfish,
	dolphin: dolphin,
	shark: shark,
	whale: whale,
	whale2: whale2,
	crocodile: crocodile,
	leopard: leopard,
	zebra: zebra,
	tiger2: tiger2,
	water_buffalo: water_buffalo,
	ox: ox,
	cow2: cow2,
	deer: deer,
	dromedary_camel: dromedary_camel,
	camel: camel,
	giraffe: giraffe,
	elephant: elephant,
	rhinoceros: rhinoceros,
	goat: goat,
	ram: ram,
	sheep: sheep,
	racehorse: racehorse,
	pig2: pig2,
	rat: rat,
	mouse2: mouse2,
	rooster: rooster,
	turkey: turkey,
	dove: dove,
	dog2: dog2,
	poodle: poodle,
	cat2: cat2,
	rabbit2: rabbit2,
	chipmunk: chipmunk,
	hedgehog: hedgehog,
	raccoon: raccoon,
	llama: llama,
	hippopotamus: hippopotamus,
	kangaroo: kangaroo,
	badger: badger,
	swan: swan,
	peacock: peacock,
	parrot: parrot,
	lobster: lobster,
	mosquito: mosquito,
	paw_prints: paw_prints,
	dragon: dragon,
	dragon_face: dragon_face,
	cactus: cactus,
	christmas_tree: christmas_tree,
	evergreen_tree: evergreen_tree,
	deciduous_tree: deciduous_tree,
	palm_tree: palm_tree,
	seedling: seedling,
	herb: herb,
	shamrock: shamrock,
	four_leaf_clover: four_leaf_clover,
	bamboo: bamboo,
	tanabata_tree: tanabata_tree,
	leaves: leaves,
	fallen_leaf: fallen_leaf,
	maple_leaf: maple_leaf,
	ear_of_rice: ear_of_rice,
	hibiscus: hibiscus,
	sunflower: sunflower,
	rose: rose,
	wilted_flower: wilted_flower,
	tulip: tulip,
	blossom: blossom,
	cherry_blossom: cherry_blossom,
	bouquet: bouquet,
	mushroom: mushroom,
	chestnut: chestnut,
	jack_o_lantern: jack_o_lantern,
	shell: shell,
	spider_web: spider_web,
	earth_americas: earth_americas,
	earth_africa: earth_africa,
	earth_asia: earth_asia,
	full_moon: full_moon,
	waning_gibbous_moon: waning_gibbous_moon,
	last_quarter_moon: last_quarter_moon,
	waning_crescent_moon: waning_crescent_moon,
	new_moon: new_moon,
	waxing_crescent_moon: waxing_crescent_moon,
	first_quarter_moon: first_quarter_moon,
	waxing_gibbous_moon: waxing_gibbous_moon,
	new_moon_with_face: new_moon_with_face,
	full_moon_with_face: full_moon_with_face,
	first_quarter_moon_with_face: first_quarter_moon_with_face,
	last_quarter_moon_with_face: last_quarter_moon_with_face,
	sun_with_face: sun_with_face,
	crescent_moon: crescent_moon,
	star: star$1,
	star2: star2,
	dizzy: dizzy,
	sparkles: sparkles,
	comet: comet,
	sunny: sunny,
	sun_behind_small_cloud: sun_behind_small_cloud,
	partly_sunny: partly_sunny,
	sun_behind_large_cloud: sun_behind_large_cloud,
	sun_behind_rain_cloud: sun_behind_rain_cloud,
	cloud: cloud,
	cloud_with_rain: cloud_with_rain,
	cloud_with_lightning_and_rain: cloud_with_lightning_and_rain,
	cloud_with_lightning: cloud_with_lightning,
	zap: zap,
	fire: fire,
	boom: boom,
	snowflake: snowflake,
	cloud_with_snow: cloud_with_snow,
	snowman: snowman,
	snowman_with_snow: snowman_with_snow,
	wind_face: wind_face,
	dash: dash$1,
	tornado: tornado,
	fog: fog,
	open_umbrella: open_umbrella,
	umbrella: umbrella,
	droplet: droplet,
	sweat_drops: sweat_drops,
	ocean: ocean,
	green_apple: green_apple,
	apple: apple,
	pear: pear,
	tangerine: tangerine,
	lemon: lemon,
	banana: banana,
	watermelon: watermelon,
	grapes: grapes,
	strawberry: strawberry,
	melon: melon,
	cherries: cherries,
	peach: peach,
	pineapple: pineapple,
	coconut: coconut,
	kiwi_fruit: kiwi_fruit,
	mango: mango,
	avocado: avocado,
	broccoli: broccoli,
	tomato: tomato,
	eggplant: eggplant,
	cucumber: cucumber,
	carrot: carrot,
	hot_pepper: hot_pepper,
	potato: potato,
	corn: corn,
	leafy_greens: leafy_greens,
	sweet_potato: sweet_potato,
	peanuts: peanuts,
	honey_pot: honey_pot,
	croissant: croissant,
	bread: bread,
	baguette_bread: baguette_bread,
	bagel: bagel,
	pretzel: pretzel,
	cheese: cheese,
	egg: egg,
	bacon: bacon,
	steak: steak,
	pancakes: pancakes,
	poultry_leg: poultry_leg,
	meat_on_bone: meat_on_bone,
	bone: bone,
	fried_shrimp: fried_shrimp,
	fried_egg: fried_egg,
	hamburger: hamburger,
	fries: fries,
	stuffed_flatbread: stuffed_flatbread,
	hotdog: hotdog,
	pizza: pizza,
	sandwich: sandwich,
	canned_food: canned_food,
	spaghetti: spaghetti,
	taco: taco,
	burrito: burrito,
	green_salad: green_salad,
	shallow_pan_of_food: shallow_pan_of_food,
	ramen: ramen,
	stew: stew,
	fish_cake: fish_cake,
	fortune_cookie: fortune_cookie,
	sushi: sushi,
	bento: bento,
	curry: curry,
	rice_ball: rice_ball,
	rice: rice,
	rice_cracker: rice_cracker,
	oden: oden,
	dango: dango,
	shaved_ice: shaved_ice,
	ice_cream: ice_cream,
	icecream: icecream,
	pie: pie,
	cake: cake,
	cupcake: cupcake,
	moon_cake: moon_cake,
	birthday: birthday,
	custard: custard,
	candy: candy,
	lollipop: lollipop,
	chocolate_bar: chocolate_bar,
	popcorn: popcorn,
	dumpling: dumpling,
	doughnut: doughnut,
	cookie: cookie,
	milk_glass: milk_glass,
	beer: beer,
	beers: beers,
	clinking_glasses: clinking_glasses,
	wine_glass: wine_glass,
	tumbler_glass: tumbler_glass,
	cocktail: cocktail,
	tropical_drink: tropical_drink,
	champagne: champagne,
	sake: sake,
	tea: tea,
	cup_with_straw: cup_with_straw,
	coffee: coffee,
	baby_bottle: baby_bottle,
	salt: salt,
	spoon: spoon,
	fork_and_knife: fork_and_knife,
	plate_with_cutlery: plate_with_cutlery,
	bowl_with_spoon: bowl_with_spoon,
	takeout_box: takeout_box,
	chopsticks: chopsticks,
	soccer: soccer,
	basketball: basketball,
	football: football,
	baseball: baseball,
	softball: softball,
	tennis: tennis,
	volleyball: volleyball,
	rugby_football: rugby_football,
	flying_disc: flying_disc,
	"8ball": {
	keywords: [
		"pool",
		"hobby",
		"game",
		"luck",
		"magic"
	],
	char: "🎱",
	fitzpatrick_scale: false,
	category: "activity"
},
	golf: golf,
	golfing_woman: golfing_woman,
	golfing_man: golfing_man,
	ping_pong: ping_pong,
	badminton: badminton,
	goal_net: goal_net,
	ice_hockey: ice_hockey,
	field_hockey: field_hockey,
	lacrosse: lacrosse,
	cricket: cricket,
	ski: ski,
	skier: skier,
	snowboarder: snowboarder,
	person_fencing: person_fencing,
	women_wrestling: women_wrestling,
	men_wrestling: men_wrestling,
	woman_cartwheeling: woman_cartwheeling,
	man_cartwheeling: man_cartwheeling,
	woman_playing_handball: woman_playing_handball,
	man_playing_handball: man_playing_handball,
	ice_skate: ice_skate,
	curling_stone: curling_stone,
	skateboard: skateboard,
	sled: sled,
	bow_and_arrow: bow_and_arrow,
	fishing_pole_and_fish: fishing_pole_and_fish,
	boxing_glove: boxing_glove,
	martial_arts_uniform: martial_arts_uniform,
	rowing_woman: rowing_woman,
	rowing_man: rowing_man,
	climbing_woman: climbing_woman,
	climbing_man: climbing_man,
	swimming_woman: swimming_woman,
	swimming_man: swimming_man,
	woman_playing_water_polo: woman_playing_water_polo,
	man_playing_water_polo: man_playing_water_polo,
	woman_in_lotus_position: woman_in_lotus_position,
	man_in_lotus_position: man_in_lotus_position,
	surfing_woman: surfing_woman,
	surfing_man: surfing_man,
	bath: bath,
	basketball_woman: basketball_woman,
	basketball_man: basketball_man,
	weight_lifting_woman: weight_lifting_woman,
	weight_lifting_man: weight_lifting_man,
	biking_woman: biking_woman,
	biking_man: biking_man,
	mountain_biking_woman: mountain_biking_woman,
	mountain_biking_man: mountain_biking_man,
	horse_racing: horse_racing,
	business_suit_levitating: business_suit_levitating,
	trophy: trophy,
	running_shirt_with_sash: running_shirt_with_sash,
	medal_sports: medal_sports,
	medal_military: medal_military,
	"1st_place_medal": {
	keywords: [
		"award",
		"winning",
		"first"
	],
	char: "🥇",
	fitzpatrick_scale: false,
	category: "activity"
},
	"2nd_place_medal": {
	keywords: [
		"award",
		"second"
	],
	char: "🥈",
	fitzpatrick_scale: false,
	category: "activity"
},
	"3rd_place_medal": {
	keywords: [
		"award",
		"third"
	],
	char: "🥉",
	fitzpatrick_scale: false,
	category: "activity"
},
	reminder_ribbon: reminder_ribbon,
	rosette: rosette,
	ticket: ticket,
	tickets: tickets,
	performing_arts: performing_arts,
	art: art,
	circus_tent: circus_tent,
	woman_juggling: woman_juggling,
	man_juggling: man_juggling,
	microphone: microphone,
	headphones: headphones,
	musical_score: musical_score,
	musical_keyboard: musical_keyboard,
	drum: drum,
	saxophone: saxophone,
	trumpet: trumpet,
	guitar: guitar,
	violin: violin,
	clapper: clapper,
	video_game: video_game,
	space_invader: space_invader,
	dart: dart,
	game_die: game_die,
	chess_pawn: chess_pawn,
	slot_machine: slot_machine,
	jigsaw: jigsaw,
	bowling: bowling,
	red_car: red_car,
	taxi: taxi,
	blue_car: blue_car,
	bus: bus,
	trolleybus: trolleybus,
	racing_car: racing_car,
	police_car: police_car,
	ambulance: ambulance,
	fire_engine: fire_engine,
	minibus: minibus,
	truck: truck,
	articulated_lorry: articulated_lorry,
	tractor: tractor,
	kick_scooter: kick_scooter,
	motorcycle: motorcycle,
	bike: bike,
	motor_scooter: motor_scooter,
	rotating_light: rotating_light,
	oncoming_police_car: oncoming_police_car,
	oncoming_bus: oncoming_bus,
	oncoming_automobile: oncoming_automobile,
	oncoming_taxi: oncoming_taxi,
	aerial_tramway: aerial_tramway,
	mountain_cableway: mountain_cableway,
	suspension_railway: suspension_railway,
	railway_car: railway_car,
	train: train,
	monorail: monorail,
	bullettrain_side: bullettrain_side,
	bullettrain_front: bullettrain_front,
	light_rail: light_rail,
	mountain_railway: mountain_railway,
	steam_locomotive: steam_locomotive,
	train2: train2,
	metro: metro,
	tram: tram,
	station: station,
	flying_saucer: flying_saucer,
	helicopter: helicopter,
	small_airplane: small_airplane,
	airplane: airplane,
	flight_departure: flight_departure,
	flight_arrival: flight_arrival,
	sailboat: sailboat,
	motor_boat: motor_boat,
	speedboat: speedboat,
	ferry: ferry,
	passenger_ship: passenger_ship,
	rocket: rocket,
	artificial_satellite: artificial_satellite,
	seat: seat,
	canoe: canoe,
	anchor: anchor,
	construction: construction,
	fuelpump: fuelpump,
	busstop: busstop,
	vertical_traffic_light: vertical_traffic_light,
	traffic_light: traffic_light,
	checkered_flag: checkered_flag,
	ship: ship,
	ferris_wheel: ferris_wheel,
	roller_coaster: roller_coaster,
	carousel_horse: carousel_horse,
	building_construction: building_construction,
	foggy: foggy,
	tokyo_tower: tokyo_tower,
	factory: factory,
	fountain: fountain,
	rice_scene: rice_scene,
	mountain: mountain,
	mountain_snow: mountain_snow,
	mount_fuji: mount_fuji,
	volcano: volcano,
	japan: japan,
	camping: camping,
	tent: tent,
	national_park: national_park,
	motorway: motorway,
	railway_track: railway_track,
	sunrise: sunrise,
	sunrise_over_mountains: sunrise_over_mountains,
	desert: desert,
	beach_umbrella: beach_umbrella,
	desert_island: desert_island,
	city_sunrise: city_sunrise,
	city_sunset: city_sunset,
	cityscape: cityscape,
	night_with_stars: night_with_stars,
	bridge_at_night: bridge_at_night,
	milky_way: milky_way,
	stars: stars,
	sparkler: sparkler,
	fireworks: fireworks,
	rainbow: rainbow,
	houses: houses,
	european_castle: european_castle,
	japanese_castle: japanese_castle,
	stadium: stadium,
	statue_of_liberty: statue_of_liberty,
	house: house,
	house_with_garden: house_with_garden,
	derelict_house: derelict_house,
	office: office,
	department_store: department_store,
	post_office: post_office,
	european_post_office: european_post_office,
	hospital: hospital,
	bank: bank,
	hotel: hotel,
	convenience_store: convenience_store,
	school: school,
	love_hotel: love_hotel,
	wedding: wedding,
	classical_building: classical_building,
	church: church,
	mosque: mosque,
	synagogue: synagogue,
	kaaba: kaaba,
	shinto_shrine: shinto_shrine,
	watch: watch,
	iphone: iphone,
	calling: calling,
	computer: computer,
	keyboard: keyboard,
	desktop_computer: desktop_computer,
	printer: printer,
	computer_mouse: computer_mouse,
	trackball: trackball,
	joystick: joystick,
	clamp: clamp,
	minidisc: minidisc,
	floppy_disk: floppy_disk,
	cd: cd,
	dvd: dvd,
	vhs: vhs,
	camera: camera,
	camera_flash: camera_flash,
	video_camera: video_camera,
	movie_camera: movie_camera,
	film_projector: film_projector,
	film_strip: film_strip,
	telephone_receiver: telephone_receiver,
	phone: phone$1,
	pager: pager,
	fax: fax,
	tv: tv,
	radio: radio,
	studio_microphone: studio_microphone,
	level_slider: level_slider,
	control_knobs: control_knobs,
	compass: compass,
	stopwatch: stopwatch,
	timer_clock: timer_clock,
	alarm_clock: alarm_clock,
	mantelpiece_clock: mantelpiece_clock,
	hourglass_flowing_sand: hourglass_flowing_sand,
	hourglass: hourglass,
	satellite: satellite,
	battery: battery,
	electric_plug: electric_plug,
	bulb: bulb,
	flashlight: flashlight,
	candle: candle,
	fire_extinguisher: fire_extinguisher,
	wastebasket: wastebasket,
	oil_drum: oil_drum,
	money_with_wings: money_with_wings,
	dollar: dollar$1,
	yen: yen$1,
	euro: euro$1,
	pound: pound$1,
	moneybag: moneybag,
	credit_card: credit_card,
	gem: gem,
	balance_scale: balance_scale,
	toolbox: toolbox,
	wrench: wrench,
	hammer: hammer,
	hammer_and_pick: hammer_and_pick,
	hammer_and_wrench: hammer_and_wrench,
	pick: pick,
	nut_and_bolt: nut_and_bolt,
	gear: gear,
	brick: brick,
	chains: chains,
	magnet: magnet,
	gun: gun,
	bomb: bomb,
	firecracker: firecracker,
	hocho: hocho,
	dagger: dagger$1,
	crossed_swords: crossed_swords,
	shield: shield,
	smoking: smoking,
	skull_and_crossbones: skull_and_crossbones,
	coffin: coffin,
	funeral_urn: funeral_urn,
	amphora: amphora,
	crystal_ball: crystal_ball,
	prayer_beads: prayer_beads,
	nazar_amulet: nazar_amulet,
	barber: barber,
	alembic: alembic,
	telescope: telescope,
	microscope: microscope,
	hole: hole,
	pill: pill,
	syringe: syringe,
	dna: dna,
	microbe: microbe,
	petri_dish: petri_dish,
	test_tube: test_tube,
	thermometer: thermometer,
	broom: broom,
	basket: basket,
	toilet_paper: toilet_paper,
	label: label,
	bookmark: bookmark,
	toilet: toilet,
	shower: shower,
	bathtub: bathtub,
	soap: soap,
	sponge: sponge,
	lotion_bottle: lotion_bottle,
	key: key,
	old_key: old_key,
	couch_and_lamp: couch_and_lamp,
	sleeping_bed: sleeping_bed,
	bed: bed,
	door: door,
	bellhop_bell: bellhop_bell,
	teddy_bear: teddy_bear,
	framed_picture: framed_picture,
	world_map: world_map,
	parasol_on_ground: parasol_on_ground,
	moyai: moyai,
	shopping: shopping,
	shopping_cart: shopping_cart,
	balloon: balloon,
	flags: flags,
	ribbon: ribbon,
	gift: gift,
	confetti_ball: confetti_ball,
	tada: tada,
	dolls: dolls,
	wind_chime: wind_chime,
	crossed_flags: crossed_flags,
	izakaya_lantern: izakaya_lantern,
	red_envelope: red_envelope,
	email: email,
	envelope_with_arrow: envelope_with_arrow,
	incoming_envelope: incoming_envelope,
	"e-mail": {
	keywords: [
		"communication",
		"inbox"
	],
	char: "📧",
	fitzpatrick_scale: false,
	category: "objects"
},
	love_letter: love_letter,
	postbox: postbox,
	mailbox_closed: mailbox_closed,
	mailbox: mailbox,
	mailbox_with_mail: mailbox_with_mail,
	mailbox_with_no_mail: mailbox_with_no_mail,
	"package": {
	keywords: [
		"mail",
		"gift",
		"cardboard",
		"box",
		"moving"
	],
	char: "📦",
	fitzpatrick_scale: false,
	category: "objects"
},
	postal_horn: postal_horn,
	inbox_tray: inbox_tray,
	outbox_tray: outbox_tray,
	scroll: scroll,
	page_with_curl: page_with_curl,
	bookmark_tabs: bookmark_tabs,
	receipt: receipt,
	bar_chart: bar_chart,
	chart_with_upwards_trend: chart_with_upwards_trend,
	chart_with_downwards_trend: chart_with_downwards_trend,
	page_facing_up: page_facing_up,
	date: date,
	calendar: calendar,
	spiral_calendar: spiral_calendar,
	card_index: card_index,
	card_file_box: card_file_box,
	ballot_box: ballot_box,
	file_cabinet: file_cabinet,
	clipboard: clipboard$1,
	spiral_notepad: spiral_notepad,
	file_folder: file_folder,
	open_file_folder: open_file_folder,
	card_index_dividers: card_index_dividers,
	newspaper_roll: newspaper_roll,
	newspaper: newspaper,
	notebook: notebook,
	closed_book: closed_book,
	green_book: green_book,
	blue_book: blue_book,
	orange_book: orange_book,
	notebook_with_decorative_cover: notebook_with_decorative_cover,
	ledger: ledger,
	books: books,
	open_book: open_book,
	safety_pin: safety_pin,
	link: link$2,
	paperclip: paperclip,
	paperclips: paperclips,
	scissors: scissors,
	triangular_ruler: triangular_ruler,
	straight_ruler: straight_ruler,
	abacus: abacus,
	pushpin: pushpin,
	round_pushpin: round_pushpin,
	triangular_flag_on_post: triangular_flag_on_post,
	white_flag: white_flag,
	black_flag: black_flag,
	rainbow_flag: rainbow_flag,
	closed_lock_with_key: closed_lock_with_key,
	lock: lock,
	unlock: unlock,
	lock_with_ink_pen: lock_with_ink_pen,
	pen: pen,
	fountain_pen: fountain_pen,
	black_nib: black_nib,
	memo: memo,
	pencil2: pencil2,
	crayon: crayon,
	paintbrush: paintbrush,
	mag: mag,
	mag_right: mag_right,
	heart: heart,
	orange_heart: orange_heart,
	yellow_heart: yellow_heart,
	green_heart: green_heart,
	blue_heart: blue_heart,
	purple_heart: purple_heart,
	black_heart: black_heart,
	broken_heart: broken_heart,
	heavy_heart_exclamation: heavy_heart_exclamation,
	two_hearts: two_hearts,
	revolving_hearts: revolving_hearts,
	heartbeat: heartbeat,
	heartpulse: heartpulse,
	sparkling_heart: sparkling_heart,
	cupid: cupid,
	gift_heart: gift_heart,
	heart_decoration: heart_decoration,
	peace_symbol: peace_symbol,
	latin_cross: latin_cross,
	star_and_crescent: star_and_crescent,
	om: om,
	wheel_of_dharma: wheel_of_dharma,
	star_of_david: star_of_david,
	six_pointed_star: six_pointed_star,
	menorah: menorah,
	yin_yang: yin_yang,
	orthodox_cross: orthodox_cross,
	place_of_worship: place_of_worship,
	ophiuchus: ophiuchus,
	aries: aries,
	taurus: taurus,
	gemini: gemini,
	cancer: cancer,
	leo: leo,
	virgo: virgo,
	libra: libra,
	scorpius: scorpius,
	sagittarius: sagittarius,
	capricorn: capricorn,
	aquarius: aquarius,
	pisces: pisces,
	id: id,
	atom_symbol: atom_symbol,
	u7a7a: u7a7a,
	u5272: u5272,
	radioactive: radioactive,
	biohazard: biohazard,
	mobile_phone_off: mobile_phone_off,
	vibration_mode: vibration_mode,
	u6709: u6709,
	u7121: u7121,
	u7533: u7533,
	u55b6: u55b6,
	u6708: u6708,
	eight_pointed_black_star: eight_pointed_black_star,
	vs: vs,
	accept: accept,
	white_flower: white_flower,
	ideograph_advantage: ideograph_advantage,
	secret: secret,
	congratulations: congratulations,
	u5408: u5408,
	u6e80: u6e80,
	u7981: u7981,
	a: a$1,
	b: b,
	ab: ab,
	cl: cl,
	o2: o2,
	sos: sos,
	no_entry: no_entry,
	name_badge: name_badge,
	no_entry_sign: no_entry_sign,
	x: x,
	o: o$1,
	stop_sign: stop_sign,
	anger: anger,
	hotsprings: hotsprings,
	no_pedestrians: no_pedestrians,
	do_not_litter: do_not_litter,
	no_bicycles: no_bicycles,
	"non-potable_water": {
	keywords: [
		"drink",
		"faucet",
		"tap",
		"circle"
	],
	char: "🚱",
	fitzpatrick_scale: false,
	category: "symbols"
},
	underage: underage,
	no_mobile_phones: no_mobile_phones,
	exclamation: exclamation,
	grey_exclamation: grey_exclamation,
	question: question,
	grey_question: grey_question,
	bangbang: bangbang,
	interrobang: interrobang,
	low_brightness: low_brightness,
	high_brightness: high_brightness,
	trident: trident,
	fleur_de_lis: fleur_de_lis,
	part_alternation_mark: part_alternation_mark,
	warning: warning,
	children_crossing: children_crossing,
	beginner: beginner,
	recycle: recycle,
	u6307: u6307,
	chart: chart,
	sparkle: sparkle,
	eight_spoked_asterisk: eight_spoked_asterisk,
	negative_squared_cross_mark: negative_squared_cross_mark,
	white_check_mark: white_check_mark,
	diamond_shape_with_a_dot_inside: diamond_shape_with_a_dot_inside,
	cyclone: cyclone,
	loop: loop,
	globe_with_meridians: globe_with_meridians,
	m: m,
	atm: atm,
	sa: sa,
	passport_control: passport_control,
	customs: customs,
	baggage_claim: baggage_claim,
	left_luggage: left_luggage,
	wheelchair: wheelchair,
	no_smoking: no_smoking,
	wc: wc,
	parking: parking,
	potable_water: potable_water,
	mens: mens,
	womens: womens,
	baby_symbol: baby_symbol,
	restroom: restroom,
	put_litter_in_its_place: put_litter_in_its_place,
	cinema: cinema,
	signal_strength: signal_strength,
	koko: koko,
	ng: ng,
	ok: ok,
	up: up,
	cool: cool,
	"new": {
	keywords: [
		"blue-square",
		"words",
		"start"
	],
	char: "🆕",
	fitzpatrick_scale: false,
	category: "symbols"
},
	free: free,
	zero: zero$1,
	one: one,
	two: two,
	three: three,
	four: four,
	five: five,
	six: six,
	seven: seven,
	eight: eight,
	nine: nine,
	keycap_ten: keycap_ten,
	asterisk: asterisk,
	eject_button: eject_button,
	arrow_forward: arrow_forward,
	pause_button: pause_button,
	next_track_button: next_track_button,
	stop_button: stop_button,
	record_button: record_button,
	play_or_pause_button: play_or_pause_button,
	previous_track_button: previous_track_button,
	fast_forward: fast_forward,
	rewind: rewind,
	twisted_rightwards_arrows: twisted_rightwards_arrows,
	repeat: repeat,
	repeat_one: repeat_one,
	arrow_backward: arrow_backward,
	arrow_up_small: arrow_up_small,
	arrow_down_small: arrow_down_small,
	arrow_double_up: arrow_double_up,
	arrow_double_down: arrow_double_down,
	arrow_right: arrow_right,
	arrow_left: arrow_left,
	arrow_up: arrow_up,
	arrow_down: arrow_down,
	arrow_upper_right: arrow_upper_right,
	arrow_lower_right: arrow_lower_right,
	arrow_lower_left: arrow_lower_left,
	arrow_upper_left: arrow_upper_left,
	arrow_up_down: arrow_up_down,
	left_right_arrow: left_right_arrow,
	arrows_counterclockwise: arrows_counterclockwise,
	arrow_right_hook: arrow_right_hook,
	leftwards_arrow_with_hook: leftwards_arrow_with_hook,
	arrow_heading_up: arrow_heading_up,
	arrow_heading_down: arrow_heading_down,
	hash: hash,
	information_source: information_source,
	abc: abc,
	abcd: abcd,
	capital_abcd: capital_abcd,
	symbols: symbols,
	musical_note: musical_note,
	notes: notes,
	wavy_dash: wavy_dash,
	curly_loop: curly_loop,
	heavy_check_mark: heavy_check_mark,
	arrows_clockwise: arrows_clockwise,
	heavy_plus_sign: heavy_plus_sign,
	heavy_minus_sign: heavy_minus_sign,
	heavy_division_sign: heavy_division_sign,
	heavy_multiplication_x: heavy_multiplication_x,
	infinity: infinity,
	heavy_dollar_sign: heavy_dollar_sign,
	currency_exchange: currency_exchange,
	copyright: copyright,
	registered: registered,
	tm: tm,
	end: end,
	back: back,
	on: on,
	top: top$1,
	soon: soon,
	ballot_box_with_check: ballot_box_with_check,
	radio_button: radio_button,
	white_circle: white_circle,
	black_circle: black_circle,
	red_circle: red_circle,
	large_blue_circle: large_blue_circle,
	small_orange_diamond: small_orange_diamond,
	small_blue_diamond: small_blue_diamond,
	large_orange_diamond: large_orange_diamond,
	large_blue_diamond: large_blue_diamond,
	small_red_triangle: small_red_triangle,
	black_small_square: black_small_square,
	white_small_square: white_small_square,
	black_large_square: black_large_square,
	white_large_square: white_large_square,
	small_red_triangle_down: small_red_triangle_down,
	black_medium_square: black_medium_square,
	white_medium_square: white_medium_square,
	black_medium_small_square: black_medium_small_square,
	white_medium_small_square: white_medium_small_square,
	black_square_button: black_square_button,
	white_square_button: white_square_button,
	speaker: speaker,
	sound: sound,
	loud_sound: loud_sound,
	mute: mute,
	mega: mega,
	loudspeaker: loudspeaker,
	bell: bell,
	no_bell: no_bell,
	black_joker: black_joker,
	mahjong: mahjong,
	spades: spades$1,
	clubs: clubs$1,
	hearts: hearts$1,
	diamonds: diamonds,
	flower_playing_cards: flower_playing_cards,
	thought_balloon: thought_balloon,
	right_anger_bubble: right_anger_bubble,
	speech_balloon: speech_balloon,
	left_speech_bubble: left_speech_bubble,
	clock1: clock1,
	clock2: clock2,
	clock3: clock3,
	clock4: clock4,
	clock5: clock5,
	clock6: clock6,
	clock7: clock7,
	clock8: clock8,
	clock9: clock9,
	clock10: clock10,
	clock11: clock11,
	clock12: clock12,
	clock130: clock130,
	clock230: clock230,
	clock330: clock330,
	clock430: clock430,
	clock530: clock530,
	clock630: clock630,
	clock730: clock730,
	clock830: clock830,
	clock930: clock930,
	clock1030: clock1030,
	clock1130: clock1130,
	clock1230: clock1230,
	afghanistan: afghanistan,
	aland_islands: aland_islands,
	albania: albania,
	algeria: algeria,
	american_samoa: american_samoa,
	andorra: andorra,
	angola: angola,
	anguilla: anguilla,
	antarctica: antarctica,
	antigua_barbuda: antigua_barbuda,
	argentina: argentina,
	armenia: armenia,
	aruba: aruba,
	australia: australia,
	austria: austria,
	azerbaijan: azerbaijan,
	bahamas: bahamas,
	bahrain: bahrain,
	bangladesh: bangladesh,
	barbados: barbados,
	belarus: belarus,
	belgium: belgium,
	belize: belize,
	benin: benin,
	bermuda: bermuda,
	bhutan: bhutan,
	bolivia: bolivia,
	caribbean_netherlands: caribbean_netherlands,
	bosnia_herzegovina: bosnia_herzegovina,
	botswana: botswana,
	brazil: brazil,
	british_indian_ocean_territory: british_indian_ocean_territory,
	british_virgin_islands: british_virgin_islands,
	brunei: brunei,
	bulgaria: bulgaria,
	burkina_faso: burkina_faso,
	burundi: burundi,
	cape_verde: cape_verde,
	cambodia: cambodia,
	cameroon: cameroon,
	canada: canada,
	canary_islands: canary_islands,
	cayman_islands: cayman_islands,
	central_african_republic: central_african_republic,
	chad: chad,
	chile: chile,
	cn: cn,
	christmas_island: christmas_island,
	cocos_islands: cocos_islands,
	colombia: colombia,
	comoros: comoros,
	congo_brazzaville: congo_brazzaville,
	congo_kinshasa: congo_kinshasa,
	cook_islands: cook_islands,
	costa_rica: costa_rica,
	croatia: croatia,
	cuba: cuba,
	curacao: curacao,
	cyprus: cyprus,
	czech_republic: czech_republic,
	denmark: denmark,
	djibouti: djibouti,
	dominica: dominica,
	dominican_republic: dominican_republic,
	ecuador: ecuador,
	egypt: egypt,
	el_salvador: el_salvador,
	equatorial_guinea: equatorial_guinea,
	eritrea: eritrea,
	estonia: estonia,
	ethiopia: ethiopia,
	eu: eu,
	falkland_islands: falkland_islands,
	faroe_islands: faroe_islands,
	fiji: fiji,
	finland: finland,
	fr: fr,
	french_guiana: french_guiana,
	french_polynesia: french_polynesia,
	french_southern_territories: french_southern_territories,
	gabon: gabon,
	gambia: gambia,
	georgia: georgia,
	de: de,
	ghana: ghana,
	gibraltar: gibraltar,
	greece: greece,
	greenland: greenland,
	grenada: grenada,
	guadeloupe: guadeloupe,
	guam: guam,
	guatemala: guatemala,
	guernsey: guernsey,
	guinea: guinea,
	guinea_bissau: guinea_bissau,
	guyana: guyana,
	haiti: haiti,
	honduras: honduras,
	hong_kong: hong_kong,
	hungary: hungary,
	iceland: iceland,
	india: india,
	indonesia: indonesia,
	iran: iran,
	iraq: iraq,
	ireland: ireland,
	isle_of_man: isle_of_man,
	israel: israel,
	it: it$1,
	cote_divoire: cote_divoire,
	jamaica: jamaica,
	jp: jp,
	jersey: jersey,
	jordan: jordan,
	kazakhstan: kazakhstan,
	kenya: kenya,
	kiribati: kiribati,
	kosovo: kosovo,
	kuwait: kuwait,
	kyrgyzstan: kyrgyzstan,
	laos: laos,
	latvia: latvia,
	lebanon: lebanon,
	lesotho: lesotho,
	liberia: liberia,
	libya: libya,
	liechtenstein: liechtenstein,
	lithuania: lithuania,
	luxembourg: luxembourg,
	macau: macau,
	macedonia: macedonia,
	madagascar: madagascar,
	malawi: malawi,
	malaysia: malaysia,
	maldives: maldives,
	mali: mali,
	malta: malta,
	marshall_islands: marshall_islands,
	martinique: martinique,
	mauritania: mauritania,
	mauritius: mauritius,
	mayotte: mayotte,
	mexico: mexico,
	micronesia: micronesia,
	moldova: moldova,
	monaco: monaco,
	mongolia: mongolia,
	montenegro: montenegro,
	montserrat: montserrat,
	morocco: morocco,
	mozambique: mozambique,
	myanmar: myanmar,
	namibia: namibia,
	nauru: nauru,
	nepal: nepal,
	netherlands: netherlands,
	new_caledonia: new_caledonia,
	new_zealand: new_zealand,
	nicaragua: nicaragua,
	niger: niger,
	nigeria: nigeria,
	niue: niue,
	norfolk_island: norfolk_island,
	northern_mariana_islands: northern_mariana_islands,
	north_korea: north_korea,
	norway: norway,
	oman: oman,
	pakistan: pakistan,
	palau: palau,
	palestinian_territories: palestinian_territories,
	panama: panama,
	papua_new_guinea: papua_new_guinea,
	paraguay: paraguay,
	peru: peru,
	philippines: philippines,
	pitcairn_islands: pitcairn_islands,
	poland: poland,
	portugal: portugal,
	puerto_rico: puerto_rico,
	qatar: qatar,
	reunion: reunion,
	romania: romania,
	ru: ru,
	rwanda: rwanda,
	st_barthelemy: st_barthelemy,
	st_helena: st_helena,
	st_kitts_nevis: st_kitts_nevis,
	st_lucia: st_lucia,
	st_pierre_miquelon: st_pierre_miquelon,
	st_vincent_grenadines: st_vincent_grenadines,
	samoa: samoa,
	san_marino: san_marino,
	sao_tome_principe: sao_tome_principe,
	saudi_arabia: saudi_arabia,
	senegal: senegal,
	serbia: serbia,
	seychelles: seychelles,
	sierra_leone: sierra_leone,
	singapore: singapore,
	sint_maarten: sint_maarten,
	slovakia: slovakia,
	slovenia: slovenia,
	solomon_islands: solomon_islands,
	somalia: somalia,
	south_africa: south_africa,
	south_georgia_south_sandwich_islands: south_georgia_south_sandwich_islands,
	kr: kr,
	south_sudan: south_sudan,
	es: es,
	sri_lanka: sri_lanka,
	sudan: sudan,
	suriname: suriname,
	swaziland: swaziland,
	sweden: sweden,
	switzerland: switzerland,
	syria: syria,
	taiwan: taiwan,
	tajikistan: tajikistan,
	tanzania: tanzania,
	thailand: thailand,
	timor_leste: timor_leste,
	togo: togo,
	tokelau: tokelau,
	tonga: tonga,
	trinidad_tobago: trinidad_tobago,
	tunisia: tunisia,
	tr: tr,
	turkmenistan: turkmenistan,
	turks_caicos_islands: turks_caicos_islands,
	tuvalu: tuvalu,
	uganda: uganda,
	ukraine: ukraine,
	united_arab_emirates: united_arab_emirates,
	uk: uk,
	england: england,
	scotland: scotland,
	wales: wales,
	us: us,
	us_virgin_islands: us_virgin_islands,
	uruguay: uruguay,
	uzbekistan: uzbekistan,
	vanuatu: vanuatu,
	vatican_city: vatican_city,
	venezuela: venezuela,
	vietnam: vietnam,
	wallis_futuna: wallis_futuna,
	western_sahara: western_sahara,
	yemen: yemen,
	zambia: zambia,
	zimbabwe: zimbabwe,
	united_nations: united_nations,
	pirate_flag: pirate_flag
};var require$$1 = [
	"grinning",
	"smiley",
	"smile",
	"grin",
	"laughing",
	"sweat_smile",
	"joy",
	"rofl",
	"relaxed",
	"blush",
	"innocent",
	"slightly_smiling_face",
	"upside_down_face",
	"wink",
	"relieved",
	"heart_eyes",
	"smiling_face_with_three_hearts",
	"kissing_heart",
	"kissing",
	"kissing_smiling_eyes",
	"kissing_closed_eyes",
	"yum",
	"stuck_out_tongue",
	"stuck_out_tongue_closed_eyes",
	"stuck_out_tongue_winking_eye",
	"zany",
	"raised_eyebrow",
	"monocle",
	"nerd_face",
	"sunglasses",
	"star_struck",
	"partying",
	"smirk",
	"unamused",
	"disappointed",
	"pensive",
	"worried",
	"confused",
	"slightly_frowning_face",
	"frowning_face",
	"persevere",
	"confounded",
	"tired_face",
	"weary",
	"pleading",
	"cry",
	"sob",
	"triumph",
	"angry",
	"rage",
	"symbols_over_mouth",
	"exploding_head",
	"flushed",
	"hot",
	"cold",
	"scream",
	"fearful",
	"cold_sweat",
	"disappointed_relieved",
	"sweat",
	"hugs",
	"thinking",
	"hand_over_mouth",
	"shushing",
	"lying_face",
	"no_mouth",
	"neutral_face",
	"expressionless",
	"grimacing",
	"roll_eyes",
	"hushed",
	"frowning",
	"anguished",
	"open_mouth",
	"astonished",
	"sleeping",
	"drooling_face",
	"sleepy",
	"dizzy_face",
	"zipper_mouth_face",
	"woozy",
	"nauseated_face",
	"vomiting",
	"sneezing_face",
	"mask",
	"face_with_thermometer",
	"face_with_head_bandage",
	"money_mouth_face",
	"cowboy_hat_face",
	"smiling_imp",
	"imp",
	"japanese_ogre",
	"japanese_goblin",
	"clown_face",
	"poop",
	"ghost",
	"skull",
	"skull_and_crossbones",
	"alien",
	"space_invader",
	"robot",
	"jack_o_lantern",
	"smiley_cat",
	"smile_cat",
	"joy_cat",
	"heart_eyes_cat",
	"smirk_cat",
	"kissing_cat",
	"scream_cat",
	"crying_cat_face",
	"pouting_cat",
	"palms_up",
	"open_hands",
	"raised_hands",
	"clap",
	"handshake",
	"+1",
	"-1",
	"facepunch",
	"fist",
	"fist_left",
	"fist_right",
	"crossed_fingers",
	"v",
	"love_you",
	"metal",
	"ok_hand",
	"point_left",
	"point_right",
	"point_up",
	"point_down",
	"point_up_2",
	"raised_hand",
	"raised_back_of_hand",
	"raised_hand_with_fingers_splayed",
	"vulcan_salute",
	"wave",
	"call_me_hand",
	"muscle",
	"fu",
	"writing_hand",
	"pray",
	"foot",
	"leg",
	"ring",
	"lipstick",
	"kiss",
	"lips",
	"tooth",
	"tongue",
	"ear",
	"nose",
	"footprints",
	"eye",
	"eyes",
	"brain",
	"speaking_head",
	"bust_in_silhouette",
	"busts_in_silhouette",
	"baby",
	"girl",
	"child",
	"boy",
	"woman",
	"adult",
	"man",
	"blonde_woman",
	"blonde_man",
	"bearded_person",
	"older_woman",
	"older_adult",
	"older_man",
	"man_with_gua_pi_mao",
	"woman_with_headscarf",
	"woman_with_turban",
	"man_with_turban",
	"policewoman",
	"policeman",
	"construction_worker_woman",
	"construction_worker_man",
	"guardswoman",
	"guardsman",
	"female_detective",
	"male_detective",
	"woman_health_worker",
	"man_health_worker",
	"woman_farmer",
	"man_farmer",
	"woman_cook",
	"man_cook",
	"woman_student",
	"man_student",
	"woman_singer",
	"man_singer",
	"woman_teacher",
	"man_teacher",
	"woman_factory_worker",
	"man_factory_worker",
	"woman_technologist",
	"man_technologist",
	"woman_office_worker",
	"man_office_worker",
	"woman_mechanic",
	"man_mechanic",
	"woman_scientist",
	"man_scientist",
	"woman_artist",
	"man_artist",
	"woman_firefighter",
	"man_firefighter",
	"woman_pilot",
	"man_pilot",
	"woman_astronaut",
	"man_astronaut",
	"woman_judge",
	"man_judge",
	"bride_with_veil",
	"man_in_tuxedo",
	"princess",
	"prince",
	"woman_superhero",
	"man_superhero",
	"woman_supervillain",
	"man_supervillain",
	"mrs_claus",
	"santa",
	"sorceress",
	"wizard",
	"woman_elf",
	"man_elf",
	"woman_vampire",
	"man_vampire",
	"woman_zombie",
	"man_zombie",
	"woman_genie",
	"man_genie",
	"mermaid",
	"merman",
	"woman_fairy",
	"man_fairy",
	"angel",
	"pregnant_woman",
	"breastfeeding",
	"bowing_woman",
	"bowing_man",
	"tipping_hand_woman",
	"tipping_hand_man",
	"no_good_woman",
	"no_good_man",
	"ok_woman",
	"ok_man",
	"raising_hand_woman",
	"raising_hand_man",
	"woman_facepalming",
	"man_facepalming",
	"woman_shrugging",
	"man_shrugging",
	"pouting_woman",
	"pouting_man",
	"frowning_woman",
	"frowning_man",
	"haircut_woman",
	"haircut_man",
	"massage_woman",
	"massage_man",
	"woman_in_steamy_room",
	"man_in_steamy_room",
	"nail_care",
	"selfie",
	"dancer",
	"man_dancing",
	"dancing_women",
	"dancing_men",
	"business_suit_levitating",
	"walking_woman",
	"walking_man",
	"running_woman",
	"running_man",
	"couple",
	"two_women_holding_hands",
	"two_men_holding_hands",
	"couple_with_heart_woman_man",
	"couple_with_heart_woman_woman",
	"couple_with_heart_man_man",
	"couplekiss_man_woman",
	"couplekiss_woman_woman",
	"couplekiss_man_man",
	"family_man_woman_boy",
	"family_man_woman_girl",
	"family_man_woman_girl_boy",
	"family_man_woman_boy_boy",
	"family_man_woman_girl_girl",
	"family_woman_woman_boy",
	"family_woman_woman_girl",
	"family_woman_woman_girl_boy",
	"family_woman_woman_boy_boy",
	"family_woman_woman_girl_girl",
	"family_man_man_boy",
	"family_man_man_girl",
	"family_man_man_girl_boy",
	"family_man_man_boy_boy",
	"family_man_man_girl_girl",
	"family_woman_boy",
	"family_woman_girl",
	"family_woman_girl_boy",
	"family_woman_boy_boy",
	"family_woman_girl_girl",
	"family_man_boy",
	"family_man_girl",
	"family_man_girl_boy",
	"family_man_boy_boy",
	"family_man_girl_girl",
	"yarn",
	"thread",
	"coat",
	"labcoat",
	"womans_clothes",
	"tshirt",
	"jeans",
	"necktie",
	"dress",
	"bikini",
	"kimono",
	"flat_shoe",
	"high_heel",
	"sandal",
	"boot",
	"mans_shoe",
	"athletic_shoe",
	"hiking_boot",
	"socks",
	"gloves",
	"scarf",
	"tophat",
	"billed_hat",
	"womans_hat",
	"mortar_board",
	"rescue_worker_helmet",
	"crown",
	"pouch",
	"purse",
	"handbag",
	"briefcase",
	"school_satchel",
	"luggage",
	"eyeglasses",
	"dark_sunglasses",
	"goggles",
	"closed_umbrella",
	"dog",
	"cat",
	"mouse",
	"hamster",
	"rabbit",
	"fox_face",
	"bear",
	"panda_face",
	"koala",
	"tiger",
	"lion",
	"cow",
	"pig",
	"pig_nose",
	"frog",
	"monkey_face",
	"see_no_evil",
	"hear_no_evil",
	"speak_no_evil",
	"monkey",
	"chicken",
	"penguin",
	"bird",
	"baby_chick",
	"hatching_chick",
	"hatched_chick",
	"duck",
	"eagle",
	"owl",
	"bat",
	"wolf",
	"boar",
	"horse",
	"unicorn",
	"honeybee",
	"bug",
	"butterfly",
	"snail",
	"shell",
	"beetle",
	"ant",
	"mosquito",
	"grasshopper",
	"spider",
	"spider_web",
	"scorpion",
	"turtle",
	"snake",
	"lizard",
	"t-rex",
	"sauropod",
	"octopus",
	"squid",
	"shrimp",
	"lobster",
	"crab",
	"blowfish",
	"tropical_fish",
	"fish",
	"dolphin",
	"whale",
	"whale2",
	"shark",
	"crocodile",
	"tiger2",
	"leopard",
	"zebra",
	"gorilla",
	"elephant",
	"hippopotamus",
	"rhinoceros",
	"dromedary_camel",
	"giraffe",
	"kangaroo",
	"camel",
	"water_buffalo",
	"ox",
	"cow2",
	"racehorse",
	"pig2",
	"ram",
	"sheep",
	"llama",
	"goat",
	"deer",
	"dog2",
	"poodle",
	"cat2",
	"rooster",
	"turkey",
	"peacock",
	"parrot",
	"swan",
	"dove",
	"rabbit2",
	"raccoon",
	"badger",
	"rat",
	"mouse2",
	"chipmunk",
	"hedgehog",
	"paw_prints",
	"dragon",
	"dragon_face",
	"cactus",
	"christmas_tree",
	"evergreen_tree",
	"deciduous_tree",
	"palm_tree",
	"seedling",
	"herb",
	"shamrock",
	"four_leaf_clover",
	"bamboo",
	"tanabata_tree",
	"leaves",
	"fallen_leaf",
	"maple_leaf",
	"ear_of_rice",
	"hibiscus",
	"sunflower",
	"rose",
	"wilted_flower",
	"tulip",
	"blossom",
	"cherry_blossom",
	"bouquet",
	"mushroom",
	"earth_americas",
	"earth_africa",
	"earth_asia",
	"full_moon",
	"waning_gibbous_moon",
	"last_quarter_moon",
	"waning_crescent_moon",
	"new_moon",
	"waxing_crescent_moon",
	"first_quarter_moon",
	"waxing_gibbous_moon",
	"new_moon_with_face",
	"full_moon_with_face",
	"first_quarter_moon_with_face",
	"last_quarter_moon_with_face",
	"sun_with_face",
	"crescent_moon",
	"star",
	"star2",
	"dizzy",
	"sparkles",
	"comet",
	"sunny",
	"sun_behind_small_cloud",
	"partly_sunny",
	"sun_behind_large_cloud",
	"sun_behind_rain_cloud",
	"cloud",
	"cloud_with_rain",
	"cloud_with_lightning_and_rain",
	"cloud_with_lightning",
	"zap",
	"fire",
	"boom",
	"snowflake",
	"cloud_with_snow",
	"snowman",
	"snowman_with_snow",
	"wind_face",
	"dash",
	"tornado",
	"fog",
	"open_umbrella",
	"umbrella",
	"droplet",
	"sweat_drops",
	"ocean",
	"green_apple",
	"apple",
	"pear",
	"tangerine",
	"lemon",
	"banana",
	"watermelon",
	"grapes",
	"strawberry",
	"melon",
	"cherries",
	"peach",
	"mango",
	"pineapple",
	"coconut",
	"kiwi_fruit",
	"tomato",
	"eggplant",
	"avocado",
	"broccoli",
	"leafy_greens",
	"cucumber",
	"hot_pepper",
	"corn",
	"carrot",
	"potato",
	"sweet_potato",
	"croissant",
	"bagel",
	"bread",
	"baguette_bread",
	"pretzel",
	"cheese",
	"egg",
	"fried_egg",
	"pancakes",
	"bacon",
	"steak",
	"poultry_leg",
	"meat_on_bone",
	"bone",
	"hotdog",
	"hamburger",
	"fries",
	"pizza",
	"sandwich",
	"stuffed_flatbread",
	"taco",
	"burrito",
	"green_salad",
	"shallow_pan_of_food",
	"canned_food",
	"spaghetti",
	"ramen",
	"stew",
	"curry",
	"sushi",
	"bento",
	"fried_shrimp",
	"rice_ball",
	"rice",
	"rice_cracker",
	"fish_cake",
	"fortune_cookie",
	"moon_cake",
	"oden",
	"dango",
	"shaved_ice",
	"ice_cream",
	"icecream",
	"pie",
	"cupcake",
	"cake",
	"birthday",
	"custard",
	"lollipop",
	"candy",
	"chocolate_bar",
	"popcorn",
	"doughnut",
	"dumpling",
	"cookie",
	"chestnut",
	"peanuts",
	"honey_pot",
	"milk_glass",
	"baby_bottle",
	"coffee",
	"tea",
	"cup_with_straw",
	"sake",
	"beer",
	"beers",
	"clinking_glasses",
	"wine_glass",
	"tumbler_glass",
	"cocktail",
	"tropical_drink",
	"champagne",
	"spoon",
	"fork_and_knife",
	"plate_with_cutlery",
	"bowl_with_spoon",
	"takeout_box",
	"chopsticks",
	"salt",
	"soccer",
	"basketball",
	"football",
	"baseball",
	"softball",
	"tennis",
	"volleyball",
	"rugby_football",
	"flying_disc",
	"8ball",
	"golf",
	"golfing_woman",
	"golfing_man",
	"ping_pong",
	"badminton",
	"goal_net",
	"ice_hockey",
	"field_hockey",
	"lacrosse",
	"cricket",
	"ski",
	"skier",
	"snowboarder",
	"person_fencing",
	"women_wrestling",
	"men_wrestling",
	"woman_cartwheeling",
	"man_cartwheeling",
	"woman_playing_handball",
	"man_playing_handball",
	"ice_skate",
	"curling_stone",
	"skateboard",
	"sled",
	"bow_and_arrow",
	"fishing_pole_and_fish",
	"boxing_glove",
	"martial_arts_uniform",
	"rowing_woman",
	"rowing_man",
	"climbing_woman",
	"climbing_man",
	"swimming_woman",
	"swimming_man",
	"woman_playing_water_polo",
	"man_playing_water_polo",
	"woman_in_lotus_position",
	"man_in_lotus_position",
	"surfing_woman",
	"surfing_man",
	"basketball_woman",
	"basketball_man",
	"weight_lifting_woman",
	"weight_lifting_man",
	"biking_woman",
	"biking_man",
	"mountain_biking_woman",
	"mountain_biking_man",
	"horse_racing",
	"trophy",
	"running_shirt_with_sash",
	"medal_sports",
	"medal_military",
	"1st_place_medal",
	"2nd_place_medal",
	"3rd_place_medal",
	"reminder_ribbon",
	"rosette",
	"ticket",
	"tickets",
	"performing_arts",
	"art",
	"circus_tent",
	"woman_juggling",
	"man_juggling",
	"microphone",
	"headphones",
	"musical_score",
	"musical_keyboard",
	"drum",
	"saxophone",
	"trumpet",
	"guitar",
	"violin",
	"clapper",
	"video_game",
	"dart",
	"game_die",
	"chess_pawn",
	"slot_machine",
	"jigsaw",
	"bowling",
	"red_car",
	"taxi",
	"blue_car",
	"bus",
	"trolleybus",
	"racing_car",
	"police_car",
	"ambulance",
	"fire_engine",
	"minibus",
	"truck",
	"articulated_lorry",
	"tractor",
	"kick_scooter",
	"motorcycle",
	"bike",
	"motor_scooter",
	"rotating_light",
	"oncoming_police_car",
	"oncoming_bus",
	"oncoming_automobile",
	"oncoming_taxi",
	"aerial_tramway",
	"mountain_cableway",
	"suspension_railway",
	"railway_car",
	"train",
	"monorail",
	"bullettrain_side",
	"bullettrain_front",
	"light_rail",
	"mountain_railway",
	"steam_locomotive",
	"train2",
	"metro",
	"tram",
	"station",
	"flying_saucer",
	"helicopter",
	"small_airplane",
	"airplane",
	"flight_departure",
	"flight_arrival",
	"sailboat",
	"motor_boat",
	"speedboat",
	"ferry",
	"passenger_ship",
	"rocket",
	"artificial_satellite",
	"seat",
	"canoe",
	"anchor",
	"construction",
	"fuelpump",
	"busstop",
	"vertical_traffic_light",
	"traffic_light",
	"ship",
	"ferris_wheel",
	"roller_coaster",
	"carousel_horse",
	"building_construction",
	"foggy",
	"tokyo_tower",
	"factory",
	"fountain",
	"rice_scene",
	"mountain",
	"mountain_snow",
	"mount_fuji",
	"volcano",
	"japan",
	"camping",
	"tent",
	"national_park",
	"motorway",
	"railway_track",
	"sunrise",
	"sunrise_over_mountains",
	"desert",
	"beach_umbrella",
	"desert_island",
	"city_sunrise",
	"city_sunset",
	"cityscape",
	"night_with_stars",
	"bridge_at_night",
	"milky_way",
	"stars",
	"sparkler",
	"fireworks",
	"rainbow",
	"houses",
	"european_castle",
	"japanese_castle",
	"stadium",
	"statue_of_liberty",
	"house",
	"house_with_garden",
	"derelict_house",
	"office",
	"department_store",
	"post_office",
	"european_post_office",
	"hospital",
	"bank",
	"hotel",
	"convenience_store",
	"school",
	"love_hotel",
	"wedding",
	"classical_building",
	"church",
	"mosque",
	"synagogue",
	"kaaba",
	"shinto_shrine",
	"watch",
	"iphone",
	"calling",
	"computer",
	"keyboard",
	"desktop_computer",
	"printer",
	"computer_mouse",
	"trackball",
	"joystick",
	"clamp",
	"minidisc",
	"floppy_disk",
	"cd",
	"dvd",
	"vhs",
	"camera",
	"camera_flash",
	"video_camera",
	"movie_camera",
	"film_projector",
	"film_strip",
	"telephone_receiver",
	"phone",
	"pager",
	"fax",
	"tv",
	"radio",
	"studio_microphone",
	"level_slider",
	"control_knobs",
	"compass",
	"stopwatch",
	"timer_clock",
	"alarm_clock",
	"mantelpiece_clock",
	"hourglass_flowing_sand",
	"hourglass",
	"satellite",
	"battery",
	"electric_plug",
	"bulb",
	"flashlight",
	"candle",
	"fire_extinguisher",
	"wastebasket",
	"oil_drum",
	"money_with_wings",
	"dollar",
	"yen",
	"euro",
	"pound",
	"moneybag",
	"credit_card",
	"gem",
	"balance_scale",
	"toolbox",
	"wrench",
	"hammer",
	"hammer_and_pick",
	"hammer_and_wrench",
	"pick",
	"nut_and_bolt",
	"gear",
	"brick",
	"chains",
	"magnet",
	"gun",
	"bomb",
	"firecracker",
	"hocho",
	"dagger",
	"crossed_swords",
	"shield",
	"smoking",
	"coffin",
	"funeral_urn",
	"amphora",
	"crystal_ball",
	"prayer_beads",
	"nazar_amulet",
	"barber",
	"alembic",
	"telescope",
	"microscope",
	"hole",
	"pill",
	"syringe",
	"dna",
	"microbe",
	"petri_dish",
	"test_tube",
	"thermometer",
	"broom",
	"basket",
	"toilet_paper",
	"label",
	"bookmark",
	"toilet",
	"shower",
	"bathtub",
	"bath",
	"soap",
	"sponge",
	"lotion_bottle",
	"key",
	"old_key",
	"couch_and_lamp",
	"sleeping_bed",
	"bed",
	"door",
	"bellhop_bell",
	"teddy_bear",
	"framed_picture",
	"world_map",
	"parasol_on_ground",
	"moyai",
	"shopping",
	"shopping_cart",
	"balloon",
	"flags",
	"ribbon",
	"gift",
	"confetti_ball",
	"tada",
	"dolls",
	"wind_chime",
	"crossed_flags",
	"izakaya_lantern",
	"red_envelope",
	"email",
	"envelope_with_arrow",
	"incoming_envelope",
	"e-mail",
	"love_letter",
	"postbox",
	"mailbox_closed",
	"mailbox",
	"mailbox_with_mail",
	"mailbox_with_no_mail",
	"package",
	"postal_horn",
	"inbox_tray",
	"outbox_tray",
	"scroll",
	"page_with_curl",
	"bookmark_tabs",
	"receipt",
	"bar_chart",
	"chart_with_upwards_trend",
	"chart_with_downwards_trend",
	"page_facing_up",
	"date",
	"calendar",
	"spiral_calendar",
	"card_index",
	"card_file_box",
	"ballot_box",
	"file_cabinet",
	"clipboard",
	"spiral_notepad",
	"file_folder",
	"open_file_folder",
	"card_index_dividers",
	"newspaper_roll",
	"newspaper",
	"notebook",
	"closed_book",
	"green_book",
	"blue_book",
	"orange_book",
	"notebook_with_decorative_cover",
	"ledger",
	"books",
	"open_book",
	"safety_pin",
	"link",
	"paperclip",
	"paperclips",
	"scissors",
	"triangular_ruler",
	"straight_ruler",
	"abacus",
	"pushpin",
	"round_pushpin",
	"closed_lock_with_key",
	"lock",
	"unlock",
	"lock_with_ink_pen",
	"pen",
	"fountain_pen",
	"black_nib",
	"memo",
	"pencil2",
	"crayon",
	"paintbrush",
	"mag",
	"mag_right",
	"heart",
	"orange_heart",
	"yellow_heart",
	"green_heart",
	"blue_heart",
	"purple_heart",
	"black_heart",
	"broken_heart",
	"heavy_heart_exclamation",
	"two_hearts",
	"revolving_hearts",
	"heartbeat",
	"heartpulse",
	"sparkling_heart",
	"cupid",
	"gift_heart",
	"heart_decoration",
	"peace_symbol",
	"latin_cross",
	"star_and_crescent",
	"om",
	"wheel_of_dharma",
	"star_of_david",
	"six_pointed_star",
	"menorah",
	"yin_yang",
	"orthodox_cross",
	"place_of_worship",
	"ophiuchus",
	"aries",
	"taurus",
	"gemini",
	"cancer",
	"leo",
	"virgo",
	"libra",
	"scorpius",
	"sagittarius",
	"capricorn",
	"aquarius",
	"pisces",
	"id",
	"atom_symbol",
	"u7a7a",
	"u5272",
	"radioactive",
	"biohazard",
	"mobile_phone_off",
	"vibration_mode",
	"u6709",
	"u7121",
	"u7533",
	"u55b6",
	"u6708",
	"eight_pointed_black_star",
	"vs",
	"accept",
	"white_flower",
	"ideograph_advantage",
	"secret",
	"congratulations",
	"u5408",
	"u6e80",
	"u7981",
	"a",
	"b",
	"ab",
	"cl",
	"o2",
	"sos",
	"no_entry",
	"name_badge",
	"no_entry_sign",
	"x",
	"o",
	"stop_sign",
	"anger",
	"hotsprings",
	"no_pedestrians",
	"do_not_litter",
	"no_bicycles",
	"non-potable_water",
	"underage",
	"no_mobile_phones",
	"exclamation",
	"grey_exclamation",
	"question",
	"grey_question",
	"bangbang",
	"interrobang",
	"100",
	"low_brightness",
	"high_brightness",
	"trident",
	"fleur_de_lis",
	"part_alternation_mark",
	"warning",
	"children_crossing",
	"beginner",
	"recycle",
	"u6307",
	"chart",
	"sparkle",
	"eight_spoked_asterisk",
	"negative_squared_cross_mark",
	"white_check_mark",
	"diamond_shape_with_a_dot_inside",
	"cyclone",
	"loop",
	"globe_with_meridians",
	"m",
	"atm",
	"zzz",
	"sa",
	"passport_control",
	"customs",
	"baggage_claim",
	"left_luggage",
	"wheelchair",
	"no_smoking",
	"wc",
	"parking",
	"potable_water",
	"mens",
	"womens",
	"baby_symbol",
	"restroom",
	"put_litter_in_its_place",
	"cinema",
	"signal_strength",
	"koko",
	"ng",
	"ok",
	"up",
	"cool",
	"new",
	"free",
	"zero",
	"one",
	"two",
	"three",
	"four",
	"five",
	"six",
	"seven",
	"eight",
	"nine",
	"keycap_ten",
	"asterisk",
	"1234",
	"eject_button",
	"arrow_forward",
	"pause_button",
	"next_track_button",
	"stop_button",
	"record_button",
	"play_or_pause_button",
	"previous_track_button",
	"fast_forward",
	"rewind",
	"twisted_rightwards_arrows",
	"repeat",
	"repeat_one",
	"arrow_backward",
	"arrow_up_small",
	"arrow_down_small",
	"arrow_double_up",
	"arrow_double_down",
	"arrow_right",
	"arrow_left",
	"arrow_up",
	"arrow_down",
	"arrow_upper_right",
	"arrow_lower_right",
	"arrow_lower_left",
	"arrow_upper_left",
	"arrow_up_down",
	"left_right_arrow",
	"arrows_counterclockwise",
	"arrow_right_hook",
	"leftwards_arrow_with_hook",
	"arrow_heading_up",
	"arrow_heading_down",
	"hash",
	"information_source",
	"abc",
	"abcd",
	"capital_abcd",
	"symbols",
	"musical_note",
	"notes",
	"wavy_dash",
	"curly_loop",
	"heavy_check_mark",
	"arrows_clockwise",
	"heavy_plus_sign",
	"heavy_minus_sign",
	"heavy_division_sign",
	"heavy_multiplication_x",
	"infinity",
	"heavy_dollar_sign",
	"currency_exchange",
	"copyright",
	"registered",
	"tm",
	"end",
	"back",
	"on",
	"top",
	"soon",
	"ballot_box_with_check",
	"radio_button",
	"white_circle",
	"black_circle",
	"red_circle",
	"large_blue_circle",
	"small_orange_diamond",
	"small_blue_diamond",
	"large_orange_diamond",
	"large_blue_diamond",
	"small_red_triangle",
	"black_small_square",
	"white_small_square",
	"black_large_square",
	"white_large_square",
	"small_red_triangle_down",
	"black_medium_square",
	"white_medium_square",
	"black_medium_small_square",
	"white_medium_small_square",
	"black_square_button",
	"white_square_button",
	"speaker",
	"sound",
	"loud_sound",
	"mute",
	"mega",
	"loudspeaker",
	"bell",
	"no_bell",
	"black_joker",
	"mahjong",
	"spades",
	"clubs",
	"hearts",
	"diamonds",
	"flower_playing_cards",
	"thought_balloon",
	"right_anger_bubble",
	"speech_balloon",
	"left_speech_bubble",
	"clock1",
	"clock2",
	"clock3",
	"clock4",
	"clock5",
	"clock6",
	"clock7",
	"clock8",
	"clock9",
	"clock10",
	"clock11",
	"clock12",
	"clock130",
	"clock230",
	"clock330",
	"clock430",
	"clock530",
	"clock630",
	"clock730",
	"clock830",
	"clock930",
	"clock1030",
	"clock1130",
	"clock1230",
	"white_flag",
	"black_flag",
	"pirate_flag",
	"checkered_flag",
	"triangular_flag_on_post",
	"rainbow_flag",
	"united_nations",
	"afghanistan",
	"aland_islands",
	"albania",
	"algeria",
	"american_samoa",
	"andorra",
	"angola",
	"anguilla",
	"antarctica",
	"antigua_barbuda",
	"argentina",
	"armenia",
	"aruba",
	"australia",
	"austria",
	"azerbaijan",
	"bahamas",
	"bahrain",
	"bangladesh",
	"barbados",
	"belarus",
	"belgium",
	"belize",
	"benin",
	"bermuda",
	"bhutan",
	"bolivia",
	"caribbean_netherlands",
	"bosnia_herzegovina",
	"botswana",
	"brazil",
	"british_indian_ocean_territory",
	"british_virgin_islands",
	"brunei",
	"bulgaria",
	"burkina_faso",
	"burundi",
	"cape_verde",
	"cambodia",
	"cameroon",
	"canada",
	"canary_islands",
	"cayman_islands",
	"central_african_republic",
	"chad",
	"chile",
	"cn",
	"christmas_island",
	"cocos_islands",
	"colombia",
	"comoros",
	"congo_brazzaville",
	"congo_kinshasa",
	"cook_islands",
	"costa_rica",
	"croatia",
	"cuba",
	"curacao",
	"cyprus",
	"czech_republic",
	"denmark",
	"djibouti",
	"dominica",
	"dominican_republic",
	"ecuador",
	"egypt",
	"el_salvador",
	"equatorial_guinea",
	"eritrea",
	"estonia",
	"ethiopia",
	"eu",
	"falkland_islands",
	"faroe_islands",
	"fiji",
	"finland",
	"fr",
	"french_guiana",
	"french_polynesia",
	"french_southern_territories",
	"gabon",
	"gambia",
	"georgia",
	"de",
	"ghana",
	"gibraltar",
	"greece",
	"greenland",
	"grenada",
	"guadeloupe",
	"guam",
	"guatemala",
	"guernsey",
	"guinea",
	"guinea_bissau",
	"guyana",
	"haiti",
	"honduras",
	"hong_kong",
	"hungary",
	"iceland",
	"india",
	"indonesia",
	"iran",
	"iraq",
	"ireland",
	"isle_of_man",
	"israel",
	"it",
	"cote_divoire",
	"jamaica",
	"jp",
	"jersey",
	"jordan",
	"kazakhstan",
	"kenya",
	"kiribati",
	"kosovo",
	"kuwait",
	"kyrgyzstan",
	"laos",
	"latvia",
	"lebanon",
	"lesotho",
	"liberia",
	"libya",
	"liechtenstein",
	"lithuania",
	"luxembourg",
	"macau",
	"macedonia",
	"madagascar",
	"malawi",
	"malaysia",
	"maldives",
	"mali",
	"malta",
	"marshall_islands",
	"martinique",
	"mauritania",
	"mauritius",
	"mayotte",
	"mexico",
	"micronesia",
	"moldova",
	"monaco",
	"mongolia",
	"montenegro",
	"montserrat",
	"morocco",
	"mozambique",
	"myanmar",
	"namibia",
	"nauru",
	"nepal",
	"netherlands",
	"new_caledonia",
	"new_zealand",
	"nicaragua",
	"niger",
	"nigeria",
	"niue",
	"norfolk_island",
	"northern_mariana_islands",
	"north_korea",
	"norway",
	"oman",
	"pakistan",
	"palau",
	"palestinian_territories",
	"panama",
	"papua_new_guinea",
	"paraguay",
	"peru",
	"philippines",
	"pitcairn_islands",
	"poland",
	"portugal",
	"puerto_rico",
	"qatar",
	"reunion",
	"romania",
	"ru",
	"rwanda",
	"st_barthelemy",
	"st_helena",
	"st_kitts_nevis",
	"st_lucia",
	"st_pierre_miquelon",
	"st_vincent_grenadines",
	"samoa",
	"san_marino",
	"sao_tome_principe",
	"saudi_arabia",
	"senegal",
	"serbia",
	"seychelles",
	"sierra_leone",
	"singapore",
	"sint_maarten",
	"slovakia",
	"slovenia",
	"solomon_islands",
	"somalia",
	"south_africa",
	"south_georgia_south_sandwich_islands",
	"kr",
	"south_sudan",
	"es",
	"sri_lanka",
	"sudan",
	"suriname",
	"swaziland",
	"sweden",
	"switzerland",
	"syria",
	"taiwan",
	"tajikistan",
	"tanzania",
	"thailand",
	"timor_leste",
	"togo",
	"tokelau",
	"tonga",
	"trinidad_tobago",
	"tunisia",
	"tr",
	"turkmenistan",
	"turks_caicos_islands",
	"tuvalu",
	"uganda",
	"ukraine",
	"united_arab_emirates",
	"uk",
	"england",
	"scotland",
	"wales",
	"us",
	"us_virgin_islands",
	"uruguay",
	"uzbekistan",
	"vanuatu",
	"vatican_city",
	"venezuela",
	"vietnam",
	"wallis_futuna",
	"western_sahara",
	"yemen",
	"zambia",
	"zimbabwe"
];var emojilib = {
  lib: require$$0$2,
  ordered: require$$1,
  fitzpatrick_scale_modifiers: ["🏻", "🏼", "🏽", "🏾", "🏿"]
};var mapO = lib$1,
    iterateObject = lib$2;

var emoji$1 = emojilib;

var nameMap = lib$3.exports = {};
nameMap.emoji = mapO(emoji$1.lib, function (value) {
    return value.char;
}, true);
iterateObject(nameMap.emoji, function (value, name, obj) {
    return !value && delete obj[name] || true;
});

/**
 * get
 * Gets the emoji character (unicode) by providing the name.
 *
 * @name get
 * @function
 * @param {String} name The emoji name.
 * @return {String} The emoji character (unicode).
 */
nameMap.get = function (name) {
    if (name.charAt(0) === ":") {
        name = name.slice(1, -1);
    }
    return this.emoji[name];
};

emoji$1 = null;

var libExports = lib$3.exports;
var emojiNameMap = /*@__PURE__*/getDefaultExportFromCjs(libExports);var keywordSet = {
	"😀": [
	"grinning_face",
	"face",
	"smile",
	"happy",
	"joy",
	":D",
	"grin"
],
	"😃": [
	"grinning_face_with_big_eyes",
	"face",
	"happy",
	"joy",
	"haha",
	":D",
	":)",
	"smile",
	"funny"
],
	"😄": [
	"grinning_face_with_smiling_eyes",
	"face",
	"happy",
	"joy",
	"funny",
	"haha",
	"laugh",
	"like",
	":D",
	":)",
	"smile"
],
	"😁": [
	"beaming_face_with_smiling_eyes",
	"face",
	"happy",
	"smile",
	"joy",
	"kawaii"
],
	"😆": [
	"grinning_squinting_face",
	"happy",
	"joy",
	"lol",
	"satisfied",
	"haha",
	"face",
	"glad",
	"XD",
	"laugh"
],
	"😅": [
	"grinning_face_with_sweat",
	"face",
	"hot",
	"happy",
	"laugh",
	"sweat",
	"smile",
	"relief"
],
	"🤣": [
	"rolling_on_the_floor_laughing",
	"face",
	"rolling",
	"floor",
	"laughing",
	"lol",
	"haha",
	"rofl"
],
	"😂": [
	"face_with_tears_of_joy",
	"face",
	"cry",
	"tears",
	"weep",
	"happy",
	"happytears",
	"haha"
],
	"🙂": [
	"slightly_smiling_face",
	"face",
	"smile"
],
	"🙃": [
	"upside_down_face",
	"face",
	"flipped",
	"silly",
	"smile"
],
	"😉": [
	"winking_face",
	"face",
	"happy",
	"mischievous",
	"secret",
	";)",
	"smile",
	"eye"
],
	"😊": [
	"smiling_face_with_smiling_eyes",
	"face",
	"smile",
	"happy",
	"flushed",
	"crush",
	"embarrassed",
	"shy",
	"joy"
],
	"😇": [
	"smiling_face_with_halo",
	"face",
	"angel",
	"heaven",
	"halo",
	"innocent"
],
	"🥰": [
	"smiling_face_with_hearts",
	"face",
	"love",
	"like",
	"affection",
	"valentines",
	"infatuation",
	"crush",
	"hearts",
	"adore"
],
	"😍": [
	"smiling_face_with_heart_eyes",
	"face",
	"love",
	"like",
	"affection",
	"valentines",
	"infatuation",
	"crush",
	"heart"
],
	"🤩": [
	"star_struck",
	"face",
	"smile",
	"starry",
	"eyes",
	"grinning"
],
	"😘": [
	"face_blowing_a_kiss",
	"face",
	"love",
	"like",
	"affection",
	"valentines",
	"infatuation",
	"kiss"
],
	"😗": [
	"kissing_face",
	"love",
	"like",
	"face",
	"3",
	"valentines",
	"infatuation",
	"kiss"
],
	"☺️": [
	"smiling_face",
	"face",
	"blush",
	"massage",
	"happiness"
],
	"😚": [
	"kissing_face_with_closed_eyes",
	"face",
	"love",
	"like",
	"affection",
	"valentines",
	"infatuation",
	"kiss"
],
	"😙": [
	"kissing_face_with_smiling_eyes",
	"face",
	"affection",
	"valentines",
	"infatuation",
	"kiss"
],
	"😋": [
	"face_savoring_food",
	"happy",
	"joy",
	"tongue",
	"smile",
	"face",
	"silly",
	"yummy",
	"nom",
	"delicious",
	"savouring"
],
	"😛": [
	"face_with_tongue",
	"face",
	"prank",
	"childish",
	"playful",
	"mischievous",
	"smile",
	"tongue"
],
	"😜": [
	"winking_face_with_tongue",
	"face",
	"prank",
	"childish",
	"playful",
	"mischievous",
	"smile",
	"wink",
	"tongue"
],
	"🤪": [
	"zany_face",
	"face",
	"goofy",
	"crazy"
],
	"😝": [
	"squinting_face_with_tongue",
	"face",
	"prank",
	"playful",
	"mischievous",
	"smile",
	"tongue"
],
	"🤑": [
	"money_mouth_face",
	"face",
	"rich",
	"dollar",
	"money"
],
	"🤗": [
	"hugging_face",
	"face",
	"smile",
	"hug"
],
	"🤭": [
	"face_with_hand_over_mouth",
	"face",
	"whoops",
	"shock",
	"surprise"
],
	"🤫": [
	"shushing_face",
	"face",
	"quiet",
	"shhh"
],
	"🤔": [
	"thinking_face",
	"face",
	"hmmm",
	"think",
	"consider"
],
	"🤐": [
	"zipper_mouth_face",
	"face",
	"sealed",
	"zipper",
	"secret"
],
	"🤨": [
	"face_with_raised_eyebrow",
	"face",
	"distrust",
	"scepticism",
	"disapproval",
	"disbelief",
	"surprise",
	"suspicious"
],
	"😐": [
	"neutral_face",
	"indifference",
	"meh",
	":|",
	"neutral"
],
	"😑": [
	"expressionless_face",
	"face",
	"indifferent",
	"-_-",
	"meh",
	"deadpan"
],
	"😶": [
	"face_without_mouth",
	"face"
],
	"😏": [
	"smirking_face",
	"face",
	"smile",
	"mean",
	"prank",
	"smug",
	"sarcasm"
],
	"😒": [
	"unamused_face",
	"indifference",
	"bored",
	"straight face",
	"serious",
	"sarcasm",
	"unimpressed",
	"skeptical",
	"dubious",
	"ugh",
	"side_eye"
],
	"🙄": [
	"face_with_rolling_eyes",
	"face",
	"eyeroll",
	"frustrated"
],
	"😬": [
	"grimacing_face",
	"face",
	"grimace",
	"teeth"
],
	"🤥": [
	"lying_face",
	"face",
	"lie",
	"pinocchio"
],
	"😌": [
	"relieved_face",
	"face",
	"relaxed",
	"phew",
	"massage",
	"happiness"
],
	"😔": [
	"pensive_face",
	"face",
	"sad",
	"depressed",
	"upset"
],
	"😪": [
	"sleepy_face",
	"face",
	"tired",
	"rest",
	"nap"
],
	"🤤": [
	"drooling_face",
	"face"
],
	"😴": [
	"sleeping_face",
	"face",
	"tired",
	"sleepy",
	"night",
	"zzz"
],
	"😷": [
	"face_with_medical_mask",
	"face",
	"sick",
	"ill",
	"disease",
	"covid"
],
	"🤒": [
	"face_with_thermometer",
	"sick",
	"temperature",
	"thermometer",
	"cold",
	"fever",
	"covid"
],
	"🤕": [
	"face_with_head_bandage",
	"injured",
	"clumsy",
	"bandage",
	"hurt"
],
	"🤢": [
	"nauseated_face",
	"face",
	"vomit",
	"gross",
	"green",
	"sick",
	"throw up",
	"ill"
],
	"🤮": [
	"face_vomiting",
	"face",
	"sick"
],
	"🤧": [
	"sneezing_face",
	"face",
	"gesundheit",
	"sneeze",
	"sick",
	"allergy"
],
	"🥵": [
	"hot_face",
	"face",
	"feverish",
	"heat",
	"red",
	"sweating"
],
	"🥶": [
	"cold_face",
	"face",
	"blue",
	"freezing",
	"frozen",
	"frostbite",
	"icicles"
],
	"🥴": [
	"woozy_face",
	"face",
	"dizzy",
	"intoxicated",
	"tipsy",
	"wavy"
],
	"😵": [
	"dizzy_face",
	"spent",
	"unconscious",
	"xox",
	"dizzy"
],
	"🤯": [
	"exploding_head",
	"face",
	"shocked",
	"mind",
	"blown"
],
	"🤠": [
	"cowboy_hat_face",
	"face",
	"cowgirl",
	"hat"
],
	"🥳": [
	"partying_face",
	"face",
	"celebration",
	"woohoo"
],
	"😎": [
	"smiling_face_with_sunglasses",
	"face",
	"cool",
	"smile",
	"summer",
	"beach",
	"sunglass"
],
	"🤓": [
	"nerd_face",
	"face",
	"nerdy",
	"geek",
	"dork"
],
	"🧐": [
	"face_with_monocle",
	"face",
	"stuffy",
	"wealthy"
],
	"😕": [
	"confused_face",
	"face",
	"indifference",
	"huh",
	"weird",
	"hmmm",
	":/"
],
	"😟": [
	"worried_face",
	"face",
	"concern",
	"nervous",
	":("
],
	"🙁": [
	"slightly_frowning_face",
	"face",
	"frowning",
	"disappointed",
	"sad",
	"upset"
],
	"☹️": [
	"frowning_face",
	"face",
	"sad",
	"upset",
	"frown"
],
	"😮": [
	"face_with_open_mouth",
	"face",
	"surprise",
	"impressed",
	"wow",
	"whoa",
	":O"
],
	"😯": [
	"hushed_face",
	"face",
	"woo",
	"shh"
],
	"😲": [
	"astonished_face",
	"face",
	"xox",
	"surprised",
	"poisoned"
],
	"😳": [
	"flushed_face",
	"face",
	"blush",
	"shy",
	"flattered"
],
	"🥺": [
	"pleading_face",
	"face",
	"begging",
	"mercy",
	"cry",
	"tears",
	"sad",
	"grievance"
],
	"😦": [
	"frowning_face_with_open_mouth",
	"face",
	"aw",
	"what"
],
	"😧": [
	"anguished_face",
	"face",
	"stunned",
	"nervous"
],
	"😨": [
	"fearful_face",
	"face",
	"scared",
	"terrified",
	"nervous"
],
	"😰": [
	"anxious_face_with_sweat",
	"face",
	"nervous",
	"sweat"
],
	"😥": [
	"sad_but_relieved_face",
	"face",
	"phew",
	"sweat",
	"nervous"
],
	"😢": [
	"crying_face",
	"face",
	"tears",
	"sad",
	"depressed",
	"upset",
	":'("
],
	"😭": [
	"loudly_crying_face",
	"sobbing",
	"face",
	"cry",
	"tears",
	"sad",
	"upset",
	"depressed"
],
	"😱": [
	"face_screaming_in_fear",
	"face",
	"munch",
	"scared",
	"omg"
],
	"😖": [
	"confounded_face",
	"face",
	"confused",
	"sick",
	"unwell",
	"oops",
	":S"
],
	"😣": [
	"persevering_face",
	"face",
	"sick",
	"no",
	"upset",
	"oops"
],
	"😞": [
	"disappointed_face",
	"face",
	"sad",
	"upset",
	"depressed",
	":("
],
	"😓": [
	"downcast_face_with_sweat",
	"face",
	"hot",
	"sad",
	"tired",
	"exercise"
],
	"😩": [
	"weary_face",
	"face",
	"tired",
	"sleepy",
	"sad",
	"frustrated",
	"upset"
],
	"😫": [
	"tired_face",
	"sick",
	"whine",
	"upset",
	"frustrated"
],
	"🥱": [
	"yawning_face",
	"tired",
	"sleepy"
],
	"😤": [
	"face_with_steam_from_nose",
	"face",
	"gas",
	"phew",
	"proud",
	"pride"
],
	"😡": [
	"pouting_face",
	"angry",
	"mad",
	"hate",
	"despise"
],
	"😠": [
	"angry_face",
	"mad",
	"face",
	"annoyed",
	"frustrated"
],
	"🤬": [
	"face_with_symbols_on_mouth",
	"face",
	"swearing",
	"cursing",
	"cussing",
	"profanity",
	"expletive"
],
	"😈": [
	"smiling_face_with_horns",
	"devil",
	"horns"
],
	"👿": [
	"angry_face_with_horns",
	"devil",
	"angry",
	"horns"
],
	"💀": [
	"skull",
	"dead",
	"skeleton",
	"creepy",
	"death",
	"dead"
],
	"☠️": [
	"skull_and_crossbones",
	"poison",
	"danger",
	"deadly",
	"scary",
	"death",
	"pirate",
	"evil"
],
	"💩": [
	"pile_of_poo",
	"hankey",
	"shitface",
	"fail",
	"turd",
	"shit"
],
	"🤡": [
	"clown_face",
	"face"
],
	"👹": [
	"ogre",
	"monster",
	"red",
	"mask",
	"halloween",
	"scary",
	"creepy",
	"devil",
	"demon",
	"japanese_ogre"
],
	"👺": [
	"goblin",
	"red",
	"evil",
	"mask",
	"monster",
	"scary",
	"creepy",
	"japanese_goblin"
],
	"👻": [
	"ghost",
	"halloween",
	"spooky",
	"scary"
],
	"👽": [
	"alien",
	"UFO",
	"paul",
	"weird",
	"outer_space"
],
	"👾": [
	"alien_monster",
	"game",
	"arcade",
	"play"
],
	"🤖": [
	"robot",
	"computer",
	"machine",
	"bot"
],
	"😺": [
	"grinning_cat",
	"animal",
	"cats",
	"happy",
	"smile"
],
	"😸": [
	"grinning_cat_with_smiling_eyes",
	"animal",
	"cats",
	"smile"
],
	"😹": [
	"cat_with_tears_of_joy",
	"animal",
	"cats",
	"haha",
	"happy",
	"tears"
],
	"😻": [
	"smiling_cat_with_heart_eyes",
	"animal",
	"love",
	"like",
	"affection",
	"cats",
	"valentines",
	"heart"
],
	"😼": [
	"cat_with_wry_smile",
	"animal",
	"cats",
	"smirk"
],
	"😽": [
	"kissing_cat",
	"animal",
	"cats",
	"kiss"
],
	"🙀": [
	"weary_cat",
	"animal",
	"cats",
	"munch",
	"scared",
	"scream"
],
	"😿": [
	"crying_cat",
	"animal",
	"tears",
	"weep",
	"sad",
	"cats",
	"upset",
	"cry"
],
	"😾": [
	"pouting_cat",
	"animal",
	"cats"
],
	"🙈": [
	"see_no_evil_monkey",
	"monkey",
	"animal",
	"nature",
	"haha"
],
	"🙉": [
	"hear_no_evil_monkey",
	"animal",
	"monkey",
	"nature"
],
	"🙊": [
	"speak_no_evil_monkey",
	"monkey",
	"animal",
	"nature",
	"omg"
],
	"💋": [
	"kiss_mark",
	"face",
	"lips",
	"love",
	"like",
	"affection",
	"valentines"
],
	"💌": [
	"love_letter",
	"email",
	"like",
	"affection",
	"envelope",
	"valentines"
],
	"💘": [
	"heart_with_arrow",
	"love",
	"like",
	"heart",
	"affection",
	"valentines"
],
	"💝": [
	"heart_with_ribbon",
	"love",
	"valentines"
],
	"💖": [
	"sparkling_heart",
	"love",
	"like",
	"affection",
	"valentines"
],
	"💗": [
	"growing_heart",
	"like",
	"love",
	"affection",
	"valentines",
	"pink"
],
	"💓": [
	"beating_heart",
	"love",
	"like",
	"affection",
	"valentines",
	"pink",
	"heart"
],
	"💞": [
	"revolving_hearts",
	"love",
	"like",
	"affection",
	"valentines"
],
	"💕": [
	"two_hearts",
	"love",
	"like",
	"affection",
	"valentines",
	"heart"
],
	"💟": [
	"heart_decoration",
	"purple-square",
	"love",
	"like"
],
	"❣️": [
	"heart_exclamation",
	"decoration",
	"love"
],
	"💔": [
	"broken_heart",
	"sad",
	"sorry",
	"break",
	"heart",
	"heartbreak"
],
	"❤️": [
	"red_heart",
	"love",
	"like",
	"valentines"
],
	"🧡": [
	"orange_heart",
	"love",
	"like",
	"affection",
	"valentines"
],
	"💛": [
	"yellow_heart",
	"love",
	"like",
	"affection",
	"valentines"
],
	"💚": [
	"green_heart",
	"love",
	"like",
	"affection",
	"valentines"
],
	"💙": [
	"blue_heart",
	"love",
	"like",
	"affection",
	"valentines"
],
	"💜": [
	"purple_heart",
	"love",
	"like",
	"affection",
	"valentines"
],
	"🤎": [
	"brown_heart",
	"coffee"
],
	"🖤": [
	"black_heart",
	"evil"
],
	"🤍": [
	"white_heart",
	"pure"
],
	"💯": [
	"hundred_points",
	"score",
	"perfect",
	"numbers",
	"century",
	"exam",
	"quiz",
	"test",
	"pass",
	"hundred",
	"100"
],
	"💢": [
	"anger_symbol",
	"angry",
	"mad"
],
	"💥": [
	"collision",
	"bomb",
	"explode",
	"explosion",
	"blown"
],
	"💫": [
	"dizzy",
	"star",
	"sparkle",
	"shoot",
	"magic"
],
	"💦": [
	"sweat_droplets",
	"water",
	"drip",
	"oops"
],
	"💨": [
	"dashing_away",
	"wind",
	"air",
	"fast",
	"shoo",
	"fart",
	"smoke",
	"puff"
],
	"🕳️": [
	"hole",
	"embarrassing"
],
	"💣": [
	"bomb",
	"boom",
	"explode",
	"explosion",
	"terrorism"
],
	"💬": [
	"speech_balloon",
	"bubble",
	"words",
	"message",
	"talk",
	"chatting"
],
	"👁️‍🗨️": [
	"eye_in_speech_bubble",
	"info"
],
	"🗨️": [
	"left_speech_bubble",
	"words",
	"message",
	"talk",
	"chatting"
],
	"🗯️": [
	"right_anger_bubble",
	"caption",
	"speech",
	"thinking",
	"mad"
],
	"💭": [
	"thought_balloon",
	"bubble",
	"cloud",
	"speech",
	"thinking",
	"dream"
],
	"💤": [
	"zzz",
	"sleepy",
	"tired",
	"dream"
],
	"👋": [
	"waving_hand",
	"wave",
	"hands",
	"gesture",
	"goodbye",
	"solong",
	"farewell",
	"hello",
	"hi",
	"palm"
],
	"🤚": [
	"raised_back_of_hand",
	"fingers",
	"raised",
	"backhand"
],
	"🖐️": [
	"hand_with_fingers_splayed",
	"hand",
	"fingers",
	"palm"
],
	"✋": [
	"raised_hand",
	"fingers",
	"stop",
	"highfive",
	"palm",
	"ban"
],
	"🖖": [
	"vulcan_salute",
	"hand",
	"fingers",
	"spock",
	"star trek"
],
	"👌": [
	"ok_hand",
	"fingers",
	"limbs",
	"perfect",
	"ok",
	"okay"
],
	"🤏": [
	"pinching_hand",
	"tiny",
	"small",
	"size"
],
	"✌️": [
	"victory_hand",
	"fingers",
	"ohyeah",
	"hand",
	"peace",
	"victory",
	"two"
],
	"🤞": [
	"crossed_fingers",
	"good",
	"lucky"
],
	"🤟": [
	"love_you_gesture",
	"hand",
	"fingers",
	"gesture"
],
	"🤘": [
	"sign_of_the_horns",
	"hand",
	"fingers",
	"evil_eye",
	"sign_of_horns",
	"rock_on"
],
	"🤙": [
	"call_me_hand",
	"hands",
	"gesture",
	"shaka"
],
	"👈": [
	"backhand_index_pointing_left",
	"direction",
	"fingers",
	"hand",
	"left"
],
	"👉": [
	"backhand_index_pointing_right",
	"fingers",
	"hand",
	"direction",
	"right"
],
	"👆": [
	"backhand_index_pointing_up",
	"fingers",
	"hand",
	"direction",
	"up"
],
	"🖕": [
	"middle_finger",
	"hand",
	"fingers",
	"rude",
	"middle",
	"flipping"
],
	"👇": [
	"backhand_index_pointing_down",
	"fingers",
	"hand",
	"direction",
	"down"
],
	"☝️": [
	"index_pointing_up",
	"hand",
	"fingers",
	"direction",
	"up"
],
	"👍": [
	"thumbs_up",
	"thumbsup",
	"yes",
	"awesome",
	"good",
	"agree",
	"accept",
	"cool",
	"hand",
	"like",
	"+1"
],
	"👎": [
	"thumbs_down",
	"thumbsdown",
	"no",
	"dislike",
	"hand",
	"-1"
],
	"✊": [
	"raised_fist",
	"fingers",
	"hand",
	"grasp"
],
	"👊": [
	"oncoming_fist",
	"angry",
	"violence",
	"fist",
	"hit",
	"attack",
	"hand"
],
	"🤛": [
	"left_facing_fist",
	"hand",
	"fistbump"
],
	"🤜": [
	"right_facing_fist",
	"hand",
	"fistbump"
],
	"👏": [
	"clapping_hands",
	"hands",
	"praise",
	"applause",
	"congrats",
	"yay"
],
	"🙌": [
	"raising_hands",
	"gesture",
	"hooray",
	"yea",
	"celebration",
	"hands"
],
	"👐": [
	"open_hands",
	"fingers",
	"butterfly",
	"hands",
	"open"
],
	"🤲": [
	"palms_up_together",
	"hands",
	"gesture",
	"cupped",
	"prayer"
],
	"🤝": [
	"handshake",
	"agreement",
	"shake"
],
	"🙏": [
	"folded_hands",
	"please",
	"hope",
	"wish",
	"namaste",
	"highfive",
	"pray",
	"thank you",
	"thanks",
	"appreciate"
],
	"✍️": [
	"writing_hand",
	"lower_left_ballpoint_pen",
	"stationery",
	"write",
	"compose"
],
	"💅": [
	"nail_polish",
	"nail_care",
	"beauty",
	"manicure",
	"finger",
	"fashion",
	"nail",
	"slay"
],
	"🤳": [
	"selfie",
	"camera",
	"phone"
],
	"💪": [
	"flexed_biceps",
	"arm",
	"flex",
	"hand",
	"summer",
	"strong",
	"biceps"
],
	"🦾": [
	"mechanical_arm",
	"accessibility"
],
	"🦿": [
	"mechanical_leg",
	"accessibility"
],
	"🦵": [
	"leg",
	"kick",
	"limb"
],
	"🦶": [
	"foot",
	"kick",
	"stomp"
],
	"👂": [
	"ear",
	"face",
	"hear",
	"sound",
	"listen"
],
	"🦻": [
	"ear_with_hearing_aid",
	"accessibility"
],
	"👃": [
	"nose",
	"smell",
	"sniff"
],
	"🧠": [
	"brain",
	"smart",
	"intelligent"
],
	"🦷": [
	"tooth",
	"teeth",
	"dentist"
],
	"🦴": [
	"bone",
	"skeleton"
],
	"👀": [
	"eyes",
	"look",
	"watch",
	"stalk",
	"peek",
	"see"
],
	"👁️": [
	"eye",
	"face",
	"look",
	"see",
	"watch",
	"stare"
],
	"👅": [
	"tongue",
	"mouth",
	"playful"
],
	"👄": [
	"mouth",
	"kiss"
],
	"👶": [
	"baby",
	"child",
	"boy",
	"girl",
	"toddler"
],
	"🧒": [
	"child",
	"gender-neutral",
	"young"
],
	"👦": [
	"boy",
	"man",
	"male",
	"guy",
	"teenager"
],
	"👧": [
	"girl",
	"female",
	"woman",
	"teenager"
],
	"🧑": [
	"person",
	"gender-neutral"
],
	"👱": [
	"person_blond_hair",
	"hairstyle"
],
	"👨": [
	"man",
	"mustache",
	"father",
	"dad",
	"guy",
	"classy",
	"sir",
	"moustache"
],
	"🧔": [
	"man_beard",
	"person",
	"bewhiskered"
],
	"👨‍🦰": [
	"man_red_hair",
	"hairstyle"
],
	"👨‍🦱": [
	"man_curly_hair",
	"hairstyle"
],
	"👨‍🦳": [
	"man_white_hair",
	"old",
	"elder"
],
	"👨‍🦲": [
	"man_bald",
	"hairless"
],
	"👩": [
	"woman",
	"female",
	"girls",
	"lady"
],
	"👩‍🦰": [
	"woman_red_hair",
	"hairstyle"
],
	"🧑‍🦰": [
	"person_red_hair",
	"hairstyle"
],
	"👩‍🦱": [
	"woman_curly_hair",
	"hairstyle"
],
	"🧑‍🦱": [
	"person_curly_hair",
	"hairstyle"
],
	"👩‍🦳": [
	"woman_white_hair",
	"old",
	"elder"
],
	"🧑‍🦳": [
	"person_white_hair",
	"elder",
	"old"
],
	"👩‍🦲": [
	"woman_bald",
	"hairless"
],
	"🧑‍🦲": [
	"person_bald",
	"hairless"
],
	"👱‍♀️": [
	"woman_blond_hair",
	"woman",
	"female",
	"girl",
	"blonde",
	"person"
],
	"👱‍♂️": [
	"man_blond_hair",
	"man",
	"male",
	"boy",
	"blonde",
	"guy",
	"person"
],
	"🧓": [
	"older_person",
	"human",
	"elder",
	"senior",
	"gender-neutral"
],
	"👴": [
	"old_man",
	"human",
	"male",
	"men",
	"old",
	"elder",
	"senior"
],
	"👵": [
	"old_woman",
	"human",
	"female",
	"women",
	"lady",
	"old",
	"elder",
	"senior"
],
	"🙍": [
	"person_frowning",
	"worried"
],
	"🙍‍♂️": [
	"man_frowning",
	"male",
	"boy",
	"man",
	"sad",
	"depressed",
	"discouraged",
	"unhappy"
],
	"🙍‍♀️": [
	"woman_frowning",
	"female",
	"girl",
	"woman",
	"sad",
	"depressed",
	"discouraged",
	"unhappy"
],
	"🙎": [
	"person_pouting",
	"upset"
],
	"🙎‍♂️": [
	"man_pouting",
	"male",
	"boy",
	"man"
],
	"🙎‍♀️": [
	"woman_pouting",
	"female",
	"girl",
	"woman"
],
	"🙅": [
	"person_gesturing_no",
	"decline"
],
	"🙅‍♂️": [
	"man_gesturing_no",
	"male",
	"boy",
	"man",
	"nope"
],
	"🙅‍♀️": [
	"woman_gesturing_no",
	"female",
	"girl",
	"woman",
	"nope"
],
	"🙆": [
	"person_gesturing_ok",
	"agree"
],
	"🙆‍♂️": [
	"man_gesturing_ok",
	"men",
	"boy",
	"male",
	"blue",
	"human",
	"man"
],
	"🙆‍♀️": [
	"woman_gesturing_ok",
	"women",
	"girl",
	"female",
	"pink",
	"human",
	"woman"
],
	"💁": [
	"person_tipping_hand",
	"information"
],
	"💁‍♂️": [
	"man_tipping_hand",
	"male",
	"boy",
	"man",
	"human",
	"information"
],
	"💁‍♀️": [
	"woman_tipping_hand",
	"female",
	"girl",
	"woman",
	"human",
	"information"
],
	"🙋": [
	"person_raising_hand",
	"question"
],
	"🙋‍♂️": [
	"man_raising_hand",
	"male",
	"boy",
	"man"
],
	"🙋‍♀️": [
	"woman_raising_hand",
	"female",
	"girl",
	"woman"
],
	"🧏": [
	"deaf_person",
	"accessibility"
],
	"🧏‍♂️": [
	"deaf_man",
	"accessibility"
],
	"🧏‍♀️": [
	"deaf_woman",
	"accessibility"
],
	"🙇": [
	"person_bowing",
	"respectiful"
],
	"🙇‍♂️": [
	"man_bowing",
	"man",
	"male",
	"boy"
],
	"🙇‍♀️": [
	"woman_bowing",
	"woman",
	"female",
	"girl"
],
	"🤦": [
	"person_facepalming",
	"disappointed"
],
	"🤦‍♂️": [
	"man_facepalming",
	"man",
	"male",
	"boy",
	"disbelief"
],
	"🤦‍♀️": [
	"woman_facepalming",
	"woman",
	"female",
	"girl",
	"disbelief"
],
	"🤷": [
	"person_shrugging",
	"regardless"
],
	"🤷‍♂️": [
	"man_shrugging",
	"man",
	"male",
	"boy",
	"confused",
	"indifferent",
	"doubt"
],
	"🤷‍♀️": [
	"woman_shrugging",
	"woman",
	"female",
	"girl",
	"confused",
	"indifferent",
	"doubt"
],
	"🧑‍⚕️": [
	"health_worker",
	"hospital"
],
	"👨‍⚕️": [
	"man_health_worker",
	"doctor",
	"nurse",
	"therapist",
	"healthcare",
	"man",
	"human"
],
	"👩‍⚕️": [
	"woman_health_worker",
	"doctor",
	"nurse",
	"therapist",
	"healthcare",
	"woman",
	"human"
],
	"🧑‍🎓": [
	"student",
	"learn"
],
	"👨‍🎓": [
	"man_student",
	"graduate",
	"man",
	"human"
],
	"👩‍🎓": [
	"woman_student",
	"graduate",
	"woman",
	"human"
],
	"🧑‍🏫": [
	"teacher",
	"professor"
],
	"👨‍🏫": [
	"man_teacher",
	"instructor",
	"professor",
	"man",
	"human"
],
	"👩‍🏫": [
	"woman_teacher",
	"instructor",
	"professor",
	"woman",
	"human"
],
	"🧑‍⚖️": [
	"judge",
	"law"
],
	"👨‍⚖️": [
	"man_judge",
	"justice",
	"court",
	"man",
	"human"
],
	"👩‍⚖️": [
	"woman_judge",
	"justice",
	"court",
	"woman",
	"human"
],
	"🧑‍🌾": [
	"farmer",
	"crops"
],
	"👨‍🌾": [
	"man_farmer",
	"rancher",
	"gardener",
	"man",
	"human"
],
	"👩‍🌾": [
	"woman_farmer",
	"rancher",
	"gardener",
	"woman",
	"human"
],
	"🧑‍🍳": [
	"cook",
	"food",
	"kitchen",
	"culinary"
],
	"👨‍🍳": [
	"man_cook",
	"chef",
	"man",
	"human"
],
	"👩‍🍳": [
	"woman_cook",
	"chef",
	"woman",
	"human"
],
	"🧑‍🔧": [
	"mechanic",
	"worker",
	"technician"
],
	"👨‍🔧": [
	"man_mechanic",
	"plumber",
	"man",
	"human",
	"wrench"
],
	"👩‍🔧": [
	"woman_mechanic",
	"plumber",
	"woman",
	"human",
	"wrench"
],
	"🧑‍🏭": [
	"factory_worker",
	"labor"
],
	"👨‍🏭": [
	"man_factory_worker",
	"assembly",
	"industrial",
	"man",
	"human"
],
	"👩‍🏭": [
	"woman_factory_worker",
	"assembly",
	"industrial",
	"woman",
	"human"
],
	"🧑‍💼": [
	"office_worker",
	"business"
],
	"👨‍💼": [
	"man_office_worker",
	"business",
	"manager",
	"man",
	"human"
],
	"👩‍💼": [
	"woman_office_worker",
	"business",
	"manager",
	"woman",
	"human"
],
	"🧑‍🔬": [
	"scientist",
	"chemistry"
],
	"👨‍🔬": [
	"man_scientist",
	"biologist",
	"chemist",
	"engineer",
	"physicist",
	"man",
	"human"
],
	"👩‍🔬": [
	"woman_scientist",
	"biologist",
	"chemist",
	"engineer",
	"physicist",
	"woman",
	"human"
],
	"🧑‍💻": [
	"technologist",
	"computer"
],
	"👨‍💻": [
	"man_technologist",
	"coder",
	"developer",
	"engineer",
	"programmer",
	"software",
	"man",
	"human",
	"laptop",
	"computer"
],
	"👩‍💻": [
	"woman_technologist",
	"coder",
	"developer",
	"engineer",
	"programmer",
	"software",
	"woman",
	"human",
	"laptop",
	"computer"
],
	"🧑‍🎤": [
	"singer",
	"song",
	"artist",
	"performer"
],
	"👨‍🎤": [
	"man_singer",
	"rockstar",
	"entertainer",
	"man",
	"human"
],
	"👩‍🎤": [
	"woman_singer",
	"rockstar",
	"entertainer",
	"woman",
	"human"
],
	"🧑‍🎨": [
	"artist",
	"painting",
	"draw",
	"creativity"
],
	"👨‍🎨": [
	"man_artist",
	"painter",
	"man",
	"human"
],
	"👩‍🎨": [
	"woman_artist",
	"painter",
	"woman",
	"human"
],
	"🧑‍✈️": [
	"pilot",
	"fly",
	"plane",
	"airplane"
],
	"👨‍✈️": [
	"man_pilot",
	"aviator",
	"plane",
	"man",
	"human"
],
	"👩‍✈️": [
	"woman_pilot",
	"aviator",
	"plane",
	"woman",
	"human"
],
	"🧑‍🚀": [
	"astronaut",
	"outerspace"
],
	"👨‍🚀": [
	"man_astronaut",
	"space",
	"rocket",
	"man",
	"human"
],
	"👩‍🚀": [
	"woman_astronaut",
	"space",
	"rocket",
	"woman",
	"human"
],
	"🧑‍🚒": [
	"firefighter",
	"fire"
],
	"👨‍🚒": [
	"man_firefighter",
	"fireman",
	"man",
	"human"
],
	"👩‍🚒": [
	"woman_firefighter",
	"fireman",
	"woman",
	"human"
],
	"👮": [
	"police_officer",
	"cop"
],
	"👮‍♂️": [
	"man_police_officer",
	"man",
	"police",
	"law",
	"legal",
	"enforcement",
	"arrest",
	"911"
],
	"👮‍♀️": [
	"woman_police_officer",
	"woman",
	"police",
	"law",
	"legal",
	"enforcement",
	"arrest",
	"911",
	"female"
],
	"🕵️": [
	"detective",
	"human",
	"spy"
],
	"🕵️‍♂️": [
	"man_detective",
	"crime"
],
	"🕵️‍♀️": [
	"woman_detective",
	"human",
	"spy",
	"detective",
	"female",
	"woman"
],
	"💂": [
	"guard",
	"protect"
],
	"💂‍♂️": [
	"man_guard",
	"uk",
	"gb",
	"british",
	"male",
	"guy",
	"royal"
],
	"💂‍♀️": [
	"woman_guard",
	"uk",
	"gb",
	"british",
	"female",
	"royal",
	"woman"
],
	"👷": [
	"construction_worker",
	"labor",
	"build"
],
	"👷‍♂️": [
	"man_construction_worker",
	"male",
	"human",
	"wip",
	"guy",
	"build",
	"construction",
	"worker",
	"labor"
],
	"👷‍♀️": [
	"woman_construction_worker",
	"female",
	"human",
	"wip",
	"build",
	"construction",
	"worker",
	"labor",
	"woman"
],
	"🤴": [
	"prince",
	"boy",
	"man",
	"male",
	"crown",
	"royal",
	"king"
],
	"👸": [
	"princess",
	"girl",
	"woman",
	"female",
	"blond",
	"crown",
	"royal",
	"queen"
],
	"👳": [
	"person_wearing_turban",
	"headdress"
],
	"👳‍♂️": [
	"man_wearing_turban",
	"male",
	"indian",
	"hinduism",
	"arabs"
],
	"👳‍♀️": [
	"woman_wearing_turban",
	"female",
	"indian",
	"hinduism",
	"arabs",
	"woman"
],
	"👲": [
	"man_with_skullcap",
	"male",
	"boy",
	"chinese"
],
	"🧕": [
	"woman_with_headscarf",
	"female",
	"hijab",
	"mantilla",
	"tichel"
],
	"🤵": [
	"man_in_tuxedo",
	"couple",
	"marriage",
	"wedding",
	"groom"
],
	"👰": [
	"bride_with_veil",
	"couple",
	"marriage",
	"wedding",
	"woman",
	"bride"
],
	"🤰": [
	"pregnant_woman",
	"baby"
],
	"🤱": [
	"breast_feeding",
	"nursing",
	"baby"
],
	"👼": [
	"baby_angel",
	"heaven",
	"wings",
	"halo"
],
	"🎅": [
	"santa_claus",
	"festival",
	"man",
	"male",
	"xmas",
	"father christmas"
],
	"🤶": [
	"mrs_claus",
	"woman",
	"female",
	"xmas",
	"mother christmas"
],
	"🦸": [
	"superhero",
	"marvel"
],
	"🦸‍♂️": [
	"man_superhero",
	"man",
	"male",
	"good",
	"hero",
	"superpowers"
],
	"🦸‍♀️": [
	"woman_superhero",
	"woman",
	"female",
	"good",
	"heroine",
	"superpowers"
],
	"🦹": [
	"supervillain",
	"marvel"
],
	"🦹‍♂️": [
	"man_supervillain",
	"man",
	"male",
	"evil",
	"bad",
	"criminal",
	"hero",
	"superpowers"
],
	"🦹‍♀️": [
	"woman_supervillain",
	"woman",
	"female",
	"evil",
	"bad",
	"criminal",
	"heroine",
	"superpowers"
],
	"🧙": [
	"mage",
	"magic"
],
	"🧙‍♂️": [
	"man_mage",
	"man",
	"male",
	"mage",
	"sorcerer"
],
	"🧙‍♀️": [
	"woman_mage",
	"woman",
	"female",
	"mage",
	"witch"
],
	"🧚": [
	"fairy",
	"wings",
	"magical"
],
	"🧚‍♂️": [
	"man_fairy",
	"man",
	"male"
],
	"🧚‍♀️": [
	"woman_fairy",
	"woman",
	"female"
],
	"🧛": [
	"vampire",
	"blood",
	"twilight"
],
	"🧛‍♂️": [
	"man_vampire",
	"man",
	"male",
	"dracula"
],
	"🧛‍♀️": [
	"woman_vampire",
	"woman",
	"female"
],
	"🧜": [
	"merperson",
	"sea"
],
	"🧜‍♂️": [
	"merman",
	"man",
	"male",
	"triton"
],
	"🧜‍♀️": [
	"mermaid",
	"woman",
	"female",
	"merwoman",
	"ariel"
],
	"🧝": [
	"elf",
	"magical"
],
	"🧝‍♂️": [
	"man_elf",
	"man",
	"male"
],
	"🧝‍♀️": [
	"woman_elf",
	"woman",
	"female"
],
	"🧞": [
	"genie",
	"magical",
	"wishes"
],
	"🧞‍♂️": [
	"man_genie",
	"man",
	"male"
],
	"🧞‍♀️": [
	"woman_genie",
	"woman",
	"female"
],
	"🧟": [
	"zombie",
	"dead"
],
	"🧟‍♂️": [
	"man_zombie",
	"man",
	"male",
	"dracula",
	"undead",
	"walking dead"
],
	"🧟‍♀️": [
	"woman_zombie",
	"woman",
	"female",
	"undead",
	"walking dead"
],
	"💆": [
	"person_getting_massage",
	"relax"
],
	"💆‍♂️": [
	"man_getting_massage",
	"male",
	"boy",
	"man",
	"head"
],
	"💆‍♀️": [
	"woman_getting_massage",
	"female",
	"girl",
	"woman",
	"head"
],
	"💇": [
	"person_getting_haircut",
	"hairstyle"
],
	"💇‍♂️": [
	"man_getting_haircut",
	"male",
	"boy",
	"man"
],
	"💇‍♀️": [
	"woman_getting_haircut",
	"female",
	"girl",
	"woman"
],
	"🚶": [
	"person_walking",
	"move"
],
	"🚶‍♂️": [
	"man_walking",
	"human",
	"feet",
	"steps"
],
	"🚶‍♀️": [
	"woman_walking",
	"human",
	"feet",
	"steps",
	"woman",
	"female"
],
	"🧍": [
	"person_standing",
	"still"
],
	"🧍‍♂️": [
	"man_standing",
	"still"
],
	"🧍‍♀️": [
	"woman_standing",
	"still"
],
	"🧎": [
	"person_kneeling",
	"pray",
	"respectful"
],
	"🧎‍♂️": [
	"man_kneeling",
	"pray",
	"respectful"
],
	"🧎‍♀️": [
	"woman_kneeling",
	"respectful",
	"pray"
],
	"🧑‍🦯": [
	"person_with_probing_cane",
	"blind"
],
	"👨‍🦯": [
	"man_with_probing_cane",
	"blind"
],
	"👩‍🦯": [
	"woman_with_probing_cane",
	"blind"
],
	"🧑‍🦼": [
	"person_in_motorized_wheelchair",
	"disability",
	"accessibility"
],
	"👨‍🦼": [
	"man_in_motorized_wheelchair",
	"disability",
	"accessibility"
],
	"👩‍🦼": [
	"woman_in_motorized_wheelchair",
	"disability",
	"accessibility"
],
	"🧑‍🦽": [
	"person_in_manual_wheelchair",
	"disability",
	"accessibility"
],
	"👨‍🦽": [
	"man_in_manual_wheelchair",
	"disability",
	"accessibility"
],
	"👩‍🦽": [
	"woman_in_manual_wheelchair",
	"disability",
	"accessibility"
],
	"🏃": [
	"person_running",
	"move"
],
	"🏃‍♂️": [
	"man_running",
	"man",
	"walking",
	"exercise",
	"race",
	"running"
],
	"🏃‍♀️": [
	"woman_running",
	"woman",
	"walking",
	"exercise",
	"race",
	"running",
	"female"
],
	"💃": [
	"woman_dancing",
	"female",
	"girl",
	"woman",
	"fun"
],
	"🕺": [
	"man_dancing",
	"male",
	"boy",
	"fun",
	"dancer"
],
	"🕴️": [
	"man_in_suit_levitating",
	"suit",
	"business",
	"levitate",
	"hover",
	"jump"
],
	"👯": [
	"people_with_bunny_ears",
	"perform",
	"costume"
],
	"👯‍♂️": [
	"men_with_bunny_ears",
	"male",
	"bunny",
	"men",
	"boys"
],
	"👯‍♀️": [
	"women_with_bunny_ears",
	"female",
	"bunny",
	"women",
	"girls"
],
	"🧖": [
	"person_in_steamy_room",
	"relax",
	"spa"
],
	"🧖‍♂️": [
	"man_in_steamy_room",
	"male",
	"man",
	"spa",
	"steamroom",
	"sauna"
],
	"🧖‍♀️": [
	"woman_in_steamy_room",
	"female",
	"woman",
	"spa",
	"steamroom",
	"sauna"
],
	"🧗": [
	"person_climbing",
	"sport"
],
	"🧗‍♂️": [
	"man_climbing",
	"sports",
	"hobby",
	"man",
	"male",
	"rock"
],
	"🧗‍♀️": [
	"woman_climbing",
	"sports",
	"hobby",
	"woman",
	"female",
	"rock"
],
	"🤺": [
	"person_fencing",
	"sports",
	"fencing",
	"sword"
],
	"🏇": [
	"horse_racing",
	"animal",
	"betting",
	"competition",
	"gambling",
	"luck"
],
	"⛷️": [
	"skier",
	"sports",
	"winter",
	"snow"
],
	"🏂": [
	"snowboarder",
	"sports",
	"winter"
],
	"🏌️": [
	"person_golfing",
	"sports",
	"business"
],
	"🏌️‍♂️": [
	"man_golfing",
	"sport"
],
	"🏌️‍♀️": [
	"woman_golfing",
	"sports",
	"business",
	"woman",
	"female"
],
	"🏄": [
	"person_surfing",
	"sport",
	"sea"
],
	"🏄‍♂️": [
	"man_surfing",
	"sports",
	"ocean",
	"sea",
	"summer",
	"beach"
],
	"🏄‍♀️": [
	"woman_surfing",
	"sports",
	"ocean",
	"sea",
	"summer",
	"beach",
	"woman",
	"female"
],
	"🚣": [
	"person_rowing_boat",
	"sport",
	"move"
],
	"🚣‍♂️": [
	"man_rowing_boat",
	"sports",
	"hobby",
	"water",
	"ship"
],
	"🚣‍♀️": [
	"woman_rowing_boat",
	"sports",
	"hobby",
	"water",
	"ship",
	"woman",
	"female"
],
	"🏊": [
	"person_swimming",
	"sport",
	"pool"
],
	"🏊‍♂️": [
	"man_swimming",
	"sports",
	"exercise",
	"human",
	"athlete",
	"water",
	"summer"
],
	"🏊‍♀️": [
	"woman_swimming",
	"sports",
	"exercise",
	"human",
	"athlete",
	"water",
	"summer",
	"woman",
	"female"
],
	"⛹️": [
	"person_bouncing_ball",
	"sports",
	"human"
],
	"⛹️‍♂️": [
	"man_bouncing_ball",
	"sport"
],
	"⛹️‍♀️": [
	"woman_bouncing_ball",
	"sports",
	"human",
	"woman",
	"female"
],
	"🏋️": [
	"person_lifting_weights",
	"sports",
	"training",
	"exercise"
],
	"🏋️‍♂️": [
	"man_lifting_weights",
	"sport"
],
	"🏋️‍♀️": [
	"woman_lifting_weights",
	"sports",
	"training",
	"exercise",
	"woman",
	"female"
],
	"🚴": [
	"person_biking",
	"bicycle",
	"bike",
	"cyclist",
	"sport",
	"move"
],
	"🚴‍♂️": [
	"man_biking",
	"bicycle",
	"bike",
	"cyclist",
	"sports",
	"exercise",
	"hipster"
],
	"🚴‍♀️": [
	"woman_biking",
	"bicycle",
	"bike",
	"cyclist",
	"sports",
	"exercise",
	"hipster",
	"woman",
	"female"
],
	"🚵": [
	"person_mountain_biking",
	"bicycle",
	"bike",
	"cyclist",
	"sport",
	"move"
],
	"🚵‍♂️": [
	"man_mountain_biking",
	"bicycle",
	"bike",
	"cyclist",
	"transportation",
	"sports",
	"human",
	"race"
],
	"🚵‍♀️": [
	"woman_mountain_biking",
	"bicycle",
	"bike",
	"cyclist",
	"transportation",
	"sports",
	"human",
	"race",
	"woman",
	"female"
],
	"🤸": [
	"person_cartwheeling",
	"sport",
	"gymnastic"
],
	"🤸‍♂️": [
	"man_cartwheeling",
	"gymnastics"
],
	"🤸‍♀️": [
	"woman_cartwheeling",
	"gymnastics"
],
	"🤼": [
	"people_wrestling",
	"sport"
],
	"🤼‍♂️": [
	"men_wrestling",
	"sports",
	"wrestlers"
],
	"🤼‍♀️": [
	"women_wrestling",
	"sports",
	"wrestlers"
],
	"🤽": [
	"person_playing_water_polo",
	"sport"
],
	"🤽‍♂️": [
	"man_playing_water_polo",
	"sports",
	"pool"
],
	"🤽‍♀️": [
	"woman_playing_water_polo",
	"sports",
	"pool"
],
	"🤾": [
	"person_playing_handball",
	"sport"
],
	"🤾‍♂️": [
	"man_playing_handball",
	"sports"
],
	"🤾‍♀️": [
	"woman_playing_handball",
	"sports"
],
	"🤹": [
	"person_juggling",
	"performance",
	"balance"
],
	"🤹‍♂️": [
	"man_juggling",
	"juggle",
	"balance",
	"skill",
	"multitask"
],
	"🤹‍♀️": [
	"woman_juggling",
	"juggle",
	"balance",
	"skill",
	"multitask"
],
	"🧘": [
	"person_in_lotus_position",
	"meditate"
],
	"🧘‍♂️": [
	"man_in_lotus_position",
	"man",
	"male",
	"meditation",
	"yoga",
	"serenity",
	"zen",
	"mindfulness"
],
	"🧘‍♀️": [
	"woman_in_lotus_position",
	"woman",
	"female",
	"meditation",
	"yoga",
	"serenity",
	"zen",
	"mindfulness"
],
	"🛀": [
	"person_taking_bath",
	"clean",
	"shower",
	"bathroom"
],
	"🛌": [
	"person_in_bed",
	"bed",
	"rest"
],
	"🧑‍🤝‍🧑": [
	"people_holding_hands",
	"friendship"
],
	"👭": [
	"women_holding_hands",
	"pair",
	"friendship",
	"couple",
	"love",
	"like",
	"female",
	"people",
	"human"
],
	"👫": [
	"woman_and_man_holding_hands",
	"pair",
	"people",
	"human",
	"love",
	"date",
	"dating",
	"like",
	"affection",
	"valentines",
	"marriage"
],
	"👬": [
	"men_holding_hands",
	"pair",
	"couple",
	"love",
	"like",
	"bromance",
	"friendship",
	"people",
	"human"
],
	"💏": [
	"kiss",
	"pair",
	"valentines",
	"love",
	"like",
	"dating",
	"marriage"
],
	"👩‍❤️‍💋‍👨": [
	"kiss_woman_man",
	"love"
],
	"👨‍❤️‍💋‍👨": [
	"kiss_man_man",
	"pair",
	"valentines",
	"love",
	"like",
	"dating",
	"marriage"
],
	"👩‍❤️‍💋‍👩": [
	"kiss_woman_woman",
	"pair",
	"valentines",
	"love",
	"like",
	"dating",
	"marriage"
],
	"💑": [
	"couple_with_heart",
	"pair",
	"love",
	"like",
	"affection",
	"human",
	"dating",
	"valentines",
	"marriage"
],
	"👩‍❤️‍👨": [
	"couple_with_heart_woman_man",
	"love"
],
	"👨‍❤️‍👨": [
	"couple_with_heart_man_man",
	"pair",
	"love",
	"like",
	"affection",
	"human",
	"dating",
	"valentines",
	"marriage"
],
	"👩‍❤️‍👩": [
	"couple_with_heart_woman_woman",
	"pair",
	"love",
	"like",
	"affection",
	"human",
	"dating",
	"valentines",
	"marriage"
],
	"👪": [
	"family",
	"home",
	"parents",
	"child",
	"mom",
	"dad",
	"father",
	"mother",
	"people",
	"human"
],
	"👨‍👩‍👦": [
	"family_man_woman_boy",
	"love"
],
	"👨‍👩‍👧": [
	"family_man_woman_girl",
	"home",
	"parents",
	"people",
	"human",
	"child"
],
	"👨‍👩‍👧‍👦": [
	"family_man_woman_girl_boy",
	"home",
	"parents",
	"people",
	"human",
	"children"
],
	"👨‍👩‍👦‍👦": [
	"family_man_woman_boy_boy",
	"home",
	"parents",
	"people",
	"human",
	"children"
],
	"👨‍👩‍👧‍👧": [
	"family_man_woman_girl_girl",
	"home",
	"parents",
	"people",
	"human",
	"children"
],
	"👨‍👨‍👦": [
	"family_man_man_boy",
	"home",
	"parents",
	"people",
	"human",
	"children"
],
	"👨‍👨‍👧": [
	"family_man_man_girl",
	"home",
	"parents",
	"people",
	"human",
	"children"
],
	"👨‍👨‍👧‍👦": [
	"family_man_man_girl_boy",
	"home",
	"parents",
	"people",
	"human",
	"children"
],
	"👨‍👨‍👦‍👦": [
	"family_man_man_boy_boy",
	"home",
	"parents",
	"people",
	"human",
	"children"
],
	"👨‍👨‍👧‍👧": [
	"family_man_man_girl_girl",
	"home",
	"parents",
	"people",
	"human",
	"children"
],
	"👩‍👩‍👦": [
	"family_woman_woman_boy",
	"home",
	"parents",
	"people",
	"human",
	"children"
],
	"👩‍👩‍👧": [
	"family_woman_woman_girl",
	"home",
	"parents",
	"people",
	"human",
	"children"
],
	"👩‍👩‍👧‍👦": [
	"family_woman_woman_girl_boy",
	"home",
	"parents",
	"people",
	"human",
	"children"
],
	"👩‍👩‍👦‍👦": [
	"family_woman_woman_boy_boy",
	"home",
	"parents",
	"people",
	"human",
	"children"
],
	"👩‍👩‍👧‍👧": [
	"family_woman_woman_girl_girl",
	"home",
	"parents",
	"people",
	"human",
	"children"
],
	"👨‍👦": [
	"family_man_boy",
	"home",
	"parent",
	"people",
	"human",
	"child"
],
	"👨‍👦‍👦": [
	"family_man_boy_boy",
	"home",
	"parent",
	"people",
	"human",
	"children"
],
	"👨‍👧": [
	"family_man_girl",
	"home",
	"parent",
	"people",
	"human",
	"child"
],
	"👨‍👧‍👦": [
	"family_man_girl_boy",
	"home",
	"parent",
	"people",
	"human",
	"children"
],
	"👨‍👧‍👧": [
	"family_man_girl_girl",
	"home",
	"parent",
	"people",
	"human",
	"children"
],
	"👩‍👦": [
	"family_woman_boy",
	"home",
	"parent",
	"people",
	"human",
	"child"
],
	"👩‍👦‍👦": [
	"family_woman_boy_boy",
	"home",
	"parent",
	"people",
	"human",
	"children"
],
	"👩‍👧": [
	"family_woman_girl",
	"home",
	"parent",
	"people",
	"human",
	"child"
],
	"👩‍👧‍👦": [
	"family_woman_girl_boy",
	"home",
	"parent",
	"people",
	"human",
	"children"
],
	"👩‍👧‍👧": [
	"family_woman_girl_girl",
	"home",
	"parent",
	"people",
	"human",
	"children"
],
	"🗣️": [
	"speaking_head",
	"user",
	"person",
	"human",
	"sing",
	"say",
	"talk"
],
	"👤": [
	"bust_in_silhouette",
	"user",
	"person",
	"human"
],
	"👥": [
	"busts_in_silhouette",
	"user",
	"person",
	"human",
	"group",
	"team"
],
	"👣": [
	"footprints",
	"feet",
	"tracking",
	"walking",
	"beach"
],
	"🐵": [
	"monkey_face",
	"animal",
	"nature",
	"circus"
],
	"🐒": [
	"monkey",
	"animal",
	"nature",
	"banana",
	"circus"
],
	"🦍": [
	"gorilla",
	"animal",
	"nature",
	"circus"
],
	"🦧": [
	"orangutan",
	"animal"
],
	"🐶": [
	"dog_face",
	"animal",
	"friend",
	"nature",
	"woof",
	"puppy",
	"pet",
	"faithful"
],
	"🐕": [
	"dog",
	"animal",
	"nature",
	"friend",
	"doge",
	"pet",
	"faithful"
],
	"🦮": [
	"guide_dog",
	"animal",
	"blind"
],
	"🐕‍🦺": [
	"service_dog",
	"blind",
	"animal"
],
	"🐩": [
	"poodle",
	"dog",
	"animal",
	"101",
	"nature",
	"pet"
],
	"🐺": [
	"wolf",
	"animal",
	"nature",
	"wild"
],
	"🦊": [
	"fox",
	"animal",
	"nature",
	"face"
],
	"🦝": [
	"raccoon",
	"animal",
	"nature"
],
	"🐱": [
	"cat_face",
	"animal",
	"meow",
	"nature",
	"pet",
	"kitten"
],
	"🐈": [
	"cat",
	"animal",
	"meow",
	"pet",
	"cats"
],
	"🦁": [
	"lion",
	"animal",
	"nature"
],
	"🐯": [
	"tiger_face",
	"animal",
	"cat",
	"danger",
	"wild",
	"nature",
	"roar"
],
	"🐅": [
	"tiger",
	"animal",
	"nature",
	"roar"
],
	"🐆": [
	"leopard",
	"animal",
	"nature"
],
	"🐴": [
	"horse_face",
	"animal",
	"brown",
	"nature"
],
	"🐎": [
	"horse",
	"animal",
	"gamble",
	"luck"
],
	"🦄": [
	"unicorn",
	"animal",
	"nature",
	"mystical"
],
	"🦓": [
	"zebra",
	"animal",
	"nature",
	"stripes",
	"safari"
],
	"🦌": [
	"deer",
	"animal",
	"nature",
	"horns",
	"venison"
],
	"🐮": [
	"cow_face",
	"beef",
	"ox",
	"animal",
	"nature",
	"moo",
	"milk"
],
	"🐂": [
	"ox",
	"animal",
	"cow",
	"beef"
],
	"🐃": [
	"water_buffalo",
	"animal",
	"nature",
	"ox",
	"cow"
],
	"🐄": [
	"cow",
	"beef",
	"ox",
	"animal",
	"nature",
	"moo",
	"milk"
],
	"🐷": [
	"pig_face",
	"animal",
	"oink",
	"nature"
],
	"🐖": [
	"pig",
	"animal",
	"nature"
],
	"🐗": [
	"boar",
	"animal",
	"nature"
],
	"🐽": [
	"pig_nose",
	"animal",
	"oink"
],
	"🐏": [
	"ram",
	"animal",
	"sheep",
	"nature"
],
	"🐑": [
	"ewe",
	"animal",
	"nature",
	"wool",
	"shipit"
],
	"🐐": [
	"goat",
	"animal",
	"nature"
],
	"🐪": [
	"camel",
	"animal",
	"hot",
	"desert",
	"hump"
],
	"🐫": [
	"two_hump_camel",
	"animal",
	"nature",
	"hot",
	"desert",
	"hump"
],
	"🦙": [
	"llama",
	"animal",
	"nature",
	"alpaca"
],
	"🦒": [
	"giraffe",
	"animal",
	"nature",
	"spots",
	"safari"
],
	"🐘": [
	"elephant",
	"animal",
	"nature",
	"nose",
	"th",
	"circus"
],
	"🦏": [
	"rhinoceros",
	"animal",
	"nature",
	"horn"
],
	"🦛": [
	"hippopotamus",
	"animal",
	"nature"
],
	"🐭": [
	"mouse_face",
	"animal",
	"nature",
	"cheese_wedge",
	"rodent"
],
	"🐁": [
	"mouse",
	"animal",
	"nature",
	"rodent"
],
	"🐀": [
	"rat",
	"animal",
	"mouse",
	"rodent"
],
	"🐹": [
	"hamster",
	"animal",
	"nature"
],
	"🐰": [
	"rabbit_face",
	"animal",
	"nature",
	"pet",
	"spring",
	"magic",
	"bunny"
],
	"🐇": [
	"rabbit",
	"animal",
	"nature",
	"pet",
	"magic",
	"spring"
],
	"🐿️": [
	"chipmunk",
	"animal",
	"nature",
	"rodent",
	"squirrel"
],
	"🦔": [
	"hedgehog",
	"animal",
	"nature",
	"spiny"
],
	"🦇": [
	"bat",
	"animal",
	"nature",
	"blind",
	"vampire"
],
	"🐻": [
	"bear",
	"animal",
	"nature",
	"wild"
],
	"🐨": [
	"koala",
	"animal",
	"nature"
],
	"🐼": [
	"panda",
	"animal",
	"nature"
],
	"🦥": [
	"sloth",
	"animal"
],
	"🦦": [
	"otter",
	"animal"
],
	"🦨": [
	"skunk",
	"animal"
],
	"🦘": [
	"kangaroo",
	"animal",
	"nature",
	"australia",
	"joey",
	"hop",
	"marsupial"
],
	"🦡": [
	"badger",
	"animal",
	"nature",
	"honey"
],
	"🐾": [
	"paw_prints",
	"animal",
	"tracking",
	"footprints",
	"dog",
	"cat",
	"pet",
	"feet"
],
	"🦃": [
	"turkey",
	"animal",
	"bird"
],
	"🐔": [
	"chicken",
	"animal",
	"cluck",
	"nature",
	"bird"
],
	"🐓": [
	"rooster",
	"animal",
	"nature",
	"chicken"
],
	"🐣": [
	"hatching_chick",
	"animal",
	"chicken",
	"egg",
	"born",
	"baby",
	"bird"
],
	"🐤": [
	"baby_chick",
	"animal",
	"chicken",
	"bird"
],
	"🐥": [
	"front_facing_baby_chick",
	"animal",
	"chicken",
	"baby",
	"bird"
],
	"🐦": [
	"bird",
	"animal",
	"nature",
	"fly",
	"tweet",
	"spring"
],
	"🐧": [
	"penguin",
	"animal",
	"nature"
],
	"🕊️": [
	"dove",
	"animal",
	"bird"
],
	"🦅": [
	"eagle",
	"animal",
	"nature",
	"bird"
],
	"🦆": [
	"duck",
	"animal",
	"nature",
	"bird",
	"mallard"
],
	"🦢": [
	"swan",
	"animal",
	"nature",
	"bird"
],
	"🦉": [
	"owl",
	"animal",
	"nature",
	"bird",
	"hoot"
],
	"🦩": [
	"flamingo",
	"animal"
],
	"🦚": [
	"peacock",
	"animal",
	"nature",
	"peahen",
	"bird"
],
	"🦜": [
	"parrot",
	"animal",
	"nature",
	"bird",
	"pirate",
	"talk"
],
	"🐸": [
	"frog",
	"animal",
	"nature",
	"croak",
	"toad"
],
	"🐊": [
	"crocodile",
	"animal",
	"nature",
	"reptile",
	"lizard",
	"alligator"
],
	"🐢": [
	"turtle",
	"animal",
	"slow",
	"nature",
	"tortoise"
],
	"🦎": [
	"lizard",
	"animal",
	"nature",
	"reptile"
],
	"🐍": [
	"snake",
	"animal",
	"evil",
	"nature",
	"hiss",
	"python"
],
	"🐲": [
	"dragon_face",
	"animal",
	"myth",
	"nature",
	"chinese",
	"green"
],
	"🐉": [
	"dragon",
	"animal",
	"myth",
	"nature",
	"chinese",
	"green"
],
	"🦕": [
	"sauropod",
	"animal",
	"nature",
	"dinosaur",
	"brachiosaurus",
	"brontosaurus",
	"diplodocus",
	"extinct"
],
	"🦖": [
	"t_rex",
	"animal",
	"nature",
	"dinosaur",
	"tyrannosaurus",
	"extinct"
],
	"🐳": [
	"spouting_whale",
	"animal",
	"nature",
	"sea",
	"ocean"
],
	"🐋": [
	"whale",
	"animal",
	"nature",
	"sea",
	"ocean"
],
	"🐬": [
	"dolphin",
	"animal",
	"nature",
	"fish",
	"sea",
	"ocean",
	"flipper",
	"fins",
	"beach"
],
	"🐟": [
	"fish",
	"animal",
	"food",
	"nature"
],
	"🐠": [
	"tropical_fish",
	"animal",
	"swim",
	"ocean",
	"beach",
	"nemo"
],
	"🐡": [
	"blowfish",
	"animal",
	"nature",
	"food",
	"sea",
	"ocean"
],
	"🦈": [
	"shark",
	"animal",
	"nature",
	"fish",
	"sea",
	"ocean",
	"jaws",
	"fins",
	"beach"
],
	"🐙": [
	"octopus",
	"animal",
	"creature",
	"ocean",
	"sea",
	"nature",
	"beach"
],
	"🐚": [
	"spiral_shell",
	"nature",
	"sea",
	"beach"
],
	"🐌": [
	"snail",
	"slow",
	"animal",
	"shell"
],
	"🦋": [
	"butterfly",
	"animal",
	"insect",
	"nature",
	"caterpillar"
],
	"🐛": [
	"bug",
	"animal",
	"insect",
	"nature",
	"worm"
],
	"🐜": [
	"ant",
	"animal",
	"insect",
	"nature",
	"bug"
],
	"🐝": [
	"honeybee",
	"animal",
	"insect",
	"nature",
	"bug",
	"spring",
	"honey"
],
	"🐞": [
	"lady_beetle",
	"animal",
	"insect",
	"nature",
	"ladybug"
],
	"🦗": [
	"cricket",
	"animal",
	"chirp"
],
	"🕷️": [
	"spider",
	"animal",
	"arachnid"
],
	"🕸️": [
	"spider_web",
	"animal",
	"insect",
	"arachnid",
	"silk"
],
	"🦂": [
	"scorpion",
	"animal",
	"arachnid"
],
	"🦟": [
	"mosquito",
	"animal",
	"nature",
	"insect",
	"malaria"
],
	"🦠": [
	"microbe",
	"amoeba",
	"bacteria",
	"germs",
	"virus",
	"covid"
],
	"💐": [
	"bouquet",
	"flowers",
	"nature",
	"spring"
],
	"🌸": [
	"cherry_blossom",
	"nature",
	"plant",
	"spring",
	"flower"
],
	"💮": [
	"white_flower",
	"japanese",
	"spring"
],
	"🏵️": [
	"rosette",
	"flower",
	"decoration",
	"military"
],
	"🌹": [
	"rose",
	"flowers",
	"valentines",
	"love",
	"spring"
],
	"🥀": [
	"wilted_flower",
	"plant",
	"nature",
	"flower",
	"rose"
],
	"🌺": [
	"hibiscus",
	"plant",
	"vegetable",
	"flowers",
	"beach"
],
	"🌻": [
	"sunflower",
	"nature",
	"plant",
	"fall"
],
	"🌼": [
	"blossom",
	"nature",
	"flowers",
	"yellow"
],
	"🌷": [
	"tulip",
	"flowers",
	"plant",
	"nature",
	"summer",
	"spring"
],
	"🌱": [
	"seedling",
	"plant",
	"nature",
	"grass",
	"lawn",
	"spring"
],
	"🌲": [
	"evergreen_tree",
	"plant",
	"nature"
],
	"🌳": [
	"deciduous_tree",
	"plant",
	"nature"
],
	"🌴": [
	"palm_tree",
	"plant",
	"vegetable",
	"nature",
	"summer",
	"beach",
	"mojito",
	"tropical"
],
	"🌵": [
	"cactus",
	"vegetable",
	"plant",
	"nature"
],
	"🌾": [
	"sheaf_of_rice",
	"nature",
	"plant"
],
	"🌿": [
	"herb",
	"vegetable",
	"plant",
	"medicine",
	"weed",
	"grass",
	"lawn"
],
	"☘️": [
	"shamrock",
	"vegetable",
	"plant",
	"nature",
	"irish",
	"clover"
],
	"🍀": [
	"four_leaf_clover",
	"vegetable",
	"plant",
	"nature",
	"lucky",
	"irish"
],
	"🍁": [
	"maple_leaf",
	"nature",
	"plant",
	"vegetable",
	"ca",
	"fall"
],
	"🍂": [
	"fallen_leaf",
	"nature",
	"plant",
	"vegetable",
	"leaves"
],
	"🍃": [
	"leaf_fluttering_in_wind",
	"nature",
	"plant",
	"tree",
	"vegetable",
	"grass",
	"lawn",
	"spring"
],
	"🍇": [
	"grapes",
	"fruit",
	"food",
	"wine"
],
	"🍈": [
	"melon",
	"fruit",
	"nature",
	"food"
],
	"🍉": [
	"watermelon",
	"fruit",
	"food",
	"picnic",
	"summer"
],
	"🍊": [
	"tangerine",
	"food",
	"fruit",
	"nature",
	"orange"
],
	"🍋": [
	"lemon",
	"fruit",
	"nature"
],
	"🍌": [
	"banana",
	"fruit",
	"food",
	"monkey"
],
	"🍍": [
	"pineapple",
	"fruit",
	"nature",
	"food"
],
	"🥭": [
	"mango",
	"fruit",
	"food",
	"tropical"
],
	"🍎": [
	"red_apple",
	"fruit",
	"mac",
	"school"
],
	"🍏": [
	"green_apple",
	"fruit",
	"nature"
],
	"🍐": [
	"pear",
	"fruit",
	"nature",
	"food"
],
	"🍑": [
	"peach",
	"fruit",
	"nature",
	"food"
],
	"🍒": [
	"cherries",
	"food",
	"fruit"
],
	"🍓": [
	"strawberry",
	"fruit",
	"food",
	"nature"
],
	"🥝": [
	"kiwi_fruit",
	"fruit",
	"food"
],
	"🍅": [
	"tomato",
	"fruit",
	"vegetable",
	"nature",
	"food"
],
	"🥥": [
	"coconut",
	"fruit",
	"nature",
	"food",
	"palm"
],
	"🥑": [
	"avocado",
	"fruit",
	"food"
],
	"🍆": [
	"eggplant",
	"vegetable",
	"nature",
	"food",
	"aubergine"
],
	"🥔": [
	"potato",
	"food",
	"tuber",
	"vegatable",
	"starch"
],
	"🥕": [
	"carrot",
	"vegetable",
	"food",
	"orange"
],
	"🌽": [
	"ear_of_corn",
	"food",
	"vegetable",
	"plant"
],
	"🌶️": [
	"hot_pepper",
	"food",
	"spicy",
	"chilli",
	"chili"
],
	"🥒": [
	"cucumber",
	"fruit",
	"food",
	"pickle"
],
	"🥬": [
	"leafy_green",
	"food",
	"vegetable",
	"plant",
	"bok choy",
	"cabbage",
	"kale",
	"lettuce"
],
	"🥦": [
	"broccoli",
	"fruit",
	"food",
	"vegetable"
],
	"🧄": [
	"garlic",
	"food",
	"spice",
	"cook"
],
	"🧅": [
	"onion",
	"cook",
	"food",
	"spice"
],
	"🍄": [
	"mushroom",
	"plant",
	"vegetable"
],
	"🥜": [
	"peanuts",
	"food",
	"nut"
],
	"🌰": [
	"chestnut",
	"food",
	"squirrel"
],
	"🍞": [
	"bread",
	"food",
	"wheat",
	"breakfast",
	"toast"
],
	"🥐": [
	"croissant",
	"food",
	"bread",
	"french"
],
	"🥖": [
	"baguette_bread",
	"food",
	"bread",
	"french",
	"france",
	"bakery"
],
	"🥨": [
	"pretzel",
	"food",
	"bread",
	"twisted",
	"germany",
	"bakery"
],
	"🥯": [
	"bagel",
	"food",
	"bread",
	"bakery",
	"schmear",
	"jewish_bakery"
],
	"🥞": [
	"pancakes",
	"food",
	"breakfast",
	"flapjacks",
	"hotcakes",
	"brunch"
],
	"🧇": [
	"waffle",
	"food",
	"breakfast",
	"brunch"
],
	"🧀": [
	"cheese_wedge",
	"food",
	"chadder",
	"swiss"
],
	"🍖": [
	"meat_on_bone",
	"good",
	"food",
	"drumstick"
],
	"🍗": [
	"poultry_leg",
	"food",
	"meat",
	"drumstick",
	"bird",
	"chicken",
	"turkey"
],
	"🥩": [
	"cut_of_meat",
	"food",
	"cow",
	"meat",
	"cut",
	"chop",
	"lambchop",
	"porkchop"
],
	"🥓": [
	"bacon",
	"food",
	"breakfast",
	"pork",
	"pig",
	"meat",
	"brunch"
],
	"🍔": [
	"hamburger",
	"meat",
	"fast food",
	"beef",
	"cheeseburger",
	"mcdonalds",
	"burger king"
],
	"🍟": [
	"french_fries",
	"chips",
	"snack",
	"fast food",
	"potato"
],
	"🍕": [
	"pizza",
	"food",
	"party",
	"italy"
],
	"🌭": [
	"hot_dog",
	"food",
	"frankfurter",
	"america"
],
	"🥪": [
	"sandwich",
	"food",
	"lunch",
	"bread",
	"toast",
	"bakery"
],
	"🌮": [
	"taco",
	"food",
	"mexican"
],
	"🌯": [
	"burrito",
	"food",
	"mexican"
],
	"🥙": [
	"stuffed_flatbread",
	"food",
	"flatbread",
	"stuffed",
	"gyro",
	"mediterranean"
],
	"🧆": [
	"falafel",
	"food",
	"mediterranean"
],
	"🥚": [
	"egg",
	"food",
	"chicken",
	"breakfast"
],
	"🍳": [
	"cooking",
	"food",
	"breakfast",
	"kitchen",
	"egg",
	"skillet"
],
	"🥘": [
	"shallow_pan_of_food",
	"food",
	"cooking",
	"casserole",
	"paella",
	"skillet"
],
	"🍲": [
	"pot_of_food",
	"food",
	"meat",
	"soup",
	"hot pot"
],
	"🥣": [
	"bowl_with_spoon",
	"food",
	"breakfast",
	"cereal",
	"oatmeal",
	"porridge"
],
	"🥗": [
	"green_salad",
	"food",
	"healthy",
	"lettuce",
	"vegetable"
],
	"🍿": [
	"popcorn",
	"food",
	"movie theater",
	"films",
	"snack",
	"drama"
],
	"🧈": [
	"butter",
	"food",
	"cook"
],
	"🧂": [
	"salt",
	"condiment",
	"shaker"
],
	"🥫": [
	"canned_food",
	"food",
	"soup",
	"tomatoes"
],
	"🍱": [
	"bento_box",
	"food",
	"japanese",
	"box",
	"lunch"
],
	"🍘": [
	"rice_cracker",
	"food",
	"japanese",
	"snack",
	"senbei"
],
	"🍙": [
	"rice_ball",
	"food",
	"japanese",
	"onigiri",
	"omusubi"
],
	"🍚": [
	"cooked_rice",
	"food",
	"asian"
],
	"🍛": [
	"curry_rice",
	"food",
	"spicy",
	"hot",
	"indian"
],
	"🍜": [
	"steaming_bowl",
	"food",
	"japanese",
	"noodle",
	"chopsticks",
	"ramen"
],
	"🍝": [
	"spaghetti",
	"food",
	"italian",
	"pasta",
	"noodle"
],
	"🍠": [
	"roasted_sweet_potato",
	"food",
	"nature",
	"plant"
],
	"🍢": [
	"oden",
	"skewer",
	"food",
	"japanese"
],
	"🍣": [
	"sushi",
	"food",
	"fish",
	"japanese",
	"rice"
],
	"🍤": [
	"fried_shrimp",
	"food",
	"animal",
	"appetizer",
	"summer"
],
	"🍥": [
	"fish_cake_with_swirl",
	"food",
	"japan",
	"sea",
	"beach",
	"narutomaki",
	"pink",
	"swirl",
	"kamaboko",
	"surimi",
	"ramen"
],
	"🥮": [
	"moon_cake",
	"food",
	"autumn",
	"dessert"
],
	"🍡": [
	"dango",
	"food",
	"dessert",
	"sweet",
	"japanese",
	"barbecue",
	"meat"
],
	"🥟": [
	"dumpling",
	"food",
	"empanada",
	"pierogi",
	"potsticker",
	"gyoza"
],
	"🥠": [
	"fortune_cookie",
	"food",
	"prophecy",
	"dessert"
],
	"🥡": [
	"takeout_box",
	"food",
	"leftovers"
],
	"🦀": [
	"crab",
	"animal",
	"crustacean"
],
	"🦞": [
	"lobster",
	"animal",
	"nature",
	"bisque",
	"claws",
	"seafood"
],
	"🦐": [
	"shrimp",
	"animal",
	"ocean",
	"nature",
	"seafood"
],
	"🦑": [
	"squid",
	"animal",
	"nature",
	"ocean",
	"sea"
],
	"🦪": [
	"oyster",
	"food"
],
	"🍦": [
	"soft_ice_cream",
	"food",
	"hot",
	"dessert",
	"summer"
],
	"🍧": [
	"shaved_ice",
	"hot",
	"dessert",
	"summer"
],
	"🍨": [
	"ice_cream",
	"food",
	"hot",
	"dessert"
],
	"🍩": [
	"doughnut",
	"food",
	"dessert",
	"snack",
	"sweet",
	"donut"
],
	"🍪": [
	"cookie",
	"food",
	"snack",
	"oreo",
	"chocolate",
	"sweet",
	"dessert"
],
	"🎂": [
	"birthday_cake",
	"food",
	"dessert",
	"cake"
],
	"🍰": [
	"shortcake",
	"food",
	"dessert"
],
	"🧁": [
	"cupcake",
	"food",
	"dessert",
	"bakery",
	"sweet"
],
	"🥧": [
	"pie",
	"food",
	"dessert",
	"pastry"
],
	"🍫": [
	"chocolate_bar",
	"food",
	"snack",
	"dessert",
	"sweet"
],
	"🍬": [
	"candy",
	"snack",
	"dessert",
	"sweet",
	"lolly"
],
	"🍭": [
	"lollipop",
	"food",
	"snack",
	"candy",
	"sweet"
],
	"🍮": [
	"custard",
	"dessert",
	"food",
	"pudding",
	"flan"
],
	"🍯": [
	"honey_pot",
	"bees",
	"sweet",
	"kitchen"
],
	"🍼": [
	"baby_bottle",
	"food",
	"container",
	"milk"
],
	"🥛": [
	"glass_of_milk",
	"beverage",
	"drink",
	"cow"
],
	"☕": [
	"hot_beverage",
	"beverage",
	"caffeine",
	"latte",
	"espresso",
	"coffee",
	"mug"
],
	"🍵": [
	"teacup_without_handle",
	"drink",
	"bowl",
	"breakfast",
	"green",
	"british"
],
	"🍶": [
	"sake",
	"wine",
	"drink",
	"drunk",
	"beverage",
	"japanese",
	"alcohol",
	"booze"
],
	"🍾": [
	"bottle_with_popping_cork",
	"drink",
	"wine",
	"bottle",
	"celebration"
],
	"🍷": [
	"wine_glass",
	"drink",
	"beverage",
	"drunk",
	"alcohol",
	"booze"
],
	"🍸": [
	"cocktail_glass",
	"drink",
	"drunk",
	"alcohol",
	"beverage",
	"booze",
	"mojito"
],
	"🍹": [
	"tropical_drink",
	"beverage",
	"cocktail",
	"summer",
	"beach",
	"alcohol",
	"booze",
	"mojito"
],
	"🍺": [
	"beer_mug",
	"relax",
	"beverage",
	"drink",
	"drunk",
	"party",
	"pub",
	"summer",
	"alcohol",
	"booze"
],
	"🍻": [
	"clinking_beer_mugs",
	"relax",
	"beverage",
	"drink",
	"drunk",
	"party",
	"pub",
	"summer",
	"alcohol",
	"booze"
],
	"🥂": [
	"clinking_glasses",
	"beverage",
	"drink",
	"party",
	"alcohol",
	"celebrate",
	"cheers",
	"wine",
	"champagne",
	"toast"
],
	"🥃": [
	"tumbler_glass",
	"drink",
	"beverage",
	"drunk",
	"alcohol",
	"liquor",
	"booze",
	"bourbon",
	"scotch",
	"whisky",
	"glass",
	"shot"
],
	"🥤": [
	"cup_with_straw",
	"drink",
	"soda"
],
	"🧃": [
	"beverage_box",
	"drink"
],
	"🧉": [
	"mate",
	"drink",
	"tea",
	"beverage"
],
	"🧊": [
	"ice",
	"water",
	"cold"
],
	"🥢": [
	"chopsticks",
	"food"
],
	"🍽️": [
	"fork_and_knife_with_plate",
	"food",
	"eat",
	"meal",
	"lunch",
	"dinner",
	"restaurant"
],
	"🍴": [
	"fork_and_knife",
	"cutlery",
	"kitchen"
],
	"🥄": [
	"spoon",
	"cutlery",
	"kitchen",
	"tableware"
],
	"🔪": [
	"kitchen_knife",
	"knife",
	"blade",
	"cutlery",
	"kitchen",
	"weapon"
],
	"🏺": [
	"amphora",
	"vase",
	"jar"
],
	"🌍": [
	"globe_showing_europe_africa",
	"globe",
	"world",
	"earth",
	"international"
],
	"🌎": [
	"globe_showing_americas",
	"globe",
	"world",
	"USA",
	"earth",
	"international"
],
	"🌏": [
	"globe_showing_asia_australia",
	"globe",
	"world",
	"east",
	"earth",
	"international"
],
	"🌐": [
	"globe_with_meridians",
	"earth",
	"international",
	"world",
	"internet",
	"interweb",
	"i18n"
],
	"🗺️": [
	"world_map",
	"location",
	"direction"
],
	"🗾": [
	"map_of_japan",
	"nation",
	"country",
	"japanese",
	"asia"
],
	"🧭": [
	"compass",
	"magnetic",
	"navigation",
	"orienteering"
],
	"🏔️": [
	"snow_capped_mountain",
	"photo",
	"nature",
	"environment",
	"winter",
	"cold"
],
	"⛰️": [
	"mountain",
	"photo",
	"nature",
	"environment"
],
	"🌋": [
	"volcano",
	"photo",
	"nature",
	"disaster"
],
	"🗻": [
	"mount_fuji",
	"photo",
	"mountain",
	"nature",
	"japanese"
],
	"🏕️": [
	"camping",
	"photo",
	"outdoors",
	"tent"
],
	"🏖️": [
	"beach_with_umbrella",
	"weather",
	"summer",
	"sunny",
	"sand",
	"mojito"
],
	"🏜️": [
	"desert",
	"photo",
	"warm",
	"saharah"
],
	"🏝️": [
	"desert_island",
	"photo",
	"tropical",
	"mojito"
],
	"🏞️": [
	"national_park",
	"photo",
	"environment",
	"nature"
],
	"🏟️": [
	"stadium",
	"photo",
	"place",
	"sports",
	"concert",
	"venue"
],
	"🏛️": [
	"classical_building",
	"art",
	"culture",
	"history"
],
	"🏗️": [
	"building_construction",
	"wip",
	"working",
	"progress"
],
	"🧱": [
	"brick",
	"bricks"
],
	"🏘️": [
	"houses",
	"buildings",
	"photo"
],
	"🏚️": [
	"derelict_house",
	"abandon",
	"evict",
	"broken",
	"building"
],
	"🏠": [
	"house",
	"building",
	"home"
],
	"🏡": [
	"house_with_garden",
	"home",
	"plant",
	"nature"
],
	"🏢": [
	"office_building",
	"building",
	"bureau",
	"work"
],
	"🏣": [
	"japanese_post_office",
	"building",
	"envelope",
	"communication"
],
	"🏤": [
	"post_office",
	"building",
	"email"
],
	"🏥": [
	"hospital",
	"building",
	"health",
	"surgery",
	"doctor"
],
	"🏦": [
	"bank",
	"building",
	"money",
	"sales",
	"cash",
	"business",
	"enterprise"
],
	"🏨": [
	"hotel",
	"building",
	"accomodation",
	"checkin"
],
	"🏩": [
	"love_hotel",
	"like",
	"affection",
	"dating"
],
	"🏪": [
	"convenience_store",
	"building",
	"shopping",
	"groceries"
],
	"🏫": [
	"school",
	"building",
	"student",
	"education",
	"learn",
	"teach"
],
	"🏬": [
	"department_store",
	"building",
	"shopping",
	"mall"
],
	"🏭": [
	"factory",
	"building",
	"industry",
	"pollution",
	"smoke"
],
	"🏯": [
	"japanese_castle",
	"photo",
	"building"
],
	"🏰": [
	"castle",
	"building",
	"royalty",
	"history"
],
	"💒": [
	"wedding",
	"love",
	"like",
	"affection",
	"couple",
	"marriage",
	"bride",
	"groom"
],
	"🗼": [
	"tokyo_tower",
	"photo",
	"japanese"
],
	"🗽": [
	"statue_of_liberty",
	"american",
	"newyork"
],
	"⛪": [
	"church",
	"building",
	"religion",
	"christ"
],
	"🕌": [
	"mosque",
	"islam",
	"worship",
	"minaret"
],
	"🛕": [
	"hindu_temple",
	"religion"
],
	"🕍": [
	"synagogue",
	"judaism",
	"worship",
	"temple",
	"jewish"
],
	"⛩️": [
	"shinto_shrine",
	"temple",
	"japan",
	"kyoto"
],
	"🕋": [
	"kaaba",
	"mecca",
	"mosque",
	"islam"
],
	"⛲": [
	"fountain",
	"photo",
	"summer",
	"water",
	"fresh"
],
	"⛺": [
	"tent",
	"photo",
	"camping",
	"outdoors"
],
	"🌁": [
	"foggy",
	"photo",
	"mountain"
],
	"🌃": [
	"night_with_stars",
	"evening",
	"city",
	"downtown"
],
	"🏙️": [
	"cityscape",
	"photo",
	"night life",
	"urban"
],
	"🌄": [
	"sunrise_over_mountains",
	"view",
	"vacation",
	"photo"
],
	"🌅": [
	"sunrise",
	"morning",
	"view",
	"vacation",
	"photo"
],
	"🌆": [
	"cityscape_at_dusk",
	"photo",
	"evening",
	"sky",
	"buildings"
],
	"🌇": [
	"sunset",
	"photo",
	"good morning",
	"dawn"
],
	"🌉": [
	"bridge_at_night",
	"photo",
	"sanfrancisco"
],
	"♨️": [
	"hot_springs",
	"bath",
	"warm",
	"relax"
],
	"🎠": [
	"carousel_horse",
	"photo",
	"carnival"
],
	"🎡": [
	"ferris_wheel",
	"photo",
	"carnival",
	"londoneye"
],
	"🎢": [
	"roller_coaster",
	"carnival",
	"playground",
	"photo",
	"fun"
],
	"💈": [
	"barber_pole",
	"hair",
	"salon",
	"style"
],
	"🎪": [
	"circus_tent",
	"festival",
	"carnival",
	"party"
],
	"🚂": [
	"locomotive",
	"transportation",
	"vehicle",
	"train"
],
	"🚃": [
	"railway_car",
	"transportation",
	"vehicle"
],
	"🚄": [
	"high_speed_train",
	"transportation",
	"vehicle"
],
	"🚅": [
	"bullet_train",
	"transportation",
	"vehicle",
	"speed",
	"fast",
	"public",
	"travel"
],
	"🚆": [
	"train",
	"transportation",
	"vehicle"
],
	"🚇": [
	"metro",
	"transportation",
	"blue-square",
	"mrt",
	"underground",
	"tube"
],
	"🚈": [
	"light_rail",
	"transportation",
	"vehicle"
],
	"🚉": [
	"station",
	"transportation",
	"vehicle",
	"public"
],
	"🚊": [
	"tram",
	"transportation",
	"vehicle"
],
	"🚝": [
	"monorail",
	"transportation",
	"vehicle"
],
	"🚞": [
	"mountain_railway",
	"transportation",
	"vehicle"
],
	"🚋": [
	"tram_car",
	"transportation",
	"vehicle",
	"carriage",
	"public",
	"travel"
],
	"🚌": [
	"bus",
	"car",
	"vehicle",
	"transportation"
],
	"🚍": [
	"oncoming_bus",
	"vehicle",
	"transportation"
],
	"🚎": [
	"trolleybus",
	"bart",
	"transportation",
	"vehicle"
],
	"🚐": [
	"minibus",
	"vehicle",
	"car",
	"transportation"
],
	"🚑": [
	"ambulance",
	"health",
	"911",
	"hospital"
],
	"🚒": [
	"fire_engine",
	"transportation",
	"cars",
	"vehicle"
],
	"🚓": [
	"police_car",
	"vehicle",
	"cars",
	"transportation",
	"law",
	"legal",
	"enforcement"
],
	"🚔": [
	"oncoming_police_car",
	"vehicle",
	"law",
	"legal",
	"enforcement",
	"911"
],
	"🚕": [
	"taxi",
	"uber",
	"vehicle",
	"cars",
	"transportation"
],
	"🚖": [
	"oncoming_taxi",
	"vehicle",
	"cars",
	"uber"
],
	"🚗": [
	"automobile",
	"red",
	"transportation",
	"vehicle"
],
	"🚘": [
	"oncoming_automobile",
	"car",
	"vehicle",
	"transportation"
],
	"🚙": [
	"sport_utility_vehicle",
	"transportation",
	"vehicle"
],
	"🚚": [
	"delivery_truck",
	"cars",
	"transportation"
],
	"🚛": [
	"articulated_lorry",
	"vehicle",
	"cars",
	"transportation",
	"express"
],
	"🚜": [
	"tractor",
	"vehicle",
	"car",
	"farming",
	"agriculture"
],
	"🏎️": [
	"racing_car",
	"sports",
	"race",
	"fast",
	"formula",
	"f1"
],
	"🏍️": [
	"motorcycle",
	"race",
	"sports",
	"fast"
],
	"🛵": [
	"motor_scooter",
	"vehicle",
	"vespa",
	"sasha"
],
	"🦽": [
	"manual_wheelchair",
	"accessibility"
],
	"🦼": [
	"motorized_wheelchair",
	"accessibility"
],
	"🛺": [
	"auto_rickshaw",
	"move",
	"transportation"
],
	"🚲": [
	"bicycle",
	"bike",
	"sports",
	"exercise",
	"hipster"
],
	"🛴": [
	"kick_scooter",
	"vehicle",
	"kick",
	"razor"
],
	"🛹": [
	"skateboard",
	"board"
],
	"🚏": [
	"bus_stop",
	"transportation",
	"wait"
],
	"🛣️": [
	"motorway",
	"road",
	"cupertino",
	"interstate",
	"highway"
],
	"🛤️": [
	"railway_track",
	"train",
	"transportation"
],
	"🛢️": [
	"oil_drum",
	"barrell"
],
	"⛽": [
	"fuel_pump",
	"gas station",
	"petroleum"
],
	"🚨": [
	"police_car_light",
	"police",
	"ambulance",
	"911",
	"emergency",
	"alert",
	"error",
	"pinged",
	"law",
	"legal"
],
	"🚥": [
	"horizontal_traffic_light",
	"transportation",
	"signal"
],
	"🚦": [
	"vertical_traffic_light",
	"transportation",
	"driving"
],
	"🛑": [
	"stop_sign",
	"stop"
],
	"🚧": [
	"construction",
	"wip",
	"progress",
	"caution",
	"warning"
],
	"⚓": [
	"anchor",
	"ship",
	"ferry",
	"sea",
	"boat"
],
	"⛵": [
	"sailboat",
	"ship",
	"summer",
	"transportation",
	"water",
	"sailing"
],
	"🛶": [
	"canoe",
	"boat",
	"paddle",
	"water",
	"ship"
],
	"🚤": [
	"speedboat",
	"ship",
	"transportation",
	"vehicle",
	"summer"
],
	"🛳️": [
	"passenger_ship",
	"yacht",
	"cruise",
	"ferry"
],
	"⛴️": [
	"ferry",
	"boat",
	"ship",
	"yacht"
],
	"🛥️": [
	"motor_boat",
	"ship"
],
	"🚢": [
	"ship",
	"transportation",
	"titanic",
	"deploy"
],
	"✈️": [
	"airplane",
	"vehicle",
	"transportation",
	"flight",
	"fly"
],
	"🛩️": [
	"small_airplane",
	"flight",
	"transportation",
	"fly",
	"vehicle"
],
	"🛫": [
	"airplane_departure",
	"airport",
	"flight",
	"landing"
],
	"🛬": [
	"airplane_arrival",
	"airport",
	"flight",
	"boarding"
],
	"🪂": [
	"parachute",
	"fly",
	"glide"
],
	"💺": [
	"seat",
	"sit",
	"airplane",
	"transport",
	"bus",
	"flight",
	"fly"
],
	"🚁": [
	"helicopter",
	"transportation",
	"vehicle",
	"fly"
],
	"🚟": [
	"suspension_railway",
	"vehicle",
	"transportation"
],
	"🚠": [
	"mountain_cableway",
	"transportation",
	"vehicle",
	"ski"
],
	"🚡": [
	"aerial_tramway",
	"transportation",
	"vehicle",
	"ski"
],
	"🛰️": [
	"satellite",
	"communication",
	"gps",
	"orbit",
	"spaceflight",
	"NASA",
	"ISS"
],
	"🚀": [
	"rocket",
	"launch",
	"ship",
	"staffmode",
	"NASA",
	"outer space",
	"outer_space",
	"fly"
],
	"🛸": [
	"flying_saucer",
	"transportation",
	"vehicle",
	"ufo"
],
	"🛎️": [
	"bellhop_bell",
	"service"
],
	"🧳": [
	"luggage",
	"packing",
	"travel"
],
	"⌛": [
	"hourglass_done",
	"time",
	"clock",
	"oldschool",
	"limit",
	"exam",
	"quiz",
	"test"
],
	"⏳": [
	"hourglass_not_done",
	"oldschool",
	"time",
	"countdown"
],
	"⌚": [
	"watch",
	"time",
	"accessories"
],
	"⏰": [
	"alarm_clock",
	"time",
	"wake"
],
	"⏱️": [
	"stopwatch",
	"time",
	"deadline"
],
	"⏲️": [
	"timer_clock",
	"alarm"
],
	"🕰️": [
	"mantelpiece_clock",
	"time"
],
	"🕛": [
	"twelve_o_clock",
	"12",
	"00:00",
	"0000",
	"12:00",
	"1200",
	"time",
	"noon",
	"midnight",
	"midday",
	"late",
	"early",
	"schedule"
],
	"🕧": [
	"twelve_thirty",
	"00:30",
	"0030",
	"12:30",
	"1230",
	"time",
	"late",
	"early",
	"schedule"
],
	"🕐": [
	"one_o_clock",
	"1",
	"1:00",
	"100",
	"13:00",
	"1300",
	"time",
	"late",
	"early",
	"schedule"
],
	"🕜": [
	"one_thirty",
	"1:30",
	"130",
	"13:30",
	"1330",
	"time",
	"late",
	"early",
	"schedule"
],
	"🕑": [
	"two_o_clock",
	"2",
	"2:00",
	"200",
	"14:00",
	"1400",
	"time",
	"late",
	"early",
	"schedule"
],
	"🕝": [
	"two_thirty",
	"2:30",
	"230",
	"14:30",
	"1430",
	"time",
	"late",
	"early",
	"schedule"
],
	"🕒": [
	"three_o_clock",
	"3",
	"3:00",
	"300",
	"15:00",
	"1500",
	"time",
	"late",
	"early",
	"schedule"
],
	"🕞": [
	"three_thirty",
	"3:30",
	"330",
	"15:30",
	"1530",
	"time",
	"late",
	"early",
	"schedule"
],
	"🕓": [
	"four_o_clock",
	"4",
	"4:00",
	"400",
	"16:00",
	"1600",
	"time",
	"late",
	"early",
	"schedule"
],
	"🕟": [
	"four_thirty",
	"4:30",
	"430",
	"16:30",
	"1630",
	"time",
	"late",
	"early",
	"schedule"
],
	"🕔": [
	"five_o_clock",
	"5",
	"5:00",
	"500",
	"17:00",
	"1700",
	"time",
	"late",
	"early",
	"schedule"
],
	"🕠": [
	"five_thirty",
	"5:30",
	"530",
	"17:30",
	"1730",
	"time",
	"late",
	"early",
	"schedule"
],
	"🕕": [
	"six_o_clock",
	"6",
	"6:00",
	"600",
	"18:00",
	"1800",
	"time",
	"late",
	"early",
	"schedule",
	"dawn",
	"dusk"
],
	"🕡": [
	"six_thirty",
	"6:30",
	"630",
	"18:30",
	"1830",
	"time",
	"late",
	"early",
	"schedule"
],
	"🕖": [
	"seven_o_clock",
	"7",
	"7:00",
	"700",
	"19:00",
	"1900",
	"time",
	"late",
	"early",
	"schedule"
],
	"🕢": [
	"seven_thirty",
	"7:30",
	"730",
	"19:30",
	"1930",
	"time",
	"late",
	"early",
	"schedule"
],
	"🕗": [
	"eight_o_clock",
	"8",
	"8:00",
	"800",
	"20:00",
	"2000",
	"time",
	"late",
	"early",
	"schedule"
],
	"🕣": [
	"eight_thirty",
	"8:30",
	"830",
	"20:30",
	"2030",
	"time",
	"late",
	"early",
	"schedule"
],
	"🕘": [
	"nine_o_clock",
	"9",
	"9:00",
	"900",
	"21:00",
	"2100",
	"time",
	"late",
	"early",
	"schedule"
],
	"🕤": [
	"nine_thirty",
	"9:30",
	"930",
	"21:30",
	"2130",
	"time",
	"late",
	"early",
	"schedule"
],
	"🕙": [
	"ten_o_clock",
	"10",
	"10:00",
	"1000",
	"22:00",
	"2200",
	"time",
	"late",
	"early",
	"schedule"
],
	"🕥": [
	"ten_thirty",
	"10:30",
	"1030",
	"22:30",
	"2230",
	"time",
	"late",
	"early",
	"schedule"
],
	"🕚": [
	"eleven_o_clock",
	"11",
	"11:00",
	"1100",
	"23:00",
	"2300",
	"time",
	"late",
	"early",
	"schedule"
],
	"🕦": [
	"eleven_thirty",
	"11:30",
	"1130",
	"23:30",
	"2330",
	"time",
	"late",
	"early",
	"schedule"
],
	"🌑": [
	"new_moon",
	"nature",
	"twilight",
	"planet",
	"space",
	"night",
	"evening",
	"sleep"
],
	"🌒": [
	"waxing_crescent_moon",
	"nature",
	"twilight",
	"planet",
	"space",
	"night",
	"evening",
	"sleep"
],
	"🌓": [
	"first_quarter_moon",
	"nature",
	"twilight",
	"planet",
	"space",
	"night",
	"evening",
	"sleep"
],
	"🌔": [
	"waxing_gibbous_moon",
	"nature",
	"night",
	"sky",
	"gray",
	"twilight",
	"planet",
	"space",
	"evening",
	"sleep"
],
	"🌕": [
	"full_moon",
	"nature",
	"yellow",
	"twilight",
	"planet",
	"space",
	"night",
	"evening",
	"sleep"
],
	"🌖": [
	"waning_gibbous_moon",
	"nature",
	"twilight",
	"planet",
	"space",
	"night",
	"evening",
	"sleep",
	"waxing_gibbous_moon"
],
	"🌗": [
	"last_quarter_moon",
	"nature",
	"twilight",
	"planet",
	"space",
	"night",
	"evening",
	"sleep"
],
	"🌘": [
	"waning_crescent_moon",
	"nature",
	"twilight",
	"planet",
	"space",
	"night",
	"evening",
	"sleep"
],
	"🌙": [
	"crescent_moon",
	"night",
	"sleep",
	"sky",
	"evening",
	"magic"
],
	"🌚": [
	"new_moon_face",
	"nature",
	"twilight",
	"planet",
	"space",
	"night",
	"evening",
	"sleep"
],
	"🌛": [
	"first_quarter_moon_face",
	"nature",
	"twilight",
	"planet",
	"space",
	"night",
	"evening",
	"sleep"
],
	"🌜": [
	"last_quarter_moon_face",
	"nature",
	"twilight",
	"planet",
	"space",
	"night",
	"evening",
	"sleep"
],
	"🌡️": [
	"thermometer",
	"weather",
	"temperature",
	"hot",
	"cold"
],
	"☀️": [
	"sun",
	"weather",
	"nature",
	"brightness",
	"summer",
	"beach",
	"spring"
],
	"🌝": [
	"full_moon_face",
	"nature",
	"twilight",
	"planet",
	"space",
	"night",
	"evening",
	"sleep"
],
	"🌞": [
	"sun_with_face",
	"nature",
	"morning",
	"sky"
],
	"🪐": [
	"ringed_planet",
	"outerspace"
],
	"⭐": [
	"star",
	"night",
	"yellow"
],
	"🌟": [
	"glowing_star",
	"night",
	"sparkle",
	"awesome",
	"good",
	"magic"
],
	"🌠": [
	"shooting_star",
	"night",
	"photo"
],
	"🌌": [
	"milky_way",
	"photo",
	"space",
	"stars"
],
	"☁️": [
	"cloud",
	"weather",
	"sky"
],
	"⛅": [
	"sun_behind_cloud",
	"weather",
	"nature",
	"cloudy",
	"morning",
	"fall",
	"spring"
],
	"⛈️": [
	"cloud_with_lightning_and_rain",
	"weather",
	"lightning"
],
	"🌤️": [
	"sun_behind_small_cloud",
	"weather"
],
	"🌥️": [
	"sun_behind_large_cloud",
	"weather"
],
	"🌦️": [
	"sun_behind_rain_cloud",
	"weather"
],
	"🌧️": [
	"cloud_with_rain",
	"weather"
],
	"🌨️": [
	"cloud_with_snow",
	"weather"
],
	"🌩️": [
	"cloud_with_lightning",
	"weather",
	"thunder"
],
	"🌪️": [
	"tornado",
	"weather",
	"cyclone",
	"twister"
],
	"🌫️": [
	"fog",
	"weather"
],
	"🌬️": [
	"wind_face",
	"gust",
	"air"
],
	"🌀": [
	"cyclone",
	"weather",
	"swirl",
	"blue",
	"cloud",
	"vortex",
	"spiral",
	"whirlpool",
	"spin",
	"tornado",
	"hurricane",
	"typhoon"
],
	"🌈": [
	"rainbow",
	"nature",
	"happy",
	"unicorn_face",
	"photo",
	"sky",
	"spring"
],
	"🌂": [
	"closed_umbrella",
	"weather",
	"rain",
	"drizzle"
],
	"☂️": [
	"umbrella",
	"weather",
	"spring"
],
	"☔": [
	"umbrella_with_rain_drops",
	"rainy",
	"weather",
	"spring"
],
	"⛱️": [
	"umbrella_on_ground",
	"weather",
	"summer"
],
	"⚡": [
	"high_voltage",
	"thunder",
	"weather",
	"lightning bolt",
	"fast",
	"zap"
],
	"❄️": [
	"snowflake",
	"winter",
	"season",
	"cold",
	"weather",
	"christmas",
	"xmas"
],
	"☃️": [
	"snowman",
	"winter",
	"season",
	"cold",
	"weather",
	"christmas",
	"xmas",
	"frozen"
],
	"⛄": [
	"snowman_without_snow",
	"winter",
	"season",
	"cold",
	"weather",
	"christmas",
	"xmas",
	"frozen",
	"without_snow"
],
	"☄️": [
	"comet",
	"space"
],
	"🔥": [
	"fire",
	"hot",
	"cook",
	"flame"
],
	"💧": [
	"droplet",
	"water",
	"drip",
	"faucet",
	"spring"
],
	"🌊": [
	"water_wave",
	"sea",
	"water",
	"wave",
	"nature",
	"tsunami",
	"disaster"
],
	"🎃": [
	"jack_o_lantern",
	"halloween",
	"light",
	"pumpkin",
	"creepy",
	"fall"
],
	"🎄": [
	"christmas_tree",
	"festival",
	"vacation",
	"december",
	"xmas",
	"celebration"
],
	"🎆": [
	"fireworks",
	"photo",
	"festival",
	"carnival",
	"congratulations"
],
	"🎇": [
	"sparkler",
	"stars",
	"night",
	"shine"
],
	"🧨": [
	"firecracker",
	"dynamite",
	"boom",
	"explode",
	"explosion",
	"explosive"
],
	"✨": [
	"sparkles",
	"stars",
	"shine",
	"shiny",
	"cool",
	"awesome",
	"good",
	"magic"
],
	"🎈": [
	"balloon",
	"party",
	"celebration",
	"birthday",
	"circus"
],
	"🎉": [
	"party_popper",
	"party",
	"congratulations",
	"birthday",
	"magic",
	"circus",
	"celebration",
	"tada"
],
	"🎊": [
	"confetti_ball",
	"festival",
	"party",
	"birthday",
	"circus"
],
	"🎋": [
	"tanabata_tree",
	"plant",
	"nature",
	"branch",
	"summer",
	"bamboo",
	"wish",
	"star_festival",
	"tanzaku"
],
	"🎍": [
	"pine_decoration",
	"japanese",
	"plant",
	"nature",
	"vegetable",
	"panda",
	"new_years",
	"bamboo"
],
	"🎎": [
	"japanese_dolls",
	"japanese",
	"toy",
	"kimono"
],
	"🎏": [
	"carp_streamer",
	"fish",
	"japanese",
	"koinobori",
	"carp",
	"banner"
],
	"🎐": [
	"wind_chime",
	"nature",
	"ding",
	"spring",
	"bell"
],
	"🎑": [
	"moon_viewing_ceremony",
	"photo",
	"japan",
	"asia",
	"tsukimi"
],
	"🧧": [
	"red_envelope",
	"gift"
],
	"🎀": [
	"ribbon",
	"decoration",
	"pink",
	"girl",
	"bowtie"
],
	"🎁": [
	"wrapped_gift",
	"present",
	"birthday",
	"christmas",
	"xmas"
],
	"🎗️": [
	"reminder_ribbon",
	"sports",
	"cause",
	"support",
	"awareness"
],
	"🎟️": [
	"admission_tickets",
	"sports",
	"concert",
	"entrance"
],
	"🎫": [
	"ticket",
	"event",
	"concert",
	"pass"
],
	"🎖️": [
	"military_medal",
	"award",
	"winning",
	"army"
],
	"🏆": [
	"trophy",
	"win",
	"award",
	"contest",
	"place",
	"ftw",
	"ceremony"
],
	"🏅": [
	"sports_medal",
	"award",
	"winning"
],
	"🥇": [
	"1st_place_medal",
	"award",
	"winning",
	"first"
],
	"🥈": [
	"2nd_place_medal",
	"award",
	"second"
],
	"🥉": [
	"3rd_place_medal",
	"award",
	"third"
],
	"⚽": [
	"soccer_ball",
	"sports",
	"football"
],
	"⚾": [
	"baseball",
	"sports",
	"balls"
],
	"🥎": [
	"softball",
	"sports",
	"balls"
],
	"🏀": [
	"basketball",
	"sports",
	"balls",
	"NBA"
],
	"🏐": [
	"volleyball",
	"sports",
	"balls"
],
	"🏈": [
	"american_football",
	"sports",
	"balls",
	"NFL"
],
	"🏉": [
	"rugby_football",
	"sports",
	"team"
],
	"🎾": [
	"tennis",
	"sports",
	"balls",
	"green"
],
	"🥏": [
	"flying_disc",
	"sports",
	"frisbee",
	"ultimate"
],
	"🎳": [
	"bowling",
	"sports",
	"fun",
	"play"
],
	"🏏": [
	"cricket_game",
	"sports"
],
	"🏑": [
	"field_hockey",
	"sports"
],
	"🏒": [
	"ice_hockey",
	"sports"
],
	"🥍": [
	"lacrosse",
	"sports",
	"ball",
	"stick"
],
	"🏓": [
	"ping_pong",
	"sports",
	"pingpong"
],
	"🏸": [
	"badminton",
	"sports"
],
	"🥊": [
	"boxing_glove",
	"sports",
	"fighting"
],
	"🥋": [
	"martial_arts_uniform",
	"judo",
	"karate",
	"taekwondo"
],
	"🥅": [
	"goal_net",
	"sports"
],
	"⛳": [
	"flag_in_hole",
	"sports",
	"business",
	"flag",
	"hole",
	"summer"
],
	"⛸️": [
	"ice_skate",
	"sports"
],
	"🎣": [
	"fishing_pole",
	"food",
	"hobby",
	"summer"
],
	"🤿": [
	"diving_mask",
	"sport",
	"ocean"
],
	"🎽": [
	"running_shirt",
	"play",
	"pageant"
],
	"🎿": [
	"skis",
	"sports",
	"winter",
	"cold",
	"snow"
],
	"🛷": [
	"sled",
	"sleigh",
	"luge",
	"toboggan"
],
	"🥌": [
	"curling_stone",
	"sports"
],
	"🎯": [
	"direct_hit",
	"game",
	"play",
	"bar",
	"target",
	"bullseye"
],
	"🪀": [
	"yo_yo",
	"toy"
],
	"🪁": [
	"kite",
	"wind",
	"fly"
],
	"🎱": [
	"pool_8_ball",
	"pool",
	"hobby",
	"game",
	"luck",
	"magic"
],
	"🔮": [
	"crystal_ball",
	"disco",
	"party",
	"magic",
	"circus",
	"fortune_teller"
],
	"🧿": [
	"nazar_amulet",
	"bead",
	"charm"
],
	"🎮": [
	"video_game",
	"play",
	"console",
	"PS4",
	"controller"
],
	"🕹️": [
	"joystick",
	"game",
	"play"
],
	"🎰": [
	"slot_machine",
	"bet",
	"gamble",
	"vegas",
	"fruit machine",
	"luck",
	"casino"
],
	"🎲": [
	"game_die",
	"dice",
	"random",
	"tabletop",
	"play",
	"luck"
],
	"🧩": [
	"puzzle_piece",
	"interlocking",
	"puzzle",
	"piece"
],
	"🧸": [
	"teddy_bear",
	"plush",
	"stuffed"
],
	"♠️": [
	"spade_suit",
	"poker",
	"cards",
	"suits",
	"magic"
],
	"♥️": [
	"heart_suit",
	"poker",
	"cards",
	"magic",
	"suits"
],
	"♦️": [
	"diamond_suit",
	"poker",
	"cards",
	"magic",
	"suits"
],
	"♣️": [
	"club_suit",
	"poker",
	"cards",
	"magic",
	"suits"
],
	"♟️": [
	"chess_pawn",
	"expendable"
],
	"🃏": [
	"joker",
	"poker",
	"cards",
	"game",
	"play",
	"magic"
],
	"🀄": [
	"mahjong_red_dragon",
	"game",
	"play",
	"chinese",
	"kanji"
],
	"🎴": [
	"flower_playing_cards",
	"game",
	"sunset",
	"red"
],
	"🎭": [
	"performing_arts",
	"acting",
	"theater",
	"drama"
],
	"🖼️": [
	"framed_picture",
	"photography"
],
	"🎨": [
	"artist_palette",
	"design",
	"paint",
	"draw",
	"colors"
],
	"🧵": [
	"thread",
	"needle",
	"sewing",
	"spool",
	"string"
],
	"🧶": [
	"yarn",
	"ball",
	"crochet",
	"knit"
],
	"👓": [
	"glasses",
	"fashion",
	"accessories",
	"eyesight",
	"nerdy",
	"dork",
	"geek"
],
	"🕶️": [
	"sunglasses",
	"face",
	"cool",
	"accessories"
],
	"🥽": [
	"goggles",
	"eyes",
	"protection",
	"safety"
],
	"🥼": [
	"lab_coat",
	"doctor",
	"experiment",
	"scientist",
	"chemist"
],
	"🦺": [
	"safety_vest",
	"protection"
],
	"👔": [
	"necktie",
	"shirt",
	"suitup",
	"formal",
	"fashion",
	"cloth",
	"business"
],
	"👕": [
	"t_shirt",
	"fashion",
	"cloth",
	"casual",
	"shirt",
	"tee"
],
	"👖": [
	"jeans",
	"fashion",
	"shopping"
],
	"🧣": [
	"scarf",
	"neck",
	"winter",
	"clothes"
],
	"🧤": [
	"gloves",
	"hands",
	"winter",
	"clothes"
],
	"🧥": [
	"coat",
	"jacket"
],
	"🧦": [
	"socks",
	"stockings",
	"clothes"
],
	"👗": [
	"dress",
	"clothes",
	"fashion",
	"shopping"
],
	"👘": [
	"kimono",
	"dress",
	"fashion",
	"women",
	"female",
	"japanese"
],
	"🥻": [
	"sari",
	"dress"
],
	"🩱": [
	"one_piece_swimsuit",
	"fashion"
],
	"🩲": [
	"briefs",
	"clothing"
],
	"🩳": [
	"shorts",
	"clothing"
],
	"👙": [
	"bikini",
	"swimming",
	"female",
	"woman",
	"girl",
	"fashion",
	"beach",
	"summer"
],
	"👚": [
	"woman_s_clothes",
	"fashion",
	"shopping_bags",
	"female"
],
	"👛": [
	"purse",
	"fashion",
	"accessories",
	"money",
	"sales",
	"shopping"
],
	"👜": [
	"handbag",
	"fashion",
	"accessory",
	"accessories",
	"shopping"
],
	"👝": [
	"clutch_bag",
	"bag",
	"accessories",
	"shopping"
],
	"🛍️": [
	"shopping_bags",
	"mall",
	"buy",
	"purchase"
],
	"🎒": [
	"backpack",
	"student",
	"education",
	"bag"
],
	"👞": [
	"man_s_shoe",
	"fashion",
	"male"
],
	"👟": [
	"running_shoe",
	"shoes",
	"sports",
	"sneakers"
],
	"🥾": [
	"hiking_boot",
	"backpacking",
	"camping",
	"hiking"
],
	"🥿": [
	"flat_shoe",
	"ballet",
	"slip-on",
	"slipper"
],
	"👠": [
	"high_heeled_shoe",
	"fashion",
	"shoes",
	"female",
	"pumps",
	"stiletto"
],
	"👡": [
	"woman_s_sandal",
	"shoes",
	"fashion",
	"flip flops"
],
	"🩰": [
	"ballet_shoes",
	"dance"
],
	"👢": [
	"woman_s_boot",
	"shoes",
	"fashion"
],
	"👑": [
	"crown",
	"king",
	"kod",
	"leader",
	"royalty",
	"lord"
],
	"👒": [
	"woman_s_hat",
	"fashion",
	"accessories",
	"female",
	"lady",
	"spring"
],
	"🎩": [
	"top_hat",
	"magic",
	"gentleman",
	"classy",
	"circus"
],
	"🎓": [
	"graduation_cap",
	"school",
	"college",
	"degree",
	"university",
	"graduation",
	"cap",
	"hat",
	"legal",
	"learn",
	"education"
],
	"🧢": [
	"billed_cap",
	"cap",
	"baseball"
],
	"⛑️": [
	"rescue_worker_s_helmet",
	"construction",
	"build"
],
	"📿": [
	"prayer_beads",
	"dhikr",
	"religious"
],
	"💄": [
	"lipstick",
	"female",
	"girl",
	"fashion",
	"woman"
],
	"💍": [
	"ring",
	"wedding",
	"propose",
	"marriage",
	"valentines",
	"diamond",
	"fashion",
	"jewelry",
	"gem",
	"engagement"
],
	"💎": [
	"gem_stone",
	"blue",
	"ruby",
	"diamond",
	"jewelry"
],
	"🔇": [
	"muted_speaker",
	"sound",
	"volume",
	"silence",
	"quiet"
],
	"🔈": [
	"speaker_low_volume",
	"sound",
	"volume",
	"silence",
	"broadcast"
],
	"🔉": [
	"speaker_medium_volume",
	"volume",
	"speaker",
	"broadcast"
],
	"🔊": [
	"speaker_high_volume",
	"volume",
	"noise",
	"noisy",
	"speaker",
	"broadcast"
],
	"📢": [
	"loudspeaker",
	"volume",
	"sound"
],
	"📣": [
	"megaphone",
	"sound",
	"speaker",
	"volume"
],
	"📯": [
	"postal_horn",
	"instrument",
	"music"
],
	"🔔": [
	"bell",
	"sound",
	"notification",
	"christmas",
	"xmas",
	"chime"
],
	"🔕": [
	"bell_with_slash",
	"sound",
	"volume",
	"mute",
	"quiet",
	"silent"
],
	"🎼": [
	"musical_score",
	"treble",
	"clef",
	"compose"
],
	"🎵": [
	"musical_note",
	"score",
	"tone",
	"sound"
],
	"🎶": [
	"musical_notes",
	"music",
	"score"
],
	"🎙️": [
	"studio_microphone",
	"sing",
	"recording",
	"artist",
	"talkshow"
],
	"🎚️": [
	"level_slider",
	"scale"
],
	"🎛️": [
	"control_knobs",
	"dial"
],
	"🎤": [
	"microphone",
	"sound",
	"music",
	"PA",
	"sing",
	"talkshow"
],
	"🎧": [
	"headphone",
	"music",
	"score",
	"gadgets"
],
	"📻": [
	"radio",
	"communication",
	"music",
	"podcast",
	"program"
],
	"🎷": [
	"saxophone",
	"music",
	"instrument",
	"jazz",
	"blues"
],
	"🎸": [
	"guitar",
	"music",
	"instrument"
],
	"🎹": [
	"musical_keyboard",
	"piano",
	"instrument",
	"compose"
],
	"🎺": [
	"trumpet",
	"music",
	"brass"
],
	"🎻": [
	"violin",
	"music",
	"instrument",
	"orchestra",
	"symphony"
],
	"🪕": [
	"banjo",
	"music",
	"instructment"
],
	"🥁": [
	"drum",
	"music",
	"instrument",
	"drumsticks",
	"snare"
],
	"📱": [
	"mobile_phone",
	"technology",
	"apple",
	"gadgets",
	"dial"
],
	"📲": [
	"mobile_phone_with_arrow",
	"iphone",
	"incoming"
],
	"☎️": [
	"telephone",
	"technology",
	"communication",
	"dial"
],
	"📞": [
	"telephone_receiver",
	"technology",
	"communication",
	"dial"
],
	"📟": [
	"pager",
	"bbcall",
	"oldschool",
	"90s"
],
	"📠": [
	"fax_machine",
	"communication",
	"technology"
],
	"🔋": [
	"battery",
	"power",
	"energy",
	"sustain"
],
	"🔌": [
	"electric_plug",
	"charger",
	"power"
],
	"💻": [
	"laptop",
	"technology",
	"screen",
	"display",
	"monitor"
],
	"🖥️": [
	"desktop_computer",
	"technology",
	"computing",
	"screen"
],
	"🖨️": [
	"printer",
	"paper",
	"ink"
],
	"⌨️": [
	"keyboard",
	"technology",
	"computer",
	"type",
	"input",
	"text"
],
	"🖱️": [
	"computer_mouse",
	"click"
],
	"🖲️": [
	"trackball",
	"technology",
	"trackpad"
],
	"💽": [
	"computer_disk",
	"technology",
	"record",
	"data",
	"disk",
	"90s"
],
	"💾": [
	"floppy_disk",
	"oldschool",
	"technology",
	"save",
	"90s",
	"80s"
],
	"💿": [
	"optical_disk",
	"technology",
	"dvd",
	"disk",
	"disc",
	"90s"
],
	"📀": [
	"dvd",
	"cd",
	"disk",
	"disc"
],
	"🧮": [
	"abacus",
	"calculation"
],
	"🎥": [
	"movie_camera",
	"film",
	"record"
],
	"🎞️": [
	"film_frames",
	"movie"
],
	"📽️": [
	"film_projector",
	"video",
	"tape",
	"record",
	"movie"
],
	"🎬": [
	"clapper_board",
	"movie",
	"film",
	"record"
],
	"📺": [
	"television",
	"technology",
	"program",
	"oldschool",
	"show"
],
	"📷": [
	"camera",
	"gadgets",
	"photography"
],
	"📸": [
	"camera_with_flash",
	"photography",
	"gadgets"
],
	"📹": [
	"video_camera",
	"film",
	"record"
],
	"📼": [
	"videocassette",
	"record",
	"video",
	"oldschool",
	"90s",
	"80s"
],
	"🔍": [
	"magnifying_glass_tilted_left",
	"search",
	"zoom",
	"find",
	"detective"
],
	"🔎": [
	"magnifying_glass_tilted_right",
	"search",
	"zoom",
	"find",
	"detective"
],
	"🕯️": [
	"candle",
	"fire",
	"wax"
],
	"💡": [
	"light_bulb",
	"light",
	"electricity",
	"idea"
],
	"🔦": [
	"flashlight",
	"dark",
	"camping",
	"sight",
	"night"
],
	"🏮": [
	"red_paper_lantern",
	"light",
	"paper",
	"halloween",
	"spooky"
],
	"🪔": [
	"diya_lamp",
	"lighting"
],
	"📔": [
	"notebook_with_decorative_cover",
	"classroom",
	"notes",
	"record",
	"paper",
	"study"
],
	"📕": [
	"closed_book",
	"read",
	"library",
	"knowledge",
	"textbook",
	"learn"
],
	"📖": [
	"open_book",
	"book",
	"read",
	"library",
	"knowledge",
	"literature",
	"learn",
	"study"
],
	"📗": [
	"green_book",
	"read",
	"library",
	"knowledge",
	"study"
],
	"📘": [
	"blue_book",
	"read",
	"library",
	"knowledge",
	"learn",
	"study"
],
	"📙": [
	"orange_book",
	"read",
	"library",
	"knowledge",
	"textbook",
	"study"
],
	"📚": [
	"books",
	"literature",
	"library",
	"study"
],
	"📓": [
	"notebook",
	"stationery",
	"record",
	"notes",
	"paper",
	"study"
],
	"📒": [
	"ledger",
	"notes",
	"paper"
],
	"📃": [
	"page_with_curl",
	"documents",
	"office",
	"paper"
],
	"📜": [
	"scroll",
	"documents",
	"ancient",
	"history",
	"paper"
],
	"📄": [
	"page_facing_up",
	"documents",
	"office",
	"paper",
	"information"
],
	"📰": [
	"newspaper",
	"press",
	"headline"
],
	"🗞️": [
	"rolled_up_newspaper",
	"press",
	"headline"
],
	"📑": [
	"bookmark_tabs",
	"favorite",
	"save",
	"order",
	"tidy"
],
	"🔖": [
	"bookmark",
	"favorite",
	"label",
	"save"
],
	"🏷️": [
	"label",
	"sale",
	"tag"
],
	"💰": [
	"money_bag",
	"dollar",
	"payment",
	"coins",
	"sale"
],
	"💴": [
	"yen_banknote",
	"money",
	"sales",
	"japanese",
	"dollar",
	"currency"
],
	"💵": [
	"dollar_banknote",
	"money",
	"sales",
	"bill",
	"currency"
],
	"💶": [
	"euro_banknote",
	"money",
	"sales",
	"dollar",
	"currency"
],
	"💷": [
	"pound_banknote",
	"british",
	"sterling",
	"money",
	"sales",
	"bills",
	"uk",
	"england",
	"currency"
],
	"💸": [
	"money_with_wings",
	"dollar",
	"bills",
	"payment",
	"sale"
],
	"💳": [
	"credit_card",
	"money",
	"sales",
	"dollar",
	"bill",
	"payment",
	"shopping"
],
	"🧾": [
	"receipt",
	"accounting",
	"expenses"
],
	"💹": [
	"chart_increasing_with_yen",
	"green-square",
	"graph",
	"presentation",
	"stats"
],
	"💱": [
	"currency_exchange",
	"money",
	"sales",
	"dollar",
	"travel"
],
	"💲": [
	"heavy_dollar_sign",
	"money",
	"sales",
	"payment",
	"currency",
	"buck"
],
	"✉️": [
	"envelope",
	"letter",
	"postal",
	"inbox",
	"communication"
],
	"📧": [
	"e_mail",
	"communication",
	"inbox"
],
	"📨": [
	"incoming_envelope",
	"email",
	"inbox"
],
	"📩": [
	"envelope_with_arrow",
	"email",
	"communication"
],
	"📤": [
	"outbox_tray",
	"inbox",
	"email"
],
	"📥": [
	"inbox_tray",
	"email",
	"documents"
],
	"📦": [
	"package",
	"mail",
	"gift",
	"cardboard",
	"box",
	"moving"
],
	"📫": [
	"closed_mailbox_with_raised_flag",
	"email",
	"inbox",
	"communication"
],
	"📪": [
	"closed_mailbox_with_lowered_flag",
	"email",
	"communication",
	"inbox"
],
	"📬": [
	"open_mailbox_with_raised_flag",
	"email",
	"inbox",
	"communication"
],
	"📭": [
	"open_mailbox_with_lowered_flag",
	"email",
	"inbox"
],
	"📮": [
	"postbox",
	"email",
	"letter",
	"envelope"
],
	"🗳️": [
	"ballot_box_with_ballot",
	"election",
	"vote"
],
	"✏️": [
	"pencil",
	"stationery",
	"write",
	"paper",
	"writing",
	"school",
	"study"
],
	"✒️": [
	"black_nib",
	"pen",
	"stationery",
	"writing",
	"write"
],
	"🖋️": [
	"fountain_pen",
	"stationery",
	"writing",
	"write"
],
	"🖊️": [
	"pen",
	"stationery",
	"writing",
	"write"
],
	"🖌️": [
	"paintbrush",
	"drawing",
	"creativity",
	"art"
],
	"🖍️": [
	"crayon",
	"drawing",
	"creativity"
],
	"📝": [
	"memo",
	"write",
	"documents",
	"stationery",
	"pencil",
	"paper",
	"writing",
	"legal",
	"exam",
	"quiz",
	"test",
	"study",
	"compose"
],
	"💼": [
	"briefcase",
	"business",
	"documents",
	"work",
	"law",
	"legal",
	"job",
	"career"
],
	"📁": [
	"file_folder",
	"documents",
	"business",
	"office"
],
	"📂": [
	"open_file_folder",
	"documents",
	"load"
],
	"🗂️": [
	"card_index_dividers",
	"organizing",
	"business",
	"stationery"
],
	"📅": [
	"calendar",
	"schedule"
],
	"📆": [
	"tear_off_calendar",
	"schedule",
	"date",
	"planning"
],
	"🗒️": [
	"spiral_notepad",
	"memo",
	"stationery"
],
	"🗓️": [
	"spiral_calendar",
	"date",
	"schedule",
	"planning"
],
	"📇": [
	"card_index",
	"business",
	"stationery"
],
	"📈": [
	"chart_increasing",
	"graph",
	"presentation",
	"stats",
	"recovery",
	"business",
	"economics",
	"money",
	"sales",
	"good",
	"success"
],
	"📉": [
	"chart_decreasing",
	"graph",
	"presentation",
	"stats",
	"recession",
	"business",
	"economics",
	"money",
	"sales",
	"bad",
	"failure"
],
	"📊": [
	"bar_chart",
	"graph",
	"presentation",
	"stats"
],
	"📋": [
	"clipboard",
	"stationery",
	"documents"
],
	"📌": [
	"pushpin",
	"stationery",
	"mark",
	"here"
],
	"📍": [
	"round_pushpin",
	"stationery",
	"location",
	"map",
	"here"
],
	"📎": [
	"paperclip",
	"documents",
	"stationery"
],
	"🖇️": [
	"linked_paperclips",
	"documents",
	"stationery"
],
	"📏": [
	"straight_ruler",
	"stationery",
	"calculate",
	"length",
	"math",
	"school",
	"drawing",
	"architect",
	"sketch"
],
	"📐": [
	"triangular_ruler",
	"stationery",
	"math",
	"architect",
	"sketch"
],
	"✂️": [
	"scissors",
	"stationery",
	"cut"
],
	"🗃️": [
	"card_file_box",
	"business",
	"stationery"
],
	"🗄️": [
	"file_cabinet",
	"filing",
	"organizing"
],
	"🗑️": [
	"wastebasket",
	"bin",
	"trash",
	"rubbish",
	"garbage",
	"toss"
],
	"🔒": [
	"locked",
	"security",
	"password",
	"padlock"
],
	"🔓": [
	"unlocked",
	"privacy",
	"security"
],
	"🔏": [
	"locked_with_pen",
	"security",
	"secret"
],
	"🔐": [
	"locked_with_key",
	"security",
	"privacy"
],
	"🔑": [
	"key",
	"lock",
	"door",
	"password"
],
	"🗝️": [
	"old_key",
	"lock",
	"door",
	"password"
],
	"🔨": [
	"hammer",
	"tools",
	"build",
	"create"
],
	"🪓": [
	"axe",
	"tool",
	"chop",
	"cut"
],
	"⛏️": [
	"pick",
	"tools",
	"dig"
],
	"⚒️": [
	"hammer_and_pick",
	"tools",
	"build",
	"create"
],
	"🛠️": [
	"hammer_and_wrench",
	"tools",
	"build",
	"create"
],
	"🗡️": [
	"dagger",
	"weapon"
],
	"⚔️": [
	"crossed_swords",
	"weapon"
],
	"🔫": [
	"pistol",
	"violence",
	"weapon",
	"revolver"
],
	"🏹": [
	"bow_and_arrow",
	"sports"
],
	"🛡️": [
	"shield",
	"protection",
	"security"
],
	"🔧": [
	"wrench",
	"tools",
	"diy",
	"ikea",
	"fix",
	"maintainer"
],
	"🔩": [
	"nut_and_bolt",
	"handy",
	"tools",
	"fix"
],
	"⚙️": [
	"gear",
	"cog"
],
	"🗜️": [
	"clamp",
	"tool"
],
	"⚖️": [
	"balance_scale",
	"law",
	"fairness",
	"weight"
],
	"🦯": [
	"probing_cane",
	"accessibility"
],
	"🔗": [
	"link",
	"rings",
	"url"
],
	"⛓️": [
	"chains",
	"lock",
	"arrest"
],
	"🧰": [
	"toolbox",
	"tools",
	"diy",
	"fix",
	"maintainer",
	"mechanic"
],
	"🧲": [
	"magnet",
	"attraction",
	"magnetic"
],
	"⚗️": [
	"alembic",
	"distilling",
	"science",
	"experiment",
	"chemistry"
],
	"🧪": [
	"test_tube",
	"chemistry",
	"experiment",
	"lab",
	"science"
],
	"🧫": [
	"petri_dish",
	"bacteria",
	"biology",
	"culture",
	"lab"
],
	"🧬": [
	"dna",
	"biologist",
	"genetics",
	"life"
],
	"🔬": [
	"microscope",
	"laboratory",
	"experiment",
	"zoomin",
	"science",
	"study"
],
	"🔭": [
	"telescope",
	"stars",
	"space",
	"zoom",
	"science",
	"astronomy"
],
	"📡": [
	"satellite_antenna",
	"communication",
	"future",
	"radio",
	"space"
],
	"💉": [
	"syringe",
	"health",
	"hospital",
	"drugs",
	"blood",
	"medicine",
	"needle",
	"doctor",
	"nurse"
],
	"🩸": [
	"drop_of_blood",
	"period",
	"hurt",
	"harm",
	"wound"
],
	"💊": [
	"pill",
	"health",
	"medicine",
	"doctor",
	"pharmacy",
	"drug"
],
	"🩹": [
	"adhesive_bandage",
	"heal"
],
	"🩺": [
	"stethoscope",
	"health"
],
	"🚪": [
	"door",
	"house",
	"entry",
	"exit"
],
	"🛏️": [
	"bed",
	"sleep",
	"rest"
],
	"🛋️": [
	"couch_and_lamp",
	"read",
	"chill"
],
	"🪑": [
	"chair",
	"sit",
	"furniture"
],
	"🚽": [
	"toilet",
	"restroom",
	"wc",
	"washroom",
	"bathroom",
	"potty"
],
	"🚿": [
	"shower",
	"clean",
	"water",
	"bathroom"
],
	"🛁": [
	"bathtub",
	"clean",
	"shower",
	"bathroom"
],
	"🪒": [
	"razor",
	"cut"
],
	"🧴": [
	"lotion_bottle",
	"moisturizer",
	"sunscreen"
],
	"🧷": [
	"safety_pin",
	"diaper"
],
	"🧹": [
	"broom",
	"cleaning",
	"sweeping",
	"witch"
],
	"🧺": [
	"basket",
	"laundry"
],
	"🧻": [
	"roll_of_paper",
	"roll"
],
	"🧼": [
	"soap",
	"bar",
	"bathing",
	"cleaning",
	"lather"
],
	"🧽": [
	"sponge",
	"absorbing",
	"cleaning",
	"porous"
],
	"🧯": [
	"fire_extinguisher",
	"quench"
],
	"🛒": [
	"shopping_cart",
	"trolley"
],
	"🚬": [
	"cigarette",
	"kills",
	"tobacco",
	"joint",
	"smoke"
],
	"⚰️": [
	"coffin",
	"vampire",
	"dead",
	"die",
	"death",
	"rip",
	"graveyard",
	"cemetery",
	"casket",
	"funeral",
	"box"
],
	"⚱️": [
	"funeral_urn",
	"dead",
	"die",
	"death",
	"rip",
	"ashes"
],
	"🗿": [
	"moai",
	"rock",
	"easter island"
],
	"🏧": [
	"atm_sign",
	"money",
	"sales",
	"cash",
	"blue-square",
	"payment",
	"bank"
],
	"🚮": [
	"litter_in_bin_sign",
	"blue-square",
	"sign",
	"human",
	"info"
],
	"🚰": [
	"potable_water",
	"blue-square",
	"liquid",
	"restroom",
	"cleaning",
	"faucet"
],
	"♿": [
	"wheelchair_symbol",
	"blue-square",
	"disabled",
	"accessibility"
],
	"🚹": [
	"men_s_room",
	"toilet",
	"restroom",
	"wc",
	"blue-square",
	"gender",
	"male"
],
	"🚺": [
	"women_s_room",
	"purple-square",
	"woman",
	"female",
	"toilet",
	"loo",
	"restroom",
	"gender"
],
	"🚻": [
	"restroom",
	"blue-square",
	"toilet",
	"refresh",
	"wc",
	"gender"
],
	"🚼": [
	"baby_symbol",
	"orange-square",
	"child"
],
	"🚾": [
	"water_closet",
	"toilet",
	"restroom",
	"blue-square"
],
	"🛂": [
	"passport_control",
	"custom",
	"blue-square"
],
	"🛃": [
	"customs",
	"passport",
	"border",
	"blue-square"
],
	"🛄": [
	"baggage_claim",
	"blue-square",
	"airport",
	"transport"
],
	"🛅": [
	"left_luggage",
	"blue-square",
	"travel"
],
	"⚠️": [
	"warning",
	"exclamation",
	"wip",
	"alert",
	"error",
	"problem",
	"issue"
],
	"🚸": [
	"children_crossing",
	"school",
	"warning",
	"danger",
	"sign",
	"driving",
	"yellow-diamond"
],
	"⛔": [
	"no_entry",
	"limit",
	"security",
	"privacy",
	"bad",
	"denied",
	"stop",
	"circle"
],
	"🚫": [
	"prohibited",
	"forbid",
	"stop",
	"limit",
	"denied",
	"disallow",
	"circle"
],
	"🚳": [
	"no_bicycles",
	"no_bikes",
	"bicycle",
	"bike",
	"cyclist",
	"prohibited",
	"circle"
],
	"🚭": [
	"no_smoking",
	"cigarette",
	"blue-square",
	"smell",
	"smoke"
],
	"🚯": [
	"no_littering",
	"trash",
	"bin",
	"garbage",
	"circle"
],
	"🚱": [
	"non_potable_water",
	"drink",
	"faucet",
	"tap",
	"circle"
],
	"🚷": [
	"no_pedestrians",
	"rules",
	"crossing",
	"walking",
	"circle"
],
	"📵": [
	"no_mobile_phones",
	"iphone",
	"mute",
	"circle"
],
	"🔞": [
	"no_one_under_eighteen",
	"18",
	"drink",
	"pub",
	"night",
	"minor",
	"circle"
],
	"☢️": [
	"radioactive",
	"nuclear",
	"danger"
],
	"☣️": [
	"biohazard",
	"danger"
],
	"⬆️": [
	"up_arrow",
	"blue-square",
	"continue",
	"top",
	"direction"
],
	"↗️": [
	"up_right_arrow",
	"blue-square",
	"point",
	"direction",
	"diagonal",
	"northeast"
],
	"➡️": [
	"right_arrow",
	"blue-square",
	"next"
],
	"↘️": [
	"down_right_arrow",
	"blue-square",
	"direction",
	"diagonal",
	"southeast"
],
	"⬇️": [
	"down_arrow",
	"blue-square",
	"direction",
	"bottom"
],
	"↙️": [
	"down_left_arrow",
	"blue-square",
	"direction",
	"diagonal",
	"southwest"
],
	"⬅️": [
	"left_arrow",
	"blue-square",
	"previous",
	"back"
],
	"↖️": [
	"up_left_arrow",
	"blue-square",
	"point",
	"direction",
	"diagonal",
	"northwest"
],
	"↕️": [
	"up_down_arrow",
	"blue-square",
	"direction",
	"way",
	"vertical"
],
	"↔️": [
	"left_right_arrow",
	"shape",
	"direction",
	"horizontal",
	"sideways"
],
	"↩️": [
	"right_arrow_curving_left",
	"back",
	"return",
	"blue-square",
	"undo",
	"enter"
],
	"↪️": [
	"left_arrow_curving_right",
	"blue-square",
	"return",
	"rotate",
	"direction"
],
	"⤴️": [
	"right_arrow_curving_up",
	"blue-square",
	"direction",
	"top"
],
	"⤵️": [
	"right_arrow_curving_down",
	"blue-square",
	"direction",
	"bottom"
],
	"🔃": [
	"clockwise_vertical_arrows",
	"sync",
	"cycle",
	"round",
	"repeat"
],
	"🔄": [
	"counterclockwise_arrows_button",
	"blue-square",
	"sync",
	"cycle"
],
	"🔙": [
	"back_arrow",
	"arrow",
	"words",
	"return"
],
	"🔚": [
	"end_arrow",
	"words",
	"arrow"
],
	"🔛": [
	"on_arrow",
	"arrow",
	"words"
],
	"🔜": [
	"soon_arrow",
	"arrow",
	"words"
],
	"🔝": [
	"top_arrow",
	"words",
	"blue-square"
],
	"🛐": [
	"place_of_worship",
	"religion",
	"church",
	"temple",
	"prayer"
],
	"⚛️": [
	"atom_symbol",
	"science",
	"physics",
	"chemistry"
],
	"🕉️": [
	"om",
	"hinduism",
	"buddhism",
	"sikhism",
	"jainism"
],
	"✡️": [
	"star_of_david",
	"judaism"
],
	"☸️": [
	"wheel_of_dharma",
	"hinduism",
	"buddhism",
	"sikhism",
	"jainism"
],
	"☯️": [
	"yin_yang",
	"balance"
],
	"✝️": [
	"latin_cross",
	"christianity"
],
	"☦️": [
	"orthodox_cross",
	"suppedaneum",
	"religion"
],
	"☪️": [
	"star_and_crescent",
	"islam"
],
	"☮️": [
	"peace_symbol",
	"hippie"
],
	"🕎": [
	"menorah",
	"hanukkah",
	"candles",
	"jewish"
],
	"🔯": [
	"dotted_six_pointed_star",
	"purple-square",
	"religion",
	"jewish",
	"hexagram"
],
	"♈": [
	"aries",
	"sign",
	"purple-square",
	"zodiac",
	"astrology"
],
	"♉": [
	"taurus",
	"purple-square",
	"sign",
	"zodiac",
	"astrology"
],
	"♊": [
	"gemini",
	"sign",
	"zodiac",
	"purple-square",
	"astrology"
],
	"♋": [
	"cancer",
	"sign",
	"zodiac",
	"purple-square",
	"astrology"
],
	"♌": [
	"leo",
	"sign",
	"purple-square",
	"zodiac",
	"astrology"
],
	"♍": [
	"virgo",
	"sign",
	"zodiac",
	"purple-square",
	"astrology"
],
	"♎": [
	"libra",
	"sign",
	"purple-square",
	"zodiac",
	"astrology"
],
	"♏": [
	"scorpio",
	"sign",
	"zodiac",
	"purple-square",
	"astrology"
],
	"♐": [
	"sagittarius",
	"sign",
	"zodiac",
	"purple-square",
	"astrology"
],
	"♑": [
	"capricorn",
	"sign",
	"zodiac",
	"purple-square",
	"astrology"
],
	"♒": [
	"aquarius",
	"sign",
	"purple-square",
	"zodiac",
	"astrology"
],
	"♓": [
	"pisces",
	"purple-square",
	"sign",
	"zodiac",
	"astrology"
],
	"⛎": [
	"ophiuchus",
	"sign",
	"purple-square",
	"constellation",
	"astrology"
],
	"🔀": [
	"shuffle_tracks_button",
	"blue-square",
	"shuffle",
	"music",
	"random"
],
	"🔁": [
	"repeat_button",
	"loop",
	"record"
],
	"🔂": [
	"repeat_single_button",
	"blue-square",
	"loop"
],
	"▶️": [
	"play_button",
	"blue-square",
	"right",
	"direction",
	"play"
],
	"⏩": [
	"fast_forward_button",
	"blue-square",
	"play",
	"speed",
	"continue"
],
	"⏭️": [
	"next_track_button",
	"forward",
	"next",
	"blue-square"
],
	"⏯️": [
	"play_or_pause_button",
	"blue-square",
	"play",
	"pause"
],
	"◀️": [
	"reverse_button",
	"blue-square",
	"left",
	"direction"
],
	"⏪": [
	"fast_reverse_button",
	"play",
	"blue-square"
],
	"⏮️": [
	"last_track_button",
	"backward"
],
	"🔼": [
	"upwards_button",
	"blue-square",
	"triangle",
	"direction",
	"point",
	"forward",
	"top"
],
	"⏫": [
	"fast_up_button",
	"blue-square",
	"direction",
	"top"
],
	"🔽": [
	"downwards_button",
	"blue-square",
	"direction",
	"bottom"
],
	"⏬": [
	"fast_down_button",
	"blue-square",
	"direction",
	"bottom"
],
	"⏸️": [
	"pause_button",
	"pause",
	"blue-square"
],
	"⏹️": [
	"stop_button",
	"blue-square"
],
	"⏺️": [
	"record_button",
	"blue-square"
],
	"⏏️": [
	"eject_button",
	"blue-square"
],
	"🎦": [
	"cinema",
	"blue-square",
	"record",
	"film",
	"movie",
	"curtain",
	"stage",
	"theater"
],
	"🔅": [
	"dim_button",
	"sun",
	"afternoon",
	"warm",
	"summer"
],
	"🔆": [
	"bright_button",
	"sun",
	"light"
],
	"📶": [
	"antenna_bars",
	"blue-square",
	"reception",
	"phone",
	"internet",
	"connection",
	"wifi",
	"bluetooth",
	"bars"
],
	"📳": [
	"vibration_mode",
	"orange-square",
	"phone"
],
	"📴": [
	"mobile_phone_off",
	"mute",
	"orange-square",
	"silence",
	"quiet"
],
	"♀️": [
	"female_sign",
	"woman",
	"women",
	"lady",
	"girl"
],
	"♂️": [
	"male_sign",
	"man",
	"boy",
	"men"
],
	"⚕️": [
	"medical_symbol",
	"health",
	"hospital"
],
	"♾️": [
	"infinity",
	"forever"
],
	"♻️": [
	"recycling_symbol",
	"arrow",
	"environment",
	"garbage",
	"trash"
],
	"⚜️": [
	"fleur_de_lis",
	"decorative",
	"scout"
],
	"🔱": [
	"trident_emblem",
	"weapon",
	"spear"
],
	"📛": [
	"name_badge",
	"fire",
	"forbid"
],
	"🔰": [
	"japanese_symbol_for_beginner",
	"badge",
	"shield"
],
	"⭕": [
	"hollow_red_circle",
	"circle",
	"round"
],
	"✅": [
	"check_mark_button",
	"green-square",
	"ok",
	"agree",
	"vote",
	"election",
	"answer",
	"tick"
],
	"☑️": [
	"check_box_with_check",
	"ok",
	"agree",
	"confirm",
	"black-square",
	"vote",
	"election",
	"yes",
	"tick"
],
	"✔️": [
	"check_mark",
	"ok",
	"nike",
	"answer",
	"yes",
	"tick"
],
	"✖️": [
	"multiplication_sign",
	"math",
	"calculation"
],
	"❌": [
	"cross_mark",
	"no",
	"delete",
	"remove",
	"cancel",
	"red"
],
	"❎": [
	"cross_mark_button",
	"x",
	"green-square",
	"no",
	"deny"
],
	"➕": [
	"plus_sign",
	"math",
	"calculation",
	"addition",
	"more",
	"increase"
],
	"➖": [
	"minus_sign",
	"math",
	"calculation",
	"subtract",
	"less"
],
	"➗": [
	"division_sign",
	"divide",
	"math",
	"calculation"
],
	"➰": [
	"curly_loop",
	"scribble",
	"draw",
	"shape",
	"squiggle"
],
	"➿": [
	"double_curly_loop",
	"tape",
	"cassette"
],
	"〽️": [
	"part_alternation_mark",
	"graph",
	"presentation",
	"stats",
	"business",
	"economics",
	"bad"
],
	"✳️": [
	"eight_spoked_asterisk",
	"star",
	"sparkle",
	"green-square"
],
	"✴️": [
	"eight_pointed_star",
	"orange-square",
	"shape",
	"polygon"
],
	"❇️": [
	"sparkle",
	"stars",
	"green-square",
	"awesome",
	"good",
	"fireworks"
],
	"‼️": [
	"double_exclamation_mark",
	"exclamation",
	"surprise"
],
	"⁉️": [
	"exclamation_question_mark",
	"wat",
	"punctuation",
	"surprise"
],
	"❓": [
	"question_mark",
	"doubt",
	"confused"
],
	"❔": [
	"white_question_mark",
	"doubts",
	"gray",
	"huh",
	"confused"
],
	"❕": [
	"white_exclamation_mark",
	"surprise",
	"punctuation",
	"gray",
	"wow",
	"warning"
],
	"❗": [
	"exclamation_mark",
	"heavy_exclamation_mark",
	"danger",
	"surprise",
	"punctuation",
	"wow",
	"warning"
],
	"〰️": [
	"wavy_dash",
	"draw",
	"line",
	"moustache",
	"mustache",
	"squiggle",
	"scribble"
],
	"©️": [
	"copyright",
	"ip",
	"license",
	"circle",
	"law",
	"legal"
],
	"®️": [
	"registered",
	"alphabet",
	"circle"
],
	"™️": [
	"trade_mark",
	"trademark",
	"brand",
	"law",
	"legal"
],
	"#️⃣": [
	"keycap_",
	"symbol",
	"blue-square",
	"twitter"
],
	"*️⃣": [
	"keycap_",
	"star",
	"keycap"
],
	"0️⃣": [
	"keycap_0",
	"0",
	"numbers",
	"blue-square",
	"null",
	"zero"
],
	"1️⃣": [
	"keycap_1",
	"blue-square",
	"numbers",
	"1",
	"one"
],
	"2️⃣": [
	"keycap_2",
	"numbers",
	"2",
	"prime",
	"blue-square",
	"two"
],
	"3️⃣": [
	"keycap_3",
	"3",
	"numbers",
	"prime",
	"blue-square",
	"three"
],
	"4️⃣": [
	"keycap_4",
	"4",
	"numbers",
	"blue-square",
	"four"
],
	"5️⃣": [
	"keycap_5",
	"5",
	"numbers",
	"blue-square",
	"prime",
	"five"
],
	"6️⃣": [
	"keycap_6",
	"6",
	"numbers",
	"blue-square",
	"six"
],
	"7️⃣": [
	"keycap_7",
	"7",
	"numbers",
	"blue-square",
	"prime",
	"seven"
],
	"8️⃣": [
	"keycap_8",
	"8",
	"blue-square",
	"numbers",
	"eight"
],
	"9️⃣": [
	"keycap_9",
	"blue-square",
	"numbers",
	"9",
	"nine"
],
	"🔟": [
	"keycap_10",
	"numbers",
	"10",
	"blue-square",
	"ten"
],
	"🔠": [
	"input_latin_uppercase",
	"alphabet",
	"words",
	"letters",
	"uppercase",
	"blue-square"
],
	"🔡": [
	"input_latin_lowercase",
	"blue-square",
	"letters",
	"lowercase",
	"alphabet"
],
	"🔢": [
	"input_numbers",
	"numbers",
	"blue-square",
	"1234",
	"1",
	"2",
	"3",
	"4"
],
	"🔣": [
	"input_symbols",
	"blue-square",
	"music",
	"note",
	"ampersand",
	"percent",
	"glyphs",
	"characters"
],
	"🔤": [
	"input_latin_letters",
	"blue-square",
	"alphabet"
],
	"🅰️": [
	"a_button",
	"red-square",
	"alphabet",
	"letter"
],
	"🆎": [
	"ab_button",
	"red-square",
	"alphabet"
],
	"🅱️": [
	"b_button",
	"red-square",
	"alphabet",
	"letter"
],
	"🆑": [
	"cl_button",
	"alphabet",
	"words",
	"red-square"
],
	"🆒": [
	"cool_button",
	"words",
	"blue-square"
],
	"🆓": [
	"free_button",
	"blue-square",
	"words"
],
	"ℹ️": [
	"information",
	"blue-square",
	"alphabet",
	"letter"
],
	"🆔": [
	"id_button",
	"purple-square",
	"words"
],
	"Ⓜ️": [
	"circled_m",
	"alphabet",
	"blue-circle",
	"letter"
],
	"🆕": [
	"new_button",
	"blue-square",
	"words",
	"start"
],
	"🆖": [
	"ng_button",
	"blue-square",
	"words",
	"shape",
	"icon"
],
	"🅾️": [
	"o_button",
	"alphabet",
	"red-square",
	"letter"
],
	"🆗": [
	"ok_button",
	"good",
	"agree",
	"yes",
	"blue-square"
],
	"🅿️": [
	"p_button",
	"cars",
	"blue-square",
	"alphabet",
	"letter"
],
	"🆘": [
	"sos_button",
	"help",
	"red-square",
	"words",
	"emergency",
	"911"
],
	"🆙": [
	"up_button",
	"blue-square",
	"above",
	"high"
],
	"🆚": [
	"vs_button",
	"words",
	"orange-square"
],
	"🈁": [
	"japanese_here_button",
	"blue-square",
	"here",
	"katakana",
	"japanese",
	"destination"
],
	"🈂️": [
	"japanese_service_charge_button",
	"japanese",
	"blue-square",
	"katakana"
],
	"🈷️": [
	"japanese_monthly_amount_button",
	"chinese",
	"month",
	"moon",
	"japanese",
	"orange-square",
	"kanji"
],
	"🈶": [
	"japanese_not_free_of_charge_button",
	"orange-square",
	"chinese",
	"have",
	"kanji"
],
	"🈯": [
	"japanese_reserved_button",
	"chinese",
	"point",
	"green-square",
	"kanji"
],
	"🉐": [
	"japanese_bargain_button",
	"chinese",
	"kanji",
	"obtain",
	"get",
	"circle"
],
	"🈹": [
	"japanese_discount_button",
	"cut",
	"divide",
	"chinese",
	"kanji",
	"pink-square"
],
	"🈚": [
	"japanese_free_of_charge_button",
	"nothing",
	"chinese",
	"kanji",
	"japanese",
	"orange-square"
],
	"🈲": [
	"japanese_prohibited_button",
	"kanji",
	"japanese",
	"chinese",
	"forbidden",
	"limit",
	"restricted",
	"red-square"
],
	"🉑": [
	"japanese_acceptable_button",
	"ok",
	"good",
	"chinese",
	"kanji",
	"agree",
	"yes",
	"orange-circle"
],
	"🈸": [
	"japanese_application_button",
	"chinese",
	"japanese",
	"kanji",
	"orange-square"
],
	"🈴": [
	"japanese_passing_grade_button",
	"japanese",
	"chinese",
	"join",
	"kanji",
	"red-square"
],
	"🈳": [
	"japanese_vacancy_button",
	"kanji",
	"japanese",
	"chinese",
	"empty",
	"sky",
	"blue-square"
],
	"㊗️": [
	"japanese_congratulations_button",
	"chinese",
	"kanji",
	"japanese",
	"red-circle"
],
	"㊙️": [
	"japanese_secret_button",
	"privacy",
	"chinese",
	"sshh",
	"kanji",
	"red-circle"
],
	"🈺": [
	"japanese_open_for_business_button",
	"japanese",
	"opening hours",
	"orange-square"
],
	"🈵": [
	"japanese_no_vacancy_button",
	"full",
	"chinese",
	"japanese",
	"red-square",
	"kanji"
],
	"🔴": [
	"red_circle",
	"shape",
	"error",
	"danger"
],
	"🟠": [
	"orange_circle",
	"round"
],
	"🟡": [
	"yellow_circle",
	"round"
],
	"🟢": [
	"green_circle",
	"round"
],
	"🔵": [
	"blue_circle",
	"shape",
	"icon",
	"button"
],
	"🟣": [
	"purple_circle",
	"round"
],
	"🟤": [
	"brown_circle",
	"round"
],
	"⚫": [
	"black_circle",
	"shape",
	"button",
	"round"
],
	"⚪": [
	"white_circle",
	"shape",
	"round"
],
	"🟥": [
	"red_square"
],
	"🟧": [
	"orange_square"
],
	"🟨": [
	"yellow_square"
],
	"🟩": [
	"green_square"
],
	"🟦": [
	"blue_square"
],
	"🟪": [
	"purple_square"
],
	"🟫": [
	"brown_square"
],
	"⬛": [
	"black_large_square",
	"shape",
	"icon",
	"button"
],
	"⬜": [
	"white_large_square",
	"shape",
	"icon",
	"stone",
	"button"
],
	"◼️": [
	"black_medium_square",
	"shape",
	"button",
	"icon"
],
	"◻️": [
	"white_medium_square",
	"shape",
	"stone",
	"icon"
],
	"◾": [
	"black_medium_small_square",
	"icon",
	"shape",
	"button"
],
	"◽": [
	"white_medium_small_square",
	"shape",
	"stone",
	"icon",
	"button"
],
	"▪️": [
	"black_small_square",
	"shape",
	"icon"
],
	"▫️": [
	"white_small_square",
	"shape",
	"icon"
],
	"🔶": [
	"large_orange_diamond",
	"shape",
	"jewel",
	"gem"
],
	"🔷": [
	"large_blue_diamond",
	"shape",
	"jewel",
	"gem"
],
	"🔸": [
	"small_orange_diamond",
	"shape",
	"jewel",
	"gem"
],
	"🔹": [
	"small_blue_diamond",
	"shape",
	"jewel",
	"gem"
],
	"🔺": [
	"red_triangle_pointed_up",
	"shape",
	"direction",
	"up",
	"top"
],
	"🔻": [
	"red_triangle_pointed_down",
	"shape",
	"direction",
	"bottom"
],
	"💠": [
	"diamond_with_a_dot",
	"jewel",
	"blue",
	"gem",
	"crystal",
	"fancy"
],
	"🔘": [
	"radio_button",
	"input",
	"old",
	"music",
	"circle"
],
	"🔳": [
	"white_square_button",
	"shape",
	"input"
],
	"🔲": [
	"black_square_button",
	"shape",
	"input",
	"frame"
],
	"🏁": [
	"chequered_flag",
	"contest",
	"finishline",
	"race",
	"gokart"
],
	"🚩": [
	"triangular_flag",
	"mark",
	"milestone",
	"place"
],
	"🎌": [
	"crossed_flags",
	"japanese",
	"nation",
	"country",
	"border"
],
	"🏴": [
	"black_flag",
	"pirate"
],
	"🏳️": [
	"white_flag",
	"losing",
	"loser",
	"lost",
	"surrender",
	"give up",
	"fail"
],
	"🏳️‍🌈": [
	"rainbow_flag",
	"flag",
	"rainbow",
	"pride",
	"gay",
	"lgbt",
	"queer",
	"homosexual",
	"lesbian",
	"bisexual"
],
	"🏴‍☠️": [
	"pirate_flag",
	"skull",
	"crossbones",
	"flag",
	"banner"
],
	"🇦🇨": [
	"flag_ascension_island"
],
	"🇦🇩": [
	"flag_andorra",
	"ad",
	"flag",
	"nation",
	"country",
	"banner",
	"andorra"
],
	"🇦🇪": [
	"flag_united_arab_emirates",
	"united",
	"arab",
	"emirates",
	"flag",
	"nation",
	"country",
	"banner",
	"united_arab_emirates"
],
	"🇦🇫": [
	"flag_afghanistan",
	"af",
	"flag",
	"nation",
	"country",
	"banner",
	"afghanistan"
],
	"🇦🇬": [
	"flag_antigua_barbuda",
	"antigua",
	"barbuda",
	"flag",
	"nation",
	"country",
	"banner",
	"antigua_barbuda"
],
	"🇦🇮": [
	"flag_anguilla",
	"ai",
	"flag",
	"nation",
	"country",
	"banner",
	"anguilla"
],
	"🇦🇱": [
	"flag_albania",
	"al",
	"flag",
	"nation",
	"country",
	"banner",
	"albania"
],
	"🇦🇲": [
	"flag_armenia",
	"am",
	"flag",
	"nation",
	"country",
	"banner",
	"armenia"
],
	"🇦🇴": [
	"flag_angola",
	"ao",
	"flag",
	"nation",
	"country",
	"banner",
	"angola"
],
	"🇦🇶": [
	"flag_antarctica",
	"aq",
	"flag",
	"nation",
	"country",
	"banner",
	"antarctica"
],
	"🇦🇷": [
	"flag_argentina",
	"ar",
	"flag",
	"nation",
	"country",
	"banner",
	"argentina"
],
	"🇦🇸": [
	"flag_american_samoa",
	"american",
	"ws",
	"flag",
	"nation",
	"country",
	"banner",
	"american_samoa"
],
	"🇦🇹": [
	"flag_austria",
	"at",
	"flag",
	"nation",
	"country",
	"banner",
	"austria"
],
	"🇦🇺": [
	"flag_australia",
	"au",
	"flag",
	"nation",
	"country",
	"banner",
	"australia"
],
	"🇦🇼": [
	"flag_aruba",
	"aw",
	"flag",
	"nation",
	"country",
	"banner",
	"aruba"
],
	"🇦🇽": [
	"flag_aland_islands",
	"Åland",
	"islands",
	"flag",
	"nation",
	"country",
	"banner",
	"aland_islands"
],
	"🇦🇿": [
	"flag_azerbaijan",
	"az",
	"flag",
	"nation",
	"country",
	"banner",
	"azerbaijan"
],
	"🇧🇦": [
	"flag_bosnia_herzegovina",
	"bosnia",
	"herzegovina",
	"flag",
	"nation",
	"country",
	"banner",
	"bosnia_herzegovina"
],
	"🇧🇧": [
	"flag_barbados",
	"bb",
	"flag",
	"nation",
	"country",
	"banner",
	"barbados"
],
	"🇧🇩": [
	"flag_bangladesh",
	"bd",
	"flag",
	"nation",
	"country",
	"banner",
	"bangladesh"
],
	"🇧🇪": [
	"flag_belgium",
	"be",
	"flag",
	"nation",
	"country",
	"banner",
	"belgium"
],
	"🇧🇫": [
	"flag_burkina_faso",
	"burkina",
	"faso",
	"flag",
	"nation",
	"country",
	"banner",
	"burkina_faso"
],
	"🇧🇬": [
	"flag_bulgaria",
	"bg",
	"flag",
	"nation",
	"country",
	"banner",
	"bulgaria"
],
	"🇧🇭": [
	"flag_bahrain",
	"bh",
	"flag",
	"nation",
	"country",
	"banner",
	"bahrain"
],
	"🇧🇮": [
	"flag_burundi",
	"bi",
	"flag",
	"nation",
	"country",
	"banner",
	"burundi"
],
	"🇧🇯": [
	"flag_benin",
	"bj",
	"flag",
	"nation",
	"country",
	"banner",
	"benin"
],
	"🇧🇱": [
	"flag_st_barthelemy",
	"saint",
	"barthélemy",
	"flag",
	"nation",
	"country",
	"banner",
	"st_barthelemy"
],
	"🇧🇲": [
	"flag_bermuda",
	"bm",
	"flag",
	"nation",
	"country",
	"banner",
	"bermuda"
],
	"🇧🇳": [
	"flag_brunei",
	"bn",
	"darussalam",
	"flag",
	"nation",
	"country",
	"banner",
	"brunei"
],
	"🇧🇴": [
	"flag_bolivia",
	"bo",
	"flag",
	"nation",
	"country",
	"banner",
	"bolivia"
],
	"🇧🇶": [
	"flag_caribbean_netherlands",
	"bonaire",
	"flag",
	"nation",
	"country",
	"banner",
	"caribbean_netherlands"
],
	"🇧🇷": [
	"flag_brazil",
	"br",
	"flag",
	"nation",
	"country",
	"banner",
	"brazil"
],
	"🇧🇸": [
	"flag_bahamas",
	"bs",
	"flag",
	"nation",
	"country",
	"banner",
	"bahamas"
],
	"🇧🇹": [
	"flag_bhutan",
	"bt",
	"flag",
	"nation",
	"country",
	"banner",
	"bhutan"
],
	"🇧🇻": [
	"flag_bouvet_island",
	"norway"
],
	"🇧🇼": [
	"flag_botswana",
	"bw",
	"flag",
	"nation",
	"country",
	"banner",
	"botswana"
],
	"🇧🇾": [
	"flag_belarus",
	"by",
	"flag",
	"nation",
	"country",
	"banner",
	"belarus"
],
	"🇧🇿": [
	"flag_belize",
	"bz",
	"flag",
	"nation",
	"country",
	"banner",
	"belize"
],
	"🇨🇦": [
	"flag_canada",
	"ca",
	"flag",
	"nation",
	"country",
	"banner",
	"canada"
],
	"🇨🇨": [
	"flag_cocos_islands",
	"cocos",
	"keeling",
	"islands",
	"flag",
	"nation",
	"country",
	"banner",
	"cocos_islands"
],
	"🇨🇩": [
	"flag_congo_kinshasa",
	"congo",
	"democratic",
	"republic",
	"flag",
	"nation",
	"country",
	"banner",
	"congo_kinshasa"
],
	"🇨🇫": [
	"flag_central_african_republic",
	"central",
	"african",
	"republic",
	"flag",
	"nation",
	"country",
	"banner",
	"central_african_republic"
],
	"🇨🇬": [
	"flag_congo_brazzaville",
	"congo",
	"flag",
	"nation",
	"country",
	"banner",
	"congo_brazzaville"
],
	"🇨🇭": [
	"flag_switzerland",
	"ch",
	"flag",
	"nation",
	"country",
	"banner",
	"switzerland"
],
	"🇨🇮": [
	"flag_cote_d_ivoire",
	"ivory",
	"coast",
	"flag",
	"nation",
	"country",
	"banner",
	"cote_d_ivoire"
],
	"🇨🇰": [
	"flag_cook_islands",
	"cook",
	"islands",
	"flag",
	"nation",
	"country",
	"banner",
	"cook_islands"
],
	"🇨🇱": [
	"flag_chile",
	"flag",
	"nation",
	"country",
	"banner",
	"chile"
],
	"🇨🇲": [
	"flag_cameroon",
	"cm",
	"flag",
	"nation",
	"country",
	"banner",
	"cameroon"
],
	"🇨🇳": [
	"flag_china",
	"china",
	"chinese",
	"prc",
	"flag",
	"country",
	"nation",
	"banner"
],
	"🇨🇴": [
	"flag_colombia",
	"co",
	"flag",
	"nation",
	"country",
	"banner",
	"colombia"
],
	"🇨🇵": [
	"flag_clipperton_island"
],
	"🇨🇷": [
	"flag_costa_rica",
	"costa",
	"rica",
	"flag",
	"nation",
	"country",
	"banner",
	"costa_rica"
],
	"🇨🇺": [
	"flag_cuba",
	"cu",
	"flag",
	"nation",
	"country",
	"banner",
	"cuba"
],
	"🇨🇻": [
	"flag_cape_verde",
	"cabo",
	"verde",
	"flag",
	"nation",
	"country",
	"banner",
	"cape_verde"
],
	"🇨🇼": [
	"flag_curacao",
	"curaçao",
	"flag",
	"nation",
	"country",
	"banner",
	"curacao"
],
	"🇨🇽": [
	"flag_christmas_island",
	"christmas",
	"island",
	"flag",
	"nation",
	"country",
	"banner",
	"christmas_island"
],
	"🇨🇾": [
	"flag_cyprus",
	"cy",
	"flag",
	"nation",
	"country",
	"banner",
	"cyprus"
],
	"🇨🇿": [
	"flag_czechia",
	"cz",
	"flag",
	"nation",
	"country",
	"banner",
	"czechia"
],
	"🇩🇪": [
	"flag_germany",
	"german",
	"nation",
	"flag",
	"country",
	"banner",
	"germany"
],
	"🇩🇬": [
	"flag_diego_garcia"
],
	"🇩🇯": [
	"flag_djibouti",
	"dj",
	"flag",
	"nation",
	"country",
	"banner",
	"djibouti"
],
	"🇩🇰": [
	"flag_denmark",
	"dk",
	"flag",
	"nation",
	"country",
	"banner",
	"denmark"
],
	"🇩🇲": [
	"flag_dominica",
	"dm",
	"flag",
	"nation",
	"country",
	"banner",
	"dominica"
],
	"🇩🇴": [
	"flag_dominican_republic",
	"dominican",
	"republic",
	"flag",
	"nation",
	"country",
	"banner",
	"dominican_republic"
],
	"🇩🇿": [
	"flag_algeria",
	"dz",
	"flag",
	"nation",
	"country",
	"banner",
	"algeria"
],
	"🇪🇦": [
	"flag_ceuta_melilla"
],
	"🇪🇨": [
	"flag_ecuador",
	"ec",
	"flag",
	"nation",
	"country",
	"banner",
	"ecuador"
],
	"🇪🇪": [
	"flag_estonia",
	"ee",
	"flag",
	"nation",
	"country",
	"banner",
	"estonia"
],
	"🇪🇬": [
	"flag_egypt",
	"eg",
	"flag",
	"nation",
	"country",
	"banner",
	"egypt"
],
	"🇪🇭": [
	"flag_western_sahara",
	"western",
	"sahara",
	"flag",
	"nation",
	"country",
	"banner",
	"western_sahara"
],
	"🇪🇷": [
	"flag_eritrea",
	"er",
	"flag",
	"nation",
	"country",
	"banner",
	"eritrea"
],
	"🇪🇸": [
	"flag_spain",
	"spain",
	"flag",
	"nation",
	"country",
	"banner"
],
	"🇪🇹": [
	"flag_ethiopia",
	"et",
	"flag",
	"nation",
	"country",
	"banner",
	"ethiopia"
],
	"🇪🇺": [
	"flag_european_union",
	"european",
	"union",
	"flag",
	"banner"
],
	"🇫🇮": [
	"flag_finland",
	"fi",
	"flag",
	"nation",
	"country",
	"banner",
	"finland"
],
	"🇫🇯": [
	"flag_fiji",
	"fj",
	"flag",
	"nation",
	"country",
	"banner",
	"fiji"
],
	"🇫🇰": [
	"flag_falkland_islands",
	"falkland",
	"islands",
	"malvinas",
	"flag",
	"nation",
	"country",
	"banner",
	"falkland_islands"
],
	"🇫🇲": [
	"flag_micronesia",
	"micronesia",
	"federated",
	"states",
	"flag",
	"nation",
	"country",
	"banner"
],
	"🇫🇴": [
	"flag_faroe_islands",
	"faroe",
	"islands",
	"flag",
	"nation",
	"country",
	"banner",
	"faroe_islands"
],
	"🇫🇷": [
	"flag_france",
	"banner",
	"flag",
	"nation",
	"france",
	"french",
	"country"
],
	"🇬🇦": [
	"flag_gabon",
	"ga",
	"flag",
	"nation",
	"country",
	"banner",
	"gabon"
],
	"🇬🇧": [
	"flag_united_kingdom",
	"united",
	"kingdom",
	"great",
	"britain",
	"northern",
	"ireland",
	"flag",
	"nation",
	"country",
	"banner",
	"british",
	"UK",
	"english",
	"england",
	"union jack",
	"united_kingdom"
],
	"🇬🇩": [
	"flag_grenada",
	"gd",
	"flag",
	"nation",
	"country",
	"banner",
	"grenada"
],
	"🇬🇪": [
	"flag_georgia",
	"ge",
	"flag",
	"nation",
	"country",
	"banner",
	"georgia"
],
	"🇬🇫": [
	"flag_french_guiana",
	"french",
	"guiana",
	"flag",
	"nation",
	"country",
	"banner",
	"french_guiana"
],
	"🇬🇬": [
	"flag_guernsey",
	"gg",
	"flag",
	"nation",
	"country",
	"banner",
	"guernsey"
],
	"🇬🇭": [
	"flag_ghana",
	"gh",
	"flag",
	"nation",
	"country",
	"banner",
	"ghana"
],
	"🇬🇮": [
	"flag_gibraltar",
	"gi",
	"flag",
	"nation",
	"country",
	"banner",
	"gibraltar"
],
	"🇬🇱": [
	"flag_greenland",
	"gl",
	"flag",
	"nation",
	"country",
	"banner",
	"greenland"
],
	"🇬🇲": [
	"flag_gambia",
	"gm",
	"flag",
	"nation",
	"country",
	"banner",
	"gambia"
],
	"🇬🇳": [
	"flag_guinea",
	"gn",
	"flag",
	"nation",
	"country",
	"banner",
	"guinea"
],
	"🇬🇵": [
	"flag_guadeloupe",
	"gp",
	"flag",
	"nation",
	"country",
	"banner",
	"guadeloupe"
],
	"🇬🇶": [
	"flag_equatorial_guinea",
	"equatorial",
	"gn",
	"flag",
	"nation",
	"country",
	"banner",
	"equatorial_guinea"
],
	"🇬🇷": [
	"flag_greece",
	"gr",
	"flag",
	"nation",
	"country",
	"banner",
	"greece"
],
	"🇬🇸": [
	"flag_south_georgia_south_sandwich_islands",
	"south",
	"georgia",
	"sandwich",
	"islands",
	"flag",
	"nation",
	"country",
	"banner",
	"south_georgia_south_sandwich_islands"
],
	"🇬🇹": [
	"flag_guatemala",
	"gt",
	"flag",
	"nation",
	"country",
	"banner",
	"guatemala"
],
	"🇬🇺": [
	"flag_guam",
	"gu",
	"flag",
	"nation",
	"country",
	"banner",
	"guam"
],
	"🇬🇼": [
	"flag_guinea_bissau",
	"gw",
	"bissau",
	"flag",
	"nation",
	"country",
	"banner",
	"guinea_bissau"
],
	"🇬🇾": [
	"flag_guyana",
	"gy",
	"flag",
	"nation",
	"country",
	"banner",
	"guyana"
],
	"🇭🇰": [
	"flag_hong_kong_sar_china",
	"hong",
	"kong",
	"flag",
	"nation",
	"country",
	"banner",
	"hong_kong_sar_china"
],
	"🇭🇲": [
	"flag_heard_mcdonald_islands"
],
	"🇭🇳": [
	"flag_honduras",
	"hn",
	"flag",
	"nation",
	"country",
	"banner",
	"honduras"
],
	"🇭🇷": [
	"flag_croatia",
	"hr",
	"flag",
	"nation",
	"country",
	"banner",
	"croatia"
],
	"🇭🇹": [
	"flag_haiti",
	"ht",
	"flag",
	"nation",
	"country",
	"banner",
	"haiti"
],
	"🇭🇺": [
	"flag_hungary",
	"hu",
	"flag",
	"nation",
	"country",
	"banner",
	"hungary"
],
	"🇮🇨": [
	"flag_canary_islands",
	"canary",
	"islands",
	"flag",
	"nation",
	"country",
	"banner",
	"canary_islands"
],
	"🇮🇩": [
	"flag_indonesia",
	"flag",
	"nation",
	"country",
	"banner",
	"indonesia"
],
	"🇮🇪": [
	"flag_ireland",
	"ie",
	"flag",
	"nation",
	"country",
	"banner",
	"ireland"
],
	"🇮🇱": [
	"flag_israel",
	"il",
	"flag",
	"nation",
	"country",
	"banner",
	"israel"
],
	"🇮🇲": [
	"flag_isle_of_man",
	"isle",
	"man",
	"flag",
	"nation",
	"country",
	"banner",
	"isle_of_man"
],
	"🇮🇳": [
	"flag_india",
	"in",
	"flag",
	"nation",
	"country",
	"banner",
	"india"
],
	"🇮🇴": [
	"flag_british_indian_ocean_territory",
	"british",
	"indian",
	"ocean",
	"territory",
	"flag",
	"nation",
	"country",
	"banner",
	"british_indian_ocean_territory"
],
	"🇮🇶": [
	"flag_iraq",
	"iq",
	"flag",
	"nation",
	"country",
	"banner",
	"iraq"
],
	"🇮🇷": [
	"flag_iran",
	"iran",
	"islamic",
	"republic",
	"flag",
	"nation",
	"country",
	"banner"
],
	"🇮🇸": [
	"flag_iceland",
	"is",
	"flag",
	"nation",
	"country",
	"banner",
	"iceland"
],
	"🇮🇹": [
	"flag_italy",
	"italy",
	"flag",
	"nation",
	"country",
	"banner"
],
	"🇯🇪": [
	"flag_jersey",
	"je",
	"flag",
	"nation",
	"country",
	"banner",
	"jersey"
],
	"🇯🇲": [
	"flag_jamaica",
	"jm",
	"flag",
	"nation",
	"country",
	"banner",
	"jamaica"
],
	"🇯🇴": [
	"flag_jordan",
	"jo",
	"flag",
	"nation",
	"country",
	"banner",
	"jordan"
],
	"🇯🇵": [
	"flag_japan",
	"japanese",
	"nation",
	"flag",
	"country",
	"banner",
	"japan",
	"jp",
	"ja"
],
	"🇰🇪": [
	"flag_kenya",
	"ke",
	"flag",
	"nation",
	"country",
	"banner",
	"kenya"
],
	"🇰🇬": [
	"flag_kyrgyzstan",
	"kg",
	"flag",
	"nation",
	"country",
	"banner",
	"kyrgyzstan"
],
	"🇰🇭": [
	"flag_cambodia",
	"kh",
	"flag",
	"nation",
	"country",
	"banner",
	"cambodia"
],
	"🇰🇮": [
	"flag_kiribati",
	"ki",
	"flag",
	"nation",
	"country",
	"banner",
	"kiribati"
],
	"🇰🇲": [
	"flag_comoros",
	"km",
	"flag",
	"nation",
	"country",
	"banner",
	"comoros"
],
	"🇰🇳": [
	"flag_st_kitts_nevis",
	"saint",
	"kitts",
	"nevis",
	"flag",
	"nation",
	"country",
	"banner",
	"st_kitts_nevis"
],
	"🇰🇵": [
	"flag_north_korea",
	"north",
	"korea",
	"nation",
	"flag",
	"country",
	"banner",
	"north_korea"
],
	"🇰🇷": [
	"flag_south_korea",
	"south",
	"korea",
	"nation",
	"flag",
	"country",
	"banner",
	"south_korea"
],
	"🇰🇼": [
	"flag_kuwait",
	"kw",
	"flag",
	"nation",
	"country",
	"banner",
	"kuwait"
],
	"🇰🇾": [
	"flag_cayman_islands",
	"cayman",
	"islands",
	"flag",
	"nation",
	"country",
	"banner",
	"cayman_islands"
],
	"🇰🇿": [
	"flag_kazakhstan",
	"kz",
	"flag",
	"nation",
	"country",
	"banner",
	"kazakhstan"
],
	"🇱🇦": [
	"flag_laos",
	"lao",
	"democratic",
	"republic",
	"flag",
	"nation",
	"country",
	"banner",
	"laos"
],
	"🇱🇧": [
	"flag_lebanon",
	"lb",
	"flag",
	"nation",
	"country",
	"banner",
	"lebanon"
],
	"🇱🇨": [
	"flag_st_lucia",
	"saint",
	"lucia",
	"flag",
	"nation",
	"country",
	"banner",
	"st_lucia"
],
	"🇱🇮": [
	"flag_liechtenstein",
	"li",
	"flag",
	"nation",
	"country",
	"banner",
	"liechtenstein"
],
	"🇱🇰": [
	"flag_sri_lanka",
	"sri",
	"lanka",
	"flag",
	"nation",
	"country",
	"banner",
	"sri_lanka"
],
	"🇱🇷": [
	"flag_liberia",
	"lr",
	"flag",
	"nation",
	"country",
	"banner",
	"liberia"
],
	"🇱🇸": [
	"flag_lesotho",
	"ls",
	"flag",
	"nation",
	"country",
	"banner",
	"lesotho"
],
	"🇱🇹": [
	"flag_lithuania",
	"lt",
	"flag",
	"nation",
	"country",
	"banner",
	"lithuania"
],
	"🇱🇺": [
	"flag_luxembourg",
	"lu",
	"flag",
	"nation",
	"country",
	"banner",
	"luxembourg"
],
	"🇱🇻": [
	"flag_latvia",
	"lv",
	"flag",
	"nation",
	"country",
	"banner",
	"latvia"
],
	"🇱🇾": [
	"flag_libya",
	"ly",
	"flag",
	"nation",
	"country",
	"banner",
	"libya"
],
	"🇲🇦": [
	"flag_morocco",
	"ma",
	"flag",
	"nation",
	"country",
	"banner",
	"morocco"
],
	"🇲🇨": [
	"flag_monaco",
	"mc",
	"flag",
	"nation",
	"country",
	"banner",
	"monaco"
],
	"🇲🇩": [
	"flag_moldova",
	"moldova",
	"republic",
	"flag",
	"nation",
	"country",
	"banner"
],
	"🇲🇪": [
	"flag_montenegro",
	"me",
	"flag",
	"nation",
	"country",
	"banner",
	"montenegro"
],
	"🇲🇫": [
	"flag_st_martin"
],
	"🇲🇬": [
	"flag_madagascar",
	"mg",
	"flag",
	"nation",
	"country",
	"banner",
	"madagascar"
],
	"🇲🇭": [
	"flag_marshall_islands",
	"marshall",
	"islands",
	"flag",
	"nation",
	"country",
	"banner",
	"marshall_islands"
],
	"🇲🇰": [
	"flag_north_macedonia",
	"macedonia",
	"flag",
	"nation",
	"country",
	"banner",
	"north_macedonia"
],
	"🇲🇱": [
	"flag_mali",
	"ml",
	"flag",
	"nation",
	"country",
	"banner",
	"mali"
],
	"🇲🇲": [
	"flag_myanmar",
	"mm",
	"flag",
	"nation",
	"country",
	"banner",
	"myanmar"
],
	"🇲🇳": [
	"flag_mongolia",
	"mn",
	"flag",
	"nation",
	"country",
	"banner",
	"mongolia"
],
	"🇲🇴": [
	"flag_macao_sar_china",
	"macao",
	"flag",
	"nation",
	"country",
	"banner",
	"macao_sar_china"
],
	"🇲🇵": [
	"flag_northern_mariana_islands",
	"northern",
	"mariana",
	"islands",
	"flag",
	"nation",
	"country",
	"banner",
	"northern_mariana_islands"
],
	"🇲🇶": [
	"flag_martinique",
	"mq",
	"flag",
	"nation",
	"country",
	"banner",
	"martinique"
],
	"🇲🇷": [
	"flag_mauritania",
	"mr",
	"flag",
	"nation",
	"country",
	"banner",
	"mauritania"
],
	"🇲🇸": [
	"flag_montserrat",
	"ms",
	"flag",
	"nation",
	"country",
	"banner",
	"montserrat"
],
	"🇲🇹": [
	"flag_malta",
	"mt",
	"flag",
	"nation",
	"country",
	"banner",
	"malta"
],
	"🇲🇺": [
	"flag_mauritius",
	"mu",
	"flag",
	"nation",
	"country",
	"banner",
	"mauritius"
],
	"🇲🇻": [
	"flag_maldives",
	"mv",
	"flag",
	"nation",
	"country",
	"banner",
	"maldives"
],
	"🇲🇼": [
	"flag_malawi",
	"mw",
	"flag",
	"nation",
	"country",
	"banner",
	"malawi"
],
	"🇲🇽": [
	"flag_mexico",
	"mx",
	"flag",
	"nation",
	"country",
	"banner",
	"mexico"
],
	"🇲🇾": [
	"flag_malaysia",
	"my",
	"flag",
	"nation",
	"country",
	"banner",
	"malaysia"
],
	"🇲🇿": [
	"flag_mozambique",
	"mz",
	"flag",
	"nation",
	"country",
	"banner",
	"mozambique"
],
	"🇳🇦": [
	"flag_namibia",
	"na",
	"flag",
	"nation",
	"country",
	"banner",
	"namibia"
],
	"🇳🇨": [
	"flag_new_caledonia",
	"new",
	"caledonia",
	"flag",
	"nation",
	"country",
	"banner",
	"new_caledonia"
],
	"🇳🇪": [
	"flag_niger",
	"ne",
	"flag",
	"nation",
	"country",
	"banner",
	"niger"
],
	"🇳🇫": [
	"flag_norfolk_island",
	"norfolk",
	"island",
	"flag",
	"nation",
	"country",
	"banner",
	"norfolk_island"
],
	"🇳🇬": [
	"flag_nigeria",
	"flag",
	"nation",
	"country",
	"banner",
	"nigeria"
],
	"🇳🇮": [
	"flag_nicaragua",
	"ni",
	"flag",
	"nation",
	"country",
	"banner",
	"nicaragua"
],
	"🇳🇱": [
	"flag_netherlands",
	"nl",
	"flag",
	"nation",
	"country",
	"banner",
	"netherlands"
],
	"🇳🇴": [
	"flag_norway",
	"no",
	"flag",
	"nation",
	"country",
	"banner",
	"norway"
],
	"🇳🇵": [
	"flag_nepal",
	"np",
	"flag",
	"nation",
	"country",
	"banner",
	"nepal"
],
	"🇳🇷": [
	"flag_nauru",
	"nr",
	"flag",
	"nation",
	"country",
	"banner",
	"nauru"
],
	"🇳🇺": [
	"flag_niue",
	"nu",
	"flag",
	"nation",
	"country",
	"banner",
	"niue"
],
	"🇳🇿": [
	"flag_new_zealand",
	"new",
	"zealand",
	"flag",
	"nation",
	"country",
	"banner",
	"new_zealand"
],
	"🇴🇲": [
	"flag_oman",
	"om_symbol",
	"flag",
	"nation",
	"country",
	"banner",
	"oman"
],
	"🇵🇦": [
	"flag_panama",
	"pa",
	"flag",
	"nation",
	"country",
	"banner",
	"panama"
],
	"🇵🇪": [
	"flag_peru",
	"pe",
	"flag",
	"nation",
	"country",
	"banner",
	"peru"
],
	"🇵🇫": [
	"flag_french_polynesia",
	"french",
	"polynesia",
	"flag",
	"nation",
	"country",
	"banner",
	"french_polynesia"
],
	"🇵🇬": [
	"flag_papua_new_guinea",
	"papua",
	"new",
	"guinea",
	"flag",
	"nation",
	"country",
	"banner",
	"papua_new_guinea"
],
	"🇵🇭": [
	"flag_philippines",
	"ph",
	"flag",
	"nation",
	"country",
	"banner",
	"philippines"
],
	"🇵🇰": [
	"flag_pakistan",
	"pk",
	"flag",
	"nation",
	"country",
	"banner",
	"pakistan"
],
	"🇵🇱": [
	"flag_poland",
	"pl",
	"flag",
	"nation",
	"country",
	"banner",
	"poland"
],
	"🇵🇲": [
	"flag_st_pierre_miquelon",
	"saint",
	"pierre",
	"miquelon",
	"flag",
	"nation",
	"country",
	"banner",
	"st_pierre_miquelon"
],
	"🇵🇳": [
	"flag_pitcairn_islands",
	"pitcairn",
	"flag",
	"nation",
	"country",
	"banner",
	"pitcairn_islands"
],
	"🇵🇷": [
	"flag_puerto_rico",
	"puerto",
	"rico",
	"flag",
	"nation",
	"country",
	"banner",
	"puerto_rico"
],
	"🇵🇸": [
	"flag_palestinian_territories",
	"palestine",
	"palestinian",
	"territories",
	"flag",
	"nation",
	"country",
	"banner",
	"palestinian_territories"
],
	"🇵🇹": [
	"flag_portugal",
	"pt",
	"flag",
	"nation",
	"country",
	"banner",
	"portugal"
],
	"🇵🇼": [
	"flag_palau",
	"pw",
	"flag",
	"nation",
	"country",
	"banner",
	"palau"
],
	"🇵🇾": [
	"flag_paraguay",
	"py",
	"flag",
	"nation",
	"country",
	"banner",
	"paraguay"
],
	"🇶🇦": [
	"flag_qatar",
	"qa",
	"flag",
	"nation",
	"country",
	"banner",
	"qatar"
],
	"🇷🇪": [
	"flag_reunion",
	"réunion",
	"flag",
	"nation",
	"country",
	"banner",
	"reunion"
],
	"🇷🇴": [
	"flag_romania",
	"ro",
	"flag",
	"nation",
	"country",
	"banner",
	"romania"
],
	"🇷🇸": [
	"flag_serbia",
	"rs",
	"flag",
	"nation",
	"country",
	"banner",
	"serbia"
],
	"🇷🇺": [
	"flag_russia",
	"russian",
	"federation",
	"flag",
	"nation",
	"country",
	"banner",
	"russia"
],
	"🇷🇼": [
	"flag_rwanda",
	"rw",
	"flag",
	"nation",
	"country",
	"banner",
	"rwanda"
],
	"🇸🇦": [
	"flag_saudi_arabia",
	"flag",
	"nation",
	"country",
	"banner",
	"saudi_arabia"
],
	"🇸🇧": [
	"flag_solomon_islands",
	"solomon",
	"islands",
	"flag",
	"nation",
	"country",
	"banner",
	"solomon_islands"
],
	"🇸🇨": [
	"flag_seychelles",
	"sc",
	"flag",
	"nation",
	"country",
	"banner",
	"seychelles"
],
	"🇸🇩": [
	"flag_sudan",
	"sd",
	"flag",
	"nation",
	"country",
	"banner",
	"sudan"
],
	"🇸🇪": [
	"flag_sweden",
	"se",
	"flag",
	"nation",
	"country",
	"banner",
	"sweden"
],
	"🇸🇬": [
	"flag_singapore",
	"sg",
	"flag",
	"nation",
	"country",
	"banner",
	"singapore"
],
	"🇸🇭": [
	"flag_st_helena",
	"saint",
	"helena",
	"ascension",
	"tristan",
	"cunha",
	"flag",
	"nation",
	"country",
	"banner",
	"st_helena"
],
	"🇸🇮": [
	"flag_slovenia",
	"si",
	"flag",
	"nation",
	"country",
	"banner",
	"slovenia"
],
	"🇸🇯": [
	"flag_svalbard_jan_mayen"
],
	"🇸🇰": [
	"flag_slovakia",
	"sk",
	"flag",
	"nation",
	"country",
	"banner",
	"slovakia"
],
	"🇸🇱": [
	"flag_sierra_leone",
	"sierra",
	"leone",
	"flag",
	"nation",
	"country",
	"banner",
	"sierra_leone"
],
	"🇸🇲": [
	"flag_san_marino",
	"san",
	"marino",
	"flag",
	"nation",
	"country",
	"banner",
	"san_marino"
],
	"🇸🇳": [
	"flag_senegal",
	"sn",
	"flag",
	"nation",
	"country",
	"banner",
	"senegal"
],
	"🇸🇴": [
	"flag_somalia",
	"so",
	"flag",
	"nation",
	"country",
	"banner",
	"somalia"
],
	"🇸🇷": [
	"flag_suriname",
	"sr",
	"flag",
	"nation",
	"country",
	"banner",
	"suriname"
],
	"🇸🇸": [
	"flag_south_sudan",
	"south",
	"sd",
	"flag",
	"nation",
	"country",
	"banner",
	"south_sudan"
],
	"🇸🇹": [
	"flag_sao_tome_principe",
	"sao",
	"tome",
	"principe",
	"flag",
	"nation",
	"country",
	"banner",
	"sao_tome_principe"
],
	"🇸🇻": [
	"flag_el_salvador",
	"el",
	"salvador",
	"flag",
	"nation",
	"country",
	"banner",
	"el_salvador"
],
	"🇸🇽": [
	"flag_sint_maarten",
	"sint",
	"maarten",
	"dutch",
	"flag",
	"nation",
	"country",
	"banner",
	"sint_maarten"
],
	"🇸🇾": [
	"flag_syria",
	"syrian",
	"arab",
	"republic",
	"flag",
	"nation",
	"country",
	"banner",
	"syria"
],
	"🇸🇿": [
	"flag_eswatini",
	"sz",
	"flag",
	"nation",
	"country",
	"banner",
	"eswatini"
],
	"🇹🇦": [
	"flag_tristan_da_cunha"
],
	"🇹🇨": [
	"flag_turks_caicos_islands",
	"turks",
	"caicos",
	"islands",
	"flag",
	"nation",
	"country",
	"banner",
	"turks_caicos_islands"
],
	"🇹🇩": [
	"flag_chad",
	"td",
	"flag",
	"nation",
	"country",
	"banner",
	"chad"
],
	"🇹🇫": [
	"flag_french_southern_territories",
	"french",
	"southern",
	"territories",
	"flag",
	"nation",
	"country",
	"banner",
	"french_southern_territories"
],
	"🇹🇬": [
	"flag_togo",
	"tg",
	"flag",
	"nation",
	"country",
	"banner",
	"togo"
],
	"🇹🇭": [
	"flag_thailand",
	"th",
	"flag",
	"nation",
	"country",
	"banner",
	"thailand"
],
	"🇹🇯": [
	"flag_tajikistan",
	"tj",
	"flag",
	"nation",
	"country",
	"banner",
	"tajikistan"
],
	"🇹🇰": [
	"flag_tokelau",
	"tk",
	"flag",
	"nation",
	"country",
	"banner",
	"tokelau"
],
	"🇹🇱": [
	"flag_timor_leste",
	"timor",
	"leste",
	"flag",
	"nation",
	"country",
	"banner",
	"timor_leste"
],
	"🇹🇲": [
	"flag_turkmenistan",
	"flag",
	"nation",
	"country",
	"banner",
	"turkmenistan"
],
	"🇹🇳": [
	"flag_tunisia",
	"tn",
	"flag",
	"nation",
	"country",
	"banner",
	"tunisia"
],
	"🇹🇴": [
	"flag_tonga",
	"to",
	"flag",
	"nation",
	"country",
	"banner",
	"tonga"
],
	"🇹🇷": [
	"flag_turkey",
	"turkey",
	"flag",
	"nation",
	"country",
	"banner"
],
	"🇹🇹": [
	"flag_trinidad_tobago",
	"trinidad",
	"tobago",
	"flag",
	"nation",
	"country",
	"banner",
	"trinidad_tobago"
],
	"🇹🇻": [
	"flag_tuvalu",
	"flag",
	"nation",
	"country",
	"banner",
	"tuvalu"
],
	"🇹🇼": [
	"flag_taiwan",
	"tw",
	"flag",
	"nation",
	"country",
	"banner",
	"taiwan"
],
	"🇹🇿": [
	"flag_tanzania",
	"tanzania",
	"united",
	"republic",
	"flag",
	"nation",
	"country",
	"banner"
],
	"🇺🇦": [
	"flag_ukraine",
	"ua",
	"flag",
	"nation",
	"country",
	"banner",
	"ukraine"
],
	"🇺🇬": [
	"flag_uganda",
	"ug",
	"flag",
	"nation",
	"country",
	"banner",
	"uganda"
],
	"🇺🇲": [
	"flag_u_s_outlying_islands"
],
	"🇺🇳": [
	"flag_united_nations",
	"un",
	"flag",
	"banner"
],
	"🇺🇸": [
	"flag_united_states",
	"united",
	"states",
	"america",
	"flag",
	"nation",
	"country",
	"banner",
	"united_states"
],
	"🇺🇾": [
	"flag_uruguay",
	"uy",
	"flag",
	"nation",
	"country",
	"banner",
	"uruguay"
],
	"🇺🇿": [
	"flag_uzbekistan",
	"uz",
	"flag",
	"nation",
	"country",
	"banner",
	"uzbekistan"
],
	"🇻🇦": [
	"flag_vatican_city",
	"vatican",
	"city",
	"flag",
	"nation",
	"country",
	"banner",
	"vatican_city"
],
	"🇻🇨": [
	"flag_st_vincent_grenadines",
	"saint",
	"vincent",
	"grenadines",
	"flag",
	"nation",
	"country",
	"banner",
	"st_vincent_grenadines"
],
	"🇻🇪": [
	"flag_venezuela",
	"ve",
	"bolivarian",
	"republic",
	"flag",
	"nation",
	"country",
	"banner",
	"venezuela"
],
	"🇻🇬": [
	"flag_british_virgin_islands",
	"british",
	"virgin",
	"islands",
	"bvi",
	"flag",
	"nation",
	"country",
	"banner",
	"british_virgin_islands"
],
	"🇻🇮": [
	"flag_u_s_virgin_islands",
	"virgin",
	"islands",
	"us",
	"flag",
	"nation",
	"country",
	"banner",
	"u_s_virgin_islands"
],
	"🇻🇳": [
	"flag_vietnam",
	"viet",
	"nam",
	"flag",
	"nation",
	"country",
	"banner",
	"vietnam"
],
	"🇻🇺": [
	"flag_vanuatu",
	"vu",
	"flag",
	"nation",
	"country",
	"banner",
	"vanuatu"
],
	"🇼🇫": [
	"flag_wallis_futuna",
	"wallis",
	"futuna",
	"flag",
	"nation",
	"country",
	"banner",
	"wallis_futuna"
],
	"🇼🇸": [
	"flag_samoa",
	"ws",
	"flag",
	"nation",
	"country",
	"banner",
	"samoa"
],
	"🇽🇰": [
	"flag_kosovo",
	"xk",
	"flag",
	"nation",
	"country",
	"banner",
	"kosovo"
],
	"🇾🇪": [
	"flag_yemen",
	"ye",
	"flag",
	"nation",
	"country",
	"banner",
	"yemen"
],
	"🇾🇹": [
	"flag_mayotte",
	"yt",
	"flag",
	"nation",
	"country",
	"banner",
	"mayotte"
],
	"🇿🇦": [
	"flag_south_africa",
	"south",
	"africa",
	"flag",
	"nation",
	"country",
	"banner",
	"south_africa"
],
	"🇿🇲": [
	"flag_zambia",
	"zm",
	"flag",
	"nation",
	"country",
	"banner",
	"zambia"
],
	"🇿🇼": [
	"flag_zimbabwe",
	"zw",
	"flag",
	"nation",
	"country",
	"banner",
	"zimbabwe"
],
	"🏴󠁧󠁢󠁥󠁮󠁧󠁿": [
	"flag_england",
	"flag",
	"english"
],
	"🏴󠁧󠁢󠁳󠁣󠁴󠁿": [
	"flag_scotland",
	"flag",
	"scottish"
],
	"🏴󠁧󠁢󠁷󠁬󠁳󠁿": [
	"flag_wales",
	"flag",
	"welsh"
],
	"🥲": [
	"smiling face with tear",
	"sad",
	"cry",
	"pretend"
],
	"🥸": [
	"disguised face",
	"pretent",
	"brows",
	"glasses",
	"moustache"
],
	"🤌": [
	"pinched fingers",
	"size",
	"tiny",
	"small"
],
	"🫀": [
	"anatomical heart",
	"health",
	"heartbeat"
],
	"🫁": [
	"lungs",
	"breathe"
],
	"🥷": [
	"ninja",
	"ninjutsu",
	"skills",
	"japanese"
],
	"🤵‍♂️": [
	"man in tuxedo",
	"formal",
	"fashion"
],
	"🤵‍♀️": [
	"woman in tuxedo",
	"formal",
	"fashion"
],
	"👰‍♂️": [
	"man with veil",
	"wedding",
	"marriage"
],
	"👰‍♀️": [
	"woman with veil",
	"wedding",
	"marriage"
],
	"👩‍🍼": [
	"woman feeding baby",
	"birth",
	"food"
],
	"👨‍🍼": [
	"man feeding baby",
	"birth",
	"food"
],
	"🧑‍🍼": [
	"person feeding baby",
	"birth",
	"food"
],
	"🧑‍🎄": [
	"mx claus",
	"christmas"
],
	"🫂": [
	"people hugging",
	"care"
],
	"🐈‍⬛": [
	"black cat",
	"superstition",
	"luck"
],
	"🦬": [
	"bison",
	"ox"
],
	"🦣": [
	"mammoth",
	"elephant",
	"tusks"
],
	"🦫": [
	"beaver",
	"animal",
	"rodent"
],
	"🐻‍❄️": [
	"polar bear",
	"animal",
	"arctic"
],
	"🦤": [
	"dodo",
	"animal",
	"bird"
],
	"🪶": [
	"feather",
	"bird",
	"fly"
],
	"🦭": [
	"seal",
	"animal",
	"creature",
	"sea"
],
	"🪲": [
	"beetle",
	"insect"
],
	"🪳": [
	"cockroach",
	"insect",
	"pests"
],
	"🪰": [
	"fly",
	"insect"
],
	"🪱": [
	"worm",
	"animal"
],
	"🪴": [
	"potted plant",
	"greenery",
	"house"
],
	"🫐": [
	"blueberries",
	"fruit"
],
	"🫒": [
	"olive",
	"fruit"
],
	"🫑": [
	"bell pepper",
	"fruit",
	"plant"
],
	"🫓": [
	"flatbread",
	"flour",
	"food",
	"bakery"
],
	"🫔": [
	"tamale",
	"food",
	"masa"
],
	"🫕": [
	"fondue",
	"cheese",
	"pot",
	"food"
],
	"🫖": [
	"teapot",
	"drink",
	"hot"
],
	"🧋": [
	"bubble tea",
	"taiwan",
	"boba",
	"milk tea",
	"straw"
],
	"🪨": [
	"rock",
	"stone"
],
	"🪵": [
	"wood",
	"nature",
	"timber",
	"trunk"
],
	"🛖": [
	"hut",
	"house",
	"structure"
],
	"🛻": [
	"pickup truck",
	"car",
	"transportation"
],
	"🛼": [
	"roller skate",
	"footwear",
	"sports"
],
	"🪄": [
	"magic wand",
	"supernature",
	"power"
],
	"🪅": [
	"pinata",
	"mexico",
	"candy",
	"celebration"
],
	"🪆": [
	"nesting dolls",
	"matryoshka",
	"toy"
],
	"🪡": [
	"sewing needle",
	"stitches"
],
	"🪢": [
	"knot",
	"rope",
	"scout"
],
	"🩴": [
	"thong sandal",
	"footwear",
	"summer"
],
	"🪖": [
	"military helmet",
	"army",
	"protection"
],
	"🪗": [
	"accordion",
	"music"
],
	"🪘": [
	"long drum",
	"music"
],
	"🪙": [
	"coin",
	"money",
	"currency"
],
	"🪃": [
	"boomerang",
	"weapon"
],
	"🪚": [
	"carpentry saw",
	"cut",
	"chop"
],
	"🪛": [
	"screwdriver",
	"tools"
],
	"🪝": [
	"hook",
	"tools"
],
	"🪜": [
	"ladder",
	"tools"
],
	"🛗": [
	"elevator",
	"lift"
],
	"🪞": [
	"mirror",
	"reflection"
],
	"🪟": [
	"window",
	"scenery"
],
	"🪠": [
	"plunger",
	"toilet"
],
	"🪤": [
	"mouse trap",
	"cheese"
],
	"🪣": [
	"bucket",
	"water",
	"container"
],
	"🪥": [
	"toothbrush",
	"hygiene",
	"dental"
],
	"🪦": [
	"headstone",
	"death",
	"rip",
	"grave"
],
	"🪧": [
	"placard",
	"announcement"
],
	"⚧️": [
	"transgender symbol",
	"transgender",
	"lgbtq"
],
	"🏳️‍⚧️": [
	"transgender flag",
	"transgender",
	"flag",
	"pride",
	"lgbtq"
],
	"😶‍🌫️": [
	"face in clouds",
	"shower",
	"steam",
	"dream"
],
	"😮‍💨": [
	"face exhaling",
	"relieve",
	"relief",
	"tired",
	"sigh"
],
	"😵‍💫": [
	"face with spiral eyes",
	"sick",
	"ill",
	"confused",
	"nauseous",
	"nausea"
],
	"❤️‍🔥": [
	"heart on fire",
	"passionate",
	"enthusiastic"
],
	"❤️‍🩹": [
	"mending heart",
	"broken heart",
	"bandage",
	"wounded"
],
	"🧔‍♂️": [
	"man beard",
	"facial hair"
],
	"🧔‍♀️": [
	"woman beard",
	"facial hair"
],
	"🫠": [
	"melting face",
	"hot",
	"heat"
],
	"🫢": [
	"face with open eyes and hand over mouth",
	"silence",
	"secret",
	"shock",
	"surprise"
],
	"🫣": [
	"face with peeking eye",
	"scared",
	"frightening",
	"embarrassing",
	"shy"
],
	"🫡": [
	"saluting face",
	"respect",
	"salute"
],
	"🫥": [
	"dotted line face",
	"invisible",
	"lonely",
	"isolation",
	"depression"
],
	"🫤": [
	"face with diagonal mouth",
	"skeptic",
	"confuse",
	"frustrated",
	"indifferent"
],
	"🥹": [
	"face holding back tears",
	"touched",
	"gratitude",
	"cry"
],
	"🫱": [
	"rightwards hand",
	"palm",
	"offer"
],
	"🫲": [
	"leftwards hand",
	"palm",
	"offer"
],
	"🫳": [
	"palm down hand",
	"palm",
	"drop"
],
	"🫴": [
	"palm up hand",
	"lift",
	"offer",
	"demand"
],
	"🫰": [
	"hand with index finger and thumb crossed",
	"heart",
	"love",
	"money",
	"expensive"
],
	"🫵": [
	"index pointing at the viewer",
	"you",
	"recruit"
],
	"🫶": [
	"heart hands",
	"love",
	"appreciation",
	"support"
],
	"🫦": [
	"biting lip",
	"flirt",
	"sexy",
	"pain",
	"worry"
],
	"🫅": [
	"person with crown",
	"royalty",
	"power"
],
	"🫃": [
	"pregnant man",
	"baby",
	"belly"
],
	"🫄": [
	"pregnant person",
	"baby",
	"belly"
],
	"🧌": [
	"troll",
	"mystical",
	"monster"
],
	"🪸": [
	"coral",
	"ocean",
	"sea",
	"reef"
],
	"🪷": [
	"lotus",
	"flower",
	"calm",
	"meditation"
],
	"🪹": [
	"empty nest",
	"bird"
],
	"🪺": [
	"nest with eggs",
	"bird"
],
	"🫘": [
	"beans",
	"food"
],
	"🫗": [
	"pouring liquid",
	"cup",
	"water"
],
	"🫙": [
	"jar",
	"container",
	"sauce"
],
	"🛝": [
	"playground slide",
	"fun",
	"park"
],
	"🛞": [
	"wheel",
	"car",
	"transport"
],
	"🛟": [
	"ring buoy",
	"life saver",
	"life preserver"
],
	"🪬": [
	"hamsa",
	"religion",
	"protection"
],
	"🪩": [
	"mirror ball",
	"disco",
	"dance",
	"party"
],
	"🪫": [
	"low battery",
	"drained",
	"dead"
],
	"🩼": [
	"crutch",
	"accessibility",
	"assist"
],
	"🩻": [
	"x-ray",
	"skeleton",
	"medicine"
],
	"🫧": [
	"bubbles",
	"soap",
	"fun",
	"carbonation",
	"sparkling"
],
	"🪪": [
	"identification card",
	"document"
],
	"🟰": [
	"heavy equals sign",
	"math"
],
	"🫨": [
	"shaking face",
	"dizzy",
	"shock",
	"blurry",
	"earthquake"
],
	"🩷": [
	"pink heart",
	"valentines"
],
	"🩵": [
	"light blue heart",
	"ice",
	"baby blue"
],
	"🩶": [
	"grey heart",
	"silver",
	"monochrome"
],
	"🫷": [
	"leftwards pushing hand",
	"highfive",
	"pressing",
	"stop"
],
	"🫸": [
	"rightwards pushing hand",
	"highfive",
	"pressing",
	"stop"
],
	"🫎": [
	"moose",
	"shrek",
	"canada",
	"sweden",
	"sven",
	"cool"
],
	"🫏": [
	"donkey",
	"eeyore",
	"mule"
],
	"🪽": [
	"wing",
	"angel",
	"birds",
	"flying"
],
	"🐦‍⬛": [
	"black bird",
	"crow"
],
	"🪿": [
	"goose",
	"silly",
	"jemima",
	"goosebumps"
],
	"🪼": [
	"jellyfish",
	"sting",
	"tentacles"
],
	"🪻": [
	"hyacinth",
	"flower",
	"lavender"
],
	"🫚": [
	"ginger root",
	"spice",
	"yellow",
	"cooking",
	"gingerbread"
],
	"🫛": [
	"pea pod",
	"cozy",
	"green"
],
	"🪭": [
	"folding hand fan",
	"flamenco",
	"hot"
],
	"🪮": [
	"hair pick",
	"afro",
	"comb"
],
	"🪇": [
	"maracas",
	"music",
	"instrument",
	"percussion"
],
	"🪈": [
	"flute",
	"bamboo",
	"music",
	"instrument",
	"pied piper"
],
	"🪯": [
	"khanda",
	"Sikhism",
	"religion"
],
	"🛜": [
	"wireless",
	"wifi",
	"internet",
	"contactless",
	"signal"
]
};var emojiData = {
	"😀": {
	name: "grinning face",
	slug: "grinning_face",
	group: "Smileys & Emotion",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"😃": {
	name: "grinning face with big eyes",
	slug: "grinning_face_with_big_eyes",
	group: "Smileys & Emotion",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"😄": {
	name: "grinning face with smiling eyes",
	slug: "grinning_face_with_smiling_eyes",
	group: "Smileys & Emotion",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"😁": {
	name: "beaming face with smiling eyes",
	slug: "beaming_face_with_smiling_eyes",
	group: "Smileys & Emotion",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"😆": {
	name: "grinning squinting face",
	slug: "grinning_squinting_face",
	group: "Smileys & Emotion",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"😅": {
	name: "grinning face with sweat",
	slug: "grinning_face_with_sweat",
	group: "Smileys & Emotion",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🤣": {
	name: "rolling on the floor laughing",
	slug: "rolling_on_the_floor_laughing",
	group: "Smileys & Emotion",
	emoji_version: "3.0",
	unicode_version: "3.0",
	skin_tone_support: false
},
	"😂": {
	name: "face with tears of joy",
	slug: "face_with_tears_of_joy",
	group: "Smileys & Emotion",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🙂": {
	name: "slightly smiling face",
	slug: "slightly_smiling_face",
	group: "Smileys & Emotion",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🙃": {
	name: "upside-down face",
	slug: "upside_down_face",
	group: "Smileys & Emotion",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🫠": {
	name: "melting face",
	slug: "melting_face",
	group: "Smileys & Emotion",
	emoji_version: "14.0",
	unicode_version: "14.0",
	skin_tone_support: false
},
	"😉": {
	name: "winking face",
	slug: "winking_face",
	group: "Smileys & Emotion",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"😊": {
	name: "smiling face with smiling eyes",
	slug: "smiling_face_with_smiling_eyes",
	group: "Smileys & Emotion",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"😇": {
	name: "smiling face with halo",
	slug: "smiling_face_with_halo",
	group: "Smileys & Emotion",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🥰": {
	name: "smiling face with hearts",
	slug: "smiling_face_with_hearts",
	group: "Smileys & Emotion",
	emoji_version: "11.0",
	unicode_version: "11.0",
	skin_tone_support: false
},
	"😍": {
	name: "smiling face with heart-eyes",
	slug: "smiling_face_with_heart_eyes",
	group: "Smileys & Emotion",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🤩": {
	name: "star-struck",
	slug: "star_struck",
	group: "Smileys & Emotion",
	emoji_version: "5.0",
	unicode_version: "5.0",
	skin_tone_support: false
},
	"😘": {
	name: "face blowing a kiss",
	slug: "face_blowing_a_kiss",
	group: "Smileys & Emotion",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"😗": {
	name: "kissing face",
	slug: "kissing_face",
	group: "Smileys & Emotion",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"☺️": {
	name: "smiling face",
	slug: "smiling_face",
	group: "Smileys & Emotion",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"😚": {
	name: "kissing face with closed eyes",
	slug: "kissing_face_with_closed_eyes",
	group: "Smileys & Emotion",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"😙": {
	name: "kissing face with smiling eyes",
	slug: "kissing_face_with_smiling_eyes",
	group: "Smileys & Emotion",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🥲": {
	name: "smiling face with tear",
	slug: "smiling_face_with_tear",
	group: "Smileys & Emotion",
	emoji_version: "13.0",
	unicode_version: "13.0",
	skin_tone_support: false
},
	"😋": {
	name: "face savoring food",
	slug: "face_savoring_food",
	group: "Smileys & Emotion",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"😛": {
	name: "face with tongue",
	slug: "face_with_tongue",
	group: "Smileys & Emotion",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"😜": {
	name: "winking face with tongue",
	slug: "winking_face_with_tongue",
	group: "Smileys & Emotion",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🤪": {
	name: "zany face",
	slug: "zany_face",
	group: "Smileys & Emotion",
	emoji_version: "5.0",
	unicode_version: "5.0",
	skin_tone_support: false
},
	"😝": {
	name: "squinting face with tongue",
	slug: "squinting_face_with_tongue",
	group: "Smileys & Emotion",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🤑": {
	name: "money-mouth face",
	slug: "money_mouth_face",
	group: "Smileys & Emotion",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🤗": {
	name: "smiling face with open hands",
	slug: "smiling_face_with_open_hands",
	group: "Smileys & Emotion",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🤭": {
	name: "face with hand over mouth",
	slug: "face_with_hand_over_mouth",
	group: "Smileys & Emotion",
	emoji_version: "5.0",
	unicode_version: "5.0",
	skin_tone_support: false
},
	"🫢": {
	name: "face with open eyes and hand over mouth",
	slug: "face_with_open_eyes_and_hand_over_mouth",
	group: "Smileys & Emotion",
	emoji_version: "14.0",
	unicode_version: "14.0",
	skin_tone_support: false
},
	"🫣": {
	name: "face with peeking eye",
	slug: "face_with_peeking_eye",
	group: "Smileys & Emotion",
	emoji_version: "14.0",
	unicode_version: "14.0",
	skin_tone_support: false
},
	"🤫": {
	name: "shushing face",
	slug: "shushing_face",
	group: "Smileys & Emotion",
	emoji_version: "5.0",
	unicode_version: "5.0",
	skin_tone_support: false
},
	"🤔": {
	name: "thinking face",
	slug: "thinking_face",
	group: "Smileys & Emotion",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🫡": {
	name: "saluting face",
	slug: "saluting_face",
	group: "Smileys & Emotion",
	emoji_version: "14.0",
	unicode_version: "14.0",
	skin_tone_support: false
},
	"🤐": {
	name: "zipper-mouth face",
	slug: "zipper_mouth_face",
	group: "Smileys & Emotion",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🤨": {
	name: "face with raised eyebrow",
	slug: "face_with_raised_eyebrow",
	group: "Smileys & Emotion",
	emoji_version: "5.0",
	unicode_version: "5.0",
	skin_tone_support: false
},
	"😐": {
	name: "neutral face",
	slug: "neutral_face",
	group: "Smileys & Emotion",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"😑": {
	name: "expressionless face",
	slug: "expressionless_face",
	group: "Smileys & Emotion",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"😶": {
	name: "face without mouth",
	slug: "face_without_mouth",
	group: "Smileys & Emotion",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🫥": {
	name: "dotted line face",
	slug: "dotted_line_face",
	group: "Smileys & Emotion",
	emoji_version: "14.0",
	unicode_version: "14.0",
	skin_tone_support: false
},
	"😶‍🌫️": {
	name: "face in clouds",
	slug: "face_in_clouds",
	group: "Smileys & Emotion",
	emoji_version: "13.1",
	unicode_version: "13.1",
	skin_tone_support: false
},
	"😏": {
	name: "smirking face",
	slug: "smirking_face",
	group: "Smileys & Emotion",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"😒": {
	name: "unamused face",
	slug: "unamused_face",
	group: "Smileys & Emotion",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🙄": {
	name: "face with rolling eyes",
	slug: "face_with_rolling_eyes",
	group: "Smileys & Emotion",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"😬": {
	name: "grimacing face",
	slug: "grimacing_face",
	group: "Smileys & Emotion",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"😮‍💨": {
	name: "face exhaling",
	slug: "face_exhaling",
	group: "Smileys & Emotion",
	emoji_version: "13.1",
	unicode_version: "13.1",
	skin_tone_support: false
},
	"🤥": {
	name: "lying face",
	slug: "lying_face",
	group: "Smileys & Emotion",
	emoji_version: "3.0",
	unicode_version: "3.0",
	skin_tone_support: false
},
	"🫨": {
	name: "shaking face",
	slug: "shaking_face",
	group: "Smileys & Emotion",
	emoji_version: "15.0",
	unicode_version: "15.0",
	skin_tone_support: false
},
	"😌": {
	name: "relieved face",
	slug: "relieved_face",
	group: "Smileys & Emotion",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"😔": {
	name: "pensive face",
	slug: "pensive_face",
	group: "Smileys & Emotion",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"😪": {
	name: "sleepy face",
	slug: "sleepy_face",
	group: "Smileys & Emotion",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🤤": {
	name: "drooling face",
	slug: "drooling_face",
	group: "Smileys & Emotion",
	emoji_version: "3.0",
	unicode_version: "3.0",
	skin_tone_support: false
},
	"😴": {
	name: "sleeping face",
	slug: "sleeping_face",
	group: "Smileys & Emotion",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"😷": {
	name: "face with medical mask",
	slug: "face_with_medical_mask",
	group: "Smileys & Emotion",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🤒": {
	name: "face with thermometer",
	slug: "face_with_thermometer",
	group: "Smileys & Emotion",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🤕": {
	name: "face with head-bandage",
	slug: "face_with_head_bandage",
	group: "Smileys & Emotion",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🤢": {
	name: "nauseated face",
	slug: "nauseated_face",
	group: "Smileys & Emotion",
	emoji_version: "3.0",
	unicode_version: "3.0",
	skin_tone_support: false
},
	"🤮": {
	name: "face vomiting",
	slug: "face_vomiting",
	group: "Smileys & Emotion",
	emoji_version: "5.0",
	unicode_version: "5.0",
	skin_tone_support: false
},
	"🤧": {
	name: "sneezing face",
	slug: "sneezing_face",
	group: "Smileys & Emotion",
	emoji_version: "3.0",
	unicode_version: "3.0",
	skin_tone_support: false
},
	"🥵": {
	name: "hot face",
	slug: "hot_face",
	group: "Smileys & Emotion",
	emoji_version: "11.0",
	unicode_version: "11.0",
	skin_tone_support: false
},
	"🥶": {
	name: "cold face",
	slug: "cold_face",
	group: "Smileys & Emotion",
	emoji_version: "11.0",
	unicode_version: "11.0",
	skin_tone_support: false
},
	"🥴": {
	name: "woozy face",
	slug: "woozy_face",
	group: "Smileys & Emotion",
	emoji_version: "11.0",
	unicode_version: "11.0",
	skin_tone_support: false
},
	"😵": {
	name: "face with crossed-out eyes",
	slug: "face_with_crossed_out_eyes",
	group: "Smileys & Emotion",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"😵‍💫": {
	name: "face with spiral eyes",
	slug: "face_with_spiral_eyes",
	group: "Smileys & Emotion",
	emoji_version: "13.1",
	unicode_version: "13.1",
	skin_tone_support: false
},
	"🤯": {
	name: "exploding head",
	slug: "exploding_head",
	group: "Smileys & Emotion",
	emoji_version: "5.0",
	unicode_version: "5.0",
	skin_tone_support: false
},
	"🤠": {
	name: "cowboy hat face",
	slug: "cowboy_hat_face",
	group: "Smileys & Emotion",
	emoji_version: "3.0",
	unicode_version: "3.0",
	skin_tone_support: false
},
	"🥳": {
	name: "partying face",
	slug: "partying_face",
	group: "Smileys & Emotion",
	emoji_version: "11.0",
	unicode_version: "11.0",
	skin_tone_support: false
},
	"🥸": {
	name: "disguised face",
	slug: "disguised_face",
	group: "Smileys & Emotion",
	emoji_version: "13.0",
	unicode_version: "13.0",
	skin_tone_support: false
},
	"😎": {
	name: "smiling face with sunglasses",
	slug: "smiling_face_with_sunglasses",
	group: "Smileys & Emotion",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🤓": {
	name: "nerd face",
	slug: "nerd_face",
	group: "Smileys & Emotion",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🧐": {
	name: "face with monocle",
	slug: "face_with_monocle",
	group: "Smileys & Emotion",
	emoji_version: "5.0",
	unicode_version: "5.0",
	skin_tone_support: false
},
	"😕": {
	name: "confused face",
	slug: "confused_face",
	group: "Smileys & Emotion",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🫤": {
	name: "face with diagonal mouth",
	slug: "face_with_diagonal_mouth",
	group: "Smileys & Emotion",
	emoji_version: "14.0",
	unicode_version: "14.0",
	skin_tone_support: false
},
	"😟": {
	name: "worried face",
	slug: "worried_face",
	group: "Smileys & Emotion",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🙁": {
	name: "slightly frowning face",
	slug: "slightly_frowning_face",
	group: "Smileys & Emotion",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"☹️": {
	name: "frowning face",
	slug: "frowning_face",
	group: "Smileys & Emotion",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"😮": {
	name: "face with open mouth",
	slug: "face_with_open_mouth",
	group: "Smileys & Emotion",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"😯": {
	name: "hushed face",
	slug: "hushed_face",
	group: "Smileys & Emotion",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"😲": {
	name: "astonished face",
	slug: "astonished_face",
	group: "Smileys & Emotion",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"😳": {
	name: "flushed face",
	slug: "flushed_face",
	group: "Smileys & Emotion",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🥺": {
	name: "pleading face",
	slug: "pleading_face",
	group: "Smileys & Emotion",
	emoji_version: "11.0",
	unicode_version: "11.0",
	skin_tone_support: false
},
	"🥹": {
	name: "face holding back tears",
	slug: "face_holding_back_tears",
	group: "Smileys & Emotion",
	emoji_version: "14.0",
	unicode_version: "14.0",
	skin_tone_support: false
},
	"😦": {
	name: "frowning face with open mouth",
	slug: "frowning_face_with_open_mouth",
	group: "Smileys & Emotion",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"😧": {
	name: "anguished face",
	slug: "anguished_face",
	group: "Smileys & Emotion",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"😨": {
	name: "fearful face",
	slug: "fearful_face",
	group: "Smileys & Emotion",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"😰": {
	name: "anxious face with sweat",
	slug: "anxious_face_with_sweat",
	group: "Smileys & Emotion",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"😥": {
	name: "sad but relieved face",
	slug: "sad_but_relieved_face",
	group: "Smileys & Emotion",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"😢": {
	name: "crying face",
	slug: "crying_face",
	group: "Smileys & Emotion",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"😭": {
	name: "loudly crying face",
	slug: "loudly_crying_face",
	group: "Smileys & Emotion",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"😱": {
	name: "face screaming in fear",
	slug: "face_screaming_in_fear",
	group: "Smileys & Emotion",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"😖": {
	name: "confounded face",
	slug: "confounded_face",
	group: "Smileys & Emotion",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"😣": {
	name: "persevering face",
	slug: "persevering_face",
	group: "Smileys & Emotion",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"😞": {
	name: "disappointed face",
	slug: "disappointed_face",
	group: "Smileys & Emotion",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"😓": {
	name: "downcast face with sweat",
	slug: "downcast_face_with_sweat",
	group: "Smileys & Emotion",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"😩": {
	name: "weary face",
	slug: "weary_face",
	group: "Smileys & Emotion",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"😫": {
	name: "tired face",
	slug: "tired_face",
	group: "Smileys & Emotion",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🥱": {
	name: "yawning face",
	slug: "yawning_face",
	group: "Smileys & Emotion",
	emoji_version: "12.0",
	unicode_version: "12.0",
	skin_tone_support: false
},
	"😤": {
	name: "face with steam from nose",
	slug: "face_with_steam_from_nose",
	group: "Smileys & Emotion",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"😡": {
	name: "enraged face",
	slug: "enraged_face",
	group: "Smileys & Emotion",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"😠": {
	name: "angry face",
	slug: "angry_face",
	group: "Smileys & Emotion",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🤬": {
	name: "face with symbols on mouth",
	slug: "face_with_symbols_on_mouth",
	group: "Smileys & Emotion",
	emoji_version: "5.0",
	unicode_version: "5.0",
	skin_tone_support: false
},
	"😈": {
	name: "smiling face with horns",
	slug: "smiling_face_with_horns",
	group: "Smileys & Emotion",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"👿": {
	name: "angry face with horns",
	slug: "angry_face_with_horns",
	group: "Smileys & Emotion",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"💀": {
	name: "skull",
	slug: "skull",
	group: "Smileys & Emotion",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"☠️": {
	name: "skull and crossbones",
	slug: "skull_and_crossbones",
	group: "Smileys & Emotion",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"💩": {
	name: "pile of poo",
	slug: "pile_of_poo",
	group: "Smileys & Emotion",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🤡": {
	name: "clown face",
	slug: "clown_face",
	group: "Smileys & Emotion",
	emoji_version: "3.0",
	unicode_version: "3.0",
	skin_tone_support: false
},
	"👹": {
	name: "ogre",
	slug: "ogre",
	group: "Smileys & Emotion",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"👺": {
	name: "goblin",
	slug: "goblin",
	group: "Smileys & Emotion",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"👻": {
	name: "ghost",
	slug: "ghost",
	group: "Smileys & Emotion",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"👽": {
	name: "alien",
	slug: "alien",
	group: "Smileys & Emotion",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"👾": {
	name: "alien monster",
	slug: "alien_monster",
	group: "Smileys & Emotion",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🤖": {
	name: "robot",
	slug: "robot",
	group: "Smileys & Emotion",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"😺": {
	name: "grinning cat",
	slug: "grinning_cat",
	group: "Smileys & Emotion",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"😸": {
	name: "grinning cat with smiling eyes",
	slug: "grinning_cat_with_smiling_eyes",
	group: "Smileys & Emotion",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"😹": {
	name: "cat with tears of joy",
	slug: "cat_with_tears_of_joy",
	group: "Smileys & Emotion",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"😻": {
	name: "smiling cat with heart-eyes",
	slug: "smiling_cat_with_heart_eyes",
	group: "Smileys & Emotion",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"😼": {
	name: "cat with wry smile",
	slug: "cat_with_wry_smile",
	group: "Smileys & Emotion",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"😽": {
	name: "kissing cat",
	slug: "kissing_cat",
	group: "Smileys & Emotion",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🙀": {
	name: "weary cat",
	slug: "weary_cat",
	group: "Smileys & Emotion",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"😿": {
	name: "crying cat",
	slug: "crying_cat",
	group: "Smileys & Emotion",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"😾": {
	name: "pouting cat",
	slug: "pouting_cat",
	group: "Smileys & Emotion",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🙈": {
	name: "see-no-evil monkey",
	slug: "see_no_evil_monkey",
	group: "Smileys & Emotion",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🙉": {
	name: "hear-no-evil monkey",
	slug: "hear_no_evil_monkey",
	group: "Smileys & Emotion",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🙊": {
	name: "speak-no-evil monkey",
	slug: "speak_no_evil_monkey",
	group: "Smileys & Emotion",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"💌": {
	name: "love letter",
	slug: "love_letter",
	group: "Smileys & Emotion",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"💘": {
	name: "heart with arrow",
	slug: "heart_with_arrow",
	group: "Smileys & Emotion",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"💝": {
	name: "heart with ribbon",
	slug: "heart_with_ribbon",
	group: "Smileys & Emotion",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"💖": {
	name: "sparkling heart",
	slug: "sparkling_heart",
	group: "Smileys & Emotion",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"💗": {
	name: "growing heart",
	slug: "growing_heart",
	group: "Smileys & Emotion",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"💓": {
	name: "beating heart",
	slug: "beating_heart",
	group: "Smileys & Emotion",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"💞": {
	name: "revolving hearts",
	slug: "revolving_hearts",
	group: "Smileys & Emotion",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"💕": {
	name: "two hearts",
	slug: "two_hearts",
	group: "Smileys & Emotion",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"💟": {
	name: "heart decoration",
	slug: "heart_decoration",
	group: "Smileys & Emotion",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"❣️": {
	name: "heart exclamation",
	slug: "heart_exclamation",
	group: "Smileys & Emotion",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"💔": {
	name: "broken heart",
	slug: "broken_heart",
	group: "Smileys & Emotion",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"❤️‍🔥": {
	name: "heart on fire",
	slug: "heart_on_fire",
	group: "Smileys & Emotion",
	emoji_version: "13.1",
	unicode_version: "13.1",
	skin_tone_support: false
},
	"❤️‍🩹": {
	name: "mending heart",
	slug: "mending_heart",
	group: "Smileys & Emotion",
	emoji_version: "13.1",
	unicode_version: "13.1",
	skin_tone_support: false
},
	"❤️": {
	name: "red heart",
	slug: "red_heart",
	group: "Smileys & Emotion",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🩷": {
	name: "pink heart",
	slug: "pink_heart",
	group: "Smileys & Emotion",
	emoji_version: "15.0",
	unicode_version: "15.0",
	skin_tone_support: false
},
	"🧡": {
	name: "orange heart",
	slug: "orange_heart",
	group: "Smileys & Emotion",
	emoji_version: "5.0",
	unicode_version: "5.0",
	skin_tone_support: false
},
	"💛": {
	name: "yellow heart",
	slug: "yellow_heart",
	group: "Smileys & Emotion",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"💚": {
	name: "green heart",
	slug: "green_heart",
	group: "Smileys & Emotion",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"💙": {
	name: "blue heart",
	slug: "blue_heart",
	group: "Smileys & Emotion",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🩵": {
	name: "light blue heart",
	slug: "light_blue_heart",
	group: "Smileys & Emotion",
	emoji_version: "15.0",
	unicode_version: "15.0",
	skin_tone_support: false
},
	"💜": {
	name: "purple heart",
	slug: "purple_heart",
	group: "Smileys & Emotion",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🤎": {
	name: "brown heart",
	slug: "brown_heart",
	group: "Smileys & Emotion",
	emoji_version: "12.0",
	unicode_version: "12.0",
	skin_tone_support: false
},
	"🖤": {
	name: "black heart",
	slug: "black_heart",
	group: "Smileys & Emotion",
	emoji_version: "3.0",
	unicode_version: "3.0",
	skin_tone_support: false
},
	"🩶": {
	name: "grey heart",
	slug: "grey_heart",
	group: "Smileys & Emotion",
	emoji_version: "15.0",
	unicode_version: "15.0",
	skin_tone_support: false
},
	"🤍": {
	name: "white heart",
	slug: "white_heart",
	group: "Smileys & Emotion",
	emoji_version: "12.0",
	unicode_version: "12.0",
	skin_tone_support: false
},
	"💋": {
	name: "kiss mark",
	slug: "kiss_mark",
	group: "Smileys & Emotion",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"💯": {
	name: "hundred points",
	slug: "hundred_points",
	group: "Smileys & Emotion",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"💢": {
	name: "anger symbol",
	slug: "anger_symbol",
	group: "Smileys & Emotion",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"💥": {
	name: "collision",
	slug: "collision",
	group: "Smileys & Emotion",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"💫": {
	name: "dizzy",
	slug: "dizzy",
	group: "Smileys & Emotion",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"💦": {
	name: "sweat droplets",
	slug: "sweat_droplets",
	group: "Smileys & Emotion",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"💨": {
	name: "dashing away",
	slug: "dashing_away",
	group: "Smileys & Emotion",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🕳️": {
	name: "hole",
	slug: "hole",
	group: "Smileys & Emotion",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"💬": {
	name: "speech balloon",
	slug: "speech_balloon",
	group: "Smileys & Emotion",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"👁️‍🗨️": {
	name: "eye in speech bubble",
	slug: "eye_in_speech_bubble",
	group: "Smileys & Emotion",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🗨️": {
	name: "left speech bubble",
	slug: "left_speech_bubble",
	group: "Smileys & Emotion",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🗯️": {
	name: "right anger bubble",
	slug: "right_anger_bubble",
	group: "Smileys & Emotion",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"💭": {
	name: "thought balloon",
	slug: "thought_balloon",
	group: "Smileys & Emotion",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"💤": {
	name: "ZZZ",
	slug: "zzz",
	group: "Smileys & Emotion",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"👋": {
	name: "waving hand",
	slug: "waving_hand",
	group: "People & Body",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "1.0"
},
	"🤚": {
	name: "raised back of hand",
	slug: "raised_back_of_hand",
	group: "People & Body",
	emoji_version: "3.0",
	unicode_version: "3.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "3.0"
},
	"🖐️": {
	name: "hand with fingers splayed",
	slug: "hand_with_fingers_splayed",
	group: "People & Body",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "1.0"
},
	"✋": {
	name: "raised hand",
	slug: "raised_hand",
	group: "People & Body",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "1.0"
},
	"🖖": {
	name: "vulcan salute",
	slug: "vulcan_salute",
	group: "People & Body",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "1.0"
},
	"🫱": {
	name: "rightwards hand",
	slug: "rightwards_hand",
	group: "People & Body",
	emoji_version: "14.0",
	unicode_version: "14.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "14.0"
},
	"🫲": {
	name: "leftwards hand",
	slug: "leftwards_hand",
	group: "People & Body",
	emoji_version: "14.0",
	unicode_version: "14.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "14.0"
},
	"🫳": {
	name: "palm down hand",
	slug: "palm_down_hand",
	group: "People & Body",
	emoji_version: "14.0",
	unicode_version: "14.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "14.0"
},
	"🫴": {
	name: "palm up hand",
	slug: "palm_up_hand",
	group: "People & Body",
	emoji_version: "14.0",
	unicode_version: "14.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "14.0"
},
	"🫷": {
	name: "leftwards pushing hand",
	slug: "leftwards_pushing_hand",
	group: "People & Body",
	emoji_version: "15.0",
	unicode_version: "15.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "15.0"
},
	"🫸": {
	name: "rightwards pushing hand",
	slug: "rightwards_pushing_hand",
	group: "People & Body",
	emoji_version: "15.0",
	unicode_version: "15.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "15.0"
},
	"👌": {
	name: "OK hand",
	slug: "ok_hand",
	group: "People & Body",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "1.0"
},
	"🤌": {
	name: "pinched fingers",
	slug: "pinched_fingers",
	group: "People & Body",
	emoji_version: "13.0",
	unicode_version: "13.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "13.0"
},
	"🤏": {
	name: "pinching hand",
	slug: "pinching_hand",
	group: "People & Body",
	emoji_version: "12.0",
	unicode_version: "12.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "12.0"
},
	"✌️": {
	name: "victory hand",
	slug: "victory_hand",
	group: "People & Body",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "1.0"
},
	"🤞": {
	name: "crossed fingers",
	slug: "crossed_fingers",
	group: "People & Body",
	emoji_version: "3.0",
	unicode_version: "3.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "3.0"
},
	"🫰": {
	name: "hand with index finger and thumb crossed",
	slug: "hand_with_index_finger_and_thumb_crossed",
	group: "People & Body",
	emoji_version: "14.0",
	unicode_version: "14.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "14.0"
},
	"🤟": {
	name: "love-you gesture",
	slug: "love_you_gesture",
	group: "People & Body",
	emoji_version: "5.0",
	unicode_version: "5.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "5.0"
},
	"🤘": {
	name: "sign of the horns",
	slug: "sign_of_the_horns",
	group: "People & Body",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "1.0"
},
	"🤙": {
	name: "call me hand",
	slug: "call_me_hand",
	group: "People & Body",
	emoji_version: "3.0",
	unicode_version: "3.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "3.0"
},
	"👈": {
	name: "backhand index pointing left",
	slug: "backhand_index_pointing_left",
	group: "People & Body",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "1.0"
},
	"👉": {
	name: "backhand index pointing right",
	slug: "backhand_index_pointing_right",
	group: "People & Body",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "1.0"
},
	"👆": {
	name: "backhand index pointing up",
	slug: "backhand_index_pointing_up",
	group: "People & Body",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "1.0"
},
	"🖕": {
	name: "middle finger",
	slug: "middle_finger",
	group: "People & Body",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "1.0"
},
	"👇": {
	name: "backhand index pointing down",
	slug: "backhand_index_pointing_down",
	group: "People & Body",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "1.0"
},
	"☝️": {
	name: "index pointing up",
	slug: "index_pointing_up",
	group: "People & Body",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "1.0"
},
	"🫵": {
	name: "index pointing at the viewer",
	slug: "index_pointing_at_the_viewer",
	group: "People & Body",
	emoji_version: "14.0",
	unicode_version: "14.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "14.0"
},
	"👍": {
	name: "thumbs up",
	slug: "thumbs_up",
	group: "People & Body",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "1.0"
},
	"👎": {
	name: "thumbs down",
	slug: "thumbs_down",
	group: "People & Body",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "1.0"
},
	"✊": {
	name: "raised fist",
	slug: "raised_fist",
	group: "People & Body",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "1.0"
},
	"👊": {
	name: "oncoming fist",
	slug: "oncoming_fist",
	group: "People & Body",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "1.0"
},
	"🤛": {
	name: "left-facing fist",
	slug: "left_facing_fist",
	group: "People & Body",
	emoji_version: "3.0",
	unicode_version: "3.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "3.0"
},
	"🤜": {
	name: "right-facing fist",
	slug: "right_facing_fist",
	group: "People & Body",
	emoji_version: "3.0",
	unicode_version: "3.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "3.0"
},
	"👏": {
	name: "clapping hands",
	slug: "clapping_hands",
	group: "People & Body",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "1.0"
},
	"🙌": {
	name: "raising hands",
	slug: "raising_hands",
	group: "People & Body",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "1.0"
},
	"🫶": {
	name: "heart hands",
	slug: "heart_hands",
	group: "People & Body",
	emoji_version: "14.0",
	unicode_version: "14.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "14.0"
},
	"👐": {
	name: "open hands",
	slug: "open_hands",
	group: "People & Body",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "1.0"
},
	"🤲": {
	name: "palms up together",
	slug: "palms_up_together",
	group: "People & Body",
	emoji_version: "5.0",
	unicode_version: "5.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "5.0"
},
	"🤝": {
	name: "handshake",
	slug: "handshake",
	group: "People & Body",
	emoji_version: "3.0",
	unicode_version: "3.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "14.0"
},
	"🙏": {
	name: "folded hands",
	slug: "folded_hands",
	group: "People & Body",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "1.0"
},
	"✍️": {
	name: "writing hand",
	slug: "writing_hand",
	group: "People & Body",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "1.0"
},
	"💅": {
	name: "nail polish",
	slug: "nail_polish",
	group: "People & Body",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "1.0"
},
	"🤳": {
	name: "selfie",
	slug: "selfie",
	group: "People & Body",
	emoji_version: "3.0",
	unicode_version: "3.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "3.0"
},
	"💪": {
	name: "flexed biceps",
	slug: "flexed_biceps",
	group: "People & Body",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "1.0"
},
	"🦾": {
	name: "mechanical arm",
	slug: "mechanical_arm",
	group: "People & Body",
	emoji_version: "12.0",
	unicode_version: "12.0",
	skin_tone_support: false
},
	"🦿": {
	name: "mechanical leg",
	slug: "mechanical_leg",
	group: "People & Body",
	emoji_version: "12.0",
	unicode_version: "12.0",
	skin_tone_support: false
},
	"🦵": {
	name: "leg",
	slug: "leg",
	group: "People & Body",
	emoji_version: "11.0",
	unicode_version: "11.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "11.0"
},
	"🦶": {
	name: "foot",
	slug: "foot",
	group: "People & Body",
	emoji_version: "11.0",
	unicode_version: "11.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "11.0"
},
	"👂": {
	name: "ear",
	slug: "ear",
	group: "People & Body",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "1.0"
},
	"🦻": {
	name: "ear with hearing aid",
	slug: "ear_with_hearing_aid",
	group: "People & Body",
	emoji_version: "12.0",
	unicode_version: "12.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "12.0"
},
	"👃": {
	name: "nose",
	slug: "nose",
	group: "People & Body",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "1.0"
},
	"🧠": {
	name: "brain",
	slug: "brain",
	group: "People & Body",
	emoji_version: "5.0",
	unicode_version: "5.0",
	skin_tone_support: false
},
	"🫀": {
	name: "anatomical heart",
	slug: "anatomical_heart",
	group: "People & Body",
	emoji_version: "13.0",
	unicode_version: "13.0",
	skin_tone_support: false
},
	"🫁": {
	name: "lungs",
	slug: "lungs",
	group: "People & Body",
	emoji_version: "13.0",
	unicode_version: "13.0",
	skin_tone_support: false
},
	"🦷": {
	name: "tooth",
	slug: "tooth",
	group: "People & Body",
	emoji_version: "11.0",
	unicode_version: "11.0",
	skin_tone_support: false
},
	"🦴": {
	name: "bone",
	slug: "bone",
	group: "People & Body",
	emoji_version: "11.0",
	unicode_version: "11.0",
	skin_tone_support: false
},
	"👀": {
	name: "eyes",
	slug: "eyes",
	group: "People & Body",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"👁️": {
	name: "eye",
	slug: "eye",
	group: "People & Body",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"👅": {
	name: "tongue",
	slug: "tongue",
	group: "People & Body",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"👄": {
	name: "mouth",
	slug: "mouth",
	group: "People & Body",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🫦": {
	name: "biting lip",
	slug: "biting_lip",
	group: "People & Body",
	emoji_version: "14.0",
	unicode_version: "14.0",
	skin_tone_support: false
},
	"👶": {
	name: "baby",
	slug: "baby",
	group: "People & Body",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "1.0"
},
	"🧒": {
	name: "child",
	slug: "child",
	group: "People & Body",
	emoji_version: "5.0",
	unicode_version: "5.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "5.0"
},
	"👦": {
	name: "boy",
	slug: "boy",
	group: "People & Body",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "1.0"
},
	"👧": {
	name: "girl",
	slug: "girl",
	group: "People & Body",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "1.0"
},
	"🧑": {
	name: "person",
	slug: "person",
	group: "People & Body",
	emoji_version: "5.0",
	unicode_version: "5.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "5.0"
},
	"👱": {
	name: "person blond hair",
	slug: "person_blond_hair",
	group: "People & Body",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "1.0"
},
	"👨": {
	name: "man",
	slug: "man",
	group: "People & Body",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "1.0"
},
	"🧔": {
	name: "person beard",
	slug: "person_beard",
	group: "People & Body",
	emoji_version: "5.0",
	unicode_version: "5.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "5.0"
},
	"🧔‍♂️": {
	name: "man beard",
	slug: "man_beard",
	group: "People & Body",
	emoji_version: "13.1",
	unicode_version: "13.1",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "13.1"
},
	"🧔‍♀️": {
	name: "woman beard",
	slug: "woman_beard",
	group: "People & Body",
	emoji_version: "13.1",
	unicode_version: "13.1",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "13.1"
},
	"👨‍🦰": {
	name: "man red hair",
	slug: "man_red_hair",
	group: "People & Body",
	emoji_version: "11.0",
	unicode_version: "11.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "11.0"
},
	"👨‍🦱": {
	name: "man curly hair",
	slug: "man_curly_hair",
	group: "People & Body",
	emoji_version: "11.0",
	unicode_version: "11.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "11.0"
},
	"👨‍🦳": {
	name: "man white hair",
	slug: "man_white_hair",
	group: "People & Body",
	emoji_version: "11.0",
	unicode_version: "11.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "11.0"
},
	"👨‍🦲": {
	name: "man bald",
	slug: "man_bald",
	group: "People & Body",
	emoji_version: "11.0",
	unicode_version: "11.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "11.0"
},
	"👩": {
	name: "woman",
	slug: "woman",
	group: "People & Body",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "1.0"
},
	"👩‍🦰": {
	name: "woman red hair",
	slug: "woman_red_hair",
	group: "People & Body",
	emoji_version: "11.0",
	unicode_version: "11.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "11.0"
},
	"🧑‍🦰": {
	name: "person red hair",
	slug: "person_red_hair",
	group: "People & Body",
	emoji_version: "12.1",
	unicode_version: "12.1",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "12.1"
},
	"👩‍🦱": {
	name: "woman curly hair",
	slug: "woman_curly_hair",
	group: "People & Body",
	emoji_version: "11.0",
	unicode_version: "11.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "11.0"
},
	"🧑‍🦱": {
	name: "person curly hair",
	slug: "person_curly_hair",
	group: "People & Body",
	emoji_version: "12.1",
	unicode_version: "12.1",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "12.1"
},
	"👩‍🦳": {
	name: "woman white hair",
	slug: "woman_white_hair",
	group: "People & Body",
	emoji_version: "11.0",
	unicode_version: "11.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "11.0"
},
	"🧑‍🦳": {
	name: "person white hair",
	slug: "person_white_hair",
	group: "People & Body",
	emoji_version: "12.1",
	unicode_version: "12.1",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "12.1"
},
	"👩‍🦲": {
	name: "woman bald",
	slug: "woman_bald",
	group: "People & Body",
	emoji_version: "11.0",
	unicode_version: "11.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "11.0"
},
	"🧑‍🦲": {
	name: "person bald",
	slug: "person_bald",
	group: "People & Body",
	emoji_version: "12.1",
	unicode_version: "12.1",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "12.1"
},
	"👱‍♀️": {
	name: "woman blond hair",
	slug: "woman_blond_hair",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"👱‍♂️": {
	name: "man blond hair",
	slug: "man_blond_hair",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"🧓": {
	name: "older person",
	slug: "older_person",
	group: "People & Body",
	emoji_version: "5.0",
	unicode_version: "5.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "5.0"
},
	"👴": {
	name: "old man",
	slug: "old_man",
	group: "People & Body",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "1.0"
},
	"👵": {
	name: "old woman",
	slug: "old_woman",
	group: "People & Body",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "1.0"
},
	"🙍": {
	name: "person frowning",
	slug: "person_frowning",
	group: "People & Body",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "1.0"
},
	"🙍‍♂️": {
	name: "man frowning",
	slug: "man_frowning",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"🙍‍♀️": {
	name: "woman frowning",
	slug: "woman_frowning",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"🙎": {
	name: "person pouting",
	slug: "person_pouting",
	group: "People & Body",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "1.0"
},
	"🙎‍♂️": {
	name: "man pouting",
	slug: "man_pouting",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"🙎‍♀️": {
	name: "woman pouting",
	slug: "woman_pouting",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"🙅": {
	name: "person gesturing NO",
	slug: "person_gesturing_no",
	group: "People & Body",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "1.0"
},
	"🙅‍♂️": {
	name: "man gesturing NO",
	slug: "man_gesturing_no",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"🙅‍♀️": {
	name: "woman gesturing NO",
	slug: "woman_gesturing_no",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"🙆": {
	name: "person gesturing OK",
	slug: "person_gesturing_ok",
	group: "People & Body",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "1.0"
},
	"🙆‍♂️": {
	name: "man gesturing OK",
	slug: "man_gesturing_ok",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"🙆‍♀️": {
	name: "woman gesturing OK",
	slug: "woman_gesturing_ok",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"💁": {
	name: "person tipping hand",
	slug: "person_tipping_hand",
	group: "People & Body",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "1.0"
},
	"💁‍♂️": {
	name: "man tipping hand",
	slug: "man_tipping_hand",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"💁‍♀️": {
	name: "woman tipping hand",
	slug: "woman_tipping_hand",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"🙋": {
	name: "person raising hand",
	slug: "person_raising_hand",
	group: "People & Body",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "1.0"
},
	"🙋‍♂️": {
	name: "man raising hand",
	slug: "man_raising_hand",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"🙋‍♀️": {
	name: "woman raising hand",
	slug: "woman_raising_hand",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"🧏": {
	name: "deaf person",
	slug: "deaf_person",
	group: "People & Body",
	emoji_version: "12.0",
	unicode_version: "12.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "12.0"
},
	"🧏‍♂️": {
	name: "deaf man",
	slug: "deaf_man",
	group: "People & Body",
	emoji_version: "12.0",
	unicode_version: "12.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "12.0"
},
	"🧏‍♀️": {
	name: "deaf woman",
	slug: "deaf_woman",
	group: "People & Body",
	emoji_version: "12.0",
	unicode_version: "12.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "12.0"
},
	"🙇": {
	name: "person bowing",
	slug: "person_bowing",
	group: "People & Body",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "1.0"
},
	"🙇‍♂️": {
	name: "man bowing",
	slug: "man_bowing",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"🙇‍♀️": {
	name: "woman bowing",
	slug: "woman_bowing",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"🤦": {
	name: "person facepalming",
	slug: "person_facepalming",
	group: "People & Body",
	emoji_version: "3.0",
	unicode_version: "3.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "3.0"
},
	"🤦‍♂️": {
	name: "man facepalming",
	slug: "man_facepalming",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"🤦‍♀️": {
	name: "woman facepalming",
	slug: "woman_facepalming",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"🤷": {
	name: "person shrugging",
	slug: "person_shrugging",
	group: "People & Body",
	emoji_version: "3.0",
	unicode_version: "3.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "3.0"
},
	"🤷‍♂️": {
	name: "man shrugging",
	slug: "man_shrugging",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"🤷‍♀️": {
	name: "woman shrugging",
	slug: "woman_shrugging",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"🧑‍⚕️": {
	name: "health worker",
	slug: "health_worker",
	group: "People & Body",
	emoji_version: "12.1",
	unicode_version: "12.1",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "12.1"
},
	"👨‍⚕️": {
	name: "man health worker",
	slug: "man_health_worker",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"👩‍⚕️": {
	name: "woman health worker",
	slug: "woman_health_worker",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"🧑‍🎓": {
	name: "student",
	slug: "student",
	group: "People & Body",
	emoji_version: "12.1",
	unicode_version: "12.1",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "12.1"
},
	"👨‍🎓": {
	name: "man student",
	slug: "man_student",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"👩‍🎓": {
	name: "woman student",
	slug: "woman_student",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"🧑‍🏫": {
	name: "teacher",
	slug: "teacher",
	group: "People & Body",
	emoji_version: "12.1",
	unicode_version: "12.1",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "12.1"
},
	"👨‍🏫": {
	name: "man teacher",
	slug: "man_teacher",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"👩‍🏫": {
	name: "woman teacher",
	slug: "woman_teacher",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"🧑‍⚖️": {
	name: "judge",
	slug: "judge",
	group: "People & Body",
	emoji_version: "12.1",
	unicode_version: "12.1",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "12.1"
},
	"👨‍⚖️": {
	name: "man judge",
	slug: "man_judge",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"👩‍⚖️": {
	name: "woman judge",
	slug: "woman_judge",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"🧑‍🌾": {
	name: "farmer",
	slug: "farmer",
	group: "People & Body",
	emoji_version: "12.1",
	unicode_version: "12.1",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "12.1"
},
	"👨‍🌾": {
	name: "man farmer",
	slug: "man_farmer",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"👩‍🌾": {
	name: "woman farmer",
	slug: "woman_farmer",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"🧑‍🍳": {
	name: "cook",
	slug: "cook",
	group: "People & Body",
	emoji_version: "12.1",
	unicode_version: "12.1",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "12.1"
},
	"👨‍🍳": {
	name: "man cook",
	slug: "man_cook",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"👩‍🍳": {
	name: "woman cook",
	slug: "woman_cook",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"🧑‍🔧": {
	name: "mechanic",
	slug: "mechanic",
	group: "People & Body",
	emoji_version: "12.1",
	unicode_version: "12.1",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "12.1"
},
	"👨‍🔧": {
	name: "man mechanic",
	slug: "man_mechanic",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"👩‍🔧": {
	name: "woman mechanic",
	slug: "woman_mechanic",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"🧑‍🏭": {
	name: "factory worker",
	slug: "factory_worker",
	group: "People & Body",
	emoji_version: "12.1",
	unicode_version: "12.1",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "12.1"
},
	"👨‍🏭": {
	name: "man factory worker",
	slug: "man_factory_worker",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"👩‍🏭": {
	name: "woman factory worker",
	slug: "woman_factory_worker",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"🧑‍💼": {
	name: "office worker",
	slug: "office_worker",
	group: "People & Body",
	emoji_version: "12.1",
	unicode_version: "12.1",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "12.1"
},
	"👨‍💼": {
	name: "man office worker",
	slug: "man_office_worker",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"👩‍💼": {
	name: "woman office worker",
	slug: "woman_office_worker",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"🧑‍🔬": {
	name: "scientist",
	slug: "scientist",
	group: "People & Body",
	emoji_version: "12.1",
	unicode_version: "12.1",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "12.1"
},
	"👨‍🔬": {
	name: "man scientist",
	slug: "man_scientist",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"👩‍🔬": {
	name: "woman scientist",
	slug: "woman_scientist",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"🧑‍💻": {
	name: "technologist",
	slug: "technologist",
	group: "People & Body",
	emoji_version: "12.1",
	unicode_version: "12.1",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "12.1"
},
	"👨‍💻": {
	name: "man technologist",
	slug: "man_technologist",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"👩‍💻": {
	name: "woman technologist",
	slug: "woman_technologist",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"🧑‍🎤": {
	name: "singer",
	slug: "singer",
	group: "People & Body",
	emoji_version: "12.1",
	unicode_version: "12.1",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "12.1"
},
	"👨‍🎤": {
	name: "man singer",
	slug: "man_singer",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"👩‍🎤": {
	name: "woman singer",
	slug: "woman_singer",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"🧑‍🎨": {
	name: "artist",
	slug: "artist",
	group: "People & Body",
	emoji_version: "12.1",
	unicode_version: "12.1",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "12.1"
},
	"👨‍🎨": {
	name: "man artist",
	slug: "man_artist",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"👩‍🎨": {
	name: "woman artist",
	slug: "woman_artist",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"🧑‍✈️": {
	name: "pilot",
	slug: "pilot",
	group: "People & Body",
	emoji_version: "12.1",
	unicode_version: "12.1",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "12.1"
},
	"👨‍✈️": {
	name: "man pilot",
	slug: "man_pilot",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"👩‍✈️": {
	name: "woman pilot",
	slug: "woman_pilot",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"🧑‍🚀": {
	name: "astronaut",
	slug: "astronaut",
	group: "People & Body",
	emoji_version: "12.1",
	unicode_version: "12.1",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "12.1"
},
	"👨‍🚀": {
	name: "man astronaut",
	slug: "man_astronaut",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"👩‍🚀": {
	name: "woman astronaut",
	slug: "woman_astronaut",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"🧑‍🚒": {
	name: "firefighter",
	slug: "firefighter",
	group: "People & Body",
	emoji_version: "12.1",
	unicode_version: "12.1",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "12.1"
},
	"👨‍🚒": {
	name: "man firefighter",
	slug: "man_firefighter",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"👩‍🚒": {
	name: "woman firefighter",
	slug: "woman_firefighter",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"👮": {
	name: "police officer",
	slug: "police_officer",
	group: "People & Body",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "1.0"
},
	"👮‍♂️": {
	name: "man police officer",
	slug: "man_police_officer",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"👮‍♀️": {
	name: "woman police officer",
	slug: "woman_police_officer",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"🕵️": {
	name: "detective",
	slug: "detective",
	group: "People & Body",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "2.0"
},
	"🕵️‍♂️": {
	name: "man detective",
	slug: "man_detective",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"🕵️‍♀️": {
	name: "woman detective",
	slug: "woman_detective",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"💂": {
	name: "guard",
	slug: "guard",
	group: "People & Body",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "1.0"
},
	"💂‍♂️": {
	name: "man guard",
	slug: "man_guard",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"💂‍♀️": {
	name: "woman guard",
	slug: "woman_guard",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"🥷": {
	name: "ninja",
	slug: "ninja",
	group: "People & Body",
	emoji_version: "13.0",
	unicode_version: "13.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "13.0"
},
	"👷": {
	name: "construction worker",
	slug: "construction_worker",
	group: "People & Body",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "1.0"
},
	"👷‍♂️": {
	name: "man construction worker",
	slug: "man_construction_worker",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"👷‍♀️": {
	name: "woman construction worker",
	slug: "woman_construction_worker",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"🫅": {
	name: "person with crown",
	slug: "person_with_crown",
	group: "People & Body",
	emoji_version: "14.0",
	unicode_version: "14.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "14.0"
},
	"🤴": {
	name: "prince",
	slug: "prince",
	group: "People & Body",
	emoji_version: "3.0",
	unicode_version: "3.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "3.0"
},
	"👸": {
	name: "princess",
	slug: "princess",
	group: "People & Body",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "1.0"
},
	"👳": {
	name: "person wearing turban",
	slug: "person_wearing_turban",
	group: "People & Body",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "1.0"
},
	"👳‍♂️": {
	name: "man wearing turban",
	slug: "man_wearing_turban",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"👳‍♀️": {
	name: "woman wearing turban",
	slug: "woman_wearing_turban",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"👲": {
	name: "person with skullcap",
	slug: "person_with_skullcap",
	group: "People & Body",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "1.0"
},
	"🧕": {
	name: "woman with headscarf",
	slug: "woman_with_headscarf",
	group: "People & Body",
	emoji_version: "5.0",
	unicode_version: "5.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "5.0"
},
	"🤵": {
	name: "person in tuxedo",
	slug: "person_in_tuxedo",
	group: "People & Body",
	emoji_version: "3.0",
	unicode_version: "3.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "3.0"
},
	"🤵‍♂️": {
	name: "man in tuxedo",
	slug: "man_in_tuxedo",
	group: "People & Body",
	emoji_version: "13.0",
	unicode_version: "13.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "13.0"
},
	"🤵‍♀️": {
	name: "woman in tuxedo",
	slug: "woman_in_tuxedo",
	group: "People & Body",
	emoji_version: "13.0",
	unicode_version: "13.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "13.0"
},
	"👰": {
	name: "person with veil",
	slug: "person_with_veil",
	group: "People & Body",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "1.0"
},
	"👰‍♂️": {
	name: "man with veil",
	slug: "man_with_veil",
	group: "People & Body",
	emoji_version: "13.0",
	unicode_version: "13.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "13.0"
},
	"👰‍♀️": {
	name: "woman with veil",
	slug: "woman_with_veil",
	group: "People & Body",
	emoji_version: "13.0",
	unicode_version: "13.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "13.0"
},
	"🤰": {
	name: "pregnant woman",
	slug: "pregnant_woman",
	group: "People & Body",
	emoji_version: "3.0",
	unicode_version: "3.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "3.0"
},
	"🫃": {
	name: "pregnant man",
	slug: "pregnant_man",
	group: "People & Body",
	emoji_version: "14.0",
	unicode_version: "14.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "14.0"
},
	"🫄": {
	name: "pregnant person",
	slug: "pregnant_person",
	group: "People & Body",
	emoji_version: "14.0",
	unicode_version: "14.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "14.0"
},
	"🤱": {
	name: "breast-feeding",
	slug: "breast_feeding",
	group: "People & Body",
	emoji_version: "5.0",
	unicode_version: "5.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "5.0"
},
	"👩‍🍼": {
	name: "woman feeding baby",
	slug: "woman_feeding_baby",
	group: "People & Body",
	emoji_version: "13.0",
	unicode_version: "13.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "13.0"
},
	"👨‍🍼": {
	name: "man feeding baby",
	slug: "man_feeding_baby",
	group: "People & Body",
	emoji_version: "13.0",
	unicode_version: "13.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "13.0"
},
	"🧑‍🍼": {
	name: "person feeding baby",
	slug: "person_feeding_baby",
	group: "People & Body",
	emoji_version: "13.0",
	unicode_version: "13.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "13.0"
},
	"👼": {
	name: "baby angel",
	slug: "baby_angel",
	group: "People & Body",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "1.0"
},
	"🎅": {
	name: "Santa Claus",
	slug: "santa_claus",
	group: "People & Body",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "1.0"
},
	"🤶": {
	name: "Mrs. Claus",
	slug: "mrs_claus",
	group: "People & Body",
	emoji_version: "3.0",
	unicode_version: "3.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "3.0"
},
	"🧑‍🎄": {
	name: "mx claus",
	slug: "mx_claus",
	group: "People & Body",
	emoji_version: "13.0",
	unicode_version: "13.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "13.0"
},
	"🦸": {
	name: "superhero",
	slug: "superhero",
	group: "People & Body",
	emoji_version: "11.0",
	unicode_version: "11.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "11.0"
},
	"🦸‍♂️": {
	name: "man superhero",
	slug: "man_superhero",
	group: "People & Body",
	emoji_version: "11.0",
	unicode_version: "11.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "11.0"
},
	"🦸‍♀️": {
	name: "woman superhero",
	slug: "woman_superhero",
	group: "People & Body",
	emoji_version: "11.0",
	unicode_version: "11.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "11.0"
},
	"🦹": {
	name: "supervillain",
	slug: "supervillain",
	group: "People & Body",
	emoji_version: "11.0",
	unicode_version: "11.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "11.0"
},
	"🦹‍♂️": {
	name: "man supervillain",
	slug: "man_supervillain",
	group: "People & Body",
	emoji_version: "11.0",
	unicode_version: "11.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "11.0"
},
	"🦹‍♀️": {
	name: "woman supervillain",
	slug: "woman_supervillain",
	group: "People & Body",
	emoji_version: "11.0",
	unicode_version: "11.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "11.0"
},
	"🧙": {
	name: "mage",
	slug: "mage",
	group: "People & Body",
	emoji_version: "5.0",
	unicode_version: "5.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "5.0"
},
	"🧙‍♂️": {
	name: "man mage",
	slug: "man_mage",
	group: "People & Body",
	emoji_version: "5.0",
	unicode_version: "5.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "5.0"
},
	"🧙‍♀️": {
	name: "woman mage",
	slug: "woman_mage",
	group: "People & Body",
	emoji_version: "5.0",
	unicode_version: "5.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "5.0"
},
	"🧚": {
	name: "fairy",
	slug: "fairy",
	group: "People & Body",
	emoji_version: "5.0",
	unicode_version: "5.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "5.0"
},
	"🧚‍♂️": {
	name: "man fairy",
	slug: "man_fairy",
	group: "People & Body",
	emoji_version: "5.0",
	unicode_version: "5.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "5.0"
},
	"🧚‍♀️": {
	name: "woman fairy",
	slug: "woman_fairy",
	group: "People & Body",
	emoji_version: "5.0",
	unicode_version: "5.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "5.0"
},
	"🧛": {
	name: "vampire",
	slug: "vampire",
	group: "People & Body",
	emoji_version: "5.0",
	unicode_version: "5.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "5.0"
},
	"🧛‍♂️": {
	name: "man vampire",
	slug: "man_vampire",
	group: "People & Body",
	emoji_version: "5.0",
	unicode_version: "5.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "5.0"
},
	"🧛‍♀️": {
	name: "woman vampire",
	slug: "woman_vampire",
	group: "People & Body",
	emoji_version: "5.0",
	unicode_version: "5.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "5.0"
},
	"🧜": {
	name: "merperson",
	slug: "merperson",
	group: "People & Body",
	emoji_version: "5.0",
	unicode_version: "5.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "5.0"
},
	"🧜‍♂️": {
	name: "merman",
	slug: "merman",
	group: "People & Body",
	emoji_version: "5.0",
	unicode_version: "5.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "5.0"
},
	"🧜‍♀️": {
	name: "mermaid",
	slug: "mermaid",
	group: "People & Body",
	emoji_version: "5.0",
	unicode_version: "5.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "5.0"
},
	"🧝": {
	name: "elf",
	slug: "elf",
	group: "People & Body",
	emoji_version: "5.0",
	unicode_version: "5.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "5.0"
},
	"🧝‍♂️": {
	name: "man elf",
	slug: "man_elf",
	group: "People & Body",
	emoji_version: "5.0",
	unicode_version: "5.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "5.0"
},
	"🧝‍♀️": {
	name: "woman elf",
	slug: "woman_elf",
	group: "People & Body",
	emoji_version: "5.0",
	unicode_version: "5.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "5.0"
},
	"🧞": {
	name: "genie",
	slug: "genie",
	group: "People & Body",
	emoji_version: "5.0",
	unicode_version: "5.0",
	skin_tone_support: false
},
	"🧞‍♂️": {
	name: "man genie",
	slug: "man_genie",
	group: "People & Body",
	emoji_version: "5.0",
	unicode_version: "5.0",
	skin_tone_support: false
},
	"🧞‍♀️": {
	name: "woman genie",
	slug: "woman_genie",
	group: "People & Body",
	emoji_version: "5.0",
	unicode_version: "5.0",
	skin_tone_support: false
},
	"🧟": {
	name: "zombie",
	slug: "zombie",
	group: "People & Body",
	emoji_version: "5.0",
	unicode_version: "5.0",
	skin_tone_support: false
},
	"🧟‍♂️": {
	name: "man zombie",
	slug: "man_zombie",
	group: "People & Body",
	emoji_version: "5.0",
	unicode_version: "5.0",
	skin_tone_support: false
},
	"🧟‍♀️": {
	name: "woman zombie",
	slug: "woman_zombie",
	group: "People & Body",
	emoji_version: "5.0",
	unicode_version: "5.0",
	skin_tone_support: false
},
	"🧌": {
	name: "troll",
	slug: "troll",
	group: "People & Body",
	emoji_version: "14.0",
	unicode_version: "14.0",
	skin_tone_support: false
},
	"💆": {
	name: "person getting massage",
	slug: "person_getting_massage",
	group: "People & Body",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "1.0"
},
	"💆‍♂️": {
	name: "man getting massage",
	slug: "man_getting_massage",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"💆‍♀️": {
	name: "woman getting massage",
	slug: "woman_getting_massage",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"💇": {
	name: "person getting haircut",
	slug: "person_getting_haircut",
	group: "People & Body",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "1.0"
},
	"💇‍♂️": {
	name: "man getting haircut",
	slug: "man_getting_haircut",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"💇‍♀️": {
	name: "woman getting haircut",
	slug: "woman_getting_haircut",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"🚶": {
	name: "person walking",
	slug: "person_walking",
	group: "People & Body",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "1.0"
},
	"🚶‍♂️": {
	name: "man walking",
	slug: "man_walking",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"🚶‍♀️": {
	name: "woman walking",
	slug: "woman_walking",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"🧍": {
	name: "person standing",
	slug: "person_standing",
	group: "People & Body",
	emoji_version: "12.0",
	unicode_version: "12.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "12.0"
},
	"🧍‍♂️": {
	name: "man standing",
	slug: "man_standing",
	group: "People & Body",
	emoji_version: "12.0",
	unicode_version: "12.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "12.0"
},
	"🧍‍♀️": {
	name: "woman standing",
	slug: "woman_standing",
	group: "People & Body",
	emoji_version: "12.0",
	unicode_version: "12.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "12.0"
},
	"🧎": {
	name: "person kneeling",
	slug: "person_kneeling",
	group: "People & Body",
	emoji_version: "12.0",
	unicode_version: "12.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "12.0"
},
	"🧎‍♂️": {
	name: "man kneeling",
	slug: "man_kneeling",
	group: "People & Body",
	emoji_version: "12.0",
	unicode_version: "12.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "12.0"
},
	"🧎‍♀️": {
	name: "woman kneeling",
	slug: "woman_kneeling",
	group: "People & Body",
	emoji_version: "12.0",
	unicode_version: "12.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "12.0"
},
	"🧑‍🦯": {
	name: "person with white cane",
	slug: "person_with_white_cane",
	group: "People & Body",
	emoji_version: "12.1",
	unicode_version: "12.1",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "12.1"
},
	"👨‍🦯": {
	name: "man with white cane",
	slug: "man_with_white_cane",
	group: "People & Body",
	emoji_version: "12.0",
	unicode_version: "12.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "12.0"
},
	"👩‍🦯": {
	name: "woman with white cane",
	slug: "woman_with_white_cane",
	group: "People & Body",
	emoji_version: "12.0",
	unicode_version: "12.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "12.0"
},
	"🧑‍🦼": {
	name: "person in motorized wheelchair",
	slug: "person_in_motorized_wheelchair",
	group: "People & Body",
	emoji_version: "12.1",
	unicode_version: "12.1",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "12.1"
},
	"👨‍🦼": {
	name: "man in motorized wheelchair",
	slug: "man_in_motorized_wheelchair",
	group: "People & Body",
	emoji_version: "12.0",
	unicode_version: "12.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "12.0"
},
	"👩‍🦼": {
	name: "woman in motorized wheelchair",
	slug: "woman_in_motorized_wheelchair",
	group: "People & Body",
	emoji_version: "12.0",
	unicode_version: "12.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "12.0"
},
	"🧑‍🦽": {
	name: "person in manual wheelchair",
	slug: "person_in_manual_wheelchair",
	group: "People & Body",
	emoji_version: "12.1",
	unicode_version: "12.1",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "12.1"
},
	"👨‍🦽": {
	name: "man in manual wheelchair",
	slug: "man_in_manual_wheelchair",
	group: "People & Body",
	emoji_version: "12.0",
	unicode_version: "12.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "12.0"
},
	"👩‍🦽": {
	name: "woman in manual wheelchair",
	slug: "woman_in_manual_wheelchair",
	group: "People & Body",
	emoji_version: "12.0",
	unicode_version: "12.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "12.0"
},
	"🏃": {
	name: "person running",
	slug: "person_running",
	group: "People & Body",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "1.0"
},
	"🏃‍♂️": {
	name: "man running",
	slug: "man_running",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"🏃‍♀️": {
	name: "woman running",
	slug: "woman_running",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"💃": {
	name: "woman dancing",
	slug: "woman_dancing",
	group: "People & Body",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "1.0"
},
	"🕺": {
	name: "man dancing",
	slug: "man_dancing",
	group: "People & Body",
	emoji_version: "3.0",
	unicode_version: "3.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "3.0"
},
	"🕴️": {
	name: "person in suit levitating",
	slug: "person_in_suit_levitating",
	group: "People & Body",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"👯": {
	name: "people with bunny ears",
	slug: "people_with_bunny_ears",
	group: "People & Body",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"👯‍♂️": {
	name: "men with bunny ears",
	slug: "men_with_bunny_ears",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: false
},
	"👯‍♀️": {
	name: "women with bunny ears",
	slug: "women_with_bunny_ears",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: false
},
	"🧖": {
	name: "person in steamy room",
	slug: "person_in_steamy_room",
	group: "People & Body",
	emoji_version: "5.0",
	unicode_version: "5.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "5.0"
},
	"🧖‍♂️": {
	name: "man in steamy room",
	slug: "man_in_steamy_room",
	group: "People & Body",
	emoji_version: "5.0",
	unicode_version: "5.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "5.0"
},
	"🧖‍♀️": {
	name: "woman in steamy room",
	slug: "woman_in_steamy_room",
	group: "People & Body",
	emoji_version: "5.0",
	unicode_version: "5.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "5.0"
},
	"🧗": {
	name: "person climbing",
	slug: "person_climbing",
	group: "People & Body",
	emoji_version: "5.0",
	unicode_version: "5.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "5.0"
},
	"🧗‍♂️": {
	name: "man climbing",
	slug: "man_climbing",
	group: "People & Body",
	emoji_version: "5.0",
	unicode_version: "5.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "5.0"
},
	"🧗‍♀️": {
	name: "woman climbing",
	slug: "woman_climbing",
	group: "People & Body",
	emoji_version: "5.0",
	unicode_version: "5.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "5.0"
},
	"🤺": {
	name: "person fencing",
	slug: "person_fencing",
	group: "People & Body",
	emoji_version: "3.0",
	unicode_version: "3.0",
	skin_tone_support: false
},
	"🏇": {
	name: "horse racing",
	slug: "horse_racing",
	group: "People & Body",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "1.0"
},
	"⛷️": {
	name: "skier",
	slug: "skier",
	group: "People & Body",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🏂": {
	name: "snowboarder",
	slug: "snowboarder",
	group: "People & Body",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "1.0"
},
	"🏌️": {
	name: "person golfing",
	slug: "person_golfing",
	group: "People & Body",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"🏌️‍♂️": {
	name: "man golfing",
	slug: "man_golfing",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"🏌️‍♀️": {
	name: "woman golfing",
	slug: "woman_golfing",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"🏄": {
	name: "person surfing",
	slug: "person_surfing",
	group: "People & Body",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "1.0"
},
	"🏄‍♂️": {
	name: "man surfing",
	slug: "man_surfing",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"🏄‍♀️": {
	name: "woman surfing",
	slug: "woman_surfing",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"🚣": {
	name: "person rowing boat",
	slug: "person_rowing_boat",
	group: "People & Body",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "1.0"
},
	"🚣‍♂️": {
	name: "man rowing boat",
	slug: "man_rowing_boat",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"🚣‍♀️": {
	name: "woman rowing boat",
	slug: "woman_rowing_boat",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"🏊": {
	name: "person swimming",
	slug: "person_swimming",
	group: "People & Body",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "1.0"
},
	"🏊‍♂️": {
	name: "man swimming",
	slug: "man_swimming",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"🏊‍♀️": {
	name: "woman swimming",
	slug: "woman_swimming",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"⛹️": {
	name: "person bouncing ball",
	slug: "person_bouncing_ball",
	group: "People & Body",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "2.0"
},
	"⛹️‍♂️": {
	name: "man bouncing ball",
	slug: "man_bouncing_ball",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"⛹️‍♀️": {
	name: "woman bouncing ball",
	slug: "woman_bouncing_ball",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"🏋️": {
	name: "person lifting weights",
	slug: "person_lifting_weights",
	group: "People & Body",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "2.0"
},
	"🏋️‍♂️": {
	name: "man lifting weights",
	slug: "man_lifting_weights",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"🏋️‍♀️": {
	name: "woman lifting weights",
	slug: "woman_lifting_weights",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"🚴": {
	name: "person biking",
	slug: "person_biking",
	group: "People & Body",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "1.0"
},
	"🚴‍♂️": {
	name: "man biking",
	slug: "man_biking",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"🚴‍♀️": {
	name: "woman biking",
	slug: "woman_biking",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"🚵": {
	name: "person mountain biking",
	slug: "person_mountain_biking",
	group: "People & Body",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "1.0"
},
	"🚵‍♂️": {
	name: "man mountain biking",
	slug: "man_mountain_biking",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"🚵‍♀️": {
	name: "woman mountain biking",
	slug: "woman_mountain_biking",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"🤸": {
	name: "person cartwheeling",
	slug: "person_cartwheeling",
	group: "People & Body",
	emoji_version: "3.0",
	unicode_version: "3.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "3.0"
},
	"🤸‍♂️": {
	name: "man cartwheeling",
	slug: "man_cartwheeling",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"🤸‍♀️": {
	name: "woman cartwheeling",
	slug: "woman_cartwheeling",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"🤼": {
	name: "people wrestling",
	slug: "people_wrestling",
	group: "People & Body",
	emoji_version: "3.0",
	unicode_version: "3.0",
	skin_tone_support: false
},
	"🤼‍♂️": {
	name: "men wrestling",
	slug: "men_wrestling",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: false
},
	"🤼‍♀️": {
	name: "women wrestling",
	slug: "women_wrestling",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: false
},
	"🤽": {
	name: "person playing water polo",
	slug: "person_playing_water_polo",
	group: "People & Body",
	emoji_version: "3.0",
	unicode_version: "3.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "3.0"
},
	"🤽‍♂️": {
	name: "man playing water polo",
	slug: "man_playing_water_polo",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"🤽‍♀️": {
	name: "woman playing water polo",
	slug: "woman_playing_water_polo",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"🤾": {
	name: "person playing handball",
	slug: "person_playing_handball",
	group: "People & Body",
	emoji_version: "3.0",
	unicode_version: "3.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "3.0"
},
	"🤾‍♂️": {
	name: "man playing handball",
	slug: "man_playing_handball",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"🤾‍♀️": {
	name: "woman playing handball",
	slug: "woman_playing_handball",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"🤹": {
	name: "person juggling",
	slug: "person_juggling",
	group: "People & Body",
	emoji_version: "3.0",
	unicode_version: "3.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "3.0"
},
	"🤹‍♂️": {
	name: "man juggling",
	slug: "man_juggling",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"🤹‍♀️": {
	name: "woman juggling",
	slug: "woman_juggling",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"🧘": {
	name: "person in lotus position",
	slug: "person_in_lotus_position",
	group: "People & Body",
	emoji_version: "5.0",
	unicode_version: "5.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "5.0"
},
	"🧘‍♂️": {
	name: "man in lotus position",
	slug: "man_in_lotus_position",
	group: "People & Body",
	emoji_version: "5.0",
	unicode_version: "5.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "5.0"
},
	"🧘‍♀️": {
	name: "woman in lotus position",
	slug: "woman_in_lotus_position",
	group: "People & Body",
	emoji_version: "5.0",
	unicode_version: "5.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "5.0"
},
	"🛀": {
	name: "person taking bath",
	slug: "person_taking_bath",
	group: "People & Body",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "1.0"
},
	"🛌": {
	name: "person in bed",
	slug: "person_in_bed",
	group: "People & Body",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "4.0"
},
	"🧑‍🤝‍🧑": {
	name: "people holding hands",
	slug: "people_holding_hands",
	group: "People & Body",
	emoji_version: "12.0",
	unicode_version: "12.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "12.0"
},
	"👭": {
	name: "women holding hands",
	slug: "women_holding_hands",
	group: "People & Body",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "12.0"
},
	"👫": {
	name: "woman and man holding hands",
	slug: "woman_and_man_holding_hands",
	group: "People & Body",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "12.0"
},
	"👬": {
	name: "men holding hands",
	slug: "men_holding_hands",
	group: "People & Body",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "12.0"
},
	"💏": {
	name: "kiss",
	slug: "kiss",
	group: "People & Body",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "13.1"
},
	"👩‍❤️‍💋‍👨": {
	name: "kiss woman, man",
	slug: "kiss_woman_man",
	group: "People & Body",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "13.1"
},
	"👨‍❤️‍💋‍👨": {
	name: "kiss man, man",
	slug: "kiss_man_man",
	group: "People & Body",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "13.1"
},
	"👩‍❤️‍💋‍👩": {
	name: "kiss woman, woman",
	slug: "kiss_woman_woman",
	group: "People & Body",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "13.1"
},
	"💑": {
	name: "couple with heart",
	slug: "couple_with_heart",
	group: "People & Body",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "13.1"
},
	"👩‍❤️‍👨": {
	name: "couple with heart woman, man",
	slug: "couple_with_heart_woman_man",
	group: "People & Body",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "13.1"
},
	"👨‍❤️‍👨": {
	name: "couple with heart man, man",
	slug: "couple_with_heart_man_man",
	group: "People & Body",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "13.1"
},
	"👩‍❤️‍👩": {
	name: "couple with heart woman, woman",
	slug: "couple_with_heart_woman_woman",
	group: "People & Body",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: true,
	skin_tone_support_unicode_version: "13.1"
},
	"👪": {
	name: "family",
	slug: "family",
	group: "People & Body",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"👨‍👩‍👦": {
	name: "family man, woman, boy",
	slug: "family_man_woman_boy",
	group: "People & Body",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"👨‍👩‍👧": {
	name: "family man, woman, girl",
	slug: "family_man_woman_girl",
	group: "People & Body",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"👨‍👩‍👧‍👦": {
	name: "family man, woman, girl, boy",
	slug: "family_man_woman_girl_boy",
	group: "People & Body",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"👨‍👩‍👦‍👦": {
	name: "family man, woman, boy, boy",
	slug: "family_man_woman_boy_boy",
	group: "People & Body",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"👨‍👩‍👧‍👧": {
	name: "family man, woman, girl, girl",
	slug: "family_man_woman_girl_girl",
	group: "People & Body",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"👨‍👨‍👦": {
	name: "family man, man, boy",
	slug: "family_man_man_boy",
	group: "People & Body",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"👨‍👨‍👧": {
	name: "family man, man, girl",
	slug: "family_man_man_girl",
	group: "People & Body",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"👨‍👨‍👧‍👦": {
	name: "family man, man, girl, boy",
	slug: "family_man_man_girl_boy",
	group: "People & Body",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"👨‍👨‍👦‍👦": {
	name: "family man, man, boy, boy",
	slug: "family_man_man_boy_boy",
	group: "People & Body",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"👨‍👨‍👧‍👧": {
	name: "family man, man, girl, girl",
	slug: "family_man_man_girl_girl",
	group: "People & Body",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"👩‍👩‍👦": {
	name: "family woman, woman, boy",
	slug: "family_woman_woman_boy",
	group: "People & Body",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"👩‍👩‍👧": {
	name: "family woman, woman, girl",
	slug: "family_woman_woman_girl",
	group: "People & Body",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"👩‍👩‍👧‍👦": {
	name: "family woman, woman, girl, boy",
	slug: "family_woman_woman_girl_boy",
	group: "People & Body",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"👩‍👩‍👦‍👦": {
	name: "family woman, woman, boy, boy",
	slug: "family_woman_woman_boy_boy",
	group: "People & Body",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"👩‍👩‍👧‍👧": {
	name: "family woman, woman, girl, girl",
	slug: "family_woman_woman_girl_girl",
	group: "People & Body",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"👨‍👦": {
	name: "family man, boy",
	slug: "family_man_boy",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: false
},
	"👨‍👦‍👦": {
	name: "family man, boy, boy",
	slug: "family_man_boy_boy",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: false
},
	"👨‍👧": {
	name: "family man, girl",
	slug: "family_man_girl",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: false
},
	"👨‍👧‍👦": {
	name: "family man, girl, boy",
	slug: "family_man_girl_boy",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: false
},
	"👨‍👧‍👧": {
	name: "family man, girl, girl",
	slug: "family_man_girl_girl",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: false
},
	"👩‍👦": {
	name: "family woman, boy",
	slug: "family_woman_boy",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: false
},
	"👩‍👦‍👦": {
	name: "family woman, boy, boy",
	slug: "family_woman_boy_boy",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: false
},
	"👩‍👧": {
	name: "family woman, girl",
	slug: "family_woman_girl",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: false
},
	"👩‍👧‍👦": {
	name: "family woman, girl, boy",
	slug: "family_woman_girl_boy",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: false
},
	"👩‍👧‍👧": {
	name: "family woman, girl, girl",
	slug: "family_woman_girl_girl",
	group: "People & Body",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: false
},
	"🗣️": {
	name: "speaking head",
	slug: "speaking_head",
	group: "People & Body",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"👤": {
	name: "bust in silhouette",
	slug: "bust_in_silhouette",
	group: "People & Body",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"👥": {
	name: "busts in silhouette",
	slug: "busts_in_silhouette",
	group: "People & Body",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🫂": {
	name: "people hugging",
	slug: "people_hugging",
	group: "People & Body",
	emoji_version: "13.0",
	unicode_version: "13.0",
	skin_tone_support: false
},
	"👣": {
	name: "footprints",
	slug: "footprints",
	group: "People & Body",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🐵": {
	name: "monkey face",
	slug: "monkey_face",
	group: "Animals & Nature",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🐒": {
	name: "monkey",
	slug: "monkey",
	group: "Animals & Nature",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🦍": {
	name: "gorilla",
	slug: "gorilla",
	group: "Animals & Nature",
	emoji_version: "3.0",
	unicode_version: "3.0",
	skin_tone_support: false
},
	"🦧": {
	name: "orangutan",
	slug: "orangutan",
	group: "Animals & Nature",
	emoji_version: "12.0",
	unicode_version: "12.0",
	skin_tone_support: false
},
	"🐶": {
	name: "dog face",
	slug: "dog_face",
	group: "Animals & Nature",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🐕": {
	name: "dog",
	slug: "dog",
	group: "Animals & Nature",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🦮": {
	name: "guide dog",
	slug: "guide_dog",
	group: "Animals & Nature",
	emoji_version: "12.0",
	unicode_version: "12.0",
	skin_tone_support: false
},
	"🐕‍🦺": {
	name: "service dog",
	slug: "service_dog",
	group: "Animals & Nature",
	emoji_version: "12.0",
	unicode_version: "12.0",
	skin_tone_support: false
},
	"🐩": {
	name: "poodle",
	slug: "poodle",
	group: "Animals & Nature",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🐺": {
	name: "wolf",
	slug: "wolf",
	group: "Animals & Nature",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🦊": {
	name: "fox",
	slug: "fox",
	group: "Animals & Nature",
	emoji_version: "3.0",
	unicode_version: "3.0",
	skin_tone_support: false
},
	"🦝": {
	name: "raccoon",
	slug: "raccoon",
	group: "Animals & Nature",
	emoji_version: "11.0",
	unicode_version: "11.0",
	skin_tone_support: false
},
	"🐱": {
	name: "cat face",
	slug: "cat_face",
	group: "Animals & Nature",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🐈": {
	name: "cat",
	slug: "cat",
	group: "Animals & Nature",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🐈‍⬛": {
	name: "black cat",
	slug: "black_cat",
	group: "Animals & Nature",
	emoji_version: "13.0",
	unicode_version: "13.0",
	skin_tone_support: false
},
	"🦁": {
	name: "lion",
	slug: "lion",
	group: "Animals & Nature",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🐯": {
	name: "tiger face",
	slug: "tiger_face",
	group: "Animals & Nature",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🐅": {
	name: "tiger",
	slug: "tiger",
	group: "Animals & Nature",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🐆": {
	name: "leopard",
	slug: "leopard",
	group: "Animals & Nature",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🐴": {
	name: "horse face",
	slug: "horse_face",
	group: "Animals & Nature",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🫎": {
	name: "moose",
	slug: "moose",
	group: "Animals & Nature",
	emoji_version: "15.0",
	unicode_version: "15.0",
	skin_tone_support: false
},
	"🫏": {
	name: "donkey",
	slug: "donkey",
	group: "Animals & Nature",
	emoji_version: "15.0",
	unicode_version: "15.0",
	skin_tone_support: false
},
	"🐎": {
	name: "horse",
	slug: "horse",
	group: "Animals & Nature",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🦄": {
	name: "unicorn",
	slug: "unicorn",
	group: "Animals & Nature",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🦓": {
	name: "zebra",
	slug: "zebra",
	group: "Animals & Nature",
	emoji_version: "5.0",
	unicode_version: "5.0",
	skin_tone_support: false
},
	"🦌": {
	name: "deer",
	slug: "deer",
	group: "Animals & Nature",
	emoji_version: "3.0",
	unicode_version: "3.0",
	skin_tone_support: false
},
	"🦬": {
	name: "bison",
	slug: "bison",
	group: "Animals & Nature",
	emoji_version: "13.0",
	unicode_version: "13.0",
	skin_tone_support: false
},
	"🐮": {
	name: "cow face",
	slug: "cow_face",
	group: "Animals & Nature",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🐂": {
	name: "ox",
	slug: "ox",
	group: "Animals & Nature",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🐃": {
	name: "water buffalo",
	slug: "water_buffalo",
	group: "Animals & Nature",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🐄": {
	name: "cow",
	slug: "cow",
	group: "Animals & Nature",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🐷": {
	name: "pig face",
	slug: "pig_face",
	group: "Animals & Nature",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🐖": {
	name: "pig",
	slug: "pig",
	group: "Animals & Nature",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🐗": {
	name: "boar",
	slug: "boar",
	group: "Animals & Nature",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🐽": {
	name: "pig nose",
	slug: "pig_nose",
	group: "Animals & Nature",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🐏": {
	name: "ram",
	slug: "ram",
	group: "Animals & Nature",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🐑": {
	name: "ewe",
	slug: "ewe",
	group: "Animals & Nature",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🐐": {
	name: "goat",
	slug: "goat",
	group: "Animals & Nature",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🐪": {
	name: "camel",
	slug: "camel",
	group: "Animals & Nature",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🐫": {
	name: "two-hump camel",
	slug: "two_hump_camel",
	group: "Animals & Nature",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🦙": {
	name: "llama",
	slug: "llama",
	group: "Animals & Nature",
	emoji_version: "11.0",
	unicode_version: "11.0",
	skin_tone_support: false
},
	"🦒": {
	name: "giraffe",
	slug: "giraffe",
	group: "Animals & Nature",
	emoji_version: "5.0",
	unicode_version: "5.0",
	skin_tone_support: false
},
	"🐘": {
	name: "elephant",
	slug: "elephant",
	group: "Animals & Nature",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🦣": {
	name: "mammoth",
	slug: "mammoth",
	group: "Animals & Nature",
	emoji_version: "13.0",
	unicode_version: "13.0",
	skin_tone_support: false
},
	"🦏": {
	name: "rhinoceros",
	slug: "rhinoceros",
	group: "Animals & Nature",
	emoji_version: "3.0",
	unicode_version: "3.0",
	skin_tone_support: false
},
	"🦛": {
	name: "hippopotamus",
	slug: "hippopotamus",
	group: "Animals & Nature",
	emoji_version: "11.0",
	unicode_version: "11.0",
	skin_tone_support: false
},
	"🐭": {
	name: "mouse face",
	slug: "mouse_face",
	group: "Animals & Nature",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🐁": {
	name: "mouse",
	slug: "mouse",
	group: "Animals & Nature",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🐀": {
	name: "rat",
	slug: "rat",
	group: "Animals & Nature",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🐹": {
	name: "hamster",
	slug: "hamster",
	group: "Animals & Nature",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🐰": {
	name: "rabbit face",
	slug: "rabbit_face",
	group: "Animals & Nature",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🐇": {
	name: "rabbit",
	slug: "rabbit",
	group: "Animals & Nature",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🐿️": {
	name: "chipmunk",
	slug: "chipmunk",
	group: "Animals & Nature",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🦫": {
	name: "beaver",
	slug: "beaver",
	group: "Animals & Nature",
	emoji_version: "13.0",
	unicode_version: "13.0",
	skin_tone_support: false
},
	"🦔": {
	name: "hedgehog",
	slug: "hedgehog",
	group: "Animals & Nature",
	emoji_version: "5.0",
	unicode_version: "5.0",
	skin_tone_support: false
},
	"🦇": {
	name: "bat",
	slug: "bat",
	group: "Animals & Nature",
	emoji_version: "3.0",
	unicode_version: "3.0",
	skin_tone_support: false
},
	"🐻": {
	name: "bear",
	slug: "bear",
	group: "Animals & Nature",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🐻‍❄️": {
	name: "polar bear",
	slug: "polar_bear",
	group: "Animals & Nature",
	emoji_version: "13.0",
	unicode_version: "13.0",
	skin_tone_support: false
},
	"🐨": {
	name: "koala",
	slug: "koala",
	group: "Animals & Nature",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🐼": {
	name: "panda",
	slug: "panda",
	group: "Animals & Nature",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🦥": {
	name: "sloth",
	slug: "sloth",
	group: "Animals & Nature",
	emoji_version: "12.0",
	unicode_version: "12.0",
	skin_tone_support: false
},
	"🦦": {
	name: "otter",
	slug: "otter",
	group: "Animals & Nature",
	emoji_version: "12.0",
	unicode_version: "12.0",
	skin_tone_support: false
},
	"🦨": {
	name: "skunk",
	slug: "skunk",
	group: "Animals & Nature",
	emoji_version: "12.0",
	unicode_version: "12.0",
	skin_tone_support: false
},
	"🦘": {
	name: "kangaroo",
	slug: "kangaroo",
	group: "Animals & Nature",
	emoji_version: "11.0",
	unicode_version: "11.0",
	skin_tone_support: false
},
	"🦡": {
	name: "badger",
	slug: "badger",
	group: "Animals & Nature",
	emoji_version: "11.0",
	unicode_version: "11.0",
	skin_tone_support: false
},
	"🐾": {
	name: "paw prints",
	slug: "paw_prints",
	group: "Animals & Nature",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🦃": {
	name: "turkey",
	slug: "turkey",
	group: "Animals & Nature",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🐔": {
	name: "chicken",
	slug: "chicken",
	group: "Animals & Nature",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🐓": {
	name: "rooster",
	slug: "rooster",
	group: "Animals & Nature",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🐣": {
	name: "hatching chick",
	slug: "hatching_chick",
	group: "Animals & Nature",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🐤": {
	name: "baby chick",
	slug: "baby_chick",
	group: "Animals & Nature",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🐥": {
	name: "front-facing baby chick",
	slug: "front_facing_baby_chick",
	group: "Animals & Nature",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🐦": {
	name: "bird",
	slug: "bird",
	group: "Animals & Nature",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🐧": {
	name: "penguin",
	slug: "penguin",
	group: "Animals & Nature",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🕊️": {
	name: "dove",
	slug: "dove",
	group: "Animals & Nature",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🦅": {
	name: "eagle",
	slug: "eagle",
	group: "Animals & Nature",
	emoji_version: "3.0",
	unicode_version: "3.0",
	skin_tone_support: false
},
	"🦆": {
	name: "duck",
	slug: "duck",
	group: "Animals & Nature",
	emoji_version: "3.0",
	unicode_version: "3.0",
	skin_tone_support: false
},
	"🦢": {
	name: "swan",
	slug: "swan",
	group: "Animals & Nature",
	emoji_version: "11.0",
	unicode_version: "11.0",
	skin_tone_support: false
},
	"🦉": {
	name: "owl",
	slug: "owl",
	group: "Animals & Nature",
	emoji_version: "3.0",
	unicode_version: "3.0",
	skin_tone_support: false
},
	"🦤": {
	name: "dodo",
	slug: "dodo",
	group: "Animals & Nature",
	emoji_version: "13.0",
	unicode_version: "13.0",
	skin_tone_support: false
},
	"🪶": {
	name: "feather",
	slug: "feather",
	group: "Animals & Nature",
	emoji_version: "13.0",
	unicode_version: "13.0",
	skin_tone_support: false
},
	"🦩": {
	name: "flamingo",
	slug: "flamingo",
	group: "Animals & Nature",
	emoji_version: "12.0",
	unicode_version: "12.0",
	skin_tone_support: false
},
	"🦚": {
	name: "peacock",
	slug: "peacock",
	group: "Animals & Nature",
	emoji_version: "11.0",
	unicode_version: "11.0",
	skin_tone_support: false
},
	"🦜": {
	name: "parrot",
	slug: "parrot",
	group: "Animals & Nature",
	emoji_version: "11.0",
	unicode_version: "11.0",
	skin_tone_support: false
},
	"🪽": {
	name: "wing",
	slug: "wing",
	group: "Animals & Nature",
	emoji_version: "15.0",
	unicode_version: "15.0",
	skin_tone_support: false
},
	"🐦‍⬛": {
	name: "black bird",
	slug: "black_bird",
	group: "Animals & Nature",
	emoji_version: "15.0",
	unicode_version: "15.0",
	skin_tone_support: false
},
	"🪿": {
	name: "goose",
	slug: "goose",
	group: "Animals & Nature",
	emoji_version: "15.0",
	unicode_version: "15.0",
	skin_tone_support: false
},
	"🐸": {
	name: "frog",
	slug: "frog",
	group: "Animals & Nature",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🐊": {
	name: "crocodile",
	slug: "crocodile",
	group: "Animals & Nature",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🐢": {
	name: "turtle",
	slug: "turtle",
	group: "Animals & Nature",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🦎": {
	name: "lizard",
	slug: "lizard",
	group: "Animals & Nature",
	emoji_version: "3.0",
	unicode_version: "3.0",
	skin_tone_support: false
},
	"🐍": {
	name: "snake",
	slug: "snake",
	group: "Animals & Nature",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🐲": {
	name: "dragon face",
	slug: "dragon_face",
	group: "Animals & Nature",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🐉": {
	name: "dragon",
	slug: "dragon",
	group: "Animals & Nature",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🦕": {
	name: "sauropod",
	slug: "sauropod",
	group: "Animals & Nature",
	emoji_version: "5.0",
	unicode_version: "5.0",
	skin_tone_support: false
},
	"🦖": {
	name: "T-Rex",
	slug: "t_rex",
	group: "Animals & Nature",
	emoji_version: "5.0",
	unicode_version: "5.0",
	skin_tone_support: false
},
	"🐳": {
	name: "spouting whale",
	slug: "spouting_whale",
	group: "Animals & Nature",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🐋": {
	name: "whale",
	slug: "whale",
	group: "Animals & Nature",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🐬": {
	name: "dolphin",
	slug: "dolphin",
	group: "Animals & Nature",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🦭": {
	name: "seal",
	slug: "seal",
	group: "Animals & Nature",
	emoji_version: "13.0",
	unicode_version: "13.0",
	skin_tone_support: false
},
	"🐟": {
	name: "fish",
	slug: "fish",
	group: "Animals & Nature",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🐠": {
	name: "tropical fish",
	slug: "tropical_fish",
	group: "Animals & Nature",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🐡": {
	name: "blowfish",
	slug: "blowfish",
	group: "Animals & Nature",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🦈": {
	name: "shark",
	slug: "shark",
	group: "Animals & Nature",
	emoji_version: "3.0",
	unicode_version: "3.0",
	skin_tone_support: false
},
	"🐙": {
	name: "octopus",
	slug: "octopus",
	group: "Animals & Nature",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🐚": {
	name: "spiral shell",
	slug: "spiral_shell",
	group: "Animals & Nature",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🪸": {
	name: "coral",
	slug: "coral",
	group: "Animals & Nature",
	emoji_version: "14.0",
	unicode_version: "14.0",
	skin_tone_support: false
},
	"🪼": {
	name: "jellyfish",
	slug: "jellyfish",
	group: "Animals & Nature",
	emoji_version: "15.0",
	unicode_version: "15.0",
	skin_tone_support: false
},
	"🐌": {
	name: "snail",
	slug: "snail",
	group: "Animals & Nature",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🦋": {
	name: "butterfly",
	slug: "butterfly",
	group: "Animals & Nature",
	emoji_version: "3.0",
	unicode_version: "3.0",
	skin_tone_support: false
},
	"🐛": {
	name: "bug",
	slug: "bug",
	group: "Animals & Nature",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🐜": {
	name: "ant",
	slug: "ant",
	group: "Animals & Nature",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🐝": {
	name: "honeybee",
	slug: "honeybee",
	group: "Animals & Nature",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🪲": {
	name: "beetle",
	slug: "beetle",
	group: "Animals & Nature",
	emoji_version: "13.0",
	unicode_version: "13.0",
	skin_tone_support: false
},
	"🐞": {
	name: "lady beetle",
	slug: "lady_beetle",
	group: "Animals & Nature",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🦗": {
	name: "cricket",
	slug: "cricket",
	group: "Animals & Nature",
	emoji_version: "5.0",
	unicode_version: "5.0",
	skin_tone_support: false
},
	"🪳": {
	name: "cockroach",
	slug: "cockroach",
	group: "Animals & Nature",
	emoji_version: "13.0",
	unicode_version: "13.0",
	skin_tone_support: false
},
	"🕷️": {
	name: "spider",
	slug: "spider",
	group: "Animals & Nature",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🕸️": {
	name: "spider web",
	slug: "spider_web",
	group: "Animals & Nature",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🦂": {
	name: "scorpion",
	slug: "scorpion",
	group: "Animals & Nature",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🦟": {
	name: "mosquito",
	slug: "mosquito",
	group: "Animals & Nature",
	emoji_version: "11.0",
	unicode_version: "11.0",
	skin_tone_support: false
},
	"🪰": {
	name: "fly",
	slug: "fly",
	group: "Animals & Nature",
	emoji_version: "13.0",
	unicode_version: "13.0",
	skin_tone_support: false
},
	"🪱": {
	name: "worm",
	slug: "worm",
	group: "Animals & Nature",
	emoji_version: "13.0",
	unicode_version: "13.0",
	skin_tone_support: false
},
	"🦠": {
	name: "microbe",
	slug: "microbe",
	group: "Animals & Nature",
	emoji_version: "11.0",
	unicode_version: "11.0",
	skin_tone_support: false
},
	"💐": {
	name: "bouquet",
	slug: "bouquet",
	group: "Animals & Nature",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🌸": {
	name: "cherry blossom",
	slug: "cherry_blossom",
	group: "Animals & Nature",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"💮": {
	name: "white flower",
	slug: "white_flower",
	group: "Animals & Nature",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🪷": {
	name: "lotus",
	slug: "lotus",
	group: "Animals & Nature",
	emoji_version: "14.0",
	unicode_version: "14.0",
	skin_tone_support: false
},
	"🏵️": {
	name: "rosette",
	slug: "rosette",
	group: "Animals & Nature",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🌹": {
	name: "rose",
	slug: "rose",
	group: "Animals & Nature",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🥀": {
	name: "wilted flower",
	slug: "wilted_flower",
	group: "Animals & Nature",
	emoji_version: "3.0",
	unicode_version: "3.0",
	skin_tone_support: false
},
	"🌺": {
	name: "hibiscus",
	slug: "hibiscus",
	group: "Animals & Nature",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🌻": {
	name: "sunflower",
	slug: "sunflower",
	group: "Animals & Nature",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🌼": {
	name: "blossom",
	slug: "blossom",
	group: "Animals & Nature",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🌷": {
	name: "tulip",
	slug: "tulip",
	group: "Animals & Nature",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🪻": {
	name: "hyacinth",
	slug: "hyacinth",
	group: "Animals & Nature",
	emoji_version: "15.0",
	unicode_version: "15.0",
	skin_tone_support: false
},
	"🌱": {
	name: "seedling",
	slug: "seedling",
	group: "Animals & Nature",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🪴": {
	name: "potted plant",
	slug: "potted_plant",
	group: "Animals & Nature",
	emoji_version: "13.0",
	unicode_version: "13.0",
	skin_tone_support: false
},
	"🌲": {
	name: "evergreen tree",
	slug: "evergreen_tree",
	group: "Animals & Nature",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🌳": {
	name: "deciduous tree",
	slug: "deciduous_tree",
	group: "Animals & Nature",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🌴": {
	name: "palm tree",
	slug: "palm_tree",
	group: "Animals & Nature",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🌵": {
	name: "cactus",
	slug: "cactus",
	group: "Animals & Nature",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🌾": {
	name: "sheaf of rice",
	slug: "sheaf_of_rice",
	group: "Animals & Nature",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🌿": {
	name: "herb",
	slug: "herb",
	group: "Animals & Nature",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"☘️": {
	name: "shamrock",
	slug: "shamrock",
	group: "Animals & Nature",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🍀": {
	name: "four leaf clover",
	slug: "four_leaf_clover",
	group: "Animals & Nature",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🍁": {
	name: "maple leaf",
	slug: "maple_leaf",
	group: "Animals & Nature",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🍂": {
	name: "fallen leaf",
	slug: "fallen_leaf",
	group: "Animals & Nature",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🍃": {
	name: "leaf fluttering in wind",
	slug: "leaf_fluttering_in_wind",
	group: "Animals & Nature",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🪹": {
	name: "empty nest",
	slug: "empty_nest",
	group: "Animals & Nature",
	emoji_version: "14.0",
	unicode_version: "14.0",
	skin_tone_support: false
},
	"🪺": {
	name: "nest with eggs",
	slug: "nest_with_eggs",
	group: "Animals & Nature",
	emoji_version: "14.0",
	unicode_version: "14.0",
	skin_tone_support: false
},
	"🍄": {
	name: "mushroom",
	slug: "mushroom",
	group: "Animals & Nature",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🍇": {
	name: "grapes",
	slug: "grapes",
	group: "Food & Drink",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🍈": {
	name: "melon",
	slug: "melon",
	group: "Food & Drink",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🍉": {
	name: "watermelon",
	slug: "watermelon",
	group: "Food & Drink",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🍊": {
	name: "tangerine",
	slug: "tangerine",
	group: "Food & Drink",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🍋": {
	name: "lemon",
	slug: "lemon",
	group: "Food & Drink",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🍌": {
	name: "banana",
	slug: "banana",
	group: "Food & Drink",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🍍": {
	name: "pineapple",
	slug: "pineapple",
	group: "Food & Drink",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🥭": {
	name: "mango",
	slug: "mango",
	group: "Food & Drink",
	emoji_version: "11.0",
	unicode_version: "11.0",
	skin_tone_support: false
},
	"🍎": {
	name: "red apple",
	slug: "red_apple",
	group: "Food & Drink",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🍏": {
	name: "green apple",
	slug: "green_apple",
	group: "Food & Drink",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🍐": {
	name: "pear",
	slug: "pear",
	group: "Food & Drink",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🍑": {
	name: "peach",
	slug: "peach",
	group: "Food & Drink",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🍒": {
	name: "cherries",
	slug: "cherries",
	group: "Food & Drink",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🍓": {
	name: "strawberry",
	slug: "strawberry",
	group: "Food & Drink",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🫐": {
	name: "blueberries",
	slug: "blueberries",
	group: "Food & Drink",
	emoji_version: "13.0",
	unicode_version: "13.0",
	skin_tone_support: false
},
	"🥝": {
	name: "kiwi fruit",
	slug: "kiwi_fruit",
	group: "Food & Drink",
	emoji_version: "3.0",
	unicode_version: "3.0",
	skin_tone_support: false
},
	"🍅": {
	name: "tomato",
	slug: "tomato",
	group: "Food & Drink",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🫒": {
	name: "olive",
	slug: "olive",
	group: "Food & Drink",
	emoji_version: "13.0",
	unicode_version: "13.0",
	skin_tone_support: false
},
	"🥥": {
	name: "coconut",
	slug: "coconut",
	group: "Food & Drink",
	emoji_version: "5.0",
	unicode_version: "5.0",
	skin_tone_support: false
},
	"🥑": {
	name: "avocado",
	slug: "avocado",
	group: "Food & Drink",
	emoji_version: "3.0",
	unicode_version: "3.0",
	skin_tone_support: false
},
	"🍆": {
	name: "eggplant",
	slug: "eggplant",
	group: "Food & Drink",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🥔": {
	name: "potato",
	slug: "potato",
	group: "Food & Drink",
	emoji_version: "3.0",
	unicode_version: "3.0",
	skin_tone_support: false
},
	"🥕": {
	name: "carrot",
	slug: "carrot",
	group: "Food & Drink",
	emoji_version: "3.0",
	unicode_version: "3.0",
	skin_tone_support: false
},
	"🌽": {
	name: "ear of corn",
	slug: "ear_of_corn",
	group: "Food & Drink",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🌶️": {
	name: "hot pepper",
	slug: "hot_pepper",
	group: "Food & Drink",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🫑": {
	name: "bell pepper",
	slug: "bell_pepper",
	group: "Food & Drink",
	emoji_version: "13.0",
	unicode_version: "13.0",
	skin_tone_support: false
},
	"🥒": {
	name: "cucumber",
	slug: "cucumber",
	group: "Food & Drink",
	emoji_version: "3.0",
	unicode_version: "3.0",
	skin_tone_support: false
},
	"🥬": {
	name: "leafy green",
	slug: "leafy_green",
	group: "Food & Drink",
	emoji_version: "11.0",
	unicode_version: "11.0",
	skin_tone_support: false
},
	"🥦": {
	name: "broccoli",
	slug: "broccoli",
	group: "Food & Drink",
	emoji_version: "5.0",
	unicode_version: "5.0",
	skin_tone_support: false
},
	"🧄": {
	name: "garlic",
	slug: "garlic",
	group: "Food & Drink",
	emoji_version: "12.0",
	unicode_version: "12.0",
	skin_tone_support: false
},
	"🧅": {
	name: "onion",
	slug: "onion",
	group: "Food & Drink",
	emoji_version: "12.0",
	unicode_version: "12.0",
	skin_tone_support: false
},
	"🥜": {
	name: "peanuts",
	slug: "peanuts",
	group: "Food & Drink",
	emoji_version: "3.0",
	unicode_version: "3.0",
	skin_tone_support: false
},
	"🫘": {
	name: "beans",
	slug: "beans",
	group: "Food & Drink",
	emoji_version: "14.0",
	unicode_version: "14.0",
	skin_tone_support: false
},
	"🌰": {
	name: "chestnut",
	slug: "chestnut",
	group: "Food & Drink",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🫚": {
	name: "ginger root",
	slug: "ginger_root",
	group: "Food & Drink",
	emoji_version: "15.0",
	unicode_version: "15.0",
	skin_tone_support: false
},
	"🫛": {
	name: "pea pod",
	slug: "pea_pod",
	group: "Food & Drink",
	emoji_version: "15.0",
	unicode_version: "15.0",
	skin_tone_support: false
},
	"🍞": {
	name: "bread",
	slug: "bread",
	group: "Food & Drink",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🥐": {
	name: "croissant",
	slug: "croissant",
	group: "Food & Drink",
	emoji_version: "3.0",
	unicode_version: "3.0",
	skin_tone_support: false
},
	"🥖": {
	name: "baguette bread",
	slug: "baguette_bread",
	group: "Food & Drink",
	emoji_version: "3.0",
	unicode_version: "3.0",
	skin_tone_support: false
},
	"🫓": {
	name: "flatbread",
	slug: "flatbread",
	group: "Food & Drink",
	emoji_version: "13.0",
	unicode_version: "13.0",
	skin_tone_support: false
},
	"🥨": {
	name: "pretzel",
	slug: "pretzel",
	group: "Food & Drink",
	emoji_version: "5.0",
	unicode_version: "5.0",
	skin_tone_support: false
},
	"🥯": {
	name: "bagel",
	slug: "bagel",
	group: "Food & Drink",
	emoji_version: "11.0",
	unicode_version: "11.0",
	skin_tone_support: false
},
	"🥞": {
	name: "pancakes",
	slug: "pancakes",
	group: "Food & Drink",
	emoji_version: "3.0",
	unicode_version: "3.0",
	skin_tone_support: false
},
	"🧇": {
	name: "waffle",
	slug: "waffle",
	group: "Food & Drink",
	emoji_version: "12.0",
	unicode_version: "12.0",
	skin_tone_support: false
},
	"🧀": {
	name: "cheese wedge",
	slug: "cheese_wedge",
	group: "Food & Drink",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🍖": {
	name: "meat on bone",
	slug: "meat_on_bone",
	group: "Food & Drink",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🍗": {
	name: "poultry leg",
	slug: "poultry_leg",
	group: "Food & Drink",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🥩": {
	name: "cut of meat",
	slug: "cut_of_meat",
	group: "Food & Drink",
	emoji_version: "5.0",
	unicode_version: "5.0",
	skin_tone_support: false
},
	"🥓": {
	name: "bacon",
	slug: "bacon",
	group: "Food & Drink",
	emoji_version: "3.0",
	unicode_version: "3.0",
	skin_tone_support: false
},
	"🍔": {
	name: "hamburger",
	slug: "hamburger",
	group: "Food & Drink",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🍟": {
	name: "french fries",
	slug: "french_fries",
	group: "Food & Drink",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🍕": {
	name: "pizza",
	slug: "pizza",
	group: "Food & Drink",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🌭": {
	name: "hot dog",
	slug: "hot_dog",
	group: "Food & Drink",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🥪": {
	name: "sandwich",
	slug: "sandwich",
	group: "Food & Drink",
	emoji_version: "5.0",
	unicode_version: "5.0",
	skin_tone_support: false
},
	"🌮": {
	name: "taco",
	slug: "taco",
	group: "Food & Drink",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🌯": {
	name: "burrito",
	slug: "burrito",
	group: "Food & Drink",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🫔": {
	name: "tamale",
	slug: "tamale",
	group: "Food & Drink",
	emoji_version: "13.0",
	unicode_version: "13.0",
	skin_tone_support: false
},
	"🥙": {
	name: "stuffed flatbread",
	slug: "stuffed_flatbread",
	group: "Food & Drink",
	emoji_version: "3.0",
	unicode_version: "3.0",
	skin_tone_support: false
},
	"🧆": {
	name: "falafel",
	slug: "falafel",
	group: "Food & Drink",
	emoji_version: "12.0",
	unicode_version: "12.0",
	skin_tone_support: false
},
	"🥚": {
	name: "egg",
	slug: "egg",
	group: "Food & Drink",
	emoji_version: "3.0",
	unicode_version: "3.0",
	skin_tone_support: false
},
	"🍳": {
	name: "cooking",
	slug: "cooking",
	group: "Food & Drink",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🥘": {
	name: "shallow pan of food",
	slug: "shallow_pan_of_food",
	group: "Food & Drink",
	emoji_version: "3.0",
	unicode_version: "3.0",
	skin_tone_support: false
},
	"🍲": {
	name: "pot of food",
	slug: "pot_of_food",
	group: "Food & Drink",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🫕": {
	name: "fondue",
	slug: "fondue",
	group: "Food & Drink",
	emoji_version: "13.0",
	unicode_version: "13.0",
	skin_tone_support: false
},
	"🥣": {
	name: "bowl with spoon",
	slug: "bowl_with_spoon",
	group: "Food & Drink",
	emoji_version: "5.0",
	unicode_version: "5.0",
	skin_tone_support: false
},
	"🥗": {
	name: "green salad",
	slug: "green_salad",
	group: "Food & Drink",
	emoji_version: "3.0",
	unicode_version: "3.0",
	skin_tone_support: false
},
	"🍿": {
	name: "popcorn",
	slug: "popcorn",
	group: "Food & Drink",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🧈": {
	name: "butter",
	slug: "butter",
	group: "Food & Drink",
	emoji_version: "12.0",
	unicode_version: "12.0",
	skin_tone_support: false
},
	"🧂": {
	name: "salt",
	slug: "salt",
	group: "Food & Drink",
	emoji_version: "11.0",
	unicode_version: "11.0",
	skin_tone_support: false
},
	"🥫": {
	name: "canned food",
	slug: "canned_food",
	group: "Food & Drink",
	emoji_version: "5.0",
	unicode_version: "5.0",
	skin_tone_support: false
},
	"🍱": {
	name: "bento box",
	slug: "bento_box",
	group: "Food & Drink",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🍘": {
	name: "rice cracker",
	slug: "rice_cracker",
	group: "Food & Drink",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🍙": {
	name: "rice ball",
	slug: "rice_ball",
	group: "Food & Drink",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🍚": {
	name: "cooked rice",
	slug: "cooked_rice",
	group: "Food & Drink",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🍛": {
	name: "curry rice",
	slug: "curry_rice",
	group: "Food & Drink",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🍜": {
	name: "steaming bowl",
	slug: "steaming_bowl",
	group: "Food & Drink",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🍝": {
	name: "spaghetti",
	slug: "spaghetti",
	group: "Food & Drink",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🍠": {
	name: "roasted sweet potato",
	slug: "roasted_sweet_potato",
	group: "Food & Drink",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🍢": {
	name: "oden",
	slug: "oden",
	group: "Food & Drink",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🍣": {
	name: "sushi",
	slug: "sushi",
	group: "Food & Drink",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🍤": {
	name: "fried shrimp",
	slug: "fried_shrimp",
	group: "Food & Drink",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🍥": {
	name: "fish cake with swirl",
	slug: "fish_cake_with_swirl",
	group: "Food & Drink",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🥮": {
	name: "moon cake",
	slug: "moon_cake",
	group: "Food & Drink",
	emoji_version: "11.0",
	unicode_version: "11.0",
	skin_tone_support: false
},
	"🍡": {
	name: "dango",
	slug: "dango",
	group: "Food & Drink",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🥟": {
	name: "dumpling",
	slug: "dumpling",
	group: "Food & Drink",
	emoji_version: "5.0",
	unicode_version: "5.0",
	skin_tone_support: false
},
	"🥠": {
	name: "fortune cookie",
	slug: "fortune_cookie",
	group: "Food & Drink",
	emoji_version: "5.0",
	unicode_version: "5.0",
	skin_tone_support: false
},
	"🥡": {
	name: "takeout box",
	slug: "takeout_box",
	group: "Food & Drink",
	emoji_version: "5.0",
	unicode_version: "5.0",
	skin_tone_support: false
},
	"🦀": {
	name: "crab",
	slug: "crab",
	group: "Food & Drink",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🦞": {
	name: "lobster",
	slug: "lobster",
	group: "Food & Drink",
	emoji_version: "11.0",
	unicode_version: "11.0",
	skin_tone_support: false
},
	"🦐": {
	name: "shrimp",
	slug: "shrimp",
	group: "Food & Drink",
	emoji_version: "3.0",
	unicode_version: "3.0",
	skin_tone_support: false
},
	"🦑": {
	name: "squid",
	slug: "squid",
	group: "Food & Drink",
	emoji_version: "3.0",
	unicode_version: "3.0",
	skin_tone_support: false
},
	"🦪": {
	name: "oyster",
	slug: "oyster",
	group: "Food & Drink",
	emoji_version: "12.0",
	unicode_version: "12.0",
	skin_tone_support: false
},
	"🍦": {
	name: "soft ice cream",
	slug: "soft_ice_cream",
	group: "Food & Drink",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🍧": {
	name: "shaved ice",
	slug: "shaved_ice",
	group: "Food & Drink",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🍨": {
	name: "ice cream",
	slug: "ice_cream",
	group: "Food & Drink",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🍩": {
	name: "doughnut",
	slug: "doughnut",
	group: "Food & Drink",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🍪": {
	name: "cookie",
	slug: "cookie",
	group: "Food & Drink",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🎂": {
	name: "birthday cake",
	slug: "birthday_cake",
	group: "Food & Drink",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🍰": {
	name: "shortcake",
	slug: "shortcake",
	group: "Food & Drink",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🧁": {
	name: "cupcake",
	slug: "cupcake",
	group: "Food & Drink",
	emoji_version: "11.0",
	unicode_version: "11.0",
	skin_tone_support: false
},
	"🥧": {
	name: "pie",
	slug: "pie",
	group: "Food & Drink",
	emoji_version: "5.0",
	unicode_version: "5.0",
	skin_tone_support: false
},
	"🍫": {
	name: "chocolate bar",
	slug: "chocolate_bar",
	group: "Food & Drink",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🍬": {
	name: "candy",
	slug: "candy",
	group: "Food & Drink",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🍭": {
	name: "lollipop",
	slug: "lollipop",
	group: "Food & Drink",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🍮": {
	name: "custard",
	slug: "custard",
	group: "Food & Drink",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🍯": {
	name: "honey pot",
	slug: "honey_pot",
	group: "Food & Drink",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🍼": {
	name: "baby bottle",
	slug: "baby_bottle",
	group: "Food & Drink",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🥛": {
	name: "glass of milk",
	slug: "glass_of_milk",
	group: "Food & Drink",
	emoji_version: "3.0",
	unicode_version: "3.0",
	skin_tone_support: false
},
	"☕": {
	name: "hot beverage",
	slug: "hot_beverage",
	group: "Food & Drink",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🫖": {
	name: "teapot",
	slug: "teapot",
	group: "Food & Drink",
	emoji_version: "13.0",
	unicode_version: "13.0",
	skin_tone_support: false
},
	"🍵": {
	name: "teacup without handle",
	slug: "teacup_without_handle",
	group: "Food & Drink",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🍶": {
	name: "sake",
	slug: "sake",
	group: "Food & Drink",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🍾": {
	name: "bottle with popping cork",
	slug: "bottle_with_popping_cork",
	group: "Food & Drink",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🍷": {
	name: "wine glass",
	slug: "wine_glass",
	group: "Food & Drink",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🍸": {
	name: "cocktail glass",
	slug: "cocktail_glass",
	group: "Food & Drink",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🍹": {
	name: "tropical drink",
	slug: "tropical_drink",
	group: "Food & Drink",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🍺": {
	name: "beer mug",
	slug: "beer_mug",
	group: "Food & Drink",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🍻": {
	name: "clinking beer mugs",
	slug: "clinking_beer_mugs",
	group: "Food & Drink",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🥂": {
	name: "clinking glasses",
	slug: "clinking_glasses",
	group: "Food & Drink",
	emoji_version: "3.0",
	unicode_version: "3.0",
	skin_tone_support: false
},
	"🥃": {
	name: "tumbler glass",
	slug: "tumbler_glass",
	group: "Food & Drink",
	emoji_version: "3.0",
	unicode_version: "3.0",
	skin_tone_support: false
},
	"🫗": {
	name: "pouring liquid",
	slug: "pouring_liquid",
	group: "Food & Drink",
	emoji_version: "14.0",
	unicode_version: "14.0",
	skin_tone_support: false
},
	"🥤": {
	name: "cup with straw",
	slug: "cup_with_straw",
	group: "Food & Drink",
	emoji_version: "5.0",
	unicode_version: "5.0",
	skin_tone_support: false
},
	"🧋": {
	name: "bubble tea",
	slug: "bubble_tea",
	group: "Food & Drink",
	emoji_version: "13.0",
	unicode_version: "13.0",
	skin_tone_support: false
},
	"🧃": {
	name: "beverage box",
	slug: "beverage_box",
	group: "Food & Drink",
	emoji_version: "12.0",
	unicode_version: "12.0",
	skin_tone_support: false
},
	"🧉": {
	name: "mate",
	slug: "mate",
	group: "Food & Drink",
	emoji_version: "12.0",
	unicode_version: "12.0",
	skin_tone_support: false
},
	"🧊": {
	name: "ice",
	slug: "ice",
	group: "Food & Drink",
	emoji_version: "12.0",
	unicode_version: "12.0",
	skin_tone_support: false
},
	"🥢": {
	name: "chopsticks",
	slug: "chopsticks",
	group: "Food & Drink",
	emoji_version: "5.0",
	unicode_version: "5.0",
	skin_tone_support: false
},
	"🍽️": {
	name: "fork and knife with plate",
	slug: "fork_and_knife_with_plate",
	group: "Food & Drink",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🍴": {
	name: "fork and knife",
	slug: "fork_and_knife",
	group: "Food & Drink",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🥄": {
	name: "spoon",
	slug: "spoon",
	group: "Food & Drink",
	emoji_version: "3.0",
	unicode_version: "3.0",
	skin_tone_support: false
},
	"🔪": {
	name: "kitchen knife",
	slug: "kitchen_knife",
	group: "Food & Drink",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🫙": {
	name: "jar",
	slug: "jar",
	group: "Food & Drink",
	emoji_version: "14.0",
	unicode_version: "14.0",
	skin_tone_support: false
},
	"🏺": {
	name: "amphora",
	slug: "amphora",
	group: "Food & Drink",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🌍": {
	name: "globe showing Europe-Africa",
	slug: "globe_showing_europe_africa",
	group: "Travel & Places",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🌎": {
	name: "globe showing Americas",
	slug: "globe_showing_americas",
	group: "Travel & Places",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🌏": {
	name: "globe showing Asia-Australia",
	slug: "globe_showing_asia_australia",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🌐": {
	name: "globe with meridians",
	slug: "globe_with_meridians",
	group: "Travel & Places",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🗺️": {
	name: "world map",
	slug: "world_map",
	group: "Travel & Places",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🗾": {
	name: "map of Japan",
	slug: "map_of_japan",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🧭": {
	name: "compass",
	slug: "compass",
	group: "Travel & Places",
	emoji_version: "11.0",
	unicode_version: "11.0",
	skin_tone_support: false
},
	"🏔️": {
	name: "snow-capped mountain",
	slug: "snow_capped_mountain",
	group: "Travel & Places",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"⛰️": {
	name: "mountain",
	slug: "mountain",
	group: "Travel & Places",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🌋": {
	name: "volcano",
	slug: "volcano",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🗻": {
	name: "mount fuji",
	slug: "mount_fuji",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🏕️": {
	name: "camping",
	slug: "camping",
	group: "Travel & Places",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🏖️": {
	name: "beach with umbrella",
	slug: "beach_with_umbrella",
	group: "Travel & Places",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🏜️": {
	name: "desert",
	slug: "desert",
	group: "Travel & Places",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🏝️": {
	name: "desert island",
	slug: "desert_island",
	group: "Travel & Places",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🏞️": {
	name: "national park",
	slug: "national_park",
	group: "Travel & Places",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🏟️": {
	name: "stadium",
	slug: "stadium",
	group: "Travel & Places",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🏛️": {
	name: "classical building",
	slug: "classical_building",
	group: "Travel & Places",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🏗️": {
	name: "building construction",
	slug: "building_construction",
	group: "Travel & Places",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🧱": {
	name: "brick",
	slug: "brick",
	group: "Travel & Places",
	emoji_version: "11.0",
	unicode_version: "11.0",
	skin_tone_support: false
},
	"🪨": {
	name: "rock",
	slug: "rock",
	group: "Travel & Places",
	emoji_version: "13.0",
	unicode_version: "13.0",
	skin_tone_support: false
},
	"🪵": {
	name: "wood",
	slug: "wood",
	group: "Travel & Places",
	emoji_version: "13.0",
	unicode_version: "13.0",
	skin_tone_support: false
},
	"🛖": {
	name: "hut",
	slug: "hut",
	group: "Travel & Places",
	emoji_version: "13.0",
	unicode_version: "13.0",
	skin_tone_support: false
},
	"🏘️": {
	name: "houses",
	slug: "houses",
	group: "Travel & Places",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🏚️": {
	name: "derelict house",
	slug: "derelict_house",
	group: "Travel & Places",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🏠": {
	name: "house",
	slug: "house",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🏡": {
	name: "house with garden",
	slug: "house_with_garden",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🏢": {
	name: "office building",
	slug: "office_building",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🏣": {
	name: "Japanese post office",
	slug: "japanese_post_office",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🏤": {
	name: "post office",
	slug: "post_office",
	group: "Travel & Places",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🏥": {
	name: "hospital",
	slug: "hospital",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🏦": {
	name: "bank",
	slug: "bank",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🏨": {
	name: "hotel",
	slug: "hotel",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🏩": {
	name: "love hotel",
	slug: "love_hotel",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🏪": {
	name: "convenience store",
	slug: "convenience_store",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🏫": {
	name: "school",
	slug: "school",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🏬": {
	name: "department store",
	slug: "department_store",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🏭": {
	name: "factory",
	slug: "factory",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🏯": {
	name: "Japanese castle",
	slug: "japanese_castle",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🏰": {
	name: "castle",
	slug: "castle",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"💒": {
	name: "wedding",
	slug: "wedding",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🗼": {
	name: "Tokyo tower",
	slug: "tokyo_tower",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🗽": {
	name: "Statue of Liberty",
	slug: "statue_of_liberty",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"⛪": {
	name: "church",
	slug: "church",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🕌": {
	name: "mosque",
	slug: "mosque",
	group: "Travel & Places",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🛕": {
	name: "hindu temple",
	slug: "hindu_temple",
	group: "Travel & Places",
	emoji_version: "12.0",
	unicode_version: "12.0",
	skin_tone_support: false
},
	"🕍": {
	name: "synagogue",
	slug: "synagogue",
	group: "Travel & Places",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"⛩️": {
	name: "shinto shrine",
	slug: "shinto_shrine",
	group: "Travel & Places",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🕋": {
	name: "kaaba",
	slug: "kaaba",
	group: "Travel & Places",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"⛲": {
	name: "fountain",
	slug: "fountain",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"⛺": {
	name: "tent",
	slug: "tent",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🌁": {
	name: "foggy",
	slug: "foggy",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🌃": {
	name: "night with stars",
	slug: "night_with_stars",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🏙️": {
	name: "cityscape",
	slug: "cityscape",
	group: "Travel & Places",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🌄": {
	name: "sunrise over mountains",
	slug: "sunrise_over_mountains",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🌅": {
	name: "sunrise",
	slug: "sunrise",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🌆": {
	name: "cityscape at dusk",
	slug: "cityscape_at_dusk",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🌇": {
	name: "sunset",
	slug: "sunset",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🌉": {
	name: "bridge at night",
	slug: "bridge_at_night",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"♨️": {
	name: "hot springs",
	slug: "hot_springs",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🎠": {
	name: "carousel horse",
	slug: "carousel_horse",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🛝": {
	name: "playground slide",
	slug: "playground_slide",
	group: "Travel & Places",
	emoji_version: "14.0",
	unicode_version: "14.0",
	skin_tone_support: false
},
	"🎡": {
	name: "ferris wheel",
	slug: "ferris_wheel",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🎢": {
	name: "roller coaster",
	slug: "roller_coaster",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"💈": {
	name: "barber pole",
	slug: "barber_pole",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🎪": {
	name: "circus tent",
	slug: "circus_tent",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🚂": {
	name: "locomotive",
	slug: "locomotive",
	group: "Travel & Places",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🚃": {
	name: "railway car",
	slug: "railway_car",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🚄": {
	name: "high-speed train",
	slug: "high_speed_train",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🚅": {
	name: "bullet train",
	slug: "bullet_train",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🚆": {
	name: "train",
	slug: "train",
	group: "Travel & Places",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🚇": {
	name: "metro",
	slug: "metro",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🚈": {
	name: "light rail",
	slug: "light_rail",
	group: "Travel & Places",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🚉": {
	name: "station",
	slug: "station",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🚊": {
	name: "tram",
	slug: "tram",
	group: "Travel & Places",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🚝": {
	name: "monorail",
	slug: "monorail",
	group: "Travel & Places",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🚞": {
	name: "mountain railway",
	slug: "mountain_railway",
	group: "Travel & Places",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🚋": {
	name: "tram car",
	slug: "tram_car",
	group: "Travel & Places",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🚌": {
	name: "bus",
	slug: "bus",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🚍": {
	name: "oncoming bus",
	slug: "oncoming_bus",
	group: "Travel & Places",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🚎": {
	name: "trolleybus",
	slug: "trolleybus",
	group: "Travel & Places",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🚐": {
	name: "minibus",
	slug: "minibus",
	group: "Travel & Places",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🚑": {
	name: "ambulance",
	slug: "ambulance",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🚒": {
	name: "fire engine",
	slug: "fire_engine",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🚓": {
	name: "police car",
	slug: "police_car",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🚔": {
	name: "oncoming police car",
	slug: "oncoming_police_car",
	group: "Travel & Places",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🚕": {
	name: "taxi",
	slug: "taxi",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🚖": {
	name: "oncoming taxi",
	slug: "oncoming_taxi",
	group: "Travel & Places",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🚗": {
	name: "automobile",
	slug: "automobile",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🚘": {
	name: "oncoming automobile",
	slug: "oncoming_automobile",
	group: "Travel & Places",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🚙": {
	name: "sport utility vehicle",
	slug: "sport_utility_vehicle",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🛻": {
	name: "pickup truck",
	slug: "pickup_truck",
	group: "Travel & Places",
	emoji_version: "13.0",
	unicode_version: "13.0",
	skin_tone_support: false
},
	"🚚": {
	name: "delivery truck",
	slug: "delivery_truck",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🚛": {
	name: "articulated lorry",
	slug: "articulated_lorry",
	group: "Travel & Places",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🚜": {
	name: "tractor",
	slug: "tractor",
	group: "Travel & Places",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🏎️": {
	name: "racing car",
	slug: "racing_car",
	group: "Travel & Places",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🏍️": {
	name: "motorcycle",
	slug: "motorcycle",
	group: "Travel & Places",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🛵": {
	name: "motor scooter",
	slug: "motor_scooter",
	group: "Travel & Places",
	emoji_version: "3.0",
	unicode_version: "3.0",
	skin_tone_support: false
},
	"🦽": {
	name: "manual wheelchair",
	slug: "manual_wheelchair",
	group: "Travel & Places",
	emoji_version: "12.0",
	unicode_version: "12.0",
	skin_tone_support: false
},
	"🦼": {
	name: "motorized wheelchair",
	slug: "motorized_wheelchair",
	group: "Travel & Places",
	emoji_version: "12.0",
	unicode_version: "12.0",
	skin_tone_support: false
},
	"🛺": {
	name: "auto rickshaw",
	slug: "auto_rickshaw",
	group: "Travel & Places",
	emoji_version: "12.0",
	unicode_version: "12.0",
	skin_tone_support: false
},
	"🚲": {
	name: "bicycle",
	slug: "bicycle",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🛴": {
	name: "kick scooter",
	slug: "kick_scooter",
	group: "Travel & Places",
	emoji_version: "3.0",
	unicode_version: "3.0",
	skin_tone_support: false
},
	"🛹": {
	name: "skateboard",
	slug: "skateboard",
	group: "Travel & Places",
	emoji_version: "11.0",
	unicode_version: "11.0",
	skin_tone_support: false
},
	"🛼": {
	name: "roller skate",
	slug: "roller_skate",
	group: "Travel & Places",
	emoji_version: "13.0",
	unicode_version: "13.0",
	skin_tone_support: false
},
	"🚏": {
	name: "bus stop",
	slug: "bus_stop",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🛣️": {
	name: "motorway",
	slug: "motorway",
	group: "Travel & Places",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🛤️": {
	name: "railway track",
	slug: "railway_track",
	group: "Travel & Places",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🛢️": {
	name: "oil drum",
	slug: "oil_drum",
	group: "Travel & Places",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"⛽": {
	name: "fuel pump",
	slug: "fuel_pump",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🛞": {
	name: "wheel",
	slug: "wheel",
	group: "Travel & Places",
	emoji_version: "14.0",
	unicode_version: "14.0",
	skin_tone_support: false
},
	"🚨": {
	name: "police car light",
	slug: "police_car_light",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🚥": {
	name: "horizontal traffic light",
	slug: "horizontal_traffic_light",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🚦": {
	name: "vertical traffic light",
	slug: "vertical_traffic_light",
	group: "Travel & Places",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🛑": {
	name: "stop sign",
	slug: "stop_sign",
	group: "Travel & Places",
	emoji_version: "3.0",
	unicode_version: "3.0",
	skin_tone_support: false
},
	"🚧": {
	name: "construction",
	slug: "construction",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"⚓": {
	name: "anchor",
	slug: "anchor",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🛟": {
	name: "ring buoy",
	slug: "ring_buoy",
	group: "Travel & Places",
	emoji_version: "14.0",
	unicode_version: "14.0",
	skin_tone_support: false
},
	"⛵": {
	name: "sailboat",
	slug: "sailboat",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🛶": {
	name: "canoe",
	slug: "canoe",
	group: "Travel & Places",
	emoji_version: "3.0",
	unicode_version: "3.0",
	skin_tone_support: false
},
	"🚤": {
	name: "speedboat",
	slug: "speedboat",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🛳️": {
	name: "passenger ship",
	slug: "passenger_ship",
	group: "Travel & Places",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"⛴️": {
	name: "ferry",
	slug: "ferry",
	group: "Travel & Places",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🛥️": {
	name: "motor boat",
	slug: "motor_boat",
	group: "Travel & Places",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🚢": {
	name: "ship",
	slug: "ship",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"✈️": {
	name: "airplane",
	slug: "airplane",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🛩️": {
	name: "small airplane",
	slug: "small_airplane",
	group: "Travel & Places",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🛫": {
	name: "airplane departure",
	slug: "airplane_departure",
	group: "Travel & Places",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🛬": {
	name: "airplane arrival",
	slug: "airplane_arrival",
	group: "Travel & Places",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🪂": {
	name: "parachute",
	slug: "parachute",
	group: "Travel & Places",
	emoji_version: "12.0",
	unicode_version: "12.0",
	skin_tone_support: false
},
	"💺": {
	name: "seat",
	slug: "seat",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🚁": {
	name: "helicopter",
	slug: "helicopter",
	group: "Travel & Places",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🚟": {
	name: "suspension railway",
	slug: "suspension_railway",
	group: "Travel & Places",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🚠": {
	name: "mountain cableway",
	slug: "mountain_cableway",
	group: "Travel & Places",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🚡": {
	name: "aerial tramway",
	slug: "aerial_tramway",
	group: "Travel & Places",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🛰️": {
	name: "satellite",
	slug: "satellite",
	group: "Travel & Places",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🚀": {
	name: "rocket",
	slug: "rocket",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🛸": {
	name: "flying saucer",
	slug: "flying_saucer",
	group: "Travel & Places",
	emoji_version: "5.0",
	unicode_version: "5.0",
	skin_tone_support: false
},
	"🛎️": {
	name: "bellhop bell",
	slug: "bellhop_bell",
	group: "Travel & Places",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🧳": {
	name: "luggage",
	slug: "luggage",
	group: "Travel & Places",
	emoji_version: "11.0",
	unicode_version: "11.0",
	skin_tone_support: false
},
	"⌛": {
	name: "hourglass done",
	slug: "hourglass_done",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"⏳": {
	name: "hourglass not done",
	slug: "hourglass_not_done",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"⌚": {
	name: "watch",
	slug: "watch",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"⏰": {
	name: "alarm clock",
	slug: "alarm_clock",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"⏱️": {
	name: "stopwatch",
	slug: "stopwatch",
	group: "Travel & Places",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"⏲️": {
	name: "timer clock",
	slug: "timer_clock",
	group: "Travel & Places",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🕰️": {
	name: "mantelpiece clock",
	slug: "mantelpiece_clock",
	group: "Travel & Places",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🕛": {
	name: "twelve o’clock",
	slug: "twelve_o_clock",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🕧": {
	name: "twelve-thirty",
	slug: "twelve_thirty",
	group: "Travel & Places",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🕐": {
	name: "one o’clock",
	slug: "one_o_clock",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🕜": {
	name: "one-thirty",
	slug: "one_thirty",
	group: "Travel & Places",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🕑": {
	name: "two o’clock",
	slug: "two_o_clock",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🕝": {
	name: "two-thirty",
	slug: "two_thirty",
	group: "Travel & Places",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🕒": {
	name: "three o’clock",
	slug: "three_o_clock",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🕞": {
	name: "three-thirty",
	slug: "three_thirty",
	group: "Travel & Places",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🕓": {
	name: "four o’clock",
	slug: "four_o_clock",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🕟": {
	name: "four-thirty",
	slug: "four_thirty",
	group: "Travel & Places",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🕔": {
	name: "five o’clock",
	slug: "five_o_clock",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🕠": {
	name: "five-thirty",
	slug: "five_thirty",
	group: "Travel & Places",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🕕": {
	name: "six o’clock",
	slug: "six_o_clock",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🕡": {
	name: "six-thirty",
	slug: "six_thirty",
	group: "Travel & Places",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🕖": {
	name: "seven o’clock",
	slug: "seven_o_clock",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🕢": {
	name: "seven-thirty",
	slug: "seven_thirty",
	group: "Travel & Places",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🕗": {
	name: "eight o’clock",
	slug: "eight_o_clock",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🕣": {
	name: "eight-thirty",
	slug: "eight_thirty",
	group: "Travel & Places",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🕘": {
	name: "nine o’clock",
	slug: "nine_o_clock",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🕤": {
	name: "nine-thirty",
	slug: "nine_thirty",
	group: "Travel & Places",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🕙": {
	name: "ten o’clock",
	slug: "ten_o_clock",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🕥": {
	name: "ten-thirty",
	slug: "ten_thirty",
	group: "Travel & Places",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🕚": {
	name: "eleven o’clock",
	slug: "eleven_o_clock",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🕦": {
	name: "eleven-thirty",
	slug: "eleven_thirty",
	group: "Travel & Places",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🌑": {
	name: "new moon",
	slug: "new_moon",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🌒": {
	name: "waxing crescent moon",
	slug: "waxing_crescent_moon",
	group: "Travel & Places",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🌓": {
	name: "first quarter moon",
	slug: "first_quarter_moon",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🌔": {
	name: "waxing gibbous moon",
	slug: "waxing_gibbous_moon",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🌕": {
	name: "full moon",
	slug: "full_moon",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🌖": {
	name: "waning gibbous moon",
	slug: "waning_gibbous_moon",
	group: "Travel & Places",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🌗": {
	name: "last quarter moon",
	slug: "last_quarter_moon",
	group: "Travel & Places",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🌘": {
	name: "waning crescent moon",
	slug: "waning_crescent_moon",
	group: "Travel & Places",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🌙": {
	name: "crescent moon",
	slug: "crescent_moon",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🌚": {
	name: "new moon face",
	slug: "new_moon_face",
	group: "Travel & Places",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🌛": {
	name: "first quarter moon face",
	slug: "first_quarter_moon_face",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🌜": {
	name: "last quarter moon face",
	slug: "last_quarter_moon_face",
	group: "Travel & Places",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🌡️": {
	name: "thermometer",
	slug: "thermometer",
	group: "Travel & Places",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"☀️": {
	name: "sun",
	slug: "sun",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🌝": {
	name: "full moon face",
	slug: "full_moon_face",
	group: "Travel & Places",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🌞": {
	name: "sun with face",
	slug: "sun_with_face",
	group: "Travel & Places",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🪐": {
	name: "ringed planet",
	slug: "ringed_planet",
	group: "Travel & Places",
	emoji_version: "12.0",
	unicode_version: "12.0",
	skin_tone_support: false
},
	"⭐": {
	name: "star",
	slug: "star",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🌟": {
	name: "glowing star",
	slug: "glowing_star",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🌠": {
	name: "shooting star",
	slug: "shooting_star",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🌌": {
	name: "milky way",
	slug: "milky_way",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"☁️": {
	name: "cloud",
	slug: "cloud",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"⛅": {
	name: "sun behind cloud",
	slug: "sun_behind_cloud",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"⛈️": {
	name: "cloud with lightning and rain",
	slug: "cloud_with_lightning_and_rain",
	group: "Travel & Places",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🌤️": {
	name: "sun behind small cloud",
	slug: "sun_behind_small_cloud",
	group: "Travel & Places",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🌥️": {
	name: "sun behind large cloud",
	slug: "sun_behind_large_cloud",
	group: "Travel & Places",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🌦️": {
	name: "sun behind rain cloud",
	slug: "sun_behind_rain_cloud",
	group: "Travel & Places",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🌧️": {
	name: "cloud with rain",
	slug: "cloud_with_rain",
	group: "Travel & Places",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🌨️": {
	name: "cloud with snow",
	slug: "cloud_with_snow",
	group: "Travel & Places",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🌩️": {
	name: "cloud with lightning",
	slug: "cloud_with_lightning",
	group: "Travel & Places",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🌪️": {
	name: "tornado",
	slug: "tornado",
	group: "Travel & Places",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🌫️": {
	name: "fog",
	slug: "fog",
	group: "Travel & Places",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🌬️": {
	name: "wind face",
	slug: "wind_face",
	group: "Travel & Places",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🌀": {
	name: "cyclone",
	slug: "cyclone",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🌈": {
	name: "rainbow",
	slug: "rainbow",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🌂": {
	name: "closed umbrella",
	slug: "closed_umbrella",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"☂️": {
	name: "umbrella",
	slug: "umbrella",
	group: "Travel & Places",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"☔": {
	name: "umbrella with rain drops",
	slug: "umbrella_with_rain_drops",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"⛱️": {
	name: "umbrella on ground",
	slug: "umbrella_on_ground",
	group: "Travel & Places",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"⚡": {
	name: "high voltage",
	slug: "high_voltage",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"❄️": {
	name: "snowflake",
	slug: "snowflake",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"☃️": {
	name: "snowman",
	slug: "snowman",
	group: "Travel & Places",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"⛄": {
	name: "snowman without snow",
	slug: "snowman_without_snow",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"☄️": {
	name: "comet",
	slug: "comet",
	group: "Travel & Places",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🔥": {
	name: "fire",
	slug: "fire",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"💧": {
	name: "droplet",
	slug: "droplet",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🌊": {
	name: "water wave",
	slug: "water_wave",
	group: "Travel & Places",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🎃": {
	name: "jack-o-lantern",
	slug: "jack_o_lantern",
	group: "Activities",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🎄": {
	name: "Christmas tree",
	slug: "christmas_tree",
	group: "Activities",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🎆": {
	name: "fireworks",
	slug: "fireworks",
	group: "Activities",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🎇": {
	name: "sparkler",
	slug: "sparkler",
	group: "Activities",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🧨": {
	name: "firecracker",
	slug: "firecracker",
	group: "Activities",
	emoji_version: "11.0",
	unicode_version: "11.0",
	skin_tone_support: false
},
	"✨": {
	name: "sparkles",
	slug: "sparkles",
	group: "Activities",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🎈": {
	name: "balloon",
	slug: "balloon",
	group: "Activities",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🎉": {
	name: "party popper",
	slug: "party_popper",
	group: "Activities",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🎊": {
	name: "confetti ball",
	slug: "confetti_ball",
	group: "Activities",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🎋": {
	name: "tanabata tree",
	slug: "tanabata_tree",
	group: "Activities",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🎍": {
	name: "pine decoration",
	slug: "pine_decoration",
	group: "Activities",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🎎": {
	name: "Japanese dolls",
	slug: "japanese_dolls",
	group: "Activities",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🎏": {
	name: "carp streamer",
	slug: "carp_streamer",
	group: "Activities",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🎐": {
	name: "wind chime",
	slug: "wind_chime",
	group: "Activities",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🎑": {
	name: "moon viewing ceremony",
	slug: "moon_viewing_ceremony",
	group: "Activities",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🧧": {
	name: "red envelope",
	slug: "red_envelope",
	group: "Activities",
	emoji_version: "11.0",
	unicode_version: "11.0",
	skin_tone_support: false
},
	"🎀": {
	name: "ribbon",
	slug: "ribbon",
	group: "Activities",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🎁": {
	name: "wrapped gift",
	slug: "wrapped_gift",
	group: "Activities",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🎗️": {
	name: "reminder ribbon",
	slug: "reminder_ribbon",
	group: "Activities",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🎟️": {
	name: "admission tickets",
	slug: "admission_tickets",
	group: "Activities",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🎫": {
	name: "ticket",
	slug: "ticket",
	group: "Activities",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🎖️": {
	name: "military medal",
	slug: "military_medal",
	group: "Activities",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🏆": {
	name: "trophy",
	slug: "trophy",
	group: "Activities",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🏅": {
	name: "sports medal",
	slug: "sports_medal",
	group: "Activities",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🥇": {
	name: "1st place medal",
	slug: "1st_place_medal",
	group: "Activities",
	emoji_version: "3.0",
	unicode_version: "3.0",
	skin_tone_support: false
},
	"🥈": {
	name: "2nd place medal",
	slug: "2nd_place_medal",
	group: "Activities",
	emoji_version: "3.0",
	unicode_version: "3.0",
	skin_tone_support: false
},
	"🥉": {
	name: "3rd place medal",
	slug: "3rd_place_medal",
	group: "Activities",
	emoji_version: "3.0",
	unicode_version: "3.0",
	skin_tone_support: false
},
	"⚽": {
	name: "soccer ball",
	slug: "soccer_ball",
	group: "Activities",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"⚾": {
	name: "baseball",
	slug: "baseball",
	group: "Activities",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🥎": {
	name: "softball",
	slug: "softball",
	group: "Activities",
	emoji_version: "11.0",
	unicode_version: "11.0",
	skin_tone_support: false
},
	"🏀": {
	name: "basketball",
	slug: "basketball",
	group: "Activities",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🏐": {
	name: "volleyball",
	slug: "volleyball",
	group: "Activities",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🏈": {
	name: "american football",
	slug: "american_football",
	group: "Activities",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🏉": {
	name: "rugby football",
	slug: "rugby_football",
	group: "Activities",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🎾": {
	name: "tennis",
	slug: "tennis",
	group: "Activities",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🥏": {
	name: "flying disc",
	slug: "flying_disc",
	group: "Activities",
	emoji_version: "11.0",
	unicode_version: "11.0",
	skin_tone_support: false
},
	"🎳": {
	name: "bowling",
	slug: "bowling",
	group: "Activities",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🏏": {
	name: "cricket game",
	slug: "cricket_game",
	group: "Activities",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🏑": {
	name: "field hockey",
	slug: "field_hockey",
	group: "Activities",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🏒": {
	name: "ice hockey",
	slug: "ice_hockey",
	group: "Activities",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🥍": {
	name: "lacrosse",
	slug: "lacrosse",
	group: "Activities",
	emoji_version: "11.0",
	unicode_version: "11.0",
	skin_tone_support: false
},
	"🏓": {
	name: "ping pong",
	slug: "ping_pong",
	group: "Activities",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🏸": {
	name: "badminton",
	slug: "badminton",
	group: "Activities",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🥊": {
	name: "boxing glove",
	slug: "boxing_glove",
	group: "Activities",
	emoji_version: "3.0",
	unicode_version: "3.0",
	skin_tone_support: false
},
	"🥋": {
	name: "martial arts uniform",
	slug: "martial_arts_uniform",
	group: "Activities",
	emoji_version: "3.0",
	unicode_version: "3.0",
	skin_tone_support: false
},
	"🥅": {
	name: "goal net",
	slug: "goal_net",
	group: "Activities",
	emoji_version: "3.0",
	unicode_version: "3.0",
	skin_tone_support: false
},
	"⛳": {
	name: "flag in hole",
	slug: "flag_in_hole",
	group: "Activities",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"⛸️": {
	name: "ice skate",
	slug: "ice_skate",
	group: "Activities",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🎣": {
	name: "fishing pole",
	slug: "fishing_pole",
	group: "Activities",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🤿": {
	name: "diving mask",
	slug: "diving_mask",
	group: "Activities",
	emoji_version: "12.0",
	unicode_version: "12.0",
	skin_tone_support: false
},
	"🎽": {
	name: "running shirt",
	slug: "running_shirt",
	group: "Activities",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🎿": {
	name: "skis",
	slug: "skis",
	group: "Activities",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🛷": {
	name: "sled",
	slug: "sled",
	group: "Activities",
	emoji_version: "5.0",
	unicode_version: "5.0",
	skin_tone_support: false
},
	"🥌": {
	name: "curling stone",
	slug: "curling_stone",
	group: "Activities",
	emoji_version: "5.0",
	unicode_version: "5.0",
	skin_tone_support: false
},
	"🎯": {
	name: "bullseye",
	slug: "bullseye",
	group: "Activities",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🪀": {
	name: "yo-yo",
	slug: "yo_yo",
	group: "Activities",
	emoji_version: "12.0",
	unicode_version: "12.0",
	skin_tone_support: false
},
	"🪁": {
	name: "kite",
	slug: "kite",
	group: "Activities",
	emoji_version: "12.0",
	unicode_version: "12.0",
	skin_tone_support: false
},
	"🔫": {
	name: "water pistol",
	slug: "water_pistol",
	group: "Activities",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🎱": {
	name: "pool 8 ball",
	slug: "pool_8_ball",
	group: "Activities",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🔮": {
	name: "crystal ball",
	slug: "crystal_ball",
	group: "Activities",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🪄": {
	name: "magic wand",
	slug: "magic_wand",
	group: "Activities",
	emoji_version: "13.0",
	unicode_version: "13.0",
	skin_tone_support: false
},
	"🎮": {
	name: "video game",
	slug: "video_game",
	group: "Activities",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🕹️": {
	name: "joystick",
	slug: "joystick",
	group: "Activities",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🎰": {
	name: "slot machine",
	slug: "slot_machine",
	group: "Activities",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🎲": {
	name: "game die",
	slug: "game_die",
	group: "Activities",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🧩": {
	name: "puzzle piece",
	slug: "puzzle_piece",
	group: "Activities",
	emoji_version: "11.0",
	unicode_version: "11.0",
	skin_tone_support: false
},
	"🧸": {
	name: "teddy bear",
	slug: "teddy_bear",
	group: "Activities",
	emoji_version: "11.0",
	unicode_version: "11.0",
	skin_tone_support: false
},
	"🪅": {
	name: "piñata",
	slug: "pinata",
	group: "Activities",
	emoji_version: "13.0",
	unicode_version: "13.0",
	skin_tone_support: false
},
	"🪩": {
	name: "mirror ball",
	slug: "mirror_ball",
	group: "Activities",
	emoji_version: "14.0",
	unicode_version: "14.0",
	skin_tone_support: false
},
	"🪆": {
	name: "nesting dolls",
	slug: "nesting_dolls",
	group: "Activities",
	emoji_version: "13.0",
	unicode_version: "13.0",
	skin_tone_support: false
},
	"♠️": {
	name: "spade suit",
	slug: "spade_suit",
	group: "Activities",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"♥️": {
	name: "heart suit",
	slug: "heart_suit",
	group: "Activities",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"♦️": {
	name: "diamond suit",
	slug: "diamond_suit",
	group: "Activities",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"♣️": {
	name: "club suit",
	slug: "club_suit",
	group: "Activities",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"♟️": {
	name: "chess pawn",
	slug: "chess_pawn",
	group: "Activities",
	emoji_version: "11.0",
	unicode_version: "11.0",
	skin_tone_support: false
},
	"🃏": {
	name: "joker",
	slug: "joker",
	group: "Activities",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🀄": {
	name: "mahjong red dragon",
	slug: "mahjong_red_dragon",
	group: "Activities",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🎴": {
	name: "flower playing cards",
	slug: "flower_playing_cards",
	group: "Activities",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🎭": {
	name: "performing arts",
	slug: "performing_arts",
	group: "Activities",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🖼️": {
	name: "framed picture",
	slug: "framed_picture",
	group: "Activities",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🎨": {
	name: "artist palette",
	slug: "artist_palette",
	group: "Activities",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🧵": {
	name: "thread",
	slug: "thread",
	group: "Activities",
	emoji_version: "11.0",
	unicode_version: "11.0",
	skin_tone_support: false
},
	"🪡": {
	name: "sewing needle",
	slug: "sewing_needle",
	group: "Activities",
	emoji_version: "13.0",
	unicode_version: "13.0",
	skin_tone_support: false
},
	"🧶": {
	name: "yarn",
	slug: "yarn",
	group: "Activities",
	emoji_version: "11.0",
	unicode_version: "11.0",
	skin_tone_support: false
},
	"🪢": {
	name: "knot",
	slug: "knot",
	group: "Activities",
	emoji_version: "13.0",
	unicode_version: "13.0",
	skin_tone_support: false
},
	"👓": {
	name: "glasses",
	slug: "glasses",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🕶️": {
	name: "sunglasses",
	slug: "sunglasses",
	group: "Objects",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🥽": {
	name: "goggles",
	slug: "goggles",
	group: "Objects",
	emoji_version: "11.0",
	unicode_version: "11.0",
	skin_tone_support: false
},
	"🥼": {
	name: "lab coat",
	slug: "lab_coat",
	group: "Objects",
	emoji_version: "11.0",
	unicode_version: "11.0",
	skin_tone_support: false
},
	"🦺": {
	name: "safety vest",
	slug: "safety_vest",
	group: "Objects",
	emoji_version: "12.0",
	unicode_version: "12.0",
	skin_tone_support: false
},
	"👔": {
	name: "necktie",
	slug: "necktie",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"👕": {
	name: "t-shirt",
	slug: "t_shirt",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"👖": {
	name: "jeans",
	slug: "jeans",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🧣": {
	name: "scarf",
	slug: "scarf",
	group: "Objects",
	emoji_version: "5.0",
	unicode_version: "5.0",
	skin_tone_support: false
},
	"🧤": {
	name: "gloves",
	slug: "gloves",
	group: "Objects",
	emoji_version: "5.0",
	unicode_version: "5.0",
	skin_tone_support: false
},
	"🧥": {
	name: "coat",
	slug: "coat",
	group: "Objects",
	emoji_version: "5.0",
	unicode_version: "5.0",
	skin_tone_support: false
},
	"🧦": {
	name: "socks",
	slug: "socks",
	group: "Objects",
	emoji_version: "5.0",
	unicode_version: "5.0",
	skin_tone_support: false
},
	"👗": {
	name: "dress",
	slug: "dress",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"👘": {
	name: "kimono",
	slug: "kimono",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🥻": {
	name: "sari",
	slug: "sari",
	group: "Objects",
	emoji_version: "12.0",
	unicode_version: "12.0",
	skin_tone_support: false
},
	"🩱": {
	name: "one-piece swimsuit",
	slug: "one_piece_swimsuit",
	group: "Objects",
	emoji_version: "12.0",
	unicode_version: "12.0",
	skin_tone_support: false
},
	"🩲": {
	name: "briefs",
	slug: "briefs",
	group: "Objects",
	emoji_version: "12.0",
	unicode_version: "12.0",
	skin_tone_support: false
},
	"🩳": {
	name: "shorts",
	slug: "shorts",
	group: "Objects",
	emoji_version: "12.0",
	unicode_version: "12.0",
	skin_tone_support: false
},
	"👙": {
	name: "bikini",
	slug: "bikini",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"👚": {
	name: "woman’s clothes",
	slug: "woman_s_clothes",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🪭": {
	name: "folding hand fan",
	slug: "folding_hand_fan",
	group: "Objects",
	emoji_version: "15.0",
	unicode_version: "15.0",
	skin_tone_support: false
},
	"👛": {
	name: "purse",
	slug: "purse",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"👜": {
	name: "handbag",
	slug: "handbag",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"👝": {
	name: "clutch bag",
	slug: "clutch_bag",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🛍️": {
	name: "shopping bags",
	slug: "shopping_bags",
	group: "Objects",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🎒": {
	name: "backpack",
	slug: "backpack",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🩴": {
	name: "thong sandal",
	slug: "thong_sandal",
	group: "Objects",
	emoji_version: "13.0",
	unicode_version: "13.0",
	skin_tone_support: false
},
	"👞": {
	name: "man’s shoe",
	slug: "man_s_shoe",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"👟": {
	name: "running shoe",
	slug: "running_shoe",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🥾": {
	name: "hiking boot",
	slug: "hiking_boot",
	group: "Objects",
	emoji_version: "11.0",
	unicode_version: "11.0",
	skin_tone_support: false
},
	"🥿": {
	name: "flat shoe",
	slug: "flat_shoe",
	group: "Objects",
	emoji_version: "11.0",
	unicode_version: "11.0",
	skin_tone_support: false
},
	"👠": {
	name: "high-heeled shoe",
	slug: "high_heeled_shoe",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"👡": {
	name: "woman’s sandal",
	slug: "woman_s_sandal",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🩰": {
	name: "ballet shoes",
	slug: "ballet_shoes",
	group: "Objects",
	emoji_version: "12.0",
	unicode_version: "12.0",
	skin_tone_support: false
},
	"👢": {
	name: "woman’s boot",
	slug: "woman_s_boot",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🪮": {
	name: "hair pick",
	slug: "hair_pick",
	group: "Objects",
	emoji_version: "15.0",
	unicode_version: "15.0",
	skin_tone_support: false
},
	"👑": {
	name: "crown",
	slug: "crown",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"👒": {
	name: "woman’s hat",
	slug: "woman_s_hat",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🎩": {
	name: "top hat",
	slug: "top_hat",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🎓": {
	name: "graduation cap",
	slug: "graduation_cap",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🧢": {
	name: "billed cap",
	slug: "billed_cap",
	group: "Objects",
	emoji_version: "5.0",
	unicode_version: "5.0",
	skin_tone_support: false
},
	"🪖": {
	name: "military helmet",
	slug: "military_helmet",
	group: "Objects",
	emoji_version: "13.0",
	unicode_version: "13.0",
	skin_tone_support: false
},
	"⛑️": {
	name: "rescue worker’s helmet",
	slug: "rescue_worker_s_helmet",
	group: "Objects",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"📿": {
	name: "prayer beads",
	slug: "prayer_beads",
	group: "Objects",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"💄": {
	name: "lipstick",
	slug: "lipstick",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"💍": {
	name: "ring",
	slug: "ring",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"💎": {
	name: "gem stone",
	slug: "gem_stone",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🔇": {
	name: "muted speaker",
	slug: "muted_speaker",
	group: "Objects",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🔈": {
	name: "speaker low volume",
	slug: "speaker_low_volume",
	group: "Objects",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🔉": {
	name: "speaker medium volume",
	slug: "speaker_medium_volume",
	group: "Objects",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🔊": {
	name: "speaker high volume",
	slug: "speaker_high_volume",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"📢": {
	name: "loudspeaker",
	slug: "loudspeaker",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"📣": {
	name: "megaphone",
	slug: "megaphone",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"📯": {
	name: "postal horn",
	slug: "postal_horn",
	group: "Objects",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🔔": {
	name: "bell",
	slug: "bell",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🔕": {
	name: "bell with slash",
	slug: "bell_with_slash",
	group: "Objects",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🎼": {
	name: "musical score",
	slug: "musical_score",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🎵": {
	name: "musical note",
	slug: "musical_note",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🎶": {
	name: "musical notes",
	slug: "musical_notes",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🎙️": {
	name: "studio microphone",
	slug: "studio_microphone",
	group: "Objects",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🎚️": {
	name: "level slider",
	slug: "level_slider",
	group: "Objects",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🎛️": {
	name: "control knobs",
	slug: "control_knobs",
	group: "Objects",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🎤": {
	name: "microphone",
	slug: "microphone",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🎧": {
	name: "headphone",
	slug: "headphone",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"📻": {
	name: "radio",
	slug: "radio",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🎷": {
	name: "saxophone",
	slug: "saxophone",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🪗": {
	name: "accordion",
	slug: "accordion",
	group: "Objects",
	emoji_version: "13.0",
	unicode_version: "13.0",
	skin_tone_support: false
},
	"🎸": {
	name: "guitar",
	slug: "guitar",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🎹": {
	name: "musical keyboard",
	slug: "musical_keyboard",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🎺": {
	name: "trumpet",
	slug: "trumpet",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🎻": {
	name: "violin",
	slug: "violin",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🪕": {
	name: "banjo",
	slug: "banjo",
	group: "Objects",
	emoji_version: "12.0",
	unicode_version: "12.0",
	skin_tone_support: false
},
	"🥁": {
	name: "drum",
	slug: "drum",
	group: "Objects",
	emoji_version: "3.0",
	unicode_version: "3.0",
	skin_tone_support: false
},
	"🪘": {
	name: "long drum",
	slug: "long_drum",
	group: "Objects",
	emoji_version: "13.0",
	unicode_version: "13.0",
	skin_tone_support: false
},
	"🪇": {
	name: "maracas",
	slug: "maracas",
	group: "Objects",
	emoji_version: "15.0",
	unicode_version: "15.0",
	skin_tone_support: false
},
	"🪈": {
	name: "flute",
	slug: "flute",
	group: "Objects",
	emoji_version: "15.0",
	unicode_version: "15.0",
	skin_tone_support: false
},
	"📱": {
	name: "mobile phone",
	slug: "mobile_phone",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"📲": {
	name: "mobile phone with arrow",
	slug: "mobile_phone_with_arrow",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"☎️": {
	name: "telephone",
	slug: "telephone",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"📞": {
	name: "telephone receiver",
	slug: "telephone_receiver",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"📟": {
	name: "pager",
	slug: "pager",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"📠": {
	name: "fax machine",
	slug: "fax_machine",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🔋": {
	name: "battery",
	slug: "battery",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🪫": {
	name: "low battery",
	slug: "low_battery",
	group: "Objects",
	emoji_version: "14.0",
	unicode_version: "14.0",
	skin_tone_support: false
},
	"🔌": {
	name: "electric plug",
	slug: "electric_plug",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"💻": {
	name: "laptop",
	slug: "laptop",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🖥️": {
	name: "desktop computer",
	slug: "desktop_computer",
	group: "Objects",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🖨️": {
	name: "printer",
	slug: "printer",
	group: "Objects",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"⌨️": {
	name: "keyboard",
	slug: "keyboard",
	group: "Objects",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🖱️": {
	name: "computer mouse",
	slug: "computer_mouse",
	group: "Objects",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🖲️": {
	name: "trackball",
	slug: "trackball",
	group: "Objects",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"💽": {
	name: "computer disk",
	slug: "computer_disk",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"💾": {
	name: "floppy disk",
	slug: "floppy_disk",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"💿": {
	name: "optical disk",
	slug: "optical_disk",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"📀": {
	name: "dvd",
	slug: "dvd",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🧮": {
	name: "abacus",
	slug: "abacus",
	group: "Objects",
	emoji_version: "11.0",
	unicode_version: "11.0",
	skin_tone_support: false
},
	"🎥": {
	name: "movie camera",
	slug: "movie_camera",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🎞️": {
	name: "film frames",
	slug: "film_frames",
	group: "Objects",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"📽️": {
	name: "film projector",
	slug: "film_projector",
	group: "Objects",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🎬": {
	name: "clapper board",
	slug: "clapper_board",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"📺": {
	name: "television",
	slug: "television",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"📷": {
	name: "camera",
	slug: "camera",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"📸": {
	name: "camera with flash",
	slug: "camera_with_flash",
	group: "Objects",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"📹": {
	name: "video camera",
	slug: "video_camera",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"📼": {
	name: "videocassette",
	slug: "videocassette",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🔍": {
	name: "magnifying glass tilted left",
	slug: "magnifying_glass_tilted_left",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🔎": {
	name: "magnifying glass tilted right",
	slug: "magnifying_glass_tilted_right",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🕯️": {
	name: "candle",
	slug: "candle",
	group: "Objects",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"💡": {
	name: "light bulb",
	slug: "light_bulb",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🔦": {
	name: "flashlight",
	slug: "flashlight",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🏮": {
	name: "red paper lantern",
	slug: "red_paper_lantern",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🪔": {
	name: "diya lamp",
	slug: "diya_lamp",
	group: "Objects",
	emoji_version: "12.0",
	unicode_version: "12.0",
	skin_tone_support: false
},
	"📔": {
	name: "notebook with decorative cover",
	slug: "notebook_with_decorative_cover",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"📕": {
	name: "closed book",
	slug: "closed_book",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"📖": {
	name: "open book",
	slug: "open_book",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"📗": {
	name: "green book",
	slug: "green_book",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"📘": {
	name: "blue book",
	slug: "blue_book",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"📙": {
	name: "orange book",
	slug: "orange_book",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"📚": {
	name: "books",
	slug: "books",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"📓": {
	name: "notebook",
	slug: "notebook",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"📒": {
	name: "ledger",
	slug: "ledger",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"📃": {
	name: "page with curl",
	slug: "page_with_curl",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"📜": {
	name: "scroll",
	slug: "scroll",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"📄": {
	name: "page facing up",
	slug: "page_facing_up",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"📰": {
	name: "newspaper",
	slug: "newspaper",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🗞️": {
	name: "rolled-up newspaper",
	slug: "rolled_up_newspaper",
	group: "Objects",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"📑": {
	name: "bookmark tabs",
	slug: "bookmark_tabs",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🔖": {
	name: "bookmark",
	slug: "bookmark",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🏷️": {
	name: "label",
	slug: "label",
	group: "Objects",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"💰": {
	name: "money bag",
	slug: "money_bag",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🪙": {
	name: "coin",
	slug: "coin",
	group: "Objects",
	emoji_version: "13.0",
	unicode_version: "13.0",
	skin_tone_support: false
},
	"💴": {
	name: "yen banknote",
	slug: "yen_banknote",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"💵": {
	name: "dollar banknote",
	slug: "dollar_banknote",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"💶": {
	name: "euro banknote",
	slug: "euro_banknote",
	group: "Objects",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"💷": {
	name: "pound banknote",
	slug: "pound_banknote",
	group: "Objects",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"💸": {
	name: "money with wings",
	slug: "money_with_wings",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"💳": {
	name: "credit card",
	slug: "credit_card",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🧾": {
	name: "receipt",
	slug: "receipt",
	group: "Objects",
	emoji_version: "11.0",
	unicode_version: "11.0",
	skin_tone_support: false
},
	"💹": {
	name: "chart increasing with yen",
	slug: "chart_increasing_with_yen",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"✉️": {
	name: "envelope",
	slug: "envelope",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"📧": {
	name: "e-mail",
	slug: "e_mail",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"📨": {
	name: "incoming envelope",
	slug: "incoming_envelope",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"📩": {
	name: "envelope with arrow",
	slug: "envelope_with_arrow",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"📤": {
	name: "outbox tray",
	slug: "outbox_tray",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"📥": {
	name: "inbox tray",
	slug: "inbox_tray",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"📦": {
	name: "package",
	slug: "package",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"📫": {
	name: "closed mailbox with raised flag",
	slug: "closed_mailbox_with_raised_flag",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"📪": {
	name: "closed mailbox with lowered flag",
	slug: "closed_mailbox_with_lowered_flag",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"📬": {
	name: "open mailbox with raised flag",
	slug: "open_mailbox_with_raised_flag",
	group: "Objects",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"📭": {
	name: "open mailbox with lowered flag",
	slug: "open_mailbox_with_lowered_flag",
	group: "Objects",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"📮": {
	name: "postbox",
	slug: "postbox",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🗳️": {
	name: "ballot box with ballot",
	slug: "ballot_box_with_ballot",
	group: "Objects",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"✏️": {
	name: "pencil",
	slug: "pencil",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"✒️": {
	name: "black nib",
	slug: "black_nib",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🖋️": {
	name: "fountain pen",
	slug: "fountain_pen",
	group: "Objects",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🖊️": {
	name: "pen",
	slug: "pen",
	group: "Objects",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🖌️": {
	name: "paintbrush",
	slug: "paintbrush",
	group: "Objects",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🖍️": {
	name: "crayon",
	slug: "crayon",
	group: "Objects",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"📝": {
	name: "memo",
	slug: "memo",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"💼": {
	name: "briefcase",
	slug: "briefcase",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"📁": {
	name: "file folder",
	slug: "file_folder",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"📂": {
	name: "open file folder",
	slug: "open_file_folder",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🗂️": {
	name: "card index dividers",
	slug: "card_index_dividers",
	group: "Objects",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"📅": {
	name: "calendar",
	slug: "calendar",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"📆": {
	name: "tear-off calendar",
	slug: "tear_off_calendar",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🗒️": {
	name: "spiral notepad",
	slug: "spiral_notepad",
	group: "Objects",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🗓️": {
	name: "spiral calendar",
	slug: "spiral_calendar",
	group: "Objects",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"📇": {
	name: "card index",
	slug: "card_index",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"📈": {
	name: "chart increasing",
	slug: "chart_increasing",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"📉": {
	name: "chart decreasing",
	slug: "chart_decreasing",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"📊": {
	name: "bar chart",
	slug: "bar_chart",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"📋": {
	name: "clipboard",
	slug: "clipboard",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"📌": {
	name: "pushpin",
	slug: "pushpin",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"📍": {
	name: "round pushpin",
	slug: "round_pushpin",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"📎": {
	name: "paperclip",
	slug: "paperclip",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🖇️": {
	name: "linked paperclips",
	slug: "linked_paperclips",
	group: "Objects",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"📏": {
	name: "straight ruler",
	slug: "straight_ruler",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"📐": {
	name: "triangular ruler",
	slug: "triangular_ruler",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"✂️": {
	name: "scissors",
	slug: "scissors",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🗃️": {
	name: "card file box",
	slug: "card_file_box",
	group: "Objects",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🗄️": {
	name: "file cabinet",
	slug: "file_cabinet",
	group: "Objects",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🗑️": {
	name: "wastebasket",
	slug: "wastebasket",
	group: "Objects",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🔒": {
	name: "locked",
	slug: "locked",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🔓": {
	name: "unlocked",
	slug: "unlocked",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🔏": {
	name: "locked with pen",
	slug: "locked_with_pen",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🔐": {
	name: "locked with key",
	slug: "locked_with_key",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🔑": {
	name: "key",
	slug: "key",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🗝️": {
	name: "old key",
	slug: "old_key",
	group: "Objects",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🔨": {
	name: "hammer",
	slug: "hammer",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🪓": {
	name: "axe",
	slug: "axe",
	group: "Objects",
	emoji_version: "12.0",
	unicode_version: "12.0",
	skin_tone_support: false
},
	"⛏️": {
	name: "pick",
	slug: "pick",
	group: "Objects",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"⚒️": {
	name: "hammer and pick",
	slug: "hammer_and_pick",
	group: "Objects",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🛠️": {
	name: "hammer and wrench",
	slug: "hammer_and_wrench",
	group: "Objects",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🗡️": {
	name: "dagger",
	slug: "dagger",
	group: "Objects",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"⚔️": {
	name: "crossed swords",
	slug: "crossed_swords",
	group: "Objects",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"💣": {
	name: "bomb",
	slug: "bomb",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🪃": {
	name: "boomerang",
	slug: "boomerang",
	group: "Objects",
	emoji_version: "13.0",
	unicode_version: "13.0",
	skin_tone_support: false
},
	"🏹": {
	name: "bow and arrow",
	slug: "bow_and_arrow",
	group: "Objects",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🛡️": {
	name: "shield",
	slug: "shield",
	group: "Objects",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🪚": {
	name: "carpentry saw",
	slug: "carpentry_saw",
	group: "Objects",
	emoji_version: "13.0",
	unicode_version: "13.0",
	skin_tone_support: false
},
	"🔧": {
	name: "wrench",
	slug: "wrench",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🪛": {
	name: "screwdriver",
	slug: "screwdriver",
	group: "Objects",
	emoji_version: "13.0",
	unicode_version: "13.0",
	skin_tone_support: false
},
	"🔩": {
	name: "nut and bolt",
	slug: "nut_and_bolt",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"⚙️": {
	name: "gear",
	slug: "gear",
	group: "Objects",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🗜️": {
	name: "clamp",
	slug: "clamp",
	group: "Objects",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"⚖️": {
	name: "balance scale",
	slug: "balance_scale",
	group: "Objects",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🦯": {
	name: "white cane",
	slug: "white_cane",
	group: "Objects",
	emoji_version: "12.0",
	unicode_version: "12.0",
	skin_tone_support: false
},
	"🔗": {
	name: "link",
	slug: "link",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"⛓️": {
	name: "chains",
	slug: "chains",
	group: "Objects",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🪝": {
	name: "hook",
	slug: "hook",
	group: "Objects",
	emoji_version: "13.0",
	unicode_version: "13.0",
	skin_tone_support: false
},
	"🧰": {
	name: "toolbox",
	slug: "toolbox",
	group: "Objects",
	emoji_version: "11.0",
	unicode_version: "11.0",
	skin_tone_support: false
},
	"🧲": {
	name: "magnet",
	slug: "magnet",
	group: "Objects",
	emoji_version: "11.0",
	unicode_version: "11.0",
	skin_tone_support: false
},
	"🪜": {
	name: "ladder",
	slug: "ladder",
	group: "Objects",
	emoji_version: "13.0",
	unicode_version: "13.0",
	skin_tone_support: false
},
	"⚗️": {
	name: "alembic",
	slug: "alembic",
	group: "Objects",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🧪": {
	name: "test tube",
	slug: "test_tube",
	group: "Objects",
	emoji_version: "11.0",
	unicode_version: "11.0",
	skin_tone_support: false
},
	"🧫": {
	name: "petri dish",
	slug: "petri_dish",
	group: "Objects",
	emoji_version: "11.0",
	unicode_version: "11.0",
	skin_tone_support: false
},
	"🧬": {
	name: "dna",
	slug: "dna",
	group: "Objects",
	emoji_version: "11.0",
	unicode_version: "11.0",
	skin_tone_support: false
},
	"🔬": {
	name: "microscope",
	slug: "microscope",
	group: "Objects",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🔭": {
	name: "telescope",
	slug: "telescope",
	group: "Objects",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"📡": {
	name: "satellite antenna",
	slug: "satellite_antenna",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"💉": {
	name: "syringe",
	slug: "syringe",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🩸": {
	name: "drop of blood",
	slug: "drop_of_blood",
	group: "Objects",
	emoji_version: "12.0",
	unicode_version: "12.0",
	skin_tone_support: false
},
	"💊": {
	name: "pill",
	slug: "pill",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🩹": {
	name: "adhesive bandage",
	slug: "adhesive_bandage",
	group: "Objects",
	emoji_version: "12.0",
	unicode_version: "12.0",
	skin_tone_support: false
},
	"🩼": {
	name: "crutch",
	slug: "crutch",
	group: "Objects",
	emoji_version: "14.0",
	unicode_version: "14.0",
	skin_tone_support: false
},
	"🩺": {
	name: "stethoscope",
	slug: "stethoscope",
	group: "Objects",
	emoji_version: "12.0",
	unicode_version: "12.0",
	skin_tone_support: false
},
	"🩻": {
	name: "x-ray",
	slug: "x_ray",
	group: "Objects",
	emoji_version: "14.0",
	unicode_version: "14.0",
	skin_tone_support: false
},
	"🚪": {
	name: "door",
	slug: "door",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🛗": {
	name: "elevator",
	slug: "elevator",
	group: "Objects",
	emoji_version: "13.0",
	unicode_version: "13.0",
	skin_tone_support: false
},
	"🪞": {
	name: "mirror",
	slug: "mirror",
	group: "Objects",
	emoji_version: "13.0",
	unicode_version: "13.0",
	skin_tone_support: false
},
	"🪟": {
	name: "window",
	slug: "window",
	group: "Objects",
	emoji_version: "13.0",
	unicode_version: "13.0",
	skin_tone_support: false
},
	"🛏️": {
	name: "bed",
	slug: "bed",
	group: "Objects",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🛋️": {
	name: "couch and lamp",
	slug: "couch_and_lamp",
	group: "Objects",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🪑": {
	name: "chair",
	slug: "chair",
	group: "Objects",
	emoji_version: "12.0",
	unicode_version: "12.0",
	skin_tone_support: false
},
	"🚽": {
	name: "toilet",
	slug: "toilet",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🪠": {
	name: "plunger",
	slug: "plunger",
	group: "Objects",
	emoji_version: "13.0",
	unicode_version: "13.0",
	skin_tone_support: false
},
	"🚿": {
	name: "shower",
	slug: "shower",
	group: "Objects",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🛁": {
	name: "bathtub",
	slug: "bathtub",
	group: "Objects",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🪤": {
	name: "mouse trap",
	slug: "mouse_trap",
	group: "Objects",
	emoji_version: "13.0",
	unicode_version: "13.0",
	skin_tone_support: false
},
	"🪒": {
	name: "razor",
	slug: "razor",
	group: "Objects",
	emoji_version: "12.0",
	unicode_version: "12.0",
	skin_tone_support: false
},
	"🧴": {
	name: "lotion bottle",
	slug: "lotion_bottle",
	group: "Objects",
	emoji_version: "11.0",
	unicode_version: "11.0",
	skin_tone_support: false
},
	"🧷": {
	name: "safety pin",
	slug: "safety_pin",
	group: "Objects",
	emoji_version: "11.0",
	unicode_version: "11.0",
	skin_tone_support: false
},
	"🧹": {
	name: "broom",
	slug: "broom",
	group: "Objects",
	emoji_version: "11.0",
	unicode_version: "11.0",
	skin_tone_support: false
},
	"🧺": {
	name: "basket",
	slug: "basket",
	group: "Objects",
	emoji_version: "11.0",
	unicode_version: "11.0",
	skin_tone_support: false
},
	"🧻": {
	name: "roll of paper",
	slug: "roll_of_paper",
	group: "Objects",
	emoji_version: "11.0",
	unicode_version: "11.0",
	skin_tone_support: false
},
	"🪣": {
	name: "bucket",
	slug: "bucket",
	group: "Objects",
	emoji_version: "13.0",
	unicode_version: "13.0",
	skin_tone_support: false
},
	"🧼": {
	name: "soap",
	slug: "soap",
	group: "Objects",
	emoji_version: "11.0",
	unicode_version: "11.0",
	skin_tone_support: false
},
	"🫧": {
	name: "bubbles",
	slug: "bubbles",
	group: "Objects",
	emoji_version: "14.0",
	unicode_version: "14.0",
	skin_tone_support: false
},
	"🪥": {
	name: "toothbrush",
	slug: "toothbrush",
	group: "Objects",
	emoji_version: "13.0",
	unicode_version: "13.0",
	skin_tone_support: false
},
	"🧽": {
	name: "sponge",
	slug: "sponge",
	group: "Objects",
	emoji_version: "11.0",
	unicode_version: "11.0",
	skin_tone_support: false
},
	"🧯": {
	name: "fire extinguisher",
	slug: "fire_extinguisher",
	group: "Objects",
	emoji_version: "11.0",
	unicode_version: "11.0",
	skin_tone_support: false
},
	"🛒": {
	name: "shopping cart",
	slug: "shopping_cart",
	group: "Objects",
	emoji_version: "3.0",
	unicode_version: "3.0",
	skin_tone_support: false
},
	"🚬": {
	name: "cigarette",
	slug: "cigarette",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"⚰️": {
	name: "coffin",
	slug: "coffin",
	group: "Objects",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🪦": {
	name: "headstone",
	slug: "headstone",
	group: "Objects",
	emoji_version: "13.0",
	unicode_version: "13.0",
	skin_tone_support: false
},
	"⚱️": {
	name: "funeral urn",
	slug: "funeral_urn",
	group: "Objects",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🧿": {
	name: "nazar amulet",
	slug: "nazar_amulet",
	group: "Objects",
	emoji_version: "11.0",
	unicode_version: "11.0",
	skin_tone_support: false
},
	"🪬": {
	name: "hamsa",
	slug: "hamsa",
	group: "Objects",
	emoji_version: "14.0",
	unicode_version: "14.0",
	skin_tone_support: false
},
	"🗿": {
	name: "moai",
	slug: "moai",
	group: "Objects",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🪧": {
	name: "placard",
	slug: "placard",
	group: "Objects",
	emoji_version: "13.0",
	unicode_version: "13.0",
	skin_tone_support: false
},
	"🪪": {
	name: "identification card",
	slug: "identification_card",
	group: "Objects",
	emoji_version: "14.0",
	unicode_version: "14.0",
	skin_tone_support: false
},
	"🏧": {
	name: "ATM sign",
	slug: "atm_sign",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🚮": {
	name: "litter in bin sign",
	slug: "litter_in_bin_sign",
	group: "Symbols",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🚰": {
	name: "potable water",
	slug: "potable_water",
	group: "Symbols",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"♿": {
	name: "wheelchair symbol",
	slug: "wheelchair_symbol",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🚹": {
	name: "men’s room",
	slug: "men_s_room",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🚺": {
	name: "women’s room",
	slug: "women_s_room",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🚻": {
	name: "restroom",
	slug: "restroom",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🚼": {
	name: "baby symbol",
	slug: "baby_symbol",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🚾": {
	name: "water closet",
	slug: "water_closet",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🛂": {
	name: "passport control",
	slug: "passport_control",
	group: "Symbols",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🛃": {
	name: "customs",
	slug: "customs",
	group: "Symbols",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🛄": {
	name: "baggage claim",
	slug: "baggage_claim",
	group: "Symbols",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🛅": {
	name: "left luggage",
	slug: "left_luggage",
	group: "Symbols",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"⚠️": {
	name: "warning",
	slug: "warning",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🚸": {
	name: "children crossing",
	slug: "children_crossing",
	group: "Symbols",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"⛔": {
	name: "no entry",
	slug: "no_entry",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🚫": {
	name: "prohibited",
	slug: "prohibited",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🚳": {
	name: "no bicycles",
	slug: "no_bicycles",
	group: "Symbols",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🚭": {
	name: "no smoking",
	slug: "no_smoking",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🚯": {
	name: "no littering",
	slug: "no_littering",
	group: "Symbols",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🚱": {
	name: "non-potable water",
	slug: "non_potable_water",
	group: "Symbols",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🚷": {
	name: "no pedestrians",
	slug: "no_pedestrians",
	group: "Symbols",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"📵": {
	name: "no mobile phones",
	slug: "no_mobile_phones",
	group: "Symbols",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🔞": {
	name: "no one under eighteen",
	slug: "no_one_under_eighteen",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"☢️": {
	name: "radioactive",
	slug: "radioactive",
	group: "Symbols",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"☣️": {
	name: "biohazard",
	slug: "biohazard",
	group: "Symbols",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"⬆️": {
	name: "up arrow",
	slug: "up_arrow",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"↗️": {
	name: "up-right arrow",
	slug: "up_right_arrow",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"➡️": {
	name: "right arrow",
	slug: "right_arrow",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"↘️": {
	name: "down-right arrow",
	slug: "down_right_arrow",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"⬇️": {
	name: "down arrow",
	slug: "down_arrow",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"↙️": {
	name: "down-left arrow",
	slug: "down_left_arrow",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"⬅️": {
	name: "left arrow",
	slug: "left_arrow",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"↖️": {
	name: "up-left arrow",
	slug: "up_left_arrow",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"↕️": {
	name: "up-down arrow",
	slug: "up_down_arrow",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"↔️": {
	name: "left-right arrow",
	slug: "left_right_arrow",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"↩️": {
	name: "right arrow curving left",
	slug: "right_arrow_curving_left",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"↪️": {
	name: "left arrow curving right",
	slug: "left_arrow_curving_right",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"⤴️": {
	name: "right arrow curving up",
	slug: "right_arrow_curving_up",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"⤵️": {
	name: "right arrow curving down",
	slug: "right_arrow_curving_down",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🔃": {
	name: "clockwise vertical arrows",
	slug: "clockwise_vertical_arrows",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🔄": {
	name: "counterclockwise arrows button",
	slug: "counterclockwise_arrows_button",
	group: "Symbols",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🔙": {
	name: "BACK arrow",
	slug: "back_arrow",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🔚": {
	name: "END arrow",
	slug: "end_arrow",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🔛": {
	name: "ON! arrow",
	slug: "on_arrow",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🔜": {
	name: "SOON arrow",
	slug: "soon_arrow",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🔝": {
	name: "TOP arrow",
	slug: "top_arrow",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🛐": {
	name: "place of worship",
	slug: "place_of_worship",
	group: "Symbols",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"⚛️": {
	name: "atom symbol",
	slug: "atom_symbol",
	group: "Symbols",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🕉️": {
	name: "om",
	slug: "om",
	group: "Symbols",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"✡️": {
	name: "star of David",
	slug: "star_of_david",
	group: "Symbols",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"☸️": {
	name: "wheel of dharma",
	slug: "wheel_of_dharma",
	group: "Symbols",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"☯️": {
	name: "yin yang",
	slug: "yin_yang",
	group: "Symbols",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"✝️": {
	name: "latin cross",
	slug: "latin_cross",
	group: "Symbols",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"☦️": {
	name: "orthodox cross",
	slug: "orthodox_cross",
	group: "Symbols",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"☪️": {
	name: "star and crescent",
	slug: "star_and_crescent",
	group: "Symbols",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"☮️": {
	name: "peace symbol",
	slug: "peace_symbol",
	group: "Symbols",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🕎": {
	name: "menorah",
	slug: "menorah",
	group: "Symbols",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🔯": {
	name: "dotted six-pointed star",
	slug: "dotted_six_pointed_star",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🪯": {
	name: "khanda",
	slug: "khanda",
	group: "Symbols",
	emoji_version: "15.0",
	unicode_version: "15.0",
	skin_tone_support: false
},
	"♈": {
	name: "Aries",
	slug: "aries",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"♉": {
	name: "Taurus",
	slug: "taurus",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"♊": {
	name: "Gemini",
	slug: "gemini",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"♋": {
	name: "Cancer",
	slug: "cancer",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"♌": {
	name: "Leo",
	slug: "leo",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"♍": {
	name: "Virgo",
	slug: "virgo",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"♎": {
	name: "Libra",
	slug: "libra",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"♏": {
	name: "Scorpio",
	slug: "scorpio",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"♐": {
	name: "Sagittarius",
	slug: "sagittarius",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"♑": {
	name: "Capricorn",
	slug: "capricorn",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"♒": {
	name: "Aquarius",
	slug: "aquarius",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"♓": {
	name: "Pisces",
	slug: "pisces",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"⛎": {
	name: "Ophiuchus",
	slug: "ophiuchus",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🔀": {
	name: "shuffle tracks button",
	slug: "shuffle_tracks_button",
	group: "Symbols",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🔁": {
	name: "repeat button",
	slug: "repeat_button",
	group: "Symbols",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🔂": {
	name: "repeat single button",
	slug: "repeat_single_button",
	group: "Symbols",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"▶️": {
	name: "play button",
	slug: "play_button",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"⏩": {
	name: "fast-forward button",
	slug: "fast_forward_button",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"⏭️": {
	name: "next track button",
	slug: "next_track_button",
	group: "Symbols",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"⏯️": {
	name: "play or pause button",
	slug: "play_or_pause_button",
	group: "Symbols",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"◀️": {
	name: "reverse button",
	slug: "reverse_button",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"⏪": {
	name: "fast reverse button",
	slug: "fast_reverse_button",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"⏮️": {
	name: "last track button",
	slug: "last_track_button",
	group: "Symbols",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🔼": {
	name: "upwards button",
	slug: "upwards_button",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"⏫": {
	name: "fast up button",
	slug: "fast_up_button",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🔽": {
	name: "downwards button",
	slug: "downwards_button",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"⏬": {
	name: "fast down button",
	slug: "fast_down_button",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"⏸️": {
	name: "pause button",
	slug: "pause_button",
	group: "Symbols",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"⏹️": {
	name: "stop button",
	slug: "stop_button",
	group: "Symbols",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"⏺️": {
	name: "record button",
	slug: "record_button",
	group: "Symbols",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"⏏️": {
	name: "eject button",
	slug: "eject_button",
	group: "Symbols",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🎦": {
	name: "cinema",
	slug: "cinema",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🔅": {
	name: "dim button",
	slug: "dim_button",
	group: "Symbols",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🔆": {
	name: "bright button",
	slug: "bright_button",
	group: "Symbols",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"📶": {
	name: "antenna bars",
	slug: "antenna_bars",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🛜": {
	name: "wireless",
	slug: "wireless",
	group: "Symbols",
	emoji_version: "15.0",
	unicode_version: "15.0",
	skin_tone_support: false
},
	"📳": {
	name: "vibration mode",
	slug: "vibration_mode",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"📴": {
	name: "mobile phone off",
	slug: "mobile_phone_off",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"♀️": {
	name: "female sign",
	slug: "female_sign",
	group: "Symbols",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: false
},
	"♂️": {
	name: "male sign",
	slug: "male_sign",
	group: "Symbols",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: false
},
	"⚧️": {
	name: "transgender symbol",
	slug: "transgender_symbol",
	group: "Symbols",
	emoji_version: "13.0",
	unicode_version: "13.0",
	skin_tone_support: false
},
	"✖️": {
	name: "multiply",
	slug: "multiply",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"➕": {
	name: "plus",
	slug: "plus",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"➖": {
	name: "minus",
	slug: "minus",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"➗": {
	name: "divide",
	slug: "divide",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🟰": {
	name: "heavy equals sign",
	slug: "heavy_equals_sign",
	group: "Symbols",
	emoji_version: "14.0",
	unicode_version: "14.0",
	skin_tone_support: false
},
	"♾️": {
	name: "infinity",
	slug: "infinity",
	group: "Symbols",
	emoji_version: "11.0",
	unicode_version: "11.0",
	skin_tone_support: false
},
	"‼️": {
	name: "double exclamation mark",
	slug: "double_exclamation_mark",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"⁉️": {
	name: "exclamation question mark",
	slug: "exclamation_question_mark",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"❓": {
	name: "red question mark",
	slug: "red_question_mark",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"❔": {
	name: "white question mark",
	slug: "white_question_mark",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"❕": {
	name: "white exclamation mark",
	slug: "white_exclamation_mark",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"❗": {
	name: "red exclamation mark",
	slug: "red_exclamation_mark",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"〰️": {
	name: "wavy dash",
	slug: "wavy_dash",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"💱": {
	name: "currency exchange",
	slug: "currency_exchange",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"💲": {
	name: "heavy dollar sign",
	slug: "heavy_dollar_sign",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"⚕️": {
	name: "medical symbol",
	slug: "medical_symbol",
	group: "Symbols",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: false
},
	"♻️": {
	name: "recycling symbol",
	slug: "recycling_symbol",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"⚜️": {
	name: "fleur-de-lis",
	slug: "fleur_de_lis",
	group: "Symbols",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🔱": {
	name: "trident emblem",
	slug: "trident_emblem",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"📛": {
	name: "name badge",
	slug: "name_badge",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🔰": {
	name: "Japanese symbol for beginner",
	slug: "japanese_symbol_for_beginner",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"⭕": {
	name: "hollow red circle",
	slug: "hollow_red_circle",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"✅": {
	name: "check mark button",
	slug: "check_mark_button",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"☑️": {
	name: "check box with check",
	slug: "check_box_with_check",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"✔️": {
	name: "check mark",
	slug: "check_mark",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"❌": {
	name: "cross mark",
	slug: "cross_mark",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"❎": {
	name: "cross mark button",
	slug: "cross_mark_button",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"➰": {
	name: "curly loop",
	slug: "curly_loop",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"➿": {
	name: "double curly loop",
	slug: "double_curly_loop",
	group: "Symbols",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"〽️": {
	name: "part alternation mark",
	slug: "part_alternation_mark",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"✳️": {
	name: "eight-spoked asterisk",
	slug: "eight_spoked_asterisk",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"✴️": {
	name: "eight-pointed star",
	slug: "eight_pointed_star",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"❇️": {
	name: "sparkle",
	slug: "sparkle",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"©️": {
	name: "copyright",
	slug: "copyright",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"®️": {
	name: "registered",
	slug: "registered",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"™️": {
	name: "trade mark",
	slug: "trade_mark",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"#️⃣": {
	name: "keycap #",
	slug: "keycap_number_sign",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"*️⃣": {
	name: "keycap *",
	slug: "keycap_asterisk",
	group: "Symbols",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"0️⃣": {
	name: "keycap 0",
	slug: "keycap_0",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"1️⃣": {
	name: "keycap 1",
	slug: "keycap_1",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"2️⃣": {
	name: "keycap 2",
	slug: "keycap_2",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"3️⃣": {
	name: "keycap 3",
	slug: "keycap_3",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"4️⃣": {
	name: "keycap 4",
	slug: "keycap_4",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"5️⃣": {
	name: "keycap 5",
	slug: "keycap_5",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"6️⃣": {
	name: "keycap 6",
	slug: "keycap_6",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"7️⃣": {
	name: "keycap 7",
	slug: "keycap_7",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"8️⃣": {
	name: "keycap 8",
	slug: "keycap_8",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"9️⃣": {
	name: "keycap 9",
	slug: "keycap_9",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🔟": {
	name: "keycap 10",
	slug: "keycap_10",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🔠": {
	name: "input latin uppercase",
	slug: "input_latin_uppercase",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🔡": {
	name: "input latin lowercase",
	slug: "input_latin_lowercase",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🔢": {
	name: "input numbers",
	slug: "input_numbers",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🔣": {
	name: "input symbols",
	slug: "input_symbols",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🔤": {
	name: "input latin letters",
	slug: "input_latin_letters",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🅰️": {
	name: "A button (blood type)",
	slug: "a_button",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🆎": {
	name: "AB button (blood type)",
	slug: "ab_button",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🅱️": {
	name: "B button (blood type)",
	slug: "b_button",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🆑": {
	name: "CL button",
	slug: "cl_button",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🆒": {
	name: "COOL button",
	slug: "cool_button",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🆓": {
	name: "FREE button",
	slug: "free_button",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"ℹ️": {
	name: "information",
	slug: "information",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🆔": {
	name: "ID button",
	slug: "id_button",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"Ⓜ️": {
	name: "circled M",
	slug: "circled_m",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🆕": {
	name: "NEW button",
	slug: "new_button",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🆖": {
	name: "NG button",
	slug: "ng_button",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🅾️": {
	name: "O button (blood type)",
	slug: "o_button",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🆗": {
	name: "OK button",
	slug: "ok_button",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🅿️": {
	name: "P button",
	slug: "p_button",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🆘": {
	name: "SOS button",
	slug: "sos_button",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🆙": {
	name: "UP! button",
	slug: "up_button",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🆚": {
	name: "VS button",
	slug: "vs_button",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🈁": {
	name: "Japanese “here” button",
	slug: "japanese_here_button",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🈂️": {
	name: "Japanese “service charge” button",
	slug: "japanese_service_charge_button",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🈷️": {
	name: "Japanese “monthly amount” button",
	slug: "japanese_monthly_amount_button",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🈶": {
	name: "Japanese “not free of charge” button",
	slug: "japanese_not_free_of_charge_button",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🈯": {
	name: "Japanese “reserved” button",
	slug: "japanese_reserved_button",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🉐": {
	name: "Japanese “bargain” button",
	slug: "japanese_bargain_button",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🈹": {
	name: "Japanese “discount” button",
	slug: "japanese_discount_button",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🈚": {
	name: "Japanese “free of charge” button",
	slug: "japanese_free_of_charge_button",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🈲": {
	name: "Japanese “prohibited” button",
	slug: "japanese_prohibited_button",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🉑": {
	name: "Japanese “acceptable” button",
	slug: "japanese_acceptable_button",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🈸": {
	name: "Japanese “application” button",
	slug: "japanese_application_button",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🈴": {
	name: "Japanese “passing grade” button",
	slug: "japanese_passing_grade_button",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🈳": {
	name: "Japanese “vacancy” button",
	slug: "japanese_vacancy_button",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"㊗️": {
	name: "Japanese “congratulations” button",
	slug: "japanese_congratulations_button",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"㊙️": {
	name: "Japanese “secret” button",
	slug: "japanese_secret_button",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🈺": {
	name: "Japanese “open for business” button",
	slug: "japanese_open_for_business_button",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🈵": {
	name: "Japanese “no vacancy” button",
	slug: "japanese_no_vacancy_button",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🔴": {
	name: "red circle",
	slug: "red_circle",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🟠": {
	name: "orange circle",
	slug: "orange_circle",
	group: "Symbols",
	emoji_version: "12.0",
	unicode_version: "12.0",
	skin_tone_support: false
},
	"🟡": {
	name: "yellow circle",
	slug: "yellow_circle",
	group: "Symbols",
	emoji_version: "12.0",
	unicode_version: "12.0",
	skin_tone_support: false
},
	"🟢": {
	name: "green circle",
	slug: "green_circle",
	group: "Symbols",
	emoji_version: "12.0",
	unicode_version: "12.0",
	skin_tone_support: false
},
	"🔵": {
	name: "blue circle",
	slug: "blue_circle",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🟣": {
	name: "purple circle",
	slug: "purple_circle",
	group: "Symbols",
	emoji_version: "12.0",
	unicode_version: "12.0",
	skin_tone_support: false
},
	"🟤": {
	name: "brown circle",
	slug: "brown_circle",
	group: "Symbols",
	emoji_version: "12.0",
	unicode_version: "12.0",
	skin_tone_support: false
},
	"⚫": {
	name: "black circle",
	slug: "black_circle",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"⚪": {
	name: "white circle",
	slug: "white_circle",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🟥": {
	name: "red square",
	slug: "red_square",
	group: "Symbols",
	emoji_version: "12.0",
	unicode_version: "12.0",
	skin_tone_support: false
},
	"🟧": {
	name: "orange square",
	slug: "orange_square",
	group: "Symbols",
	emoji_version: "12.0",
	unicode_version: "12.0",
	skin_tone_support: false
},
	"🟨": {
	name: "yellow square",
	slug: "yellow_square",
	group: "Symbols",
	emoji_version: "12.0",
	unicode_version: "12.0",
	skin_tone_support: false
},
	"🟩": {
	name: "green square",
	slug: "green_square",
	group: "Symbols",
	emoji_version: "12.0",
	unicode_version: "12.0",
	skin_tone_support: false
},
	"🟦": {
	name: "blue square",
	slug: "blue_square",
	group: "Symbols",
	emoji_version: "12.0",
	unicode_version: "12.0",
	skin_tone_support: false
},
	"🟪": {
	name: "purple square",
	slug: "purple_square",
	group: "Symbols",
	emoji_version: "12.0",
	unicode_version: "12.0",
	skin_tone_support: false
},
	"🟫": {
	name: "brown square",
	slug: "brown_square",
	group: "Symbols",
	emoji_version: "12.0",
	unicode_version: "12.0",
	skin_tone_support: false
},
	"⬛": {
	name: "black large square",
	slug: "black_large_square",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"⬜": {
	name: "white large square",
	slug: "white_large_square",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"◼️": {
	name: "black medium square",
	slug: "black_medium_square",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"◻️": {
	name: "white medium square",
	slug: "white_medium_square",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"◾": {
	name: "black medium-small square",
	slug: "black_medium_small_square",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"◽": {
	name: "white medium-small square",
	slug: "white_medium_small_square",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"▪️": {
	name: "black small square",
	slug: "black_small_square",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"▫️": {
	name: "white small square",
	slug: "white_small_square",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🔶": {
	name: "large orange diamond",
	slug: "large_orange_diamond",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🔷": {
	name: "large blue diamond",
	slug: "large_blue_diamond",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🔸": {
	name: "small orange diamond",
	slug: "small_orange_diamond",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🔹": {
	name: "small blue diamond",
	slug: "small_blue_diamond",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🔺": {
	name: "red triangle pointed up",
	slug: "red_triangle_pointed_up",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🔻": {
	name: "red triangle pointed down",
	slug: "red_triangle_pointed_down",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"💠": {
	name: "diamond with a dot",
	slug: "diamond_with_a_dot",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🔘": {
	name: "radio button",
	slug: "radio_button",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🔳": {
	name: "white square button",
	slug: "white_square_button",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🔲": {
	name: "black square button",
	slug: "black_square_button",
	group: "Symbols",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🏁": {
	name: "chequered flag",
	slug: "chequered_flag",
	group: "Flags",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🚩": {
	name: "triangular flag",
	slug: "triangular_flag",
	group: "Flags",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🎌": {
	name: "crossed flags",
	slug: "crossed_flags",
	group: "Flags",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🏴": {
	name: "black flag",
	slug: "black_flag",
	group: "Flags",
	emoji_version: "1.0",
	unicode_version: "1.0",
	skin_tone_support: false
},
	"🏳️": {
	name: "white flag",
	slug: "white_flag",
	group: "Flags",
	emoji_version: "0.7",
	unicode_version: "0.7",
	skin_tone_support: false
},
	"🏳️‍🌈": {
	name: "rainbow flag",
	slug: "rainbow_flag",
	group: "Flags",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: false
},
	"🏳️‍⚧️": {
	name: "transgender flag",
	slug: "transgender_flag",
	group: "Flags",
	emoji_version: "13.0",
	unicode_version: "13.0",
	skin_tone_support: false
},
	"🏴‍☠️": {
	name: "pirate flag",
	slug: "pirate_flag",
	group: "Flags",
	emoji_version: "11.0",
	unicode_version: "11.0",
	skin_tone_support: false
},
	"🇦🇨": {
	name: "flag Ascension Island",
	slug: "flag_ascension_island",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇦🇩": {
	name: "flag Andorra",
	slug: "flag_andorra",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇦🇪": {
	name: "flag United Arab Emirates",
	slug: "flag_united_arab_emirates",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇦🇫": {
	name: "flag Afghanistan",
	slug: "flag_afghanistan",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇦🇬": {
	name: "flag Antigua & Barbuda",
	slug: "flag_antigua_barbuda",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇦🇮": {
	name: "flag Anguilla",
	slug: "flag_anguilla",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇦🇱": {
	name: "flag Albania",
	slug: "flag_albania",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇦🇲": {
	name: "flag Armenia",
	slug: "flag_armenia",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇦🇴": {
	name: "flag Angola",
	slug: "flag_angola",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇦🇶": {
	name: "flag Antarctica",
	slug: "flag_antarctica",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇦🇷": {
	name: "flag Argentina",
	slug: "flag_argentina",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇦🇸": {
	name: "flag American Samoa",
	slug: "flag_american_samoa",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇦🇹": {
	name: "flag Austria",
	slug: "flag_austria",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇦🇺": {
	name: "flag Australia",
	slug: "flag_australia",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇦🇼": {
	name: "flag Aruba",
	slug: "flag_aruba",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇦🇽": {
	name: "flag Åland Islands",
	slug: "flag_aland_islands",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇦🇿": {
	name: "flag Azerbaijan",
	slug: "flag_azerbaijan",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇧🇦": {
	name: "flag Bosnia & Herzegovina",
	slug: "flag_bosnia_herzegovina",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇧🇧": {
	name: "flag Barbados",
	slug: "flag_barbados",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇧🇩": {
	name: "flag Bangladesh",
	slug: "flag_bangladesh",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇧🇪": {
	name: "flag Belgium",
	slug: "flag_belgium",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇧🇫": {
	name: "flag Burkina Faso",
	slug: "flag_burkina_faso",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇧🇬": {
	name: "flag Bulgaria",
	slug: "flag_bulgaria",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇧🇭": {
	name: "flag Bahrain",
	slug: "flag_bahrain",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇧🇮": {
	name: "flag Burundi",
	slug: "flag_burundi",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇧🇯": {
	name: "flag Benin",
	slug: "flag_benin",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇧🇱": {
	name: "flag St. Barthélemy",
	slug: "flag_st_barthelemy",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇧🇲": {
	name: "flag Bermuda",
	slug: "flag_bermuda",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇧🇳": {
	name: "flag Brunei",
	slug: "flag_brunei",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇧🇴": {
	name: "flag Bolivia",
	slug: "flag_bolivia",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇧🇶": {
	name: "flag Caribbean Netherlands",
	slug: "flag_caribbean_netherlands",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇧🇷": {
	name: "flag Brazil",
	slug: "flag_brazil",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇧🇸": {
	name: "flag Bahamas",
	slug: "flag_bahamas",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇧🇹": {
	name: "flag Bhutan",
	slug: "flag_bhutan",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇧🇻": {
	name: "flag Bouvet Island",
	slug: "flag_bouvet_island",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇧🇼": {
	name: "flag Botswana",
	slug: "flag_botswana",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇧🇾": {
	name: "flag Belarus",
	slug: "flag_belarus",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇧🇿": {
	name: "flag Belize",
	slug: "flag_belize",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇨🇦": {
	name: "flag Canada",
	slug: "flag_canada",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇨🇨": {
	name: "flag Cocos (Keeling) Islands",
	slug: "flag_cocos_islands",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇨🇩": {
	name: "flag Congo - Kinshasa",
	slug: "flag_congo_kinshasa",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇨🇫": {
	name: "flag Central African Republic",
	slug: "flag_central_african_republic",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇨🇬": {
	name: "flag Congo - Brazzaville",
	slug: "flag_congo_brazzaville",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇨🇭": {
	name: "flag Switzerland",
	slug: "flag_switzerland",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇨🇮": {
	name: "flag Côte d’Ivoire",
	slug: "flag_cote_d_ivoire",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇨🇰": {
	name: "flag Cook Islands",
	slug: "flag_cook_islands",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇨🇱": {
	name: "flag Chile",
	slug: "flag_chile",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇨🇲": {
	name: "flag Cameroon",
	slug: "flag_cameroon",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇨🇳": {
	name: "flag China",
	slug: "flag_china",
	group: "Flags",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🇨🇴": {
	name: "flag Colombia",
	slug: "flag_colombia",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇨🇵": {
	name: "flag Clipperton Island",
	slug: "flag_clipperton_island",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇨🇷": {
	name: "flag Costa Rica",
	slug: "flag_costa_rica",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇨🇺": {
	name: "flag Cuba",
	slug: "flag_cuba",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇨🇻": {
	name: "flag Cape Verde",
	slug: "flag_cape_verde",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇨🇼": {
	name: "flag Curaçao",
	slug: "flag_curacao",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇨🇽": {
	name: "flag Christmas Island",
	slug: "flag_christmas_island",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇨🇾": {
	name: "flag Cyprus",
	slug: "flag_cyprus",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇨🇿": {
	name: "flag Czechia",
	slug: "flag_czechia",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇩🇪": {
	name: "flag Germany",
	slug: "flag_germany",
	group: "Flags",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🇩🇬": {
	name: "flag Diego Garcia",
	slug: "flag_diego_garcia",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇩🇯": {
	name: "flag Djibouti",
	slug: "flag_djibouti",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇩🇰": {
	name: "flag Denmark",
	slug: "flag_denmark",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇩🇲": {
	name: "flag Dominica",
	slug: "flag_dominica",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇩🇴": {
	name: "flag Dominican Republic",
	slug: "flag_dominican_republic",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇩🇿": {
	name: "flag Algeria",
	slug: "flag_algeria",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇪🇦": {
	name: "flag Ceuta & Melilla",
	slug: "flag_ceuta_melilla",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇪🇨": {
	name: "flag Ecuador",
	slug: "flag_ecuador",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇪🇪": {
	name: "flag Estonia",
	slug: "flag_estonia",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇪🇬": {
	name: "flag Egypt",
	slug: "flag_egypt",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇪🇭": {
	name: "flag Western Sahara",
	slug: "flag_western_sahara",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇪🇷": {
	name: "flag Eritrea",
	slug: "flag_eritrea",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇪🇸": {
	name: "flag Spain",
	slug: "flag_spain",
	group: "Flags",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🇪🇹": {
	name: "flag Ethiopia",
	slug: "flag_ethiopia",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇪🇺": {
	name: "flag European Union",
	slug: "flag_european_union",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇫🇮": {
	name: "flag Finland",
	slug: "flag_finland",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇫🇯": {
	name: "flag Fiji",
	slug: "flag_fiji",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇫🇰": {
	name: "flag Falkland Islands",
	slug: "flag_falkland_islands",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇫🇲": {
	name: "flag Micronesia",
	slug: "flag_micronesia",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇫🇴": {
	name: "flag Faroe Islands",
	slug: "flag_faroe_islands",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇫🇷": {
	name: "flag France",
	slug: "flag_france",
	group: "Flags",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🇬🇦": {
	name: "flag Gabon",
	slug: "flag_gabon",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇬🇧": {
	name: "flag United Kingdom",
	slug: "flag_united_kingdom",
	group: "Flags",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🇬🇩": {
	name: "flag Grenada",
	slug: "flag_grenada",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇬🇪": {
	name: "flag Georgia",
	slug: "flag_georgia",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇬🇫": {
	name: "flag French Guiana",
	slug: "flag_french_guiana",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇬🇬": {
	name: "flag Guernsey",
	slug: "flag_guernsey",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇬🇭": {
	name: "flag Ghana",
	slug: "flag_ghana",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇬🇮": {
	name: "flag Gibraltar",
	slug: "flag_gibraltar",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇬🇱": {
	name: "flag Greenland",
	slug: "flag_greenland",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇬🇲": {
	name: "flag Gambia",
	slug: "flag_gambia",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇬🇳": {
	name: "flag Guinea",
	slug: "flag_guinea",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇬🇵": {
	name: "flag Guadeloupe",
	slug: "flag_guadeloupe",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇬🇶": {
	name: "flag Equatorial Guinea",
	slug: "flag_equatorial_guinea",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇬🇷": {
	name: "flag Greece",
	slug: "flag_greece",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇬🇸": {
	name: "flag South Georgia & South Sandwich Islands",
	slug: "flag_south_georgia_south_sandwich_islands",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇬🇹": {
	name: "flag Guatemala",
	slug: "flag_guatemala",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇬🇺": {
	name: "flag Guam",
	slug: "flag_guam",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇬🇼": {
	name: "flag Guinea-Bissau",
	slug: "flag_guinea_bissau",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇬🇾": {
	name: "flag Guyana",
	slug: "flag_guyana",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇭🇰": {
	name: "flag Hong Kong SAR China",
	slug: "flag_hong_kong_sar_china",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇭🇲": {
	name: "flag Heard & McDonald Islands",
	slug: "flag_heard_mcdonald_islands",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇭🇳": {
	name: "flag Honduras",
	slug: "flag_honduras",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇭🇷": {
	name: "flag Croatia",
	slug: "flag_croatia",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇭🇹": {
	name: "flag Haiti",
	slug: "flag_haiti",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇭🇺": {
	name: "flag Hungary",
	slug: "flag_hungary",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇮🇨": {
	name: "flag Canary Islands",
	slug: "flag_canary_islands",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇮🇩": {
	name: "flag Indonesia",
	slug: "flag_indonesia",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇮🇪": {
	name: "flag Ireland",
	slug: "flag_ireland",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇮🇱": {
	name: "flag Israel",
	slug: "flag_israel",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇮🇲": {
	name: "flag Isle of Man",
	slug: "flag_isle_of_man",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇮🇳": {
	name: "flag India",
	slug: "flag_india",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇮🇴": {
	name: "flag British Indian Ocean Territory",
	slug: "flag_british_indian_ocean_territory",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇮🇶": {
	name: "flag Iraq",
	slug: "flag_iraq",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇮🇷": {
	name: "flag Iran",
	slug: "flag_iran",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇮🇸": {
	name: "flag Iceland",
	slug: "flag_iceland",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇮🇹": {
	name: "flag Italy",
	slug: "flag_italy",
	group: "Flags",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🇯🇪": {
	name: "flag Jersey",
	slug: "flag_jersey",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇯🇲": {
	name: "flag Jamaica",
	slug: "flag_jamaica",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇯🇴": {
	name: "flag Jordan",
	slug: "flag_jordan",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇯🇵": {
	name: "flag Japan",
	slug: "flag_japan",
	group: "Flags",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🇰🇪": {
	name: "flag Kenya",
	slug: "flag_kenya",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇰🇬": {
	name: "flag Kyrgyzstan",
	slug: "flag_kyrgyzstan",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇰🇭": {
	name: "flag Cambodia",
	slug: "flag_cambodia",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇰🇮": {
	name: "flag Kiribati",
	slug: "flag_kiribati",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇰🇲": {
	name: "flag Comoros",
	slug: "flag_comoros",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇰🇳": {
	name: "flag St. Kitts & Nevis",
	slug: "flag_st_kitts_nevis",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇰🇵": {
	name: "flag North Korea",
	slug: "flag_north_korea",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇰🇷": {
	name: "flag South Korea",
	slug: "flag_south_korea",
	group: "Flags",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🇰🇼": {
	name: "flag Kuwait",
	slug: "flag_kuwait",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇰🇾": {
	name: "flag Cayman Islands",
	slug: "flag_cayman_islands",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇰🇿": {
	name: "flag Kazakhstan",
	slug: "flag_kazakhstan",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇱🇦": {
	name: "flag Laos",
	slug: "flag_laos",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇱🇧": {
	name: "flag Lebanon",
	slug: "flag_lebanon",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇱🇨": {
	name: "flag St. Lucia",
	slug: "flag_st_lucia",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇱🇮": {
	name: "flag Liechtenstein",
	slug: "flag_liechtenstein",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇱🇰": {
	name: "flag Sri Lanka",
	slug: "flag_sri_lanka",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇱🇷": {
	name: "flag Liberia",
	slug: "flag_liberia",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇱🇸": {
	name: "flag Lesotho",
	slug: "flag_lesotho",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇱🇹": {
	name: "flag Lithuania",
	slug: "flag_lithuania",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇱🇺": {
	name: "flag Luxembourg",
	slug: "flag_luxembourg",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇱🇻": {
	name: "flag Latvia",
	slug: "flag_latvia",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇱🇾": {
	name: "flag Libya",
	slug: "flag_libya",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇲🇦": {
	name: "flag Morocco",
	slug: "flag_morocco",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇲🇨": {
	name: "flag Monaco",
	slug: "flag_monaco",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇲🇩": {
	name: "flag Moldova",
	slug: "flag_moldova",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇲🇪": {
	name: "flag Montenegro",
	slug: "flag_montenegro",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇲🇫": {
	name: "flag St. Martin",
	slug: "flag_st_martin",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇲🇬": {
	name: "flag Madagascar",
	slug: "flag_madagascar",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇲🇭": {
	name: "flag Marshall Islands",
	slug: "flag_marshall_islands",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇲🇰": {
	name: "flag North Macedonia",
	slug: "flag_north_macedonia",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇲🇱": {
	name: "flag Mali",
	slug: "flag_mali",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇲🇲": {
	name: "flag Myanmar (Burma)",
	slug: "flag_myanmar",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇲🇳": {
	name: "flag Mongolia",
	slug: "flag_mongolia",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇲🇴": {
	name: "flag Macao SAR China",
	slug: "flag_macao_sar_china",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇲🇵": {
	name: "flag Northern Mariana Islands",
	slug: "flag_northern_mariana_islands",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇲🇶": {
	name: "flag Martinique",
	slug: "flag_martinique",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇲🇷": {
	name: "flag Mauritania",
	slug: "flag_mauritania",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇲🇸": {
	name: "flag Montserrat",
	slug: "flag_montserrat",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇲🇹": {
	name: "flag Malta",
	slug: "flag_malta",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇲🇺": {
	name: "flag Mauritius",
	slug: "flag_mauritius",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇲🇻": {
	name: "flag Maldives",
	slug: "flag_maldives",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇲🇼": {
	name: "flag Malawi",
	slug: "flag_malawi",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇲🇽": {
	name: "flag Mexico",
	slug: "flag_mexico",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇲🇾": {
	name: "flag Malaysia",
	slug: "flag_malaysia",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇲🇿": {
	name: "flag Mozambique",
	slug: "flag_mozambique",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇳🇦": {
	name: "flag Namibia",
	slug: "flag_namibia",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇳🇨": {
	name: "flag New Caledonia",
	slug: "flag_new_caledonia",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇳🇪": {
	name: "flag Niger",
	slug: "flag_niger",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇳🇫": {
	name: "flag Norfolk Island",
	slug: "flag_norfolk_island",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇳🇬": {
	name: "flag Nigeria",
	slug: "flag_nigeria",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇳🇮": {
	name: "flag Nicaragua",
	slug: "flag_nicaragua",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇳🇱": {
	name: "flag Netherlands",
	slug: "flag_netherlands",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇳🇴": {
	name: "flag Norway",
	slug: "flag_norway",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇳🇵": {
	name: "flag Nepal",
	slug: "flag_nepal",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇳🇷": {
	name: "flag Nauru",
	slug: "flag_nauru",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇳🇺": {
	name: "flag Niue",
	slug: "flag_niue",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇳🇿": {
	name: "flag New Zealand",
	slug: "flag_new_zealand",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇴🇲": {
	name: "flag Oman",
	slug: "flag_oman",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇵🇦": {
	name: "flag Panama",
	slug: "flag_panama",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇵🇪": {
	name: "flag Peru",
	slug: "flag_peru",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇵🇫": {
	name: "flag French Polynesia",
	slug: "flag_french_polynesia",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇵🇬": {
	name: "flag Papua New Guinea",
	slug: "flag_papua_new_guinea",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇵🇭": {
	name: "flag Philippines",
	slug: "flag_philippines",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇵🇰": {
	name: "flag Pakistan",
	slug: "flag_pakistan",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇵🇱": {
	name: "flag Poland",
	slug: "flag_poland",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇵🇲": {
	name: "flag St. Pierre & Miquelon",
	slug: "flag_st_pierre_miquelon",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇵🇳": {
	name: "flag Pitcairn Islands",
	slug: "flag_pitcairn_islands",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇵🇷": {
	name: "flag Puerto Rico",
	slug: "flag_puerto_rico",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇵🇸": {
	name: "flag Palestinian Territories",
	slug: "flag_palestinian_territories",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇵🇹": {
	name: "flag Portugal",
	slug: "flag_portugal",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇵🇼": {
	name: "flag Palau",
	slug: "flag_palau",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇵🇾": {
	name: "flag Paraguay",
	slug: "flag_paraguay",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇶🇦": {
	name: "flag Qatar",
	slug: "flag_qatar",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇷🇪": {
	name: "flag Réunion",
	slug: "flag_reunion",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇷🇴": {
	name: "flag Romania",
	slug: "flag_romania",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇷🇸": {
	name: "flag Serbia",
	slug: "flag_serbia",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇷🇺": {
	name: "flag Russia",
	slug: "flag_russia",
	group: "Flags",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🇷🇼": {
	name: "flag Rwanda",
	slug: "flag_rwanda",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇸🇦": {
	name: "flag Saudi Arabia",
	slug: "flag_saudi_arabia",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇸🇧": {
	name: "flag Solomon Islands",
	slug: "flag_solomon_islands",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇸🇨": {
	name: "flag Seychelles",
	slug: "flag_seychelles",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇸🇩": {
	name: "flag Sudan",
	slug: "flag_sudan",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇸🇪": {
	name: "flag Sweden",
	slug: "flag_sweden",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇸🇬": {
	name: "flag Singapore",
	slug: "flag_singapore",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇸🇭": {
	name: "flag St. Helena",
	slug: "flag_st_helena",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇸🇮": {
	name: "flag Slovenia",
	slug: "flag_slovenia",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇸🇯": {
	name: "flag Svalbard & Jan Mayen",
	slug: "flag_svalbard_jan_mayen",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇸🇰": {
	name: "flag Slovakia",
	slug: "flag_slovakia",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇸🇱": {
	name: "flag Sierra Leone",
	slug: "flag_sierra_leone",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇸🇲": {
	name: "flag San Marino",
	slug: "flag_san_marino",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇸🇳": {
	name: "flag Senegal",
	slug: "flag_senegal",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇸🇴": {
	name: "flag Somalia",
	slug: "flag_somalia",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇸🇷": {
	name: "flag Suriname",
	slug: "flag_suriname",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇸🇸": {
	name: "flag South Sudan",
	slug: "flag_south_sudan",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇸🇹": {
	name: "flag São Tomé & Príncipe",
	slug: "flag_sao_tome_principe",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇸🇻": {
	name: "flag El Salvador",
	slug: "flag_el_salvador",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇸🇽": {
	name: "flag Sint Maarten",
	slug: "flag_sint_maarten",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇸🇾": {
	name: "flag Syria",
	slug: "flag_syria",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇸🇿": {
	name: "flag Eswatini",
	slug: "flag_eswatini",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇹🇦": {
	name: "flag Tristan da Cunha",
	slug: "flag_tristan_da_cunha",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇹🇨": {
	name: "flag Turks & Caicos Islands",
	slug: "flag_turks_caicos_islands",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇹🇩": {
	name: "flag Chad",
	slug: "flag_chad",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇹🇫": {
	name: "flag French Southern Territories",
	slug: "flag_french_southern_territories",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇹🇬": {
	name: "flag Togo",
	slug: "flag_togo",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇹🇭": {
	name: "flag Thailand",
	slug: "flag_thailand",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇹🇯": {
	name: "flag Tajikistan",
	slug: "flag_tajikistan",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇹🇰": {
	name: "flag Tokelau",
	slug: "flag_tokelau",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇹🇱": {
	name: "flag Timor-Leste",
	slug: "flag_timor_leste",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇹🇲": {
	name: "flag Turkmenistan",
	slug: "flag_turkmenistan",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇹🇳": {
	name: "flag Tunisia",
	slug: "flag_tunisia",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇹🇴": {
	name: "flag Tonga",
	slug: "flag_tonga",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇹🇷": {
	name: "flag Turkey",
	slug: "flag_turkey",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇹🇹": {
	name: "flag Trinidad & Tobago",
	slug: "flag_trinidad_tobago",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇹🇻": {
	name: "flag Tuvalu",
	slug: "flag_tuvalu",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇹🇼": {
	name: "flag Taiwan",
	slug: "flag_taiwan",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇹🇿": {
	name: "flag Tanzania",
	slug: "flag_tanzania",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇺🇦": {
	name: "flag Ukraine",
	slug: "flag_ukraine",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇺🇬": {
	name: "flag Uganda",
	slug: "flag_uganda",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇺🇲": {
	name: "flag U.S. Outlying Islands",
	slug: "flag_u_s_outlying_islands",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇺🇳": {
	name: "flag United Nations",
	slug: "flag_united_nations",
	group: "Flags",
	emoji_version: "4.0",
	unicode_version: "4.0",
	skin_tone_support: false
},
	"🇺🇸": {
	name: "flag United States",
	slug: "flag_united_states",
	group: "Flags",
	emoji_version: "0.6",
	unicode_version: "0.6",
	skin_tone_support: false
},
	"🇺🇾": {
	name: "flag Uruguay",
	slug: "flag_uruguay",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇺🇿": {
	name: "flag Uzbekistan",
	slug: "flag_uzbekistan",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇻🇦": {
	name: "flag Vatican City",
	slug: "flag_vatican_city",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇻🇨": {
	name: "flag St. Vincent & Grenadines",
	slug: "flag_st_vincent_grenadines",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇻🇪": {
	name: "flag Venezuela",
	slug: "flag_venezuela",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇻🇬": {
	name: "flag British Virgin Islands",
	slug: "flag_british_virgin_islands",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇻🇮": {
	name: "flag U.S. Virgin Islands",
	slug: "flag_u_s_virgin_islands",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇻🇳": {
	name: "flag Vietnam",
	slug: "flag_vietnam",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇻🇺": {
	name: "flag Vanuatu",
	slug: "flag_vanuatu",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇼🇫": {
	name: "flag Wallis & Futuna",
	slug: "flag_wallis_futuna",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇼🇸": {
	name: "flag Samoa",
	slug: "flag_samoa",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇽🇰": {
	name: "flag Kosovo",
	slug: "flag_kosovo",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇾🇪": {
	name: "flag Yemen",
	slug: "flag_yemen",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇾🇹": {
	name: "flag Mayotte",
	slug: "flag_mayotte",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇿🇦": {
	name: "flag South Africa",
	slug: "flag_south_africa",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇿🇲": {
	name: "flag Zambia",
	slug: "flag_zambia",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🇿🇼": {
	name: "flag Zimbabwe",
	slug: "flag_zimbabwe",
	group: "Flags",
	emoji_version: "2.0",
	unicode_version: "2.0",
	skin_tone_support: false
},
	"🏴󠁧󠁢󠁥󠁮󠁧󠁿": {
	name: "flag England",
	slug: "flag_england",
	group: "Flags",
	emoji_version: "5.0",
	unicode_version: "5.0",
	skin_tone_support: false
},
	"🏴󠁧󠁢󠁳󠁣󠁴󠁿": {
	name: "flag Scotland",
	slug: "flag_scotland",
	group: "Flags",
	emoji_version: "5.0",
	unicode_version: "5.0",
	skin_tone_support: false
},
	"🏴󠁧󠁢󠁷󠁬󠁳󠁿": {
	name: "flag Wales",
	slug: "flag_wales",
	group: "Flags",
	emoji_version: "5.0",
	unicode_version: "5.0",
	skin_tone_support: false
}
};var Activities = [
	{
		emoji: "🎃",
		skin_tone_support: false,
		name: "jack-o-lantern",
		slug: "jack_o_lantern",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🎄",
		skin_tone_support: false,
		name: "Christmas tree",
		slug: "christmas_tree",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🎆",
		skin_tone_support: false,
		name: "fireworks",
		slug: "fireworks",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🎇",
		skin_tone_support: false,
		name: "sparkler",
		slug: "sparkler",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🧨",
		skin_tone_support: false,
		name: "firecracker",
		slug: "firecracker",
		unicode_version: "11.0",
		emoji_version: "11.0"
	},
	{
		emoji: "✨",
		skin_tone_support: false,
		name: "sparkles",
		slug: "sparkles",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🎈",
		skin_tone_support: false,
		name: "balloon",
		slug: "balloon",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🎉",
		skin_tone_support: false,
		name: "party popper",
		slug: "party_popper",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🎊",
		skin_tone_support: false,
		name: "confetti ball",
		slug: "confetti_ball",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🎋",
		skin_tone_support: false,
		name: "tanabata tree",
		slug: "tanabata_tree",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🎍",
		skin_tone_support: false,
		name: "pine decoration",
		slug: "pine_decoration",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🎎",
		skin_tone_support: false,
		name: "Japanese dolls",
		slug: "japanese_dolls",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🎏",
		skin_tone_support: false,
		name: "carp streamer",
		slug: "carp_streamer",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🎐",
		skin_tone_support: false,
		name: "wind chime",
		slug: "wind_chime",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🎑",
		skin_tone_support: false,
		name: "moon viewing ceremony",
		slug: "moon_viewing_ceremony",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🧧",
		skin_tone_support: false,
		name: "red envelope",
		slug: "red_envelope",
		unicode_version: "11.0",
		emoji_version: "11.0"
	},
	{
		emoji: "🎀",
		skin_tone_support: false,
		name: "ribbon",
		slug: "ribbon",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🎁",
		skin_tone_support: false,
		name: "wrapped gift",
		slug: "wrapped_gift",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🎗️",
		skin_tone_support: false,
		name: "reminder ribbon",
		slug: "reminder_ribbon",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🎟️",
		skin_tone_support: false,
		name: "admission tickets",
		slug: "admission_tickets",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🎫",
		skin_tone_support: false,
		name: "ticket",
		slug: "ticket",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🎖️",
		skin_tone_support: false,
		name: "military medal",
		slug: "military_medal",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🏆",
		skin_tone_support: false,
		name: "trophy",
		slug: "trophy",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🏅",
		skin_tone_support: false,
		name: "sports medal",
		slug: "sports_medal",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🥇",
		skin_tone_support: false,
		name: "1st place medal",
		slug: "1st_place_medal",
		unicode_version: "3.0",
		emoji_version: "3.0"
	},
	{
		emoji: "🥈",
		skin_tone_support: false,
		name: "2nd place medal",
		slug: "2nd_place_medal",
		unicode_version: "3.0",
		emoji_version: "3.0"
	},
	{
		emoji: "🥉",
		skin_tone_support: false,
		name: "3rd place medal",
		slug: "3rd_place_medal",
		unicode_version: "3.0",
		emoji_version: "3.0"
	},
	{
		emoji: "⚽",
		skin_tone_support: false,
		name: "soccer ball",
		slug: "soccer_ball",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "⚾",
		skin_tone_support: false,
		name: "baseball",
		slug: "baseball",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🥎",
		skin_tone_support: false,
		name: "softball",
		slug: "softball",
		unicode_version: "11.0",
		emoji_version: "11.0"
	},
	{
		emoji: "🏀",
		skin_tone_support: false,
		name: "basketball",
		slug: "basketball",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🏐",
		skin_tone_support: false,
		name: "volleyball",
		slug: "volleyball",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🏈",
		skin_tone_support: false,
		name: "american football",
		slug: "american_football",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🏉",
		skin_tone_support: false,
		name: "rugby football",
		slug: "rugby_football",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🎾",
		skin_tone_support: false,
		name: "tennis",
		slug: "tennis",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🥏",
		skin_tone_support: false,
		name: "flying disc",
		slug: "flying_disc",
		unicode_version: "11.0",
		emoji_version: "11.0"
	},
	{
		emoji: "🎳",
		skin_tone_support: false,
		name: "bowling",
		slug: "bowling",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🏏",
		skin_tone_support: false,
		name: "cricket game",
		slug: "cricket_game",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🏑",
		skin_tone_support: false,
		name: "field hockey",
		slug: "field_hockey",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🏒",
		skin_tone_support: false,
		name: "ice hockey",
		slug: "ice_hockey",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🥍",
		skin_tone_support: false,
		name: "lacrosse",
		slug: "lacrosse",
		unicode_version: "11.0",
		emoji_version: "11.0"
	},
	{
		emoji: "🏓",
		skin_tone_support: false,
		name: "ping pong",
		slug: "ping_pong",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🏸",
		skin_tone_support: false,
		name: "badminton",
		slug: "badminton",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🥊",
		skin_tone_support: false,
		name: "boxing glove",
		slug: "boxing_glove",
		unicode_version: "3.0",
		emoji_version: "3.0"
	},
	{
		emoji: "🥋",
		skin_tone_support: false,
		name: "martial arts uniform",
		slug: "martial_arts_uniform",
		unicode_version: "3.0",
		emoji_version: "3.0"
	},
	{
		emoji: "🥅",
		skin_tone_support: false,
		name: "goal net",
		slug: "goal_net",
		unicode_version: "3.0",
		emoji_version: "3.0"
	},
	{
		emoji: "⛳",
		skin_tone_support: false,
		name: "flag in hole",
		slug: "flag_in_hole",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "⛸️",
		skin_tone_support: false,
		name: "ice skate",
		slug: "ice_skate",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🎣",
		skin_tone_support: false,
		name: "fishing pole",
		slug: "fishing_pole",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🤿",
		skin_tone_support: false,
		name: "diving mask",
		slug: "diving_mask",
		unicode_version: "12.0",
		emoji_version: "12.0"
	},
	{
		emoji: "🎽",
		skin_tone_support: false,
		name: "running shirt",
		slug: "running_shirt",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🎿",
		skin_tone_support: false,
		name: "skis",
		slug: "skis",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🛷",
		skin_tone_support: false,
		name: "sled",
		slug: "sled",
		unicode_version: "5.0",
		emoji_version: "5.0"
	},
	{
		emoji: "🥌",
		skin_tone_support: false,
		name: "curling stone",
		slug: "curling_stone",
		unicode_version: "5.0",
		emoji_version: "5.0"
	},
	{
		emoji: "🎯",
		skin_tone_support: false,
		name: "bullseye",
		slug: "bullseye",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🪀",
		skin_tone_support: false,
		name: "yo-yo",
		slug: "yo_yo",
		unicode_version: "12.0",
		emoji_version: "12.0"
	},
	{
		emoji: "🪁",
		skin_tone_support: false,
		name: "kite",
		slug: "kite",
		unicode_version: "12.0",
		emoji_version: "12.0"
	},
	{
		emoji: "🔫",
		skin_tone_support: false,
		name: "water pistol",
		slug: "water_pistol",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🎱",
		skin_tone_support: false,
		name: "pool 8 ball",
		slug: "pool_8_ball",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🔮",
		skin_tone_support: false,
		name: "crystal ball",
		slug: "crystal_ball",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🪄",
		skin_tone_support: false,
		name: "magic wand",
		slug: "magic_wand",
		unicode_version: "13.0",
		emoji_version: "13.0"
	},
	{
		emoji: "🎮",
		skin_tone_support: false,
		name: "video game",
		slug: "video_game",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🕹️",
		skin_tone_support: false,
		name: "joystick",
		slug: "joystick",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🎰",
		skin_tone_support: false,
		name: "slot machine",
		slug: "slot_machine",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🎲",
		skin_tone_support: false,
		name: "game die",
		slug: "game_die",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🧩",
		skin_tone_support: false,
		name: "puzzle piece",
		slug: "puzzle_piece",
		unicode_version: "11.0",
		emoji_version: "11.0"
	},
	{
		emoji: "🧸",
		skin_tone_support: false,
		name: "teddy bear",
		slug: "teddy_bear",
		unicode_version: "11.0",
		emoji_version: "11.0"
	},
	{
		emoji: "🪅",
		skin_tone_support: false,
		name: "piñata",
		slug: "pinata",
		unicode_version: "13.0",
		emoji_version: "13.0"
	},
	{
		emoji: "🪩",
		skin_tone_support: false,
		name: "mirror ball",
		slug: "mirror_ball",
		unicode_version: "14.0",
		emoji_version: "14.0"
	},
	{
		emoji: "🪆",
		skin_tone_support: false,
		name: "nesting dolls",
		slug: "nesting_dolls",
		unicode_version: "13.0",
		emoji_version: "13.0"
	},
	{
		emoji: "♠️",
		skin_tone_support: false,
		name: "spade suit",
		slug: "spade_suit",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "♥️",
		skin_tone_support: false,
		name: "heart suit",
		slug: "heart_suit",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "♦️",
		skin_tone_support: false,
		name: "diamond suit",
		slug: "diamond_suit",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "♣️",
		skin_tone_support: false,
		name: "club suit",
		slug: "club_suit",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "♟️",
		skin_tone_support: false,
		name: "chess pawn",
		slug: "chess_pawn",
		unicode_version: "11.0",
		emoji_version: "11.0"
	},
	{
		emoji: "🃏",
		skin_tone_support: false,
		name: "joker",
		slug: "joker",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🀄",
		skin_tone_support: false,
		name: "mahjong red dragon",
		slug: "mahjong_red_dragon",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🎴",
		skin_tone_support: false,
		name: "flower playing cards",
		slug: "flower_playing_cards",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🎭",
		skin_tone_support: false,
		name: "performing arts",
		slug: "performing_arts",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🖼️",
		skin_tone_support: false,
		name: "framed picture",
		slug: "framed_picture",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🎨",
		skin_tone_support: false,
		name: "artist palette",
		slug: "artist_palette",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🧵",
		skin_tone_support: false,
		name: "thread",
		slug: "thread",
		unicode_version: "11.0",
		emoji_version: "11.0"
	},
	{
		emoji: "🪡",
		skin_tone_support: false,
		name: "sewing needle",
		slug: "sewing_needle",
		unicode_version: "13.0",
		emoji_version: "13.0"
	},
	{
		emoji: "🧶",
		skin_tone_support: false,
		name: "yarn",
		slug: "yarn",
		unicode_version: "11.0",
		emoji_version: "11.0"
	},
	{
		emoji: "🪢",
		skin_tone_support: false,
		name: "knot",
		slug: "knot",
		unicode_version: "13.0",
		emoji_version: "13.0"
	}
];
var Objects = [
	{
		emoji: "👓",
		skin_tone_support: false,
		name: "glasses",
		slug: "glasses",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🕶️",
		skin_tone_support: false,
		name: "sunglasses",
		slug: "sunglasses",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🥽",
		skin_tone_support: false,
		name: "goggles",
		slug: "goggles",
		unicode_version: "11.0",
		emoji_version: "11.0"
	},
	{
		emoji: "🥼",
		skin_tone_support: false,
		name: "lab coat",
		slug: "lab_coat",
		unicode_version: "11.0",
		emoji_version: "11.0"
	},
	{
		emoji: "🦺",
		skin_tone_support: false,
		name: "safety vest",
		slug: "safety_vest",
		unicode_version: "12.0",
		emoji_version: "12.0"
	},
	{
		emoji: "👔",
		skin_tone_support: false,
		name: "necktie",
		slug: "necktie",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "👕",
		skin_tone_support: false,
		name: "t-shirt",
		slug: "t_shirt",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "👖",
		skin_tone_support: false,
		name: "jeans",
		slug: "jeans",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🧣",
		skin_tone_support: false,
		name: "scarf",
		slug: "scarf",
		unicode_version: "5.0",
		emoji_version: "5.0"
	},
	{
		emoji: "🧤",
		skin_tone_support: false,
		name: "gloves",
		slug: "gloves",
		unicode_version: "5.0",
		emoji_version: "5.0"
	},
	{
		emoji: "🧥",
		skin_tone_support: false,
		name: "coat",
		slug: "coat",
		unicode_version: "5.0",
		emoji_version: "5.0"
	},
	{
		emoji: "🧦",
		skin_tone_support: false,
		name: "socks",
		slug: "socks",
		unicode_version: "5.0",
		emoji_version: "5.0"
	},
	{
		emoji: "👗",
		skin_tone_support: false,
		name: "dress",
		slug: "dress",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "👘",
		skin_tone_support: false,
		name: "kimono",
		slug: "kimono",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🥻",
		skin_tone_support: false,
		name: "sari",
		slug: "sari",
		unicode_version: "12.0",
		emoji_version: "12.0"
	},
	{
		emoji: "🩱",
		skin_tone_support: false,
		name: "one-piece swimsuit",
		slug: "one_piece_swimsuit",
		unicode_version: "12.0",
		emoji_version: "12.0"
	},
	{
		emoji: "🩲",
		skin_tone_support: false,
		name: "briefs",
		slug: "briefs",
		unicode_version: "12.0",
		emoji_version: "12.0"
	},
	{
		emoji: "🩳",
		skin_tone_support: false,
		name: "shorts",
		slug: "shorts",
		unicode_version: "12.0",
		emoji_version: "12.0"
	},
	{
		emoji: "👙",
		skin_tone_support: false,
		name: "bikini",
		slug: "bikini",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "👚",
		skin_tone_support: false,
		name: "woman’s clothes",
		slug: "woman_s_clothes",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🪭",
		skin_tone_support: false,
		name: "folding hand fan",
		slug: "folding_hand_fan",
		unicode_version: "15.0",
		emoji_version: "15.0"
	},
	{
		emoji: "👛",
		skin_tone_support: false,
		name: "purse",
		slug: "purse",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "👜",
		skin_tone_support: false,
		name: "handbag",
		slug: "handbag",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "👝",
		skin_tone_support: false,
		name: "clutch bag",
		slug: "clutch_bag",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🛍️",
		skin_tone_support: false,
		name: "shopping bags",
		slug: "shopping_bags",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🎒",
		skin_tone_support: false,
		name: "backpack",
		slug: "backpack",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🩴",
		skin_tone_support: false,
		name: "thong sandal",
		slug: "thong_sandal",
		unicode_version: "13.0",
		emoji_version: "13.0"
	},
	{
		emoji: "👞",
		skin_tone_support: false,
		name: "man’s shoe",
		slug: "man_s_shoe",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "👟",
		skin_tone_support: false,
		name: "running shoe",
		slug: "running_shoe",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🥾",
		skin_tone_support: false,
		name: "hiking boot",
		slug: "hiking_boot",
		unicode_version: "11.0",
		emoji_version: "11.0"
	},
	{
		emoji: "🥿",
		skin_tone_support: false,
		name: "flat shoe",
		slug: "flat_shoe",
		unicode_version: "11.0",
		emoji_version: "11.0"
	},
	{
		emoji: "👠",
		skin_tone_support: false,
		name: "high-heeled shoe",
		slug: "high_heeled_shoe",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "👡",
		skin_tone_support: false,
		name: "woman’s sandal",
		slug: "woman_s_sandal",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🩰",
		skin_tone_support: false,
		name: "ballet shoes",
		slug: "ballet_shoes",
		unicode_version: "12.0",
		emoji_version: "12.0"
	},
	{
		emoji: "👢",
		skin_tone_support: false,
		name: "woman’s boot",
		slug: "woman_s_boot",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🪮",
		skin_tone_support: false,
		name: "hair pick",
		slug: "hair_pick",
		unicode_version: "15.0",
		emoji_version: "15.0"
	},
	{
		emoji: "👑",
		skin_tone_support: false,
		name: "crown",
		slug: "crown",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "👒",
		skin_tone_support: false,
		name: "woman’s hat",
		slug: "woman_s_hat",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🎩",
		skin_tone_support: false,
		name: "top hat",
		slug: "top_hat",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🎓",
		skin_tone_support: false,
		name: "graduation cap",
		slug: "graduation_cap",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🧢",
		skin_tone_support: false,
		name: "billed cap",
		slug: "billed_cap",
		unicode_version: "5.0",
		emoji_version: "5.0"
	},
	{
		emoji: "🪖",
		skin_tone_support: false,
		name: "military helmet",
		slug: "military_helmet",
		unicode_version: "13.0",
		emoji_version: "13.0"
	},
	{
		emoji: "⛑️",
		skin_tone_support: false,
		name: "rescue worker’s helmet",
		slug: "rescue_worker_s_helmet",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "📿",
		skin_tone_support: false,
		name: "prayer beads",
		slug: "prayer_beads",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "💄",
		skin_tone_support: false,
		name: "lipstick",
		slug: "lipstick",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "💍",
		skin_tone_support: false,
		name: "ring",
		slug: "ring",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "💎",
		skin_tone_support: false,
		name: "gem stone",
		slug: "gem_stone",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🔇",
		skin_tone_support: false,
		name: "muted speaker",
		slug: "muted_speaker",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🔈",
		skin_tone_support: false,
		name: "speaker low volume",
		slug: "speaker_low_volume",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🔉",
		skin_tone_support: false,
		name: "speaker medium volume",
		slug: "speaker_medium_volume",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🔊",
		skin_tone_support: false,
		name: "speaker high volume",
		slug: "speaker_high_volume",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "📢",
		skin_tone_support: false,
		name: "loudspeaker",
		slug: "loudspeaker",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "📣",
		skin_tone_support: false,
		name: "megaphone",
		slug: "megaphone",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "📯",
		skin_tone_support: false,
		name: "postal horn",
		slug: "postal_horn",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🔔",
		skin_tone_support: false,
		name: "bell",
		slug: "bell",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🔕",
		skin_tone_support: false,
		name: "bell with slash",
		slug: "bell_with_slash",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🎼",
		skin_tone_support: false,
		name: "musical score",
		slug: "musical_score",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🎵",
		skin_tone_support: false,
		name: "musical note",
		slug: "musical_note",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🎶",
		skin_tone_support: false,
		name: "musical notes",
		slug: "musical_notes",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🎙️",
		skin_tone_support: false,
		name: "studio microphone",
		slug: "studio_microphone",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🎚️",
		skin_tone_support: false,
		name: "level slider",
		slug: "level_slider",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🎛️",
		skin_tone_support: false,
		name: "control knobs",
		slug: "control_knobs",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🎤",
		skin_tone_support: false,
		name: "microphone",
		slug: "microphone",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🎧",
		skin_tone_support: false,
		name: "headphone",
		slug: "headphone",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "📻",
		skin_tone_support: false,
		name: "radio",
		slug: "radio",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🎷",
		skin_tone_support: false,
		name: "saxophone",
		slug: "saxophone",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🪗",
		skin_tone_support: false,
		name: "accordion",
		slug: "accordion",
		unicode_version: "13.0",
		emoji_version: "13.0"
	},
	{
		emoji: "🎸",
		skin_tone_support: false,
		name: "guitar",
		slug: "guitar",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🎹",
		skin_tone_support: false,
		name: "musical keyboard",
		slug: "musical_keyboard",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🎺",
		skin_tone_support: false,
		name: "trumpet",
		slug: "trumpet",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🎻",
		skin_tone_support: false,
		name: "violin",
		slug: "violin",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🪕",
		skin_tone_support: false,
		name: "banjo",
		slug: "banjo",
		unicode_version: "12.0",
		emoji_version: "12.0"
	},
	{
		emoji: "🥁",
		skin_tone_support: false,
		name: "drum",
		slug: "drum",
		unicode_version: "3.0",
		emoji_version: "3.0"
	},
	{
		emoji: "🪘",
		skin_tone_support: false,
		name: "long drum",
		slug: "long_drum",
		unicode_version: "13.0",
		emoji_version: "13.0"
	},
	{
		emoji: "🪇",
		skin_tone_support: false,
		name: "maracas",
		slug: "maracas",
		unicode_version: "15.0",
		emoji_version: "15.0"
	},
	{
		emoji: "🪈",
		skin_tone_support: false,
		name: "flute",
		slug: "flute",
		unicode_version: "15.0",
		emoji_version: "15.0"
	},
	{
		emoji: "📱",
		skin_tone_support: false,
		name: "mobile phone",
		slug: "mobile_phone",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "📲",
		skin_tone_support: false,
		name: "mobile phone with arrow",
		slug: "mobile_phone_with_arrow",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "☎️",
		skin_tone_support: false,
		name: "telephone",
		slug: "telephone",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "📞",
		skin_tone_support: false,
		name: "telephone receiver",
		slug: "telephone_receiver",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "📟",
		skin_tone_support: false,
		name: "pager",
		slug: "pager",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "📠",
		skin_tone_support: false,
		name: "fax machine",
		slug: "fax_machine",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🔋",
		skin_tone_support: false,
		name: "battery",
		slug: "battery",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🪫",
		skin_tone_support: false,
		name: "low battery",
		slug: "low_battery",
		unicode_version: "14.0",
		emoji_version: "14.0"
	},
	{
		emoji: "🔌",
		skin_tone_support: false,
		name: "electric plug",
		slug: "electric_plug",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "💻",
		skin_tone_support: false,
		name: "laptop",
		slug: "laptop",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🖥️",
		skin_tone_support: false,
		name: "desktop computer",
		slug: "desktop_computer",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🖨️",
		skin_tone_support: false,
		name: "printer",
		slug: "printer",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "⌨️",
		skin_tone_support: false,
		name: "keyboard",
		slug: "keyboard",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🖱️",
		skin_tone_support: false,
		name: "computer mouse",
		slug: "computer_mouse",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🖲️",
		skin_tone_support: false,
		name: "trackball",
		slug: "trackball",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "💽",
		skin_tone_support: false,
		name: "computer disk",
		slug: "computer_disk",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "💾",
		skin_tone_support: false,
		name: "floppy disk",
		slug: "floppy_disk",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "💿",
		skin_tone_support: false,
		name: "optical disk",
		slug: "optical_disk",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "📀",
		skin_tone_support: false,
		name: "dvd",
		slug: "dvd",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🧮",
		skin_tone_support: false,
		name: "abacus",
		slug: "abacus",
		unicode_version: "11.0",
		emoji_version: "11.0"
	},
	{
		emoji: "🎥",
		skin_tone_support: false,
		name: "movie camera",
		slug: "movie_camera",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🎞️",
		skin_tone_support: false,
		name: "film frames",
		slug: "film_frames",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "📽️",
		skin_tone_support: false,
		name: "film projector",
		slug: "film_projector",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🎬",
		skin_tone_support: false,
		name: "clapper board",
		slug: "clapper_board",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "📺",
		skin_tone_support: false,
		name: "television",
		slug: "television",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "📷",
		skin_tone_support: false,
		name: "camera",
		slug: "camera",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "📸",
		skin_tone_support: false,
		name: "camera with flash",
		slug: "camera_with_flash",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "📹",
		skin_tone_support: false,
		name: "video camera",
		slug: "video_camera",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "📼",
		skin_tone_support: false,
		name: "videocassette",
		slug: "videocassette",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🔍",
		skin_tone_support: false,
		name: "magnifying glass tilted left",
		slug: "magnifying_glass_tilted_left",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🔎",
		skin_tone_support: false,
		name: "magnifying glass tilted right",
		slug: "magnifying_glass_tilted_right",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🕯️",
		skin_tone_support: false,
		name: "candle",
		slug: "candle",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "💡",
		skin_tone_support: false,
		name: "light bulb",
		slug: "light_bulb",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🔦",
		skin_tone_support: false,
		name: "flashlight",
		slug: "flashlight",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🏮",
		skin_tone_support: false,
		name: "red paper lantern",
		slug: "red_paper_lantern",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🪔",
		skin_tone_support: false,
		name: "diya lamp",
		slug: "diya_lamp",
		unicode_version: "12.0",
		emoji_version: "12.0"
	},
	{
		emoji: "📔",
		skin_tone_support: false,
		name: "notebook with decorative cover",
		slug: "notebook_with_decorative_cover",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "📕",
		skin_tone_support: false,
		name: "closed book",
		slug: "closed_book",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "📖",
		skin_tone_support: false,
		name: "open book",
		slug: "open_book",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "📗",
		skin_tone_support: false,
		name: "green book",
		slug: "green_book",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "📘",
		skin_tone_support: false,
		name: "blue book",
		slug: "blue_book",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "📙",
		skin_tone_support: false,
		name: "orange book",
		slug: "orange_book",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "📚",
		skin_tone_support: false,
		name: "books",
		slug: "books",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "📓",
		skin_tone_support: false,
		name: "notebook",
		slug: "notebook",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "📒",
		skin_tone_support: false,
		name: "ledger",
		slug: "ledger",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "📃",
		skin_tone_support: false,
		name: "page with curl",
		slug: "page_with_curl",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "📜",
		skin_tone_support: false,
		name: "scroll",
		slug: "scroll",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "📄",
		skin_tone_support: false,
		name: "page facing up",
		slug: "page_facing_up",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "📰",
		skin_tone_support: false,
		name: "newspaper",
		slug: "newspaper",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🗞️",
		skin_tone_support: false,
		name: "rolled-up newspaper",
		slug: "rolled_up_newspaper",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "📑",
		skin_tone_support: false,
		name: "bookmark tabs",
		slug: "bookmark_tabs",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🔖",
		skin_tone_support: false,
		name: "bookmark",
		slug: "bookmark",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🏷️",
		skin_tone_support: false,
		name: "label",
		slug: "label",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "💰",
		skin_tone_support: false,
		name: "money bag",
		slug: "money_bag",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🪙",
		skin_tone_support: false,
		name: "coin",
		slug: "coin",
		unicode_version: "13.0",
		emoji_version: "13.0"
	},
	{
		emoji: "💴",
		skin_tone_support: false,
		name: "yen banknote",
		slug: "yen_banknote",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "💵",
		skin_tone_support: false,
		name: "dollar banknote",
		slug: "dollar_banknote",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "💶",
		skin_tone_support: false,
		name: "euro banknote",
		slug: "euro_banknote",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "💷",
		skin_tone_support: false,
		name: "pound banknote",
		slug: "pound_banknote",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "💸",
		skin_tone_support: false,
		name: "money with wings",
		slug: "money_with_wings",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "💳",
		skin_tone_support: false,
		name: "credit card",
		slug: "credit_card",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🧾",
		skin_tone_support: false,
		name: "receipt",
		slug: "receipt",
		unicode_version: "11.0",
		emoji_version: "11.0"
	},
	{
		emoji: "💹",
		skin_tone_support: false,
		name: "chart increasing with yen",
		slug: "chart_increasing_with_yen",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "✉️",
		skin_tone_support: false,
		name: "envelope",
		slug: "envelope",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "📧",
		skin_tone_support: false,
		name: "e-mail",
		slug: "e_mail",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "📨",
		skin_tone_support: false,
		name: "incoming envelope",
		slug: "incoming_envelope",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "📩",
		skin_tone_support: false,
		name: "envelope with arrow",
		slug: "envelope_with_arrow",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "📤",
		skin_tone_support: false,
		name: "outbox tray",
		slug: "outbox_tray",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "📥",
		skin_tone_support: false,
		name: "inbox tray",
		slug: "inbox_tray",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "📦",
		skin_tone_support: false,
		name: "package",
		slug: "package",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "📫",
		skin_tone_support: false,
		name: "closed mailbox with raised flag",
		slug: "closed_mailbox_with_raised_flag",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "📪",
		skin_tone_support: false,
		name: "closed mailbox with lowered flag",
		slug: "closed_mailbox_with_lowered_flag",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "📬",
		skin_tone_support: false,
		name: "open mailbox with raised flag",
		slug: "open_mailbox_with_raised_flag",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "📭",
		skin_tone_support: false,
		name: "open mailbox with lowered flag",
		slug: "open_mailbox_with_lowered_flag",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "📮",
		skin_tone_support: false,
		name: "postbox",
		slug: "postbox",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🗳️",
		skin_tone_support: false,
		name: "ballot box with ballot",
		slug: "ballot_box_with_ballot",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "✏️",
		skin_tone_support: false,
		name: "pencil",
		slug: "pencil",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "✒️",
		skin_tone_support: false,
		name: "black nib",
		slug: "black_nib",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🖋️",
		skin_tone_support: false,
		name: "fountain pen",
		slug: "fountain_pen",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🖊️",
		skin_tone_support: false,
		name: "pen",
		slug: "pen",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🖌️",
		skin_tone_support: false,
		name: "paintbrush",
		slug: "paintbrush",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🖍️",
		skin_tone_support: false,
		name: "crayon",
		slug: "crayon",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "📝",
		skin_tone_support: false,
		name: "memo",
		slug: "memo",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "💼",
		skin_tone_support: false,
		name: "briefcase",
		slug: "briefcase",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "📁",
		skin_tone_support: false,
		name: "file folder",
		slug: "file_folder",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "📂",
		skin_tone_support: false,
		name: "open file folder",
		slug: "open_file_folder",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🗂️",
		skin_tone_support: false,
		name: "card index dividers",
		slug: "card_index_dividers",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "📅",
		skin_tone_support: false,
		name: "calendar",
		slug: "calendar",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "📆",
		skin_tone_support: false,
		name: "tear-off calendar",
		slug: "tear_off_calendar",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🗒️",
		skin_tone_support: false,
		name: "spiral notepad",
		slug: "spiral_notepad",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🗓️",
		skin_tone_support: false,
		name: "spiral calendar",
		slug: "spiral_calendar",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "📇",
		skin_tone_support: false,
		name: "card index",
		slug: "card_index",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "📈",
		skin_tone_support: false,
		name: "chart increasing",
		slug: "chart_increasing",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "📉",
		skin_tone_support: false,
		name: "chart decreasing",
		slug: "chart_decreasing",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "📊",
		skin_tone_support: false,
		name: "bar chart",
		slug: "bar_chart",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "📋",
		skin_tone_support: false,
		name: "clipboard",
		slug: "clipboard",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "📌",
		skin_tone_support: false,
		name: "pushpin",
		slug: "pushpin",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "📍",
		skin_tone_support: false,
		name: "round pushpin",
		slug: "round_pushpin",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "📎",
		skin_tone_support: false,
		name: "paperclip",
		slug: "paperclip",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🖇️",
		skin_tone_support: false,
		name: "linked paperclips",
		slug: "linked_paperclips",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "📏",
		skin_tone_support: false,
		name: "straight ruler",
		slug: "straight_ruler",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "📐",
		skin_tone_support: false,
		name: "triangular ruler",
		slug: "triangular_ruler",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "✂️",
		skin_tone_support: false,
		name: "scissors",
		slug: "scissors",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🗃️",
		skin_tone_support: false,
		name: "card file box",
		slug: "card_file_box",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🗄️",
		skin_tone_support: false,
		name: "file cabinet",
		slug: "file_cabinet",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🗑️",
		skin_tone_support: false,
		name: "wastebasket",
		slug: "wastebasket",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🔒",
		skin_tone_support: false,
		name: "locked",
		slug: "locked",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🔓",
		skin_tone_support: false,
		name: "unlocked",
		slug: "unlocked",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🔏",
		skin_tone_support: false,
		name: "locked with pen",
		slug: "locked_with_pen",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🔐",
		skin_tone_support: false,
		name: "locked with key",
		slug: "locked_with_key",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🔑",
		skin_tone_support: false,
		name: "key",
		slug: "key",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🗝️",
		skin_tone_support: false,
		name: "old key",
		slug: "old_key",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🔨",
		skin_tone_support: false,
		name: "hammer",
		slug: "hammer",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🪓",
		skin_tone_support: false,
		name: "axe",
		slug: "axe",
		unicode_version: "12.0",
		emoji_version: "12.0"
	},
	{
		emoji: "⛏️",
		skin_tone_support: false,
		name: "pick",
		slug: "pick",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "⚒️",
		skin_tone_support: false,
		name: "hammer and pick",
		slug: "hammer_and_pick",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🛠️",
		skin_tone_support: false,
		name: "hammer and wrench",
		slug: "hammer_and_wrench",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🗡️",
		skin_tone_support: false,
		name: "dagger",
		slug: "dagger",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "⚔️",
		skin_tone_support: false,
		name: "crossed swords",
		slug: "crossed_swords",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "💣",
		skin_tone_support: false,
		name: "bomb",
		slug: "bomb",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🪃",
		skin_tone_support: false,
		name: "boomerang",
		slug: "boomerang",
		unicode_version: "13.0",
		emoji_version: "13.0"
	},
	{
		emoji: "🏹",
		skin_tone_support: false,
		name: "bow and arrow",
		slug: "bow_and_arrow",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🛡️",
		skin_tone_support: false,
		name: "shield",
		slug: "shield",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🪚",
		skin_tone_support: false,
		name: "carpentry saw",
		slug: "carpentry_saw",
		unicode_version: "13.0",
		emoji_version: "13.0"
	},
	{
		emoji: "🔧",
		skin_tone_support: false,
		name: "wrench",
		slug: "wrench",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🪛",
		skin_tone_support: false,
		name: "screwdriver",
		slug: "screwdriver",
		unicode_version: "13.0",
		emoji_version: "13.0"
	},
	{
		emoji: "🔩",
		skin_tone_support: false,
		name: "nut and bolt",
		slug: "nut_and_bolt",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "⚙️",
		skin_tone_support: false,
		name: "gear",
		slug: "gear",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🗜️",
		skin_tone_support: false,
		name: "clamp",
		slug: "clamp",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "⚖️",
		skin_tone_support: false,
		name: "balance scale",
		slug: "balance_scale",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🦯",
		skin_tone_support: false,
		name: "white cane",
		slug: "white_cane",
		unicode_version: "12.0",
		emoji_version: "12.0"
	},
	{
		emoji: "🔗",
		skin_tone_support: false,
		name: "link",
		slug: "link",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "⛓️",
		skin_tone_support: false,
		name: "chains",
		slug: "chains",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🪝",
		skin_tone_support: false,
		name: "hook",
		slug: "hook",
		unicode_version: "13.0",
		emoji_version: "13.0"
	},
	{
		emoji: "🧰",
		skin_tone_support: false,
		name: "toolbox",
		slug: "toolbox",
		unicode_version: "11.0",
		emoji_version: "11.0"
	},
	{
		emoji: "🧲",
		skin_tone_support: false,
		name: "magnet",
		slug: "magnet",
		unicode_version: "11.0",
		emoji_version: "11.0"
	},
	{
		emoji: "🪜",
		skin_tone_support: false,
		name: "ladder",
		slug: "ladder",
		unicode_version: "13.0",
		emoji_version: "13.0"
	},
	{
		emoji: "⚗️",
		skin_tone_support: false,
		name: "alembic",
		slug: "alembic",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🧪",
		skin_tone_support: false,
		name: "test tube",
		slug: "test_tube",
		unicode_version: "11.0",
		emoji_version: "11.0"
	},
	{
		emoji: "🧫",
		skin_tone_support: false,
		name: "petri dish",
		slug: "petri_dish",
		unicode_version: "11.0",
		emoji_version: "11.0"
	},
	{
		emoji: "🧬",
		skin_tone_support: false,
		name: "dna",
		slug: "dna",
		unicode_version: "11.0",
		emoji_version: "11.0"
	},
	{
		emoji: "🔬",
		skin_tone_support: false,
		name: "microscope",
		slug: "microscope",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🔭",
		skin_tone_support: false,
		name: "telescope",
		slug: "telescope",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "📡",
		skin_tone_support: false,
		name: "satellite antenna",
		slug: "satellite_antenna",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "💉",
		skin_tone_support: false,
		name: "syringe",
		slug: "syringe",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🩸",
		skin_tone_support: false,
		name: "drop of blood",
		slug: "drop_of_blood",
		unicode_version: "12.0",
		emoji_version: "12.0"
	},
	{
		emoji: "💊",
		skin_tone_support: false,
		name: "pill",
		slug: "pill",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🩹",
		skin_tone_support: false,
		name: "adhesive bandage",
		slug: "adhesive_bandage",
		unicode_version: "12.0",
		emoji_version: "12.0"
	},
	{
		emoji: "🩼",
		skin_tone_support: false,
		name: "crutch",
		slug: "crutch",
		unicode_version: "14.0",
		emoji_version: "14.0"
	},
	{
		emoji: "🩺",
		skin_tone_support: false,
		name: "stethoscope",
		slug: "stethoscope",
		unicode_version: "12.0",
		emoji_version: "12.0"
	},
	{
		emoji: "🩻",
		skin_tone_support: false,
		name: "x-ray",
		slug: "x_ray",
		unicode_version: "14.0",
		emoji_version: "14.0"
	},
	{
		emoji: "🚪",
		skin_tone_support: false,
		name: "door",
		slug: "door",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🛗",
		skin_tone_support: false,
		name: "elevator",
		slug: "elevator",
		unicode_version: "13.0",
		emoji_version: "13.0"
	},
	{
		emoji: "🪞",
		skin_tone_support: false,
		name: "mirror",
		slug: "mirror",
		unicode_version: "13.0",
		emoji_version: "13.0"
	},
	{
		emoji: "🪟",
		skin_tone_support: false,
		name: "window",
		slug: "window",
		unicode_version: "13.0",
		emoji_version: "13.0"
	},
	{
		emoji: "🛏️",
		skin_tone_support: false,
		name: "bed",
		slug: "bed",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🛋️",
		skin_tone_support: false,
		name: "couch and lamp",
		slug: "couch_and_lamp",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🪑",
		skin_tone_support: false,
		name: "chair",
		slug: "chair",
		unicode_version: "12.0",
		emoji_version: "12.0"
	},
	{
		emoji: "🚽",
		skin_tone_support: false,
		name: "toilet",
		slug: "toilet",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🪠",
		skin_tone_support: false,
		name: "plunger",
		slug: "plunger",
		unicode_version: "13.0",
		emoji_version: "13.0"
	},
	{
		emoji: "🚿",
		skin_tone_support: false,
		name: "shower",
		slug: "shower",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🛁",
		skin_tone_support: false,
		name: "bathtub",
		slug: "bathtub",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🪤",
		skin_tone_support: false,
		name: "mouse trap",
		slug: "mouse_trap",
		unicode_version: "13.0",
		emoji_version: "13.0"
	},
	{
		emoji: "🪒",
		skin_tone_support: false,
		name: "razor",
		slug: "razor",
		unicode_version: "12.0",
		emoji_version: "12.0"
	},
	{
		emoji: "🧴",
		skin_tone_support: false,
		name: "lotion bottle",
		slug: "lotion_bottle",
		unicode_version: "11.0",
		emoji_version: "11.0"
	},
	{
		emoji: "🧷",
		skin_tone_support: false,
		name: "safety pin",
		slug: "safety_pin",
		unicode_version: "11.0",
		emoji_version: "11.0"
	},
	{
		emoji: "🧹",
		skin_tone_support: false,
		name: "broom",
		slug: "broom",
		unicode_version: "11.0",
		emoji_version: "11.0"
	},
	{
		emoji: "🧺",
		skin_tone_support: false,
		name: "basket",
		slug: "basket",
		unicode_version: "11.0",
		emoji_version: "11.0"
	},
	{
		emoji: "🧻",
		skin_tone_support: false,
		name: "roll of paper",
		slug: "roll_of_paper",
		unicode_version: "11.0",
		emoji_version: "11.0"
	},
	{
		emoji: "🪣",
		skin_tone_support: false,
		name: "bucket",
		slug: "bucket",
		unicode_version: "13.0",
		emoji_version: "13.0"
	},
	{
		emoji: "🧼",
		skin_tone_support: false,
		name: "soap",
		slug: "soap",
		unicode_version: "11.0",
		emoji_version: "11.0"
	},
	{
		emoji: "🫧",
		skin_tone_support: false,
		name: "bubbles",
		slug: "bubbles",
		unicode_version: "14.0",
		emoji_version: "14.0"
	},
	{
		emoji: "🪥",
		skin_tone_support: false,
		name: "toothbrush",
		slug: "toothbrush",
		unicode_version: "13.0",
		emoji_version: "13.0"
	},
	{
		emoji: "🧽",
		skin_tone_support: false,
		name: "sponge",
		slug: "sponge",
		unicode_version: "11.0",
		emoji_version: "11.0"
	},
	{
		emoji: "🧯",
		skin_tone_support: false,
		name: "fire extinguisher",
		slug: "fire_extinguisher",
		unicode_version: "11.0",
		emoji_version: "11.0"
	},
	{
		emoji: "🛒",
		skin_tone_support: false,
		name: "shopping cart",
		slug: "shopping_cart",
		unicode_version: "3.0",
		emoji_version: "3.0"
	},
	{
		emoji: "🚬",
		skin_tone_support: false,
		name: "cigarette",
		slug: "cigarette",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "⚰️",
		skin_tone_support: false,
		name: "coffin",
		slug: "coffin",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🪦",
		skin_tone_support: false,
		name: "headstone",
		slug: "headstone",
		unicode_version: "13.0",
		emoji_version: "13.0"
	},
	{
		emoji: "⚱️",
		skin_tone_support: false,
		name: "funeral urn",
		slug: "funeral_urn",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🧿",
		skin_tone_support: false,
		name: "nazar amulet",
		slug: "nazar_amulet",
		unicode_version: "11.0",
		emoji_version: "11.0"
	},
	{
		emoji: "🪬",
		skin_tone_support: false,
		name: "hamsa",
		slug: "hamsa",
		unicode_version: "14.0",
		emoji_version: "14.0"
	},
	{
		emoji: "🗿",
		skin_tone_support: false,
		name: "moai",
		slug: "moai",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🪧",
		skin_tone_support: false,
		name: "placard",
		slug: "placard",
		unicode_version: "13.0",
		emoji_version: "13.0"
	},
	{
		emoji: "🪪",
		skin_tone_support: false,
		name: "identification card",
		slug: "identification_card",
		unicode_version: "14.0",
		emoji_version: "14.0"
	}
];
var Symbols = [
	{
		emoji: "🏧",
		skin_tone_support: false,
		name: "ATM sign",
		slug: "atm_sign",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🚮",
		skin_tone_support: false,
		name: "litter in bin sign",
		slug: "litter_in_bin_sign",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🚰",
		skin_tone_support: false,
		name: "potable water",
		slug: "potable_water",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "♿",
		skin_tone_support: false,
		name: "wheelchair symbol",
		slug: "wheelchair_symbol",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🚹",
		skin_tone_support: false,
		name: "men’s room",
		slug: "men_s_room",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🚺",
		skin_tone_support: false,
		name: "women’s room",
		slug: "women_s_room",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🚻",
		skin_tone_support: false,
		name: "restroom",
		slug: "restroom",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🚼",
		skin_tone_support: false,
		name: "baby symbol",
		slug: "baby_symbol",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🚾",
		skin_tone_support: false,
		name: "water closet",
		slug: "water_closet",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🛂",
		skin_tone_support: false,
		name: "passport control",
		slug: "passport_control",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🛃",
		skin_tone_support: false,
		name: "customs",
		slug: "customs",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🛄",
		skin_tone_support: false,
		name: "baggage claim",
		slug: "baggage_claim",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🛅",
		skin_tone_support: false,
		name: "left luggage",
		slug: "left_luggage",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "⚠️",
		skin_tone_support: false,
		name: "warning",
		slug: "warning",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🚸",
		skin_tone_support: false,
		name: "children crossing",
		slug: "children_crossing",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "⛔",
		skin_tone_support: false,
		name: "no entry",
		slug: "no_entry",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🚫",
		skin_tone_support: false,
		name: "prohibited",
		slug: "prohibited",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🚳",
		skin_tone_support: false,
		name: "no bicycles",
		slug: "no_bicycles",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🚭",
		skin_tone_support: false,
		name: "no smoking",
		slug: "no_smoking",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🚯",
		skin_tone_support: false,
		name: "no littering",
		slug: "no_littering",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🚱",
		skin_tone_support: false,
		name: "non-potable water",
		slug: "non_potable_water",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🚷",
		skin_tone_support: false,
		name: "no pedestrians",
		slug: "no_pedestrians",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "📵",
		skin_tone_support: false,
		name: "no mobile phones",
		slug: "no_mobile_phones",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🔞",
		skin_tone_support: false,
		name: "no one under eighteen",
		slug: "no_one_under_eighteen",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "☢️",
		skin_tone_support: false,
		name: "radioactive",
		slug: "radioactive",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "☣️",
		skin_tone_support: false,
		name: "biohazard",
		slug: "biohazard",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "⬆️",
		skin_tone_support: false,
		name: "up arrow",
		slug: "up_arrow",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "↗️",
		skin_tone_support: false,
		name: "up-right arrow",
		slug: "up_right_arrow",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "➡️",
		skin_tone_support: false,
		name: "right arrow",
		slug: "right_arrow",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "↘️",
		skin_tone_support: false,
		name: "down-right arrow",
		slug: "down_right_arrow",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "⬇️",
		skin_tone_support: false,
		name: "down arrow",
		slug: "down_arrow",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "↙️",
		skin_tone_support: false,
		name: "down-left arrow",
		slug: "down_left_arrow",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "⬅️",
		skin_tone_support: false,
		name: "left arrow",
		slug: "left_arrow",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "↖️",
		skin_tone_support: false,
		name: "up-left arrow",
		slug: "up_left_arrow",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "↕️",
		skin_tone_support: false,
		name: "up-down arrow",
		slug: "up_down_arrow",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "↔️",
		skin_tone_support: false,
		name: "left-right arrow",
		slug: "left_right_arrow",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "↩️",
		skin_tone_support: false,
		name: "right arrow curving left",
		slug: "right_arrow_curving_left",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "↪️",
		skin_tone_support: false,
		name: "left arrow curving right",
		slug: "left_arrow_curving_right",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "⤴️",
		skin_tone_support: false,
		name: "right arrow curving up",
		slug: "right_arrow_curving_up",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "⤵️",
		skin_tone_support: false,
		name: "right arrow curving down",
		slug: "right_arrow_curving_down",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🔃",
		skin_tone_support: false,
		name: "clockwise vertical arrows",
		slug: "clockwise_vertical_arrows",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🔄",
		skin_tone_support: false,
		name: "counterclockwise arrows button",
		slug: "counterclockwise_arrows_button",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🔙",
		skin_tone_support: false,
		name: "BACK arrow",
		slug: "back_arrow",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🔚",
		skin_tone_support: false,
		name: "END arrow",
		slug: "end_arrow",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🔛",
		skin_tone_support: false,
		name: "ON! arrow",
		slug: "on_arrow",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🔜",
		skin_tone_support: false,
		name: "SOON arrow",
		slug: "soon_arrow",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🔝",
		skin_tone_support: false,
		name: "TOP arrow",
		slug: "top_arrow",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🛐",
		skin_tone_support: false,
		name: "place of worship",
		slug: "place_of_worship",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "⚛️",
		skin_tone_support: false,
		name: "atom symbol",
		slug: "atom_symbol",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🕉️",
		skin_tone_support: false,
		name: "om",
		slug: "om",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "✡️",
		skin_tone_support: false,
		name: "star of David",
		slug: "star_of_david",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "☸️",
		skin_tone_support: false,
		name: "wheel of dharma",
		slug: "wheel_of_dharma",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "☯️",
		skin_tone_support: false,
		name: "yin yang",
		slug: "yin_yang",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "✝️",
		skin_tone_support: false,
		name: "latin cross",
		slug: "latin_cross",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "☦️",
		skin_tone_support: false,
		name: "orthodox cross",
		slug: "orthodox_cross",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "☪️",
		skin_tone_support: false,
		name: "star and crescent",
		slug: "star_and_crescent",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "☮️",
		skin_tone_support: false,
		name: "peace symbol",
		slug: "peace_symbol",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🕎",
		skin_tone_support: false,
		name: "menorah",
		slug: "menorah",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🔯",
		skin_tone_support: false,
		name: "dotted six-pointed star",
		slug: "dotted_six_pointed_star",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🪯",
		skin_tone_support: false,
		name: "khanda",
		slug: "khanda",
		unicode_version: "15.0",
		emoji_version: "15.0"
	},
	{
		emoji: "♈",
		skin_tone_support: false,
		name: "Aries",
		slug: "aries",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "♉",
		skin_tone_support: false,
		name: "Taurus",
		slug: "taurus",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "♊",
		skin_tone_support: false,
		name: "Gemini",
		slug: "gemini",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "♋",
		skin_tone_support: false,
		name: "Cancer",
		slug: "cancer",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "♌",
		skin_tone_support: false,
		name: "Leo",
		slug: "leo",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "♍",
		skin_tone_support: false,
		name: "Virgo",
		slug: "virgo",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "♎",
		skin_tone_support: false,
		name: "Libra",
		slug: "libra",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "♏",
		skin_tone_support: false,
		name: "Scorpio",
		slug: "scorpio",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "♐",
		skin_tone_support: false,
		name: "Sagittarius",
		slug: "sagittarius",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "♑",
		skin_tone_support: false,
		name: "Capricorn",
		slug: "capricorn",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "♒",
		skin_tone_support: false,
		name: "Aquarius",
		slug: "aquarius",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "♓",
		skin_tone_support: false,
		name: "Pisces",
		slug: "pisces",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "⛎",
		skin_tone_support: false,
		name: "Ophiuchus",
		slug: "ophiuchus",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🔀",
		skin_tone_support: false,
		name: "shuffle tracks button",
		slug: "shuffle_tracks_button",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🔁",
		skin_tone_support: false,
		name: "repeat button",
		slug: "repeat_button",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🔂",
		skin_tone_support: false,
		name: "repeat single button",
		slug: "repeat_single_button",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "▶️",
		skin_tone_support: false,
		name: "play button",
		slug: "play_button",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "⏩",
		skin_tone_support: false,
		name: "fast-forward button",
		slug: "fast_forward_button",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "⏭️",
		skin_tone_support: false,
		name: "next track button",
		slug: "next_track_button",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "⏯️",
		skin_tone_support: false,
		name: "play or pause button",
		slug: "play_or_pause_button",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "◀️",
		skin_tone_support: false,
		name: "reverse button",
		slug: "reverse_button",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "⏪",
		skin_tone_support: false,
		name: "fast reverse button",
		slug: "fast_reverse_button",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "⏮️",
		skin_tone_support: false,
		name: "last track button",
		slug: "last_track_button",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🔼",
		skin_tone_support: false,
		name: "upwards button",
		slug: "upwards_button",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "⏫",
		skin_tone_support: false,
		name: "fast up button",
		slug: "fast_up_button",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🔽",
		skin_tone_support: false,
		name: "downwards button",
		slug: "downwards_button",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "⏬",
		skin_tone_support: false,
		name: "fast down button",
		slug: "fast_down_button",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "⏸️",
		skin_tone_support: false,
		name: "pause button",
		slug: "pause_button",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "⏹️",
		skin_tone_support: false,
		name: "stop button",
		slug: "stop_button",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "⏺️",
		skin_tone_support: false,
		name: "record button",
		slug: "record_button",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "⏏️",
		skin_tone_support: false,
		name: "eject button",
		slug: "eject_button",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🎦",
		skin_tone_support: false,
		name: "cinema",
		slug: "cinema",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🔅",
		skin_tone_support: false,
		name: "dim button",
		slug: "dim_button",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🔆",
		skin_tone_support: false,
		name: "bright button",
		slug: "bright_button",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "📶",
		skin_tone_support: false,
		name: "antenna bars",
		slug: "antenna_bars",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🛜",
		skin_tone_support: false,
		name: "wireless",
		slug: "wireless",
		unicode_version: "15.0",
		emoji_version: "15.0"
	},
	{
		emoji: "📳",
		skin_tone_support: false,
		name: "vibration mode",
		slug: "vibration_mode",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "📴",
		skin_tone_support: false,
		name: "mobile phone off",
		slug: "mobile_phone_off",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "♀️",
		skin_tone_support: false,
		name: "female sign",
		slug: "female_sign",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "♂️",
		skin_tone_support: false,
		name: "male sign",
		slug: "male_sign",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "⚧️",
		skin_tone_support: false,
		name: "transgender symbol",
		slug: "transgender_symbol",
		unicode_version: "13.0",
		emoji_version: "13.0"
	},
	{
		emoji: "✖️",
		skin_tone_support: false,
		name: "multiply",
		slug: "multiply",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "➕",
		skin_tone_support: false,
		name: "plus",
		slug: "plus",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "➖",
		skin_tone_support: false,
		name: "minus",
		slug: "minus",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "➗",
		skin_tone_support: false,
		name: "divide",
		slug: "divide",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🟰",
		skin_tone_support: false,
		name: "heavy equals sign",
		slug: "heavy_equals_sign",
		unicode_version: "14.0",
		emoji_version: "14.0"
	},
	{
		emoji: "♾️",
		skin_tone_support: false,
		name: "infinity",
		slug: "infinity",
		unicode_version: "11.0",
		emoji_version: "11.0"
	},
	{
		emoji: "‼️",
		skin_tone_support: false,
		name: "double exclamation mark",
		slug: "double_exclamation_mark",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "⁉️",
		skin_tone_support: false,
		name: "exclamation question mark",
		slug: "exclamation_question_mark",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "❓",
		skin_tone_support: false,
		name: "red question mark",
		slug: "red_question_mark",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "❔",
		skin_tone_support: false,
		name: "white question mark",
		slug: "white_question_mark",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "❕",
		skin_tone_support: false,
		name: "white exclamation mark",
		slug: "white_exclamation_mark",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "❗",
		skin_tone_support: false,
		name: "red exclamation mark",
		slug: "red_exclamation_mark",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "〰️",
		skin_tone_support: false,
		name: "wavy dash",
		slug: "wavy_dash",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "💱",
		skin_tone_support: false,
		name: "currency exchange",
		slug: "currency_exchange",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "💲",
		skin_tone_support: false,
		name: "heavy dollar sign",
		slug: "heavy_dollar_sign",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "⚕️",
		skin_tone_support: false,
		name: "medical symbol",
		slug: "medical_symbol",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "♻️",
		skin_tone_support: false,
		name: "recycling symbol",
		slug: "recycling_symbol",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "⚜️",
		skin_tone_support: false,
		name: "fleur-de-lis",
		slug: "fleur_de_lis",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🔱",
		skin_tone_support: false,
		name: "trident emblem",
		slug: "trident_emblem",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "📛",
		skin_tone_support: false,
		name: "name badge",
		slug: "name_badge",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🔰",
		skin_tone_support: false,
		name: "Japanese symbol for beginner",
		slug: "japanese_symbol_for_beginner",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "⭕",
		skin_tone_support: false,
		name: "hollow red circle",
		slug: "hollow_red_circle",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "✅",
		skin_tone_support: false,
		name: "check mark button",
		slug: "check_mark_button",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "☑️",
		skin_tone_support: false,
		name: "check box with check",
		slug: "check_box_with_check",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "✔️",
		skin_tone_support: false,
		name: "check mark",
		slug: "check_mark",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "❌",
		skin_tone_support: false,
		name: "cross mark",
		slug: "cross_mark",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "❎",
		skin_tone_support: false,
		name: "cross mark button",
		slug: "cross_mark_button",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "➰",
		skin_tone_support: false,
		name: "curly loop",
		slug: "curly_loop",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "➿",
		skin_tone_support: false,
		name: "double curly loop",
		slug: "double_curly_loop",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "〽️",
		skin_tone_support: false,
		name: "part alternation mark",
		slug: "part_alternation_mark",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "✳️",
		skin_tone_support: false,
		name: "eight-spoked asterisk",
		slug: "eight_spoked_asterisk",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "✴️",
		skin_tone_support: false,
		name: "eight-pointed star",
		slug: "eight_pointed_star",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "❇️",
		skin_tone_support: false,
		name: "sparkle",
		slug: "sparkle",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "©️",
		skin_tone_support: false,
		name: "copyright",
		slug: "copyright",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "®️",
		skin_tone_support: false,
		name: "registered",
		slug: "registered",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "™️",
		skin_tone_support: false,
		name: "trade mark",
		slug: "trade_mark",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "#️⃣",
		skin_tone_support: false,
		name: "keycap #",
		slug: "keycap_number_sign",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "*️⃣",
		skin_tone_support: false,
		name: "keycap *",
		slug: "keycap_asterisk",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "0️⃣",
		skin_tone_support: false,
		name: "keycap 0",
		slug: "keycap_0",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "1️⃣",
		skin_tone_support: false,
		name: "keycap 1",
		slug: "keycap_1",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "2️⃣",
		skin_tone_support: false,
		name: "keycap 2",
		slug: "keycap_2",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "3️⃣",
		skin_tone_support: false,
		name: "keycap 3",
		slug: "keycap_3",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "4️⃣",
		skin_tone_support: false,
		name: "keycap 4",
		slug: "keycap_4",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "5️⃣",
		skin_tone_support: false,
		name: "keycap 5",
		slug: "keycap_5",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "6️⃣",
		skin_tone_support: false,
		name: "keycap 6",
		slug: "keycap_6",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "7️⃣",
		skin_tone_support: false,
		name: "keycap 7",
		slug: "keycap_7",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "8️⃣",
		skin_tone_support: false,
		name: "keycap 8",
		slug: "keycap_8",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "9️⃣",
		skin_tone_support: false,
		name: "keycap 9",
		slug: "keycap_9",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🔟",
		skin_tone_support: false,
		name: "keycap 10",
		slug: "keycap_10",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🔠",
		skin_tone_support: false,
		name: "input latin uppercase",
		slug: "input_latin_uppercase",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🔡",
		skin_tone_support: false,
		name: "input latin lowercase",
		slug: "input_latin_lowercase",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🔢",
		skin_tone_support: false,
		name: "input numbers",
		slug: "input_numbers",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🔣",
		skin_tone_support: false,
		name: "input symbols",
		slug: "input_symbols",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🔤",
		skin_tone_support: false,
		name: "input latin letters",
		slug: "input_latin_letters",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🅰️",
		skin_tone_support: false,
		name: "A button (blood type)",
		slug: "a_button",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🆎",
		skin_tone_support: false,
		name: "AB button (blood type)",
		slug: "ab_button",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🅱️",
		skin_tone_support: false,
		name: "B button (blood type)",
		slug: "b_button",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🆑",
		skin_tone_support: false,
		name: "CL button",
		slug: "cl_button",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🆒",
		skin_tone_support: false,
		name: "COOL button",
		slug: "cool_button",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🆓",
		skin_tone_support: false,
		name: "FREE button",
		slug: "free_button",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "ℹ️",
		skin_tone_support: false,
		name: "information",
		slug: "information",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🆔",
		skin_tone_support: false,
		name: "ID button",
		slug: "id_button",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "Ⓜ️",
		skin_tone_support: false,
		name: "circled M",
		slug: "circled_m",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🆕",
		skin_tone_support: false,
		name: "NEW button",
		slug: "new_button",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🆖",
		skin_tone_support: false,
		name: "NG button",
		slug: "ng_button",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🅾️",
		skin_tone_support: false,
		name: "O button (blood type)",
		slug: "o_button",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🆗",
		skin_tone_support: false,
		name: "OK button",
		slug: "ok_button",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🅿️",
		skin_tone_support: false,
		name: "P button",
		slug: "p_button",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🆘",
		skin_tone_support: false,
		name: "SOS button",
		slug: "sos_button",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🆙",
		skin_tone_support: false,
		name: "UP! button",
		slug: "up_button",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🆚",
		skin_tone_support: false,
		name: "VS button",
		slug: "vs_button",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🈁",
		skin_tone_support: false,
		name: "Japanese “here” button",
		slug: "japanese_here_button",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🈂️",
		skin_tone_support: false,
		name: "Japanese “service charge” button",
		slug: "japanese_service_charge_button",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🈷️",
		skin_tone_support: false,
		name: "Japanese “monthly amount” button",
		slug: "japanese_monthly_amount_button",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🈶",
		skin_tone_support: false,
		name: "Japanese “not free of charge” button",
		slug: "japanese_not_free_of_charge_button",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🈯",
		skin_tone_support: false,
		name: "Japanese “reserved” button",
		slug: "japanese_reserved_button",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🉐",
		skin_tone_support: false,
		name: "Japanese “bargain” button",
		slug: "japanese_bargain_button",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🈹",
		skin_tone_support: false,
		name: "Japanese “discount” button",
		slug: "japanese_discount_button",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🈚",
		skin_tone_support: false,
		name: "Japanese “free of charge” button",
		slug: "japanese_free_of_charge_button",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🈲",
		skin_tone_support: false,
		name: "Japanese “prohibited” button",
		slug: "japanese_prohibited_button",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🉑",
		skin_tone_support: false,
		name: "Japanese “acceptable” button",
		slug: "japanese_acceptable_button",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🈸",
		skin_tone_support: false,
		name: "Japanese “application” button",
		slug: "japanese_application_button",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🈴",
		skin_tone_support: false,
		name: "Japanese “passing grade” button",
		slug: "japanese_passing_grade_button",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🈳",
		skin_tone_support: false,
		name: "Japanese “vacancy” button",
		slug: "japanese_vacancy_button",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "㊗️",
		skin_tone_support: false,
		name: "Japanese “congratulations” button",
		slug: "japanese_congratulations_button",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "㊙️",
		skin_tone_support: false,
		name: "Japanese “secret” button",
		slug: "japanese_secret_button",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🈺",
		skin_tone_support: false,
		name: "Japanese “open for business” button",
		slug: "japanese_open_for_business_button",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🈵",
		skin_tone_support: false,
		name: "Japanese “no vacancy” button",
		slug: "japanese_no_vacancy_button",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🔴",
		skin_tone_support: false,
		name: "red circle",
		slug: "red_circle",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🟠",
		skin_tone_support: false,
		name: "orange circle",
		slug: "orange_circle",
		unicode_version: "12.0",
		emoji_version: "12.0"
	},
	{
		emoji: "🟡",
		skin_tone_support: false,
		name: "yellow circle",
		slug: "yellow_circle",
		unicode_version: "12.0",
		emoji_version: "12.0"
	},
	{
		emoji: "🟢",
		skin_tone_support: false,
		name: "green circle",
		slug: "green_circle",
		unicode_version: "12.0",
		emoji_version: "12.0"
	},
	{
		emoji: "🔵",
		skin_tone_support: false,
		name: "blue circle",
		slug: "blue_circle",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🟣",
		skin_tone_support: false,
		name: "purple circle",
		slug: "purple_circle",
		unicode_version: "12.0",
		emoji_version: "12.0"
	},
	{
		emoji: "🟤",
		skin_tone_support: false,
		name: "brown circle",
		slug: "brown_circle",
		unicode_version: "12.0",
		emoji_version: "12.0"
	},
	{
		emoji: "⚫",
		skin_tone_support: false,
		name: "black circle",
		slug: "black_circle",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "⚪",
		skin_tone_support: false,
		name: "white circle",
		slug: "white_circle",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🟥",
		skin_tone_support: false,
		name: "red square",
		slug: "red_square",
		unicode_version: "12.0",
		emoji_version: "12.0"
	},
	{
		emoji: "🟧",
		skin_tone_support: false,
		name: "orange square",
		slug: "orange_square",
		unicode_version: "12.0",
		emoji_version: "12.0"
	},
	{
		emoji: "🟨",
		skin_tone_support: false,
		name: "yellow square",
		slug: "yellow_square",
		unicode_version: "12.0",
		emoji_version: "12.0"
	},
	{
		emoji: "🟩",
		skin_tone_support: false,
		name: "green square",
		slug: "green_square",
		unicode_version: "12.0",
		emoji_version: "12.0"
	},
	{
		emoji: "🟦",
		skin_tone_support: false,
		name: "blue square",
		slug: "blue_square",
		unicode_version: "12.0",
		emoji_version: "12.0"
	},
	{
		emoji: "🟪",
		skin_tone_support: false,
		name: "purple square",
		slug: "purple_square",
		unicode_version: "12.0",
		emoji_version: "12.0"
	},
	{
		emoji: "🟫",
		skin_tone_support: false,
		name: "brown square",
		slug: "brown_square",
		unicode_version: "12.0",
		emoji_version: "12.0"
	},
	{
		emoji: "⬛",
		skin_tone_support: false,
		name: "black large square",
		slug: "black_large_square",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "⬜",
		skin_tone_support: false,
		name: "white large square",
		slug: "white_large_square",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "◼️",
		skin_tone_support: false,
		name: "black medium square",
		slug: "black_medium_square",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "◻️",
		skin_tone_support: false,
		name: "white medium square",
		slug: "white_medium_square",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "◾",
		skin_tone_support: false,
		name: "black medium-small square",
		slug: "black_medium_small_square",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "◽",
		skin_tone_support: false,
		name: "white medium-small square",
		slug: "white_medium_small_square",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "▪️",
		skin_tone_support: false,
		name: "black small square",
		slug: "black_small_square",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "▫️",
		skin_tone_support: false,
		name: "white small square",
		slug: "white_small_square",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🔶",
		skin_tone_support: false,
		name: "large orange diamond",
		slug: "large_orange_diamond",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🔷",
		skin_tone_support: false,
		name: "large blue diamond",
		slug: "large_blue_diamond",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🔸",
		skin_tone_support: false,
		name: "small orange diamond",
		slug: "small_orange_diamond",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🔹",
		skin_tone_support: false,
		name: "small blue diamond",
		slug: "small_blue_diamond",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🔺",
		skin_tone_support: false,
		name: "red triangle pointed up",
		slug: "red_triangle_pointed_up",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🔻",
		skin_tone_support: false,
		name: "red triangle pointed down",
		slug: "red_triangle_pointed_down",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "💠",
		skin_tone_support: false,
		name: "diamond with a dot",
		slug: "diamond_with_a_dot",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🔘",
		skin_tone_support: false,
		name: "radio button",
		slug: "radio_button",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🔳",
		skin_tone_support: false,
		name: "white square button",
		slug: "white_square_button",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🔲",
		skin_tone_support: false,
		name: "black square button",
		slug: "black_square_button",
		unicode_version: "0.6",
		emoji_version: "0.6"
	}
];
var Flags = [
	{
		emoji: "🏁",
		skin_tone_support: false,
		name: "chequered flag",
		slug: "chequered_flag",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🚩",
		skin_tone_support: false,
		name: "triangular flag",
		slug: "triangular_flag",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🎌",
		skin_tone_support: false,
		name: "crossed flags",
		slug: "crossed_flags",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🏴",
		skin_tone_support: false,
		name: "black flag",
		slug: "black_flag",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🏳️",
		skin_tone_support: false,
		name: "white flag",
		slug: "white_flag",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🏳️‍🌈",
		skin_tone_support: false,
		name: "rainbow flag",
		slug: "rainbow_flag",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "🏳️‍⚧️",
		skin_tone_support: false,
		name: "transgender flag",
		slug: "transgender_flag",
		unicode_version: "13.0",
		emoji_version: "13.0"
	},
	{
		emoji: "🏴‍☠️",
		skin_tone_support: false,
		name: "pirate flag",
		slug: "pirate_flag",
		unicode_version: "11.0",
		emoji_version: "11.0"
	},
	{
		emoji: "🇦🇨",
		skin_tone_support: false,
		name: "flag Ascension Island",
		slug: "flag_ascension_island",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇦🇩",
		skin_tone_support: false,
		name: "flag Andorra",
		slug: "flag_andorra",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇦🇪",
		skin_tone_support: false,
		name: "flag United Arab Emirates",
		slug: "flag_united_arab_emirates",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇦🇫",
		skin_tone_support: false,
		name: "flag Afghanistan",
		slug: "flag_afghanistan",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇦🇬",
		skin_tone_support: false,
		name: "flag Antigua & Barbuda",
		slug: "flag_antigua_barbuda",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇦🇮",
		skin_tone_support: false,
		name: "flag Anguilla",
		slug: "flag_anguilla",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇦🇱",
		skin_tone_support: false,
		name: "flag Albania",
		slug: "flag_albania",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇦🇲",
		skin_tone_support: false,
		name: "flag Armenia",
		slug: "flag_armenia",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇦🇴",
		skin_tone_support: false,
		name: "flag Angola",
		slug: "flag_angola",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇦🇶",
		skin_tone_support: false,
		name: "flag Antarctica",
		slug: "flag_antarctica",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇦🇷",
		skin_tone_support: false,
		name: "flag Argentina",
		slug: "flag_argentina",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇦🇸",
		skin_tone_support: false,
		name: "flag American Samoa",
		slug: "flag_american_samoa",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇦🇹",
		skin_tone_support: false,
		name: "flag Austria",
		slug: "flag_austria",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇦🇺",
		skin_tone_support: false,
		name: "flag Australia",
		slug: "flag_australia",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇦🇼",
		skin_tone_support: false,
		name: "flag Aruba",
		slug: "flag_aruba",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇦🇽",
		skin_tone_support: false,
		name: "flag Åland Islands",
		slug: "flag_aland_islands",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇦🇿",
		skin_tone_support: false,
		name: "flag Azerbaijan",
		slug: "flag_azerbaijan",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇧🇦",
		skin_tone_support: false,
		name: "flag Bosnia & Herzegovina",
		slug: "flag_bosnia_herzegovina",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇧🇧",
		skin_tone_support: false,
		name: "flag Barbados",
		slug: "flag_barbados",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇧🇩",
		skin_tone_support: false,
		name: "flag Bangladesh",
		slug: "flag_bangladesh",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇧🇪",
		skin_tone_support: false,
		name: "flag Belgium",
		slug: "flag_belgium",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇧🇫",
		skin_tone_support: false,
		name: "flag Burkina Faso",
		slug: "flag_burkina_faso",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇧🇬",
		skin_tone_support: false,
		name: "flag Bulgaria",
		slug: "flag_bulgaria",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇧🇭",
		skin_tone_support: false,
		name: "flag Bahrain",
		slug: "flag_bahrain",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇧🇮",
		skin_tone_support: false,
		name: "flag Burundi",
		slug: "flag_burundi",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇧🇯",
		skin_tone_support: false,
		name: "flag Benin",
		slug: "flag_benin",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇧🇱",
		skin_tone_support: false,
		name: "flag St. Barthélemy",
		slug: "flag_st_barthelemy",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇧🇲",
		skin_tone_support: false,
		name: "flag Bermuda",
		slug: "flag_bermuda",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇧🇳",
		skin_tone_support: false,
		name: "flag Brunei",
		slug: "flag_brunei",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇧🇴",
		skin_tone_support: false,
		name: "flag Bolivia",
		slug: "flag_bolivia",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇧🇶",
		skin_tone_support: false,
		name: "flag Caribbean Netherlands",
		slug: "flag_caribbean_netherlands",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇧🇷",
		skin_tone_support: false,
		name: "flag Brazil",
		slug: "flag_brazil",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇧🇸",
		skin_tone_support: false,
		name: "flag Bahamas",
		slug: "flag_bahamas",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇧🇹",
		skin_tone_support: false,
		name: "flag Bhutan",
		slug: "flag_bhutan",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇧🇻",
		skin_tone_support: false,
		name: "flag Bouvet Island",
		slug: "flag_bouvet_island",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇧🇼",
		skin_tone_support: false,
		name: "flag Botswana",
		slug: "flag_botswana",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇧🇾",
		skin_tone_support: false,
		name: "flag Belarus",
		slug: "flag_belarus",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇧🇿",
		skin_tone_support: false,
		name: "flag Belize",
		slug: "flag_belize",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇨🇦",
		skin_tone_support: false,
		name: "flag Canada",
		slug: "flag_canada",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇨🇨",
		skin_tone_support: false,
		name: "flag Cocos (Keeling) Islands",
		slug: "flag_cocos_islands",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇨🇩",
		skin_tone_support: false,
		name: "flag Congo - Kinshasa",
		slug: "flag_congo_kinshasa",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇨🇫",
		skin_tone_support: false,
		name: "flag Central African Republic",
		slug: "flag_central_african_republic",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇨🇬",
		skin_tone_support: false,
		name: "flag Congo - Brazzaville",
		slug: "flag_congo_brazzaville",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇨🇭",
		skin_tone_support: false,
		name: "flag Switzerland",
		slug: "flag_switzerland",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇨🇮",
		skin_tone_support: false,
		name: "flag Côte d’Ivoire",
		slug: "flag_cote_d_ivoire",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇨🇰",
		skin_tone_support: false,
		name: "flag Cook Islands",
		slug: "flag_cook_islands",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇨🇱",
		skin_tone_support: false,
		name: "flag Chile",
		slug: "flag_chile",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇨🇲",
		skin_tone_support: false,
		name: "flag Cameroon",
		slug: "flag_cameroon",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇨🇳",
		skin_tone_support: false,
		name: "flag China",
		slug: "flag_china",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🇨🇴",
		skin_tone_support: false,
		name: "flag Colombia",
		slug: "flag_colombia",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇨🇵",
		skin_tone_support: false,
		name: "flag Clipperton Island",
		slug: "flag_clipperton_island",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇨🇷",
		skin_tone_support: false,
		name: "flag Costa Rica",
		slug: "flag_costa_rica",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇨🇺",
		skin_tone_support: false,
		name: "flag Cuba",
		slug: "flag_cuba",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇨🇻",
		skin_tone_support: false,
		name: "flag Cape Verde",
		slug: "flag_cape_verde",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇨🇼",
		skin_tone_support: false,
		name: "flag Curaçao",
		slug: "flag_curacao",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇨🇽",
		skin_tone_support: false,
		name: "flag Christmas Island",
		slug: "flag_christmas_island",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇨🇾",
		skin_tone_support: false,
		name: "flag Cyprus",
		slug: "flag_cyprus",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇨🇿",
		skin_tone_support: false,
		name: "flag Czechia",
		slug: "flag_czechia",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇩🇪",
		skin_tone_support: false,
		name: "flag Germany",
		slug: "flag_germany",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🇩🇬",
		skin_tone_support: false,
		name: "flag Diego Garcia",
		slug: "flag_diego_garcia",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇩🇯",
		skin_tone_support: false,
		name: "flag Djibouti",
		slug: "flag_djibouti",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇩🇰",
		skin_tone_support: false,
		name: "flag Denmark",
		slug: "flag_denmark",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇩🇲",
		skin_tone_support: false,
		name: "flag Dominica",
		slug: "flag_dominica",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇩🇴",
		skin_tone_support: false,
		name: "flag Dominican Republic",
		slug: "flag_dominican_republic",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇩🇿",
		skin_tone_support: false,
		name: "flag Algeria",
		slug: "flag_algeria",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇪🇦",
		skin_tone_support: false,
		name: "flag Ceuta & Melilla",
		slug: "flag_ceuta_melilla",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇪🇨",
		skin_tone_support: false,
		name: "flag Ecuador",
		slug: "flag_ecuador",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇪🇪",
		skin_tone_support: false,
		name: "flag Estonia",
		slug: "flag_estonia",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇪🇬",
		skin_tone_support: false,
		name: "flag Egypt",
		slug: "flag_egypt",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇪🇭",
		skin_tone_support: false,
		name: "flag Western Sahara",
		slug: "flag_western_sahara",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇪🇷",
		skin_tone_support: false,
		name: "flag Eritrea",
		slug: "flag_eritrea",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇪🇸",
		skin_tone_support: false,
		name: "flag Spain",
		slug: "flag_spain",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🇪🇹",
		skin_tone_support: false,
		name: "flag Ethiopia",
		slug: "flag_ethiopia",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇪🇺",
		skin_tone_support: false,
		name: "flag European Union",
		slug: "flag_european_union",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇫🇮",
		skin_tone_support: false,
		name: "flag Finland",
		slug: "flag_finland",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇫🇯",
		skin_tone_support: false,
		name: "flag Fiji",
		slug: "flag_fiji",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇫🇰",
		skin_tone_support: false,
		name: "flag Falkland Islands",
		slug: "flag_falkland_islands",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇫🇲",
		skin_tone_support: false,
		name: "flag Micronesia",
		slug: "flag_micronesia",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇫🇴",
		skin_tone_support: false,
		name: "flag Faroe Islands",
		slug: "flag_faroe_islands",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇫🇷",
		skin_tone_support: false,
		name: "flag France",
		slug: "flag_france",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🇬🇦",
		skin_tone_support: false,
		name: "flag Gabon",
		slug: "flag_gabon",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇬🇧",
		skin_tone_support: false,
		name: "flag United Kingdom",
		slug: "flag_united_kingdom",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🇬🇩",
		skin_tone_support: false,
		name: "flag Grenada",
		slug: "flag_grenada",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇬🇪",
		skin_tone_support: false,
		name: "flag Georgia",
		slug: "flag_georgia",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇬🇫",
		skin_tone_support: false,
		name: "flag French Guiana",
		slug: "flag_french_guiana",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇬🇬",
		skin_tone_support: false,
		name: "flag Guernsey",
		slug: "flag_guernsey",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇬🇭",
		skin_tone_support: false,
		name: "flag Ghana",
		slug: "flag_ghana",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇬🇮",
		skin_tone_support: false,
		name: "flag Gibraltar",
		slug: "flag_gibraltar",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇬🇱",
		skin_tone_support: false,
		name: "flag Greenland",
		slug: "flag_greenland",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇬🇲",
		skin_tone_support: false,
		name: "flag Gambia",
		slug: "flag_gambia",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇬🇳",
		skin_tone_support: false,
		name: "flag Guinea",
		slug: "flag_guinea",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇬🇵",
		skin_tone_support: false,
		name: "flag Guadeloupe",
		slug: "flag_guadeloupe",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇬🇶",
		skin_tone_support: false,
		name: "flag Equatorial Guinea",
		slug: "flag_equatorial_guinea",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇬🇷",
		skin_tone_support: false,
		name: "flag Greece",
		slug: "flag_greece",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇬🇸",
		skin_tone_support: false,
		name: "flag South Georgia & South Sandwich Islands",
		slug: "flag_south_georgia_south_sandwich_islands",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇬🇹",
		skin_tone_support: false,
		name: "flag Guatemala",
		slug: "flag_guatemala",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇬🇺",
		skin_tone_support: false,
		name: "flag Guam",
		slug: "flag_guam",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇬🇼",
		skin_tone_support: false,
		name: "flag Guinea-Bissau",
		slug: "flag_guinea_bissau",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇬🇾",
		skin_tone_support: false,
		name: "flag Guyana",
		slug: "flag_guyana",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇭🇰",
		skin_tone_support: false,
		name: "flag Hong Kong SAR China",
		slug: "flag_hong_kong_sar_china",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇭🇲",
		skin_tone_support: false,
		name: "flag Heard & McDonald Islands",
		slug: "flag_heard_mcdonald_islands",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇭🇳",
		skin_tone_support: false,
		name: "flag Honduras",
		slug: "flag_honduras",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇭🇷",
		skin_tone_support: false,
		name: "flag Croatia",
		slug: "flag_croatia",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇭🇹",
		skin_tone_support: false,
		name: "flag Haiti",
		slug: "flag_haiti",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇭🇺",
		skin_tone_support: false,
		name: "flag Hungary",
		slug: "flag_hungary",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇮🇨",
		skin_tone_support: false,
		name: "flag Canary Islands",
		slug: "flag_canary_islands",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇮🇩",
		skin_tone_support: false,
		name: "flag Indonesia",
		slug: "flag_indonesia",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇮🇪",
		skin_tone_support: false,
		name: "flag Ireland",
		slug: "flag_ireland",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇮🇱",
		skin_tone_support: false,
		name: "flag Israel",
		slug: "flag_israel",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇮🇲",
		skin_tone_support: false,
		name: "flag Isle of Man",
		slug: "flag_isle_of_man",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇮🇳",
		skin_tone_support: false,
		name: "flag India",
		slug: "flag_india",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇮🇴",
		skin_tone_support: false,
		name: "flag British Indian Ocean Territory",
		slug: "flag_british_indian_ocean_territory",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇮🇶",
		skin_tone_support: false,
		name: "flag Iraq",
		slug: "flag_iraq",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇮🇷",
		skin_tone_support: false,
		name: "flag Iran",
		slug: "flag_iran",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇮🇸",
		skin_tone_support: false,
		name: "flag Iceland",
		slug: "flag_iceland",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇮🇹",
		skin_tone_support: false,
		name: "flag Italy",
		slug: "flag_italy",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🇯🇪",
		skin_tone_support: false,
		name: "flag Jersey",
		slug: "flag_jersey",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇯🇲",
		skin_tone_support: false,
		name: "flag Jamaica",
		slug: "flag_jamaica",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇯🇴",
		skin_tone_support: false,
		name: "flag Jordan",
		slug: "flag_jordan",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇯🇵",
		skin_tone_support: false,
		name: "flag Japan",
		slug: "flag_japan",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🇰🇪",
		skin_tone_support: false,
		name: "flag Kenya",
		slug: "flag_kenya",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇰🇬",
		skin_tone_support: false,
		name: "flag Kyrgyzstan",
		slug: "flag_kyrgyzstan",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇰🇭",
		skin_tone_support: false,
		name: "flag Cambodia",
		slug: "flag_cambodia",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇰🇮",
		skin_tone_support: false,
		name: "flag Kiribati",
		slug: "flag_kiribati",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇰🇲",
		skin_tone_support: false,
		name: "flag Comoros",
		slug: "flag_comoros",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇰🇳",
		skin_tone_support: false,
		name: "flag St. Kitts & Nevis",
		slug: "flag_st_kitts_nevis",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇰🇵",
		skin_tone_support: false,
		name: "flag North Korea",
		slug: "flag_north_korea",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇰🇷",
		skin_tone_support: false,
		name: "flag South Korea",
		slug: "flag_south_korea",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🇰🇼",
		skin_tone_support: false,
		name: "flag Kuwait",
		slug: "flag_kuwait",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇰🇾",
		skin_tone_support: false,
		name: "flag Cayman Islands",
		slug: "flag_cayman_islands",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇰🇿",
		skin_tone_support: false,
		name: "flag Kazakhstan",
		slug: "flag_kazakhstan",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇱🇦",
		skin_tone_support: false,
		name: "flag Laos",
		slug: "flag_laos",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇱🇧",
		skin_tone_support: false,
		name: "flag Lebanon",
		slug: "flag_lebanon",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇱🇨",
		skin_tone_support: false,
		name: "flag St. Lucia",
		slug: "flag_st_lucia",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇱🇮",
		skin_tone_support: false,
		name: "flag Liechtenstein",
		slug: "flag_liechtenstein",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇱🇰",
		skin_tone_support: false,
		name: "flag Sri Lanka",
		slug: "flag_sri_lanka",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇱🇷",
		skin_tone_support: false,
		name: "flag Liberia",
		slug: "flag_liberia",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇱🇸",
		skin_tone_support: false,
		name: "flag Lesotho",
		slug: "flag_lesotho",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇱🇹",
		skin_tone_support: false,
		name: "flag Lithuania",
		slug: "flag_lithuania",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇱🇺",
		skin_tone_support: false,
		name: "flag Luxembourg",
		slug: "flag_luxembourg",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇱🇻",
		skin_tone_support: false,
		name: "flag Latvia",
		slug: "flag_latvia",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇱🇾",
		skin_tone_support: false,
		name: "flag Libya",
		slug: "flag_libya",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇲🇦",
		skin_tone_support: false,
		name: "flag Morocco",
		slug: "flag_morocco",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇲🇨",
		skin_tone_support: false,
		name: "flag Monaco",
		slug: "flag_monaco",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇲🇩",
		skin_tone_support: false,
		name: "flag Moldova",
		slug: "flag_moldova",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇲🇪",
		skin_tone_support: false,
		name: "flag Montenegro",
		slug: "flag_montenegro",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇲🇫",
		skin_tone_support: false,
		name: "flag St. Martin",
		slug: "flag_st_martin",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇲🇬",
		skin_tone_support: false,
		name: "flag Madagascar",
		slug: "flag_madagascar",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇲🇭",
		skin_tone_support: false,
		name: "flag Marshall Islands",
		slug: "flag_marshall_islands",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇲🇰",
		skin_tone_support: false,
		name: "flag North Macedonia",
		slug: "flag_north_macedonia",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇲🇱",
		skin_tone_support: false,
		name: "flag Mali",
		slug: "flag_mali",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇲🇲",
		skin_tone_support: false,
		name: "flag Myanmar (Burma)",
		slug: "flag_myanmar",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇲🇳",
		skin_tone_support: false,
		name: "flag Mongolia",
		slug: "flag_mongolia",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇲🇴",
		skin_tone_support: false,
		name: "flag Macao SAR China",
		slug: "flag_macao_sar_china",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇲🇵",
		skin_tone_support: false,
		name: "flag Northern Mariana Islands",
		slug: "flag_northern_mariana_islands",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇲🇶",
		skin_tone_support: false,
		name: "flag Martinique",
		slug: "flag_martinique",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇲🇷",
		skin_tone_support: false,
		name: "flag Mauritania",
		slug: "flag_mauritania",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇲🇸",
		skin_tone_support: false,
		name: "flag Montserrat",
		slug: "flag_montserrat",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇲🇹",
		skin_tone_support: false,
		name: "flag Malta",
		slug: "flag_malta",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇲🇺",
		skin_tone_support: false,
		name: "flag Mauritius",
		slug: "flag_mauritius",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇲🇻",
		skin_tone_support: false,
		name: "flag Maldives",
		slug: "flag_maldives",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇲🇼",
		skin_tone_support: false,
		name: "flag Malawi",
		slug: "flag_malawi",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇲🇽",
		skin_tone_support: false,
		name: "flag Mexico",
		slug: "flag_mexico",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇲🇾",
		skin_tone_support: false,
		name: "flag Malaysia",
		slug: "flag_malaysia",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇲🇿",
		skin_tone_support: false,
		name: "flag Mozambique",
		slug: "flag_mozambique",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇳🇦",
		skin_tone_support: false,
		name: "flag Namibia",
		slug: "flag_namibia",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇳🇨",
		skin_tone_support: false,
		name: "flag New Caledonia",
		slug: "flag_new_caledonia",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇳🇪",
		skin_tone_support: false,
		name: "flag Niger",
		slug: "flag_niger",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇳🇫",
		skin_tone_support: false,
		name: "flag Norfolk Island",
		slug: "flag_norfolk_island",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇳🇬",
		skin_tone_support: false,
		name: "flag Nigeria",
		slug: "flag_nigeria",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇳🇮",
		skin_tone_support: false,
		name: "flag Nicaragua",
		slug: "flag_nicaragua",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇳🇱",
		skin_tone_support: false,
		name: "flag Netherlands",
		slug: "flag_netherlands",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇳🇴",
		skin_tone_support: false,
		name: "flag Norway",
		slug: "flag_norway",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇳🇵",
		skin_tone_support: false,
		name: "flag Nepal",
		slug: "flag_nepal",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇳🇷",
		skin_tone_support: false,
		name: "flag Nauru",
		slug: "flag_nauru",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇳🇺",
		skin_tone_support: false,
		name: "flag Niue",
		slug: "flag_niue",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇳🇿",
		skin_tone_support: false,
		name: "flag New Zealand",
		slug: "flag_new_zealand",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇴🇲",
		skin_tone_support: false,
		name: "flag Oman",
		slug: "flag_oman",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇵🇦",
		skin_tone_support: false,
		name: "flag Panama",
		slug: "flag_panama",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇵🇪",
		skin_tone_support: false,
		name: "flag Peru",
		slug: "flag_peru",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇵🇫",
		skin_tone_support: false,
		name: "flag French Polynesia",
		slug: "flag_french_polynesia",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇵🇬",
		skin_tone_support: false,
		name: "flag Papua New Guinea",
		slug: "flag_papua_new_guinea",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇵🇭",
		skin_tone_support: false,
		name: "flag Philippines",
		slug: "flag_philippines",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇵🇰",
		skin_tone_support: false,
		name: "flag Pakistan",
		slug: "flag_pakistan",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇵🇱",
		skin_tone_support: false,
		name: "flag Poland",
		slug: "flag_poland",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇵🇲",
		skin_tone_support: false,
		name: "flag St. Pierre & Miquelon",
		slug: "flag_st_pierre_miquelon",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇵🇳",
		skin_tone_support: false,
		name: "flag Pitcairn Islands",
		slug: "flag_pitcairn_islands",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇵🇷",
		skin_tone_support: false,
		name: "flag Puerto Rico",
		slug: "flag_puerto_rico",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇵🇸",
		skin_tone_support: false,
		name: "flag Palestinian Territories",
		slug: "flag_palestinian_territories",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇵🇹",
		skin_tone_support: false,
		name: "flag Portugal",
		slug: "flag_portugal",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇵🇼",
		skin_tone_support: false,
		name: "flag Palau",
		slug: "flag_palau",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇵🇾",
		skin_tone_support: false,
		name: "flag Paraguay",
		slug: "flag_paraguay",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇶🇦",
		skin_tone_support: false,
		name: "flag Qatar",
		slug: "flag_qatar",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇷🇪",
		skin_tone_support: false,
		name: "flag Réunion",
		slug: "flag_reunion",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇷🇴",
		skin_tone_support: false,
		name: "flag Romania",
		slug: "flag_romania",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇷🇸",
		skin_tone_support: false,
		name: "flag Serbia",
		slug: "flag_serbia",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇷🇺",
		skin_tone_support: false,
		name: "flag Russia",
		slug: "flag_russia",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🇷🇼",
		skin_tone_support: false,
		name: "flag Rwanda",
		slug: "flag_rwanda",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇸🇦",
		skin_tone_support: false,
		name: "flag Saudi Arabia",
		slug: "flag_saudi_arabia",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇸🇧",
		skin_tone_support: false,
		name: "flag Solomon Islands",
		slug: "flag_solomon_islands",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇸🇨",
		skin_tone_support: false,
		name: "flag Seychelles",
		slug: "flag_seychelles",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇸🇩",
		skin_tone_support: false,
		name: "flag Sudan",
		slug: "flag_sudan",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇸🇪",
		skin_tone_support: false,
		name: "flag Sweden",
		slug: "flag_sweden",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇸🇬",
		skin_tone_support: false,
		name: "flag Singapore",
		slug: "flag_singapore",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇸🇭",
		skin_tone_support: false,
		name: "flag St. Helena",
		slug: "flag_st_helena",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇸🇮",
		skin_tone_support: false,
		name: "flag Slovenia",
		slug: "flag_slovenia",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇸🇯",
		skin_tone_support: false,
		name: "flag Svalbard & Jan Mayen",
		slug: "flag_svalbard_jan_mayen",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇸🇰",
		skin_tone_support: false,
		name: "flag Slovakia",
		slug: "flag_slovakia",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇸🇱",
		skin_tone_support: false,
		name: "flag Sierra Leone",
		slug: "flag_sierra_leone",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇸🇲",
		skin_tone_support: false,
		name: "flag San Marino",
		slug: "flag_san_marino",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇸🇳",
		skin_tone_support: false,
		name: "flag Senegal",
		slug: "flag_senegal",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇸🇴",
		skin_tone_support: false,
		name: "flag Somalia",
		slug: "flag_somalia",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇸🇷",
		skin_tone_support: false,
		name: "flag Suriname",
		slug: "flag_suriname",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇸🇸",
		skin_tone_support: false,
		name: "flag South Sudan",
		slug: "flag_south_sudan",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇸🇹",
		skin_tone_support: false,
		name: "flag São Tomé & Príncipe",
		slug: "flag_sao_tome_principe",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇸🇻",
		skin_tone_support: false,
		name: "flag El Salvador",
		slug: "flag_el_salvador",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇸🇽",
		skin_tone_support: false,
		name: "flag Sint Maarten",
		slug: "flag_sint_maarten",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇸🇾",
		skin_tone_support: false,
		name: "flag Syria",
		slug: "flag_syria",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇸🇿",
		skin_tone_support: false,
		name: "flag Eswatini",
		slug: "flag_eswatini",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇹🇦",
		skin_tone_support: false,
		name: "flag Tristan da Cunha",
		slug: "flag_tristan_da_cunha",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇹🇨",
		skin_tone_support: false,
		name: "flag Turks & Caicos Islands",
		slug: "flag_turks_caicos_islands",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇹🇩",
		skin_tone_support: false,
		name: "flag Chad",
		slug: "flag_chad",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇹🇫",
		skin_tone_support: false,
		name: "flag French Southern Territories",
		slug: "flag_french_southern_territories",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇹🇬",
		skin_tone_support: false,
		name: "flag Togo",
		slug: "flag_togo",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇹🇭",
		skin_tone_support: false,
		name: "flag Thailand",
		slug: "flag_thailand",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇹🇯",
		skin_tone_support: false,
		name: "flag Tajikistan",
		slug: "flag_tajikistan",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇹🇰",
		skin_tone_support: false,
		name: "flag Tokelau",
		slug: "flag_tokelau",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇹🇱",
		skin_tone_support: false,
		name: "flag Timor-Leste",
		slug: "flag_timor_leste",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇹🇲",
		skin_tone_support: false,
		name: "flag Turkmenistan",
		slug: "flag_turkmenistan",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇹🇳",
		skin_tone_support: false,
		name: "flag Tunisia",
		slug: "flag_tunisia",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇹🇴",
		skin_tone_support: false,
		name: "flag Tonga",
		slug: "flag_tonga",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇹🇷",
		skin_tone_support: false,
		name: "flag Turkey",
		slug: "flag_turkey",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇹🇹",
		skin_tone_support: false,
		name: "flag Trinidad & Tobago",
		slug: "flag_trinidad_tobago",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇹🇻",
		skin_tone_support: false,
		name: "flag Tuvalu",
		slug: "flag_tuvalu",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇹🇼",
		skin_tone_support: false,
		name: "flag Taiwan",
		slug: "flag_taiwan",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇹🇿",
		skin_tone_support: false,
		name: "flag Tanzania",
		slug: "flag_tanzania",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇺🇦",
		skin_tone_support: false,
		name: "flag Ukraine",
		slug: "flag_ukraine",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇺🇬",
		skin_tone_support: false,
		name: "flag Uganda",
		slug: "flag_uganda",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇺🇲",
		skin_tone_support: false,
		name: "flag U.S. Outlying Islands",
		slug: "flag_u_s_outlying_islands",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇺🇳",
		skin_tone_support: false,
		name: "flag United Nations",
		slug: "flag_united_nations",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "🇺🇸",
		skin_tone_support: false,
		name: "flag United States",
		slug: "flag_united_states",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🇺🇾",
		skin_tone_support: false,
		name: "flag Uruguay",
		slug: "flag_uruguay",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇺🇿",
		skin_tone_support: false,
		name: "flag Uzbekistan",
		slug: "flag_uzbekistan",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇻🇦",
		skin_tone_support: false,
		name: "flag Vatican City",
		slug: "flag_vatican_city",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇻🇨",
		skin_tone_support: false,
		name: "flag St. Vincent & Grenadines",
		slug: "flag_st_vincent_grenadines",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇻🇪",
		skin_tone_support: false,
		name: "flag Venezuela",
		slug: "flag_venezuela",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇻🇬",
		skin_tone_support: false,
		name: "flag British Virgin Islands",
		slug: "flag_british_virgin_islands",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇻🇮",
		skin_tone_support: false,
		name: "flag U.S. Virgin Islands",
		slug: "flag_u_s_virgin_islands",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇻🇳",
		skin_tone_support: false,
		name: "flag Vietnam",
		slug: "flag_vietnam",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇻🇺",
		skin_tone_support: false,
		name: "flag Vanuatu",
		slug: "flag_vanuatu",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇼🇫",
		skin_tone_support: false,
		name: "flag Wallis & Futuna",
		slug: "flag_wallis_futuna",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇼🇸",
		skin_tone_support: false,
		name: "flag Samoa",
		slug: "flag_samoa",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇽🇰",
		skin_tone_support: false,
		name: "flag Kosovo",
		slug: "flag_kosovo",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇾🇪",
		skin_tone_support: false,
		name: "flag Yemen",
		slug: "flag_yemen",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇾🇹",
		skin_tone_support: false,
		name: "flag Mayotte",
		slug: "flag_mayotte",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇿🇦",
		skin_tone_support: false,
		name: "flag South Africa",
		slug: "flag_south_africa",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇿🇲",
		skin_tone_support: false,
		name: "flag Zambia",
		slug: "flag_zambia",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🇿🇼",
		skin_tone_support: false,
		name: "flag Zimbabwe",
		slug: "flag_zimbabwe",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🏴󠁧󠁢󠁥󠁮󠁧󠁿",
		skin_tone_support: false,
		name: "flag England",
		slug: "flag_england",
		unicode_version: "5.0",
		emoji_version: "5.0"
	},
	{
		emoji: "🏴󠁧󠁢󠁳󠁣󠁴󠁿",
		skin_tone_support: false,
		name: "flag Scotland",
		slug: "flag_scotland",
		unicode_version: "5.0",
		emoji_version: "5.0"
	},
	{
		emoji: "🏴󠁧󠁢󠁷󠁬󠁳󠁿",
		skin_tone_support: false,
		name: "flag Wales",
		slug: "flag_wales",
		unicode_version: "5.0",
		emoji_version: "5.0"
	}
];
var groupedEmojiData = {
	"Smileys & Emotion": [
	{
		emoji: "😀",
		skin_tone_support: false,
		name: "grinning face",
		slug: "grinning_face",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "😃",
		skin_tone_support: false,
		name: "grinning face with big eyes",
		slug: "grinning_face_with_big_eyes",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "😄",
		skin_tone_support: false,
		name: "grinning face with smiling eyes",
		slug: "grinning_face_with_smiling_eyes",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "😁",
		skin_tone_support: false,
		name: "beaming face with smiling eyes",
		slug: "beaming_face_with_smiling_eyes",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "😆",
		skin_tone_support: false,
		name: "grinning squinting face",
		slug: "grinning_squinting_face",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "😅",
		skin_tone_support: false,
		name: "grinning face with sweat",
		slug: "grinning_face_with_sweat",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🤣",
		skin_tone_support: false,
		name: "rolling on the floor laughing",
		slug: "rolling_on_the_floor_laughing",
		unicode_version: "3.0",
		emoji_version: "3.0"
	},
	{
		emoji: "😂",
		skin_tone_support: false,
		name: "face with tears of joy",
		slug: "face_with_tears_of_joy",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🙂",
		skin_tone_support: false,
		name: "slightly smiling face",
		slug: "slightly_smiling_face",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🙃",
		skin_tone_support: false,
		name: "upside-down face",
		slug: "upside_down_face",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🫠",
		skin_tone_support: false,
		name: "melting face",
		slug: "melting_face",
		unicode_version: "14.0",
		emoji_version: "14.0"
	},
	{
		emoji: "😉",
		skin_tone_support: false,
		name: "winking face",
		slug: "winking_face",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "😊",
		skin_tone_support: false,
		name: "smiling face with smiling eyes",
		slug: "smiling_face_with_smiling_eyes",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "😇",
		skin_tone_support: false,
		name: "smiling face with halo",
		slug: "smiling_face_with_halo",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🥰",
		skin_tone_support: false,
		name: "smiling face with hearts",
		slug: "smiling_face_with_hearts",
		unicode_version: "11.0",
		emoji_version: "11.0"
	},
	{
		emoji: "😍",
		skin_tone_support: false,
		name: "smiling face with heart-eyes",
		slug: "smiling_face_with_heart_eyes",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🤩",
		skin_tone_support: false,
		name: "star-struck",
		slug: "star_struck",
		unicode_version: "5.0",
		emoji_version: "5.0"
	},
	{
		emoji: "😘",
		skin_tone_support: false,
		name: "face blowing a kiss",
		slug: "face_blowing_a_kiss",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "😗",
		skin_tone_support: false,
		name: "kissing face",
		slug: "kissing_face",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "☺️",
		skin_tone_support: false,
		name: "smiling face",
		slug: "smiling_face",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "😚",
		skin_tone_support: false,
		name: "kissing face with closed eyes",
		slug: "kissing_face_with_closed_eyes",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "😙",
		skin_tone_support: false,
		name: "kissing face with smiling eyes",
		slug: "kissing_face_with_smiling_eyes",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🥲",
		skin_tone_support: false,
		name: "smiling face with tear",
		slug: "smiling_face_with_tear",
		unicode_version: "13.0",
		emoji_version: "13.0"
	},
	{
		emoji: "😋",
		skin_tone_support: false,
		name: "face savoring food",
		slug: "face_savoring_food",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "😛",
		skin_tone_support: false,
		name: "face with tongue",
		slug: "face_with_tongue",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "😜",
		skin_tone_support: false,
		name: "winking face with tongue",
		slug: "winking_face_with_tongue",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🤪",
		skin_tone_support: false,
		name: "zany face",
		slug: "zany_face",
		unicode_version: "5.0",
		emoji_version: "5.0"
	},
	{
		emoji: "😝",
		skin_tone_support: false,
		name: "squinting face with tongue",
		slug: "squinting_face_with_tongue",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🤑",
		skin_tone_support: false,
		name: "money-mouth face",
		slug: "money_mouth_face",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🤗",
		skin_tone_support: false,
		name: "smiling face with open hands",
		slug: "smiling_face_with_open_hands",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🤭",
		skin_tone_support: false,
		name: "face with hand over mouth",
		slug: "face_with_hand_over_mouth",
		unicode_version: "5.0",
		emoji_version: "5.0"
	},
	{
		emoji: "🫢",
		skin_tone_support: false,
		name: "face with open eyes and hand over mouth",
		slug: "face_with_open_eyes_and_hand_over_mouth",
		unicode_version: "14.0",
		emoji_version: "14.0"
	},
	{
		emoji: "🫣",
		skin_tone_support: false,
		name: "face with peeking eye",
		slug: "face_with_peeking_eye",
		unicode_version: "14.0",
		emoji_version: "14.0"
	},
	{
		emoji: "🤫",
		skin_tone_support: false,
		name: "shushing face",
		slug: "shushing_face",
		unicode_version: "5.0",
		emoji_version: "5.0"
	},
	{
		emoji: "🤔",
		skin_tone_support: false,
		name: "thinking face",
		slug: "thinking_face",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🫡",
		skin_tone_support: false,
		name: "saluting face",
		slug: "saluting_face",
		unicode_version: "14.0",
		emoji_version: "14.0"
	},
	{
		emoji: "🤐",
		skin_tone_support: false,
		name: "zipper-mouth face",
		slug: "zipper_mouth_face",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🤨",
		skin_tone_support: false,
		name: "face with raised eyebrow",
		slug: "face_with_raised_eyebrow",
		unicode_version: "5.0",
		emoji_version: "5.0"
	},
	{
		emoji: "😐",
		skin_tone_support: false,
		name: "neutral face",
		slug: "neutral_face",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "😑",
		skin_tone_support: false,
		name: "expressionless face",
		slug: "expressionless_face",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "😶",
		skin_tone_support: false,
		name: "face without mouth",
		slug: "face_without_mouth",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🫥",
		skin_tone_support: false,
		name: "dotted line face",
		slug: "dotted_line_face",
		unicode_version: "14.0",
		emoji_version: "14.0"
	},
	{
		emoji: "😶‍🌫️",
		skin_tone_support: false,
		name: "face in clouds",
		slug: "face_in_clouds",
		unicode_version: "13.1",
		emoji_version: "13.1"
	},
	{
		emoji: "😏",
		skin_tone_support: false,
		name: "smirking face",
		slug: "smirking_face",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "😒",
		skin_tone_support: false,
		name: "unamused face",
		slug: "unamused_face",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🙄",
		skin_tone_support: false,
		name: "face with rolling eyes",
		slug: "face_with_rolling_eyes",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "😬",
		skin_tone_support: false,
		name: "grimacing face",
		slug: "grimacing_face",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "😮‍💨",
		skin_tone_support: false,
		name: "face exhaling",
		slug: "face_exhaling",
		unicode_version: "13.1",
		emoji_version: "13.1"
	},
	{
		emoji: "🤥",
		skin_tone_support: false,
		name: "lying face",
		slug: "lying_face",
		unicode_version: "3.0",
		emoji_version: "3.0"
	},
	{
		emoji: "🫨",
		skin_tone_support: false,
		name: "shaking face",
		slug: "shaking_face",
		unicode_version: "15.0",
		emoji_version: "15.0"
	},
	{
		emoji: "😌",
		skin_tone_support: false,
		name: "relieved face",
		slug: "relieved_face",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "😔",
		skin_tone_support: false,
		name: "pensive face",
		slug: "pensive_face",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "😪",
		skin_tone_support: false,
		name: "sleepy face",
		slug: "sleepy_face",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🤤",
		skin_tone_support: false,
		name: "drooling face",
		slug: "drooling_face",
		unicode_version: "3.0",
		emoji_version: "3.0"
	},
	{
		emoji: "😴",
		skin_tone_support: false,
		name: "sleeping face",
		slug: "sleeping_face",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "😷",
		skin_tone_support: false,
		name: "face with medical mask",
		slug: "face_with_medical_mask",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🤒",
		skin_tone_support: false,
		name: "face with thermometer",
		slug: "face_with_thermometer",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🤕",
		skin_tone_support: false,
		name: "face with head-bandage",
		slug: "face_with_head_bandage",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🤢",
		skin_tone_support: false,
		name: "nauseated face",
		slug: "nauseated_face",
		unicode_version: "3.0",
		emoji_version: "3.0"
	},
	{
		emoji: "🤮",
		skin_tone_support: false,
		name: "face vomiting",
		slug: "face_vomiting",
		unicode_version: "5.0",
		emoji_version: "5.0"
	},
	{
		emoji: "🤧",
		skin_tone_support: false,
		name: "sneezing face",
		slug: "sneezing_face",
		unicode_version: "3.0",
		emoji_version: "3.0"
	},
	{
		emoji: "🥵",
		skin_tone_support: false,
		name: "hot face",
		slug: "hot_face",
		unicode_version: "11.0",
		emoji_version: "11.0"
	},
	{
		emoji: "🥶",
		skin_tone_support: false,
		name: "cold face",
		slug: "cold_face",
		unicode_version: "11.0",
		emoji_version: "11.0"
	},
	{
		emoji: "🥴",
		skin_tone_support: false,
		name: "woozy face",
		slug: "woozy_face",
		unicode_version: "11.0",
		emoji_version: "11.0"
	},
	{
		emoji: "😵",
		skin_tone_support: false,
		name: "face with crossed-out eyes",
		slug: "face_with_crossed_out_eyes",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "😵‍💫",
		skin_tone_support: false,
		name: "face with spiral eyes",
		slug: "face_with_spiral_eyes",
		unicode_version: "13.1",
		emoji_version: "13.1"
	},
	{
		emoji: "🤯",
		skin_tone_support: false,
		name: "exploding head",
		slug: "exploding_head",
		unicode_version: "5.0",
		emoji_version: "5.0"
	},
	{
		emoji: "🤠",
		skin_tone_support: false,
		name: "cowboy hat face",
		slug: "cowboy_hat_face",
		unicode_version: "3.0",
		emoji_version: "3.0"
	},
	{
		emoji: "🥳",
		skin_tone_support: false,
		name: "partying face",
		slug: "partying_face",
		unicode_version: "11.0",
		emoji_version: "11.0"
	},
	{
		emoji: "🥸",
		skin_tone_support: false,
		name: "disguised face",
		slug: "disguised_face",
		unicode_version: "13.0",
		emoji_version: "13.0"
	},
	{
		emoji: "😎",
		skin_tone_support: false,
		name: "smiling face with sunglasses",
		slug: "smiling_face_with_sunglasses",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🤓",
		skin_tone_support: false,
		name: "nerd face",
		slug: "nerd_face",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🧐",
		skin_tone_support: false,
		name: "face with monocle",
		slug: "face_with_monocle",
		unicode_version: "5.0",
		emoji_version: "5.0"
	},
	{
		emoji: "😕",
		skin_tone_support: false,
		name: "confused face",
		slug: "confused_face",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🫤",
		skin_tone_support: false,
		name: "face with diagonal mouth",
		slug: "face_with_diagonal_mouth",
		unicode_version: "14.0",
		emoji_version: "14.0"
	},
	{
		emoji: "😟",
		skin_tone_support: false,
		name: "worried face",
		slug: "worried_face",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🙁",
		skin_tone_support: false,
		name: "slightly frowning face",
		slug: "slightly_frowning_face",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "☹️",
		skin_tone_support: false,
		name: "frowning face",
		slug: "frowning_face",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "😮",
		skin_tone_support: false,
		name: "face with open mouth",
		slug: "face_with_open_mouth",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "😯",
		skin_tone_support: false,
		name: "hushed face",
		slug: "hushed_face",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "😲",
		skin_tone_support: false,
		name: "astonished face",
		slug: "astonished_face",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "😳",
		skin_tone_support: false,
		name: "flushed face",
		slug: "flushed_face",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🥺",
		skin_tone_support: false,
		name: "pleading face",
		slug: "pleading_face",
		unicode_version: "11.0",
		emoji_version: "11.0"
	},
	{
		emoji: "🥹",
		skin_tone_support: false,
		name: "face holding back tears",
		slug: "face_holding_back_tears",
		unicode_version: "14.0",
		emoji_version: "14.0"
	},
	{
		emoji: "😦",
		skin_tone_support: false,
		name: "frowning face with open mouth",
		slug: "frowning_face_with_open_mouth",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "😧",
		skin_tone_support: false,
		name: "anguished face",
		slug: "anguished_face",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "😨",
		skin_tone_support: false,
		name: "fearful face",
		slug: "fearful_face",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "😰",
		skin_tone_support: false,
		name: "anxious face with sweat",
		slug: "anxious_face_with_sweat",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "😥",
		skin_tone_support: false,
		name: "sad but relieved face",
		slug: "sad_but_relieved_face",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "😢",
		skin_tone_support: false,
		name: "crying face",
		slug: "crying_face",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "😭",
		skin_tone_support: false,
		name: "loudly crying face",
		slug: "loudly_crying_face",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "😱",
		skin_tone_support: false,
		name: "face screaming in fear",
		slug: "face_screaming_in_fear",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "😖",
		skin_tone_support: false,
		name: "confounded face",
		slug: "confounded_face",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "😣",
		skin_tone_support: false,
		name: "persevering face",
		slug: "persevering_face",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "😞",
		skin_tone_support: false,
		name: "disappointed face",
		slug: "disappointed_face",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "😓",
		skin_tone_support: false,
		name: "downcast face with sweat",
		slug: "downcast_face_with_sweat",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "😩",
		skin_tone_support: false,
		name: "weary face",
		slug: "weary_face",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "😫",
		skin_tone_support: false,
		name: "tired face",
		slug: "tired_face",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🥱",
		skin_tone_support: false,
		name: "yawning face",
		slug: "yawning_face",
		unicode_version: "12.0",
		emoji_version: "12.0"
	},
	{
		emoji: "😤",
		skin_tone_support: false,
		name: "face with steam from nose",
		slug: "face_with_steam_from_nose",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "😡",
		skin_tone_support: false,
		name: "enraged face",
		slug: "enraged_face",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "😠",
		skin_tone_support: false,
		name: "angry face",
		slug: "angry_face",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🤬",
		skin_tone_support: false,
		name: "face with symbols on mouth",
		slug: "face_with_symbols_on_mouth",
		unicode_version: "5.0",
		emoji_version: "5.0"
	},
	{
		emoji: "😈",
		skin_tone_support: false,
		name: "smiling face with horns",
		slug: "smiling_face_with_horns",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "👿",
		skin_tone_support: false,
		name: "angry face with horns",
		slug: "angry_face_with_horns",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "💀",
		skin_tone_support: false,
		name: "skull",
		slug: "skull",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "☠️",
		skin_tone_support: false,
		name: "skull and crossbones",
		slug: "skull_and_crossbones",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "💩",
		skin_tone_support: false,
		name: "pile of poo",
		slug: "pile_of_poo",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🤡",
		skin_tone_support: false,
		name: "clown face",
		slug: "clown_face",
		unicode_version: "3.0",
		emoji_version: "3.0"
	},
	{
		emoji: "👹",
		skin_tone_support: false,
		name: "ogre",
		slug: "ogre",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "👺",
		skin_tone_support: false,
		name: "goblin",
		slug: "goblin",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "👻",
		skin_tone_support: false,
		name: "ghost",
		slug: "ghost",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "👽",
		skin_tone_support: false,
		name: "alien",
		slug: "alien",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "👾",
		skin_tone_support: false,
		name: "alien monster",
		slug: "alien_monster",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🤖",
		skin_tone_support: false,
		name: "robot",
		slug: "robot",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "😺",
		skin_tone_support: false,
		name: "grinning cat",
		slug: "grinning_cat",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "😸",
		skin_tone_support: false,
		name: "grinning cat with smiling eyes",
		slug: "grinning_cat_with_smiling_eyes",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "😹",
		skin_tone_support: false,
		name: "cat with tears of joy",
		slug: "cat_with_tears_of_joy",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "😻",
		skin_tone_support: false,
		name: "smiling cat with heart-eyes",
		slug: "smiling_cat_with_heart_eyes",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "😼",
		skin_tone_support: false,
		name: "cat with wry smile",
		slug: "cat_with_wry_smile",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "😽",
		skin_tone_support: false,
		name: "kissing cat",
		slug: "kissing_cat",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🙀",
		skin_tone_support: false,
		name: "weary cat",
		slug: "weary_cat",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "😿",
		skin_tone_support: false,
		name: "crying cat",
		slug: "crying_cat",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "😾",
		skin_tone_support: false,
		name: "pouting cat",
		slug: "pouting_cat",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🙈",
		skin_tone_support: false,
		name: "see-no-evil monkey",
		slug: "see_no_evil_monkey",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🙉",
		skin_tone_support: false,
		name: "hear-no-evil monkey",
		slug: "hear_no_evil_monkey",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🙊",
		skin_tone_support: false,
		name: "speak-no-evil monkey",
		slug: "speak_no_evil_monkey",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "💌",
		skin_tone_support: false,
		name: "love letter",
		slug: "love_letter",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "💘",
		skin_tone_support: false,
		name: "heart with arrow",
		slug: "heart_with_arrow",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "💝",
		skin_tone_support: false,
		name: "heart with ribbon",
		slug: "heart_with_ribbon",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "💖",
		skin_tone_support: false,
		name: "sparkling heart",
		slug: "sparkling_heart",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "💗",
		skin_tone_support: false,
		name: "growing heart",
		slug: "growing_heart",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "💓",
		skin_tone_support: false,
		name: "beating heart",
		slug: "beating_heart",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "💞",
		skin_tone_support: false,
		name: "revolving hearts",
		slug: "revolving_hearts",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "💕",
		skin_tone_support: false,
		name: "two hearts",
		slug: "two_hearts",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "💟",
		skin_tone_support: false,
		name: "heart decoration",
		slug: "heart_decoration",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "❣️",
		skin_tone_support: false,
		name: "heart exclamation",
		slug: "heart_exclamation",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "💔",
		skin_tone_support: false,
		name: "broken heart",
		slug: "broken_heart",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "❤️‍🔥",
		skin_tone_support: false,
		name: "heart on fire",
		slug: "heart_on_fire",
		unicode_version: "13.1",
		emoji_version: "13.1"
	},
	{
		emoji: "❤️‍🩹",
		skin_tone_support: false,
		name: "mending heart",
		slug: "mending_heart",
		unicode_version: "13.1",
		emoji_version: "13.1"
	},
	{
		emoji: "❤️",
		skin_tone_support: false,
		name: "red heart",
		slug: "red_heart",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🩷",
		skin_tone_support: false,
		name: "pink heart",
		slug: "pink_heart",
		unicode_version: "15.0",
		emoji_version: "15.0"
	},
	{
		emoji: "🧡",
		skin_tone_support: false,
		name: "orange heart",
		slug: "orange_heart",
		unicode_version: "5.0",
		emoji_version: "5.0"
	},
	{
		emoji: "💛",
		skin_tone_support: false,
		name: "yellow heart",
		slug: "yellow_heart",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "💚",
		skin_tone_support: false,
		name: "green heart",
		slug: "green_heart",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "💙",
		skin_tone_support: false,
		name: "blue heart",
		slug: "blue_heart",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🩵",
		skin_tone_support: false,
		name: "light blue heart",
		slug: "light_blue_heart",
		unicode_version: "15.0",
		emoji_version: "15.0"
	},
	{
		emoji: "💜",
		skin_tone_support: false,
		name: "purple heart",
		slug: "purple_heart",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🤎",
		skin_tone_support: false,
		name: "brown heart",
		slug: "brown_heart",
		unicode_version: "12.0",
		emoji_version: "12.0"
	},
	{
		emoji: "🖤",
		skin_tone_support: false,
		name: "black heart",
		slug: "black_heart",
		unicode_version: "3.0",
		emoji_version: "3.0"
	},
	{
		emoji: "🩶",
		skin_tone_support: false,
		name: "grey heart",
		slug: "grey_heart",
		unicode_version: "15.0",
		emoji_version: "15.0"
	},
	{
		emoji: "🤍",
		skin_tone_support: false,
		name: "white heart",
		slug: "white_heart",
		unicode_version: "12.0",
		emoji_version: "12.0"
	},
	{
		emoji: "💋",
		skin_tone_support: false,
		name: "kiss mark",
		slug: "kiss_mark",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "💯",
		skin_tone_support: false,
		name: "hundred points",
		slug: "hundred_points",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "💢",
		skin_tone_support: false,
		name: "anger symbol",
		slug: "anger_symbol",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "💥",
		skin_tone_support: false,
		name: "collision",
		slug: "collision",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "💫",
		skin_tone_support: false,
		name: "dizzy",
		slug: "dizzy",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "💦",
		skin_tone_support: false,
		name: "sweat droplets",
		slug: "sweat_droplets",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "💨",
		skin_tone_support: false,
		name: "dashing away",
		slug: "dashing_away",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🕳️",
		skin_tone_support: false,
		name: "hole",
		slug: "hole",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "💬",
		skin_tone_support: false,
		name: "speech balloon",
		slug: "speech_balloon",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "👁️‍🗨️",
		skin_tone_support: false,
		name: "eye in speech bubble",
		slug: "eye_in_speech_bubble",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🗨️",
		skin_tone_support: false,
		name: "left speech bubble",
		slug: "left_speech_bubble",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "🗯️",
		skin_tone_support: false,
		name: "right anger bubble",
		slug: "right_anger_bubble",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "💭",
		skin_tone_support: false,
		name: "thought balloon",
		slug: "thought_balloon",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "💤",
		skin_tone_support: false,
		name: "ZZZ",
		slug: "zzz",
		unicode_version: "0.6",
		emoji_version: "0.6"
	}
],
	"People & Body": [
	{
		emoji: "👋",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "1.0",
		name: "waving hand",
		slug: "waving_hand",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🤚",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "3.0",
		name: "raised back of hand",
		slug: "raised_back_of_hand",
		unicode_version: "3.0",
		emoji_version: "3.0"
	},
	{
		emoji: "🖐️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "1.0",
		name: "hand with fingers splayed",
		slug: "hand_with_fingers_splayed",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "✋",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "1.0",
		name: "raised hand",
		slug: "raised_hand",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🖖",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "1.0",
		name: "vulcan salute",
		slug: "vulcan_salute",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🫱",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "14.0",
		name: "rightwards hand",
		slug: "rightwards_hand",
		unicode_version: "14.0",
		emoji_version: "14.0"
	},
	{
		emoji: "🫲",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "14.0",
		name: "leftwards hand",
		slug: "leftwards_hand",
		unicode_version: "14.0",
		emoji_version: "14.0"
	},
	{
		emoji: "🫳",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "14.0",
		name: "palm down hand",
		slug: "palm_down_hand",
		unicode_version: "14.0",
		emoji_version: "14.0"
	},
	{
		emoji: "🫴",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "14.0",
		name: "palm up hand",
		slug: "palm_up_hand",
		unicode_version: "14.0",
		emoji_version: "14.0"
	},
	{
		emoji: "🫷",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "15.0",
		name: "leftwards pushing hand",
		slug: "leftwards_pushing_hand",
		unicode_version: "15.0",
		emoji_version: "15.0"
	},
	{
		emoji: "🫸",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "15.0",
		name: "rightwards pushing hand",
		slug: "rightwards_pushing_hand",
		unicode_version: "15.0",
		emoji_version: "15.0"
	},
	{
		emoji: "👌",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "1.0",
		name: "OK hand",
		slug: "ok_hand",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🤌",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "13.0",
		name: "pinched fingers",
		slug: "pinched_fingers",
		unicode_version: "13.0",
		emoji_version: "13.0"
	},
	{
		emoji: "🤏",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "12.0",
		name: "pinching hand",
		slug: "pinching_hand",
		unicode_version: "12.0",
		emoji_version: "12.0"
	},
	{
		emoji: "✌️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "1.0",
		name: "victory hand",
		slug: "victory_hand",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🤞",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "3.0",
		name: "crossed fingers",
		slug: "crossed_fingers",
		unicode_version: "3.0",
		emoji_version: "3.0"
	},
	{
		emoji: "🫰",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "14.0",
		name: "hand with index finger and thumb crossed",
		slug: "hand_with_index_finger_and_thumb_crossed",
		unicode_version: "14.0",
		emoji_version: "14.0"
	},
	{
		emoji: "🤟",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "5.0",
		name: "love-you gesture",
		slug: "love_you_gesture",
		unicode_version: "5.0",
		emoji_version: "5.0"
	},
	{
		emoji: "🤘",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "1.0",
		name: "sign of the horns",
		slug: "sign_of_the_horns",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🤙",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "3.0",
		name: "call me hand",
		slug: "call_me_hand",
		unicode_version: "3.0",
		emoji_version: "3.0"
	},
	{
		emoji: "👈",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "1.0",
		name: "backhand index pointing left",
		slug: "backhand_index_pointing_left",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "👉",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "1.0",
		name: "backhand index pointing right",
		slug: "backhand_index_pointing_right",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "👆",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "1.0",
		name: "backhand index pointing up",
		slug: "backhand_index_pointing_up",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🖕",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "1.0",
		name: "middle finger",
		slug: "middle_finger",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "👇",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "1.0",
		name: "backhand index pointing down",
		slug: "backhand_index_pointing_down",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "☝️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "1.0",
		name: "index pointing up",
		slug: "index_pointing_up",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🫵",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "14.0",
		name: "index pointing at the viewer",
		slug: "index_pointing_at_the_viewer",
		unicode_version: "14.0",
		emoji_version: "14.0"
	},
	{
		emoji: "👍",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "1.0",
		name: "thumbs up",
		slug: "thumbs_up",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "👎",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "1.0",
		name: "thumbs down",
		slug: "thumbs_down",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "✊",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "1.0",
		name: "raised fist",
		slug: "raised_fist",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "👊",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "1.0",
		name: "oncoming fist",
		slug: "oncoming_fist",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🤛",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "3.0",
		name: "left-facing fist",
		slug: "left_facing_fist",
		unicode_version: "3.0",
		emoji_version: "3.0"
	},
	{
		emoji: "🤜",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "3.0",
		name: "right-facing fist",
		slug: "right_facing_fist",
		unicode_version: "3.0",
		emoji_version: "3.0"
	},
	{
		emoji: "👏",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "1.0",
		name: "clapping hands",
		slug: "clapping_hands",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🙌",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "1.0",
		name: "raising hands",
		slug: "raising_hands",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🫶",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "14.0",
		name: "heart hands",
		slug: "heart_hands",
		unicode_version: "14.0",
		emoji_version: "14.0"
	},
	{
		emoji: "👐",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "1.0",
		name: "open hands",
		slug: "open_hands",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🤲",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "5.0",
		name: "palms up together",
		slug: "palms_up_together",
		unicode_version: "5.0",
		emoji_version: "5.0"
	},
	{
		emoji: "🤝",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "14.0",
		name: "handshake",
		slug: "handshake",
		unicode_version: "3.0",
		emoji_version: "3.0"
	},
	{
		emoji: "🙏",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "1.0",
		name: "folded hands",
		slug: "folded_hands",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "✍️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "1.0",
		name: "writing hand",
		slug: "writing_hand",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "💅",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "1.0",
		name: "nail polish",
		slug: "nail_polish",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🤳",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "3.0",
		name: "selfie",
		slug: "selfie",
		unicode_version: "3.0",
		emoji_version: "3.0"
	},
	{
		emoji: "💪",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "1.0",
		name: "flexed biceps",
		slug: "flexed_biceps",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🦾",
		skin_tone_support: false,
		name: "mechanical arm",
		slug: "mechanical_arm",
		unicode_version: "12.0",
		emoji_version: "12.0"
	},
	{
		emoji: "🦿",
		skin_tone_support: false,
		name: "mechanical leg",
		slug: "mechanical_leg",
		unicode_version: "12.0",
		emoji_version: "12.0"
	},
	{
		emoji: "🦵",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "11.0",
		name: "leg",
		slug: "leg",
		unicode_version: "11.0",
		emoji_version: "11.0"
	},
	{
		emoji: "🦶",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "11.0",
		name: "foot",
		slug: "foot",
		unicode_version: "11.0",
		emoji_version: "11.0"
	},
	{
		emoji: "👂",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "1.0",
		name: "ear",
		slug: "ear",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🦻",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "12.0",
		name: "ear with hearing aid",
		slug: "ear_with_hearing_aid",
		unicode_version: "12.0",
		emoji_version: "12.0"
	},
	{
		emoji: "👃",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "1.0",
		name: "nose",
		slug: "nose",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🧠",
		skin_tone_support: false,
		name: "brain",
		slug: "brain",
		unicode_version: "5.0",
		emoji_version: "5.0"
	},
	{
		emoji: "🫀",
		skin_tone_support: false,
		name: "anatomical heart",
		slug: "anatomical_heart",
		unicode_version: "13.0",
		emoji_version: "13.0"
	},
	{
		emoji: "🫁",
		skin_tone_support: false,
		name: "lungs",
		slug: "lungs",
		unicode_version: "13.0",
		emoji_version: "13.0"
	},
	{
		emoji: "🦷",
		skin_tone_support: false,
		name: "tooth",
		slug: "tooth",
		unicode_version: "11.0",
		emoji_version: "11.0"
	},
	{
		emoji: "🦴",
		skin_tone_support: false,
		name: "bone",
		slug: "bone",
		unicode_version: "11.0",
		emoji_version: "11.0"
	},
	{
		emoji: "👀",
		skin_tone_support: false,
		name: "eyes",
		slug: "eyes",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "👁️",
		skin_tone_support: false,
		name: "eye",
		slug: "eye",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "👅",
		skin_tone_support: false,
		name: "tongue",
		slug: "tongue",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "👄",
		skin_tone_support: false,
		name: "mouth",
		slug: "mouth",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🫦",
		skin_tone_support: false,
		name: "biting lip",
		slug: "biting_lip",
		unicode_version: "14.0",
		emoji_version: "14.0"
	},
	{
		emoji: "👶",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "1.0",
		name: "baby",
		slug: "baby",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🧒",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "5.0",
		name: "child",
		slug: "child",
		unicode_version: "5.0",
		emoji_version: "5.0"
	},
	{
		emoji: "👦",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "1.0",
		name: "boy",
		slug: "boy",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "👧",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "1.0",
		name: "girl",
		slug: "girl",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🧑",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "5.0",
		name: "person",
		slug: "person",
		unicode_version: "5.0",
		emoji_version: "5.0"
	},
	{
		emoji: "👱",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "1.0",
		name: "person blond hair",
		slug: "person_blond_hair",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "👨",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "1.0",
		name: "man",
		slug: "man",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🧔",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "5.0",
		name: "person beard",
		slug: "person_beard",
		unicode_version: "5.0",
		emoji_version: "5.0"
	},
	{
		emoji: "🧔‍♂️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "13.1",
		name: "man beard",
		slug: "man_beard",
		unicode_version: "13.1",
		emoji_version: "13.1"
	},
	{
		emoji: "🧔‍♀️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "13.1",
		name: "woman beard",
		slug: "woman_beard",
		unicode_version: "13.1",
		emoji_version: "13.1"
	},
	{
		emoji: "👨‍🦰",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "11.0",
		name: "man red hair",
		slug: "man_red_hair",
		unicode_version: "11.0",
		emoji_version: "11.0"
	},
	{
		emoji: "👨‍🦱",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "11.0",
		name: "man curly hair",
		slug: "man_curly_hair",
		unicode_version: "11.0",
		emoji_version: "11.0"
	},
	{
		emoji: "👨‍🦳",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "11.0",
		name: "man white hair",
		slug: "man_white_hair",
		unicode_version: "11.0",
		emoji_version: "11.0"
	},
	{
		emoji: "👨‍🦲",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "11.0",
		name: "man bald",
		slug: "man_bald",
		unicode_version: "11.0",
		emoji_version: "11.0"
	},
	{
		emoji: "👩",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "1.0",
		name: "woman",
		slug: "woman",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "👩‍🦰",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "11.0",
		name: "woman red hair",
		slug: "woman_red_hair",
		unicode_version: "11.0",
		emoji_version: "11.0"
	},
	{
		emoji: "🧑‍🦰",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "12.1",
		name: "person red hair",
		slug: "person_red_hair",
		unicode_version: "12.1",
		emoji_version: "12.1"
	},
	{
		emoji: "👩‍🦱",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "11.0",
		name: "woman curly hair",
		slug: "woman_curly_hair",
		unicode_version: "11.0",
		emoji_version: "11.0"
	},
	{
		emoji: "🧑‍🦱",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "12.1",
		name: "person curly hair",
		slug: "person_curly_hair",
		unicode_version: "12.1",
		emoji_version: "12.1"
	},
	{
		emoji: "👩‍🦳",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "11.0",
		name: "woman white hair",
		slug: "woman_white_hair",
		unicode_version: "11.0",
		emoji_version: "11.0"
	},
	{
		emoji: "🧑‍🦳",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "12.1",
		name: "person white hair",
		slug: "person_white_hair",
		unicode_version: "12.1",
		emoji_version: "12.1"
	},
	{
		emoji: "👩‍🦲",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "11.0",
		name: "woman bald",
		slug: "woman_bald",
		unicode_version: "11.0",
		emoji_version: "11.0"
	},
	{
		emoji: "🧑‍🦲",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "12.1",
		name: "person bald",
		slug: "person_bald",
		unicode_version: "12.1",
		emoji_version: "12.1"
	},
	{
		emoji: "👱‍♀️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "woman blond hair",
		slug: "woman_blond_hair",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "👱‍♂️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "man blond hair",
		slug: "man_blond_hair",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "🧓",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "5.0",
		name: "older person",
		slug: "older_person",
		unicode_version: "5.0",
		emoji_version: "5.0"
	},
	{
		emoji: "👴",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "1.0",
		name: "old man",
		slug: "old_man",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "👵",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "1.0",
		name: "old woman",
		slug: "old_woman",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🙍",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "1.0",
		name: "person frowning",
		slug: "person_frowning",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🙍‍♂️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "man frowning",
		slug: "man_frowning",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "🙍‍♀️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "woman frowning",
		slug: "woman_frowning",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "🙎",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "1.0",
		name: "person pouting",
		slug: "person_pouting",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🙎‍♂️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "man pouting",
		slug: "man_pouting",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "🙎‍♀️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "woman pouting",
		slug: "woman_pouting",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "🙅",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "1.0",
		name: "person gesturing NO",
		slug: "person_gesturing_no",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🙅‍♂️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "man gesturing NO",
		slug: "man_gesturing_no",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "🙅‍♀️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "woman gesturing NO",
		slug: "woman_gesturing_no",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "🙆",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "1.0",
		name: "person gesturing OK",
		slug: "person_gesturing_ok",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🙆‍♂️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "man gesturing OK",
		slug: "man_gesturing_ok",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "🙆‍♀️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "woman gesturing OK",
		slug: "woman_gesturing_ok",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "💁",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "1.0",
		name: "person tipping hand",
		slug: "person_tipping_hand",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "💁‍♂️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "man tipping hand",
		slug: "man_tipping_hand",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "💁‍♀️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "woman tipping hand",
		slug: "woman_tipping_hand",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "🙋",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "1.0",
		name: "person raising hand",
		slug: "person_raising_hand",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🙋‍♂️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "man raising hand",
		slug: "man_raising_hand",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "🙋‍♀️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "woman raising hand",
		slug: "woman_raising_hand",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "🧏",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "12.0",
		name: "deaf person",
		slug: "deaf_person",
		unicode_version: "12.0",
		emoji_version: "12.0"
	},
	{
		emoji: "🧏‍♂️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "12.0",
		name: "deaf man",
		slug: "deaf_man",
		unicode_version: "12.0",
		emoji_version: "12.0"
	},
	{
		emoji: "🧏‍♀️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "12.0",
		name: "deaf woman",
		slug: "deaf_woman",
		unicode_version: "12.0",
		emoji_version: "12.0"
	},
	{
		emoji: "🙇",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "1.0",
		name: "person bowing",
		slug: "person_bowing",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🙇‍♂️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "man bowing",
		slug: "man_bowing",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "🙇‍♀️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "woman bowing",
		slug: "woman_bowing",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "🤦",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "3.0",
		name: "person facepalming",
		slug: "person_facepalming",
		unicode_version: "3.0",
		emoji_version: "3.0"
	},
	{
		emoji: "🤦‍♂️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "man facepalming",
		slug: "man_facepalming",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "🤦‍♀️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "woman facepalming",
		slug: "woman_facepalming",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "🤷",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "3.0",
		name: "person shrugging",
		slug: "person_shrugging",
		unicode_version: "3.0",
		emoji_version: "3.0"
	},
	{
		emoji: "🤷‍♂️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "man shrugging",
		slug: "man_shrugging",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "🤷‍♀️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "woman shrugging",
		slug: "woman_shrugging",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "🧑‍⚕️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "12.1",
		name: "health worker",
		slug: "health_worker",
		unicode_version: "12.1",
		emoji_version: "12.1"
	},
	{
		emoji: "👨‍⚕️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "man health worker",
		slug: "man_health_worker",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "👩‍⚕️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "woman health worker",
		slug: "woman_health_worker",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "🧑‍🎓",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "12.1",
		name: "student",
		slug: "student",
		unicode_version: "12.1",
		emoji_version: "12.1"
	},
	{
		emoji: "👨‍🎓",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "man student",
		slug: "man_student",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "👩‍🎓",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "woman student",
		slug: "woman_student",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "🧑‍🏫",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "12.1",
		name: "teacher",
		slug: "teacher",
		unicode_version: "12.1",
		emoji_version: "12.1"
	},
	{
		emoji: "👨‍🏫",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "man teacher",
		slug: "man_teacher",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "👩‍🏫",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "woman teacher",
		slug: "woman_teacher",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "🧑‍⚖️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "12.1",
		name: "judge",
		slug: "judge",
		unicode_version: "12.1",
		emoji_version: "12.1"
	},
	{
		emoji: "👨‍⚖️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "man judge",
		slug: "man_judge",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "👩‍⚖️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "woman judge",
		slug: "woman_judge",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "🧑‍🌾",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "12.1",
		name: "farmer",
		slug: "farmer",
		unicode_version: "12.1",
		emoji_version: "12.1"
	},
	{
		emoji: "👨‍🌾",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "man farmer",
		slug: "man_farmer",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "👩‍🌾",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "woman farmer",
		slug: "woman_farmer",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "🧑‍🍳",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "12.1",
		name: "cook",
		slug: "cook",
		unicode_version: "12.1",
		emoji_version: "12.1"
	},
	{
		emoji: "👨‍🍳",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "man cook",
		slug: "man_cook",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "👩‍🍳",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "woman cook",
		slug: "woman_cook",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "🧑‍🔧",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "12.1",
		name: "mechanic",
		slug: "mechanic",
		unicode_version: "12.1",
		emoji_version: "12.1"
	},
	{
		emoji: "👨‍🔧",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "man mechanic",
		slug: "man_mechanic",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "👩‍🔧",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "woman mechanic",
		slug: "woman_mechanic",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "🧑‍🏭",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "12.1",
		name: "factory worker",
		slug: "factory_worker",
		unicode_version: "12.1",
		emoji_version: "12.1"
	},
	{
		emoji: "👨‍🏭",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "man factory worker",
		slug: "man_factory_worker",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "👩‍🏭",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "woman factory worker",
		slug: "woman_factory_worker",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "🧑‍💼",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "12.1",
		name: "office worker",
		slug: "office_worker",
		unicode_version: "12.1",
		emoji_version: "12.1"
	},
	{
		emoji: "👨‍💼",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "man office worker",
		slug: "man_office_worker",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "👩‍💼",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "woman office worker",
		slug: "woman_office_worker",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "🧑‍🔬",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "12.1",
		name: "scientist",
		slug: "scientist",
		unicode_version: "12.1",
		emoji_version: "12.1"
	},
	{
		emoji: "👨‍🔬",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "man scientist",
		slug: "man_scientist",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "👩‍🔬",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "woman scientist",
		slug: "woman_scientist",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "🧑‍💻",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "12.1",
		name: "technologist",
		slug: "technologist",
		unicode_version: "12.1",
		emoji_version: "12.1"
	},
	{
		emoji: "👨‍💻",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "man technologist",
		slug: "man_technologist",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "👩‍💻",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "woman technologist",
		slug: "woman_technologist",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "🧑‍🎤",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "12.1",
		name: "singer",
		slug: "singer",
		unicode_version: "12.1",
		emoji_version: "12.1"
	},
	{
		emoji: "👨‍🎤",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "man singer",
		slug: "man_singer",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "👩‍🎤",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "woman singer",
		slug: "woman_singer",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "🧑‍🎨",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "12.1",
		name: "artist",
		slug: "artist",
		unicode_version: "12.1",
		emoji_version: "12.1"
	},
	{
		emoji: "👨‍🎨",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "man artist",
		slug: "man_artist",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "👩‍🎨",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "woman artist",
		slug: "woman_artist",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "🧑‍✈️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "12.1",
		name: "pilot",
		slug: "pilot",
		unicode_version: "12.1",
		emoji_version: "12.1"
	},
	{
		emoji: "👨‍✈️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "man pilot",
		slug: "man_pilot",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "👩‍✈️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "woman pilot",
		slug: "woman_pilot",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "🧑‍🚀",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "12.1",
		name: "astronaut",
		slug: "astronaut",
		unicode_version: "12.1",
		emoji_version: "12.1"
	},
	{
		emoji: "👨‍🚀",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "man astronaut",
		slug: "man_astronaut",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "👩‍🚀",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "woman astronaut",
		slug: "woman_astronaut",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "🧑‍🚒",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "12.1",
		name: "firefighter",
		slug: "firefighter",
		unicode_version: "12.1",
		emoji_version: "12.1"
	},
	{
		emoji: "👨‍🚒",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "man firefighter",
		slug: "man_firefighter",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "👩‍🚒",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "woman firefighter",
		slug: "woman_firefighter",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "👮",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "1.0",
		name: "police officer",
		slug: "police_officer",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "👮‍♂️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "man police officer",
		slug: "man_police_officer",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "👮‍♀️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "woman police officer",
		slug: "woman_police_officer",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "🕵️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "2.0",
		name: "detective",
		slug: "detective",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🕵️‍♂️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "man detective",
		slug: "man_detective",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "🕵️‍♀️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "woman detective",
		slug: "woman_detective",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "💂",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "1.0",
		name: "guard",
		slug: "guard",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "💂‍♂️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "man guard",
		slug: "man_guard",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "💂‍♀️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "woman guard",
		slug: "woman_guard",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "🥷",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "13.0",
		name: "ninja",
		slug: "ninja",
		unicode_version: "13.0",
		emoji_version: "13.0"
	},
	{
		emoji: "👷",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "1.0",
		name: "construction worker",
		slug: "construction_worker",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "👷‍♂️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "man construction worker",
		slug: "man_construction_worker",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "👷‍♀️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "woman construction worker",
		slug: "woman_construction_worker",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "🫅",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "14.0",
		name: "person with crown",
		slug: "person_with_crown",
		unicode_version: "14.0",
		emoji_version: "14.0"
	},
	{
		emoji: "🤴",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "3.0",
		name: "prince",
		slug: "prince",
		unicode_version: "3.0",
		emoji_version: "3.0"
	},
	{
		emoji: "👸",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "1.0",
		name: "princess",
		slug: "princess",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "👳",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "1.0",
		name: "person wearing turban",
		slug: "person_wearing_turban",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "👳‍♂️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "man wearing turban",
		slug: "man_wearing_turban",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "👳‍♀️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "woman wearing turban",
		slug: "woman_wearing_turban",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "👲",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "1.0",
		name: "person with skullcap",
		slug: "person_with_skullcap",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🧕",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "5.0",
		name: "woman with headscarf",
		slug: "woman_with_headscarf",
		unicode_version: "5.0",
		emoji_version: "5.0"
	},
	{
		emoji: "🤵",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "3.0",
		name: "person in tuxedo",
		slug: "person_in_tuxedo",
		unicode_version: "3.0",
		emoji_version: "3.0"
	},
	{
		emoji: "🤵‍♂️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "13.0",
		name: "man in tuxedo",
		slug: "man_in_tuxedo",
		unicode_version: "13.0",
		emoji_version: "13.0"
	},
	{
		emoji: "🤵‍♀️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "13.0",
		name: "woman in tuxedo",
		slug: "woman_in_tuxedo",
		unicode_version: "13.0",
		emoji_version: "13.0"
	},
	{
		emoji: "👰",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "1.0",
		name: "person with veil",
		slug: "person_with_veil",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "👰‍♂️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "13.0",
		name: "man with veil",
		slug: "man_with_veil",
		unicode_version: "13.0",
		emoji_version: "13.0"
	},
	{
		emoji: "👰‍♀️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "13.0",
		name: "woman with veil",
		slug: "woman_with_veil",
		unicode_version: "13.0",
		emoji_version: "13.0"
	},
	{
		emoji: "🤰",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "3.0",
		name: "pregnant woman",
		slug: "pregnant_woman",
		unicode_version: "3.0",
		emoji_version: "3.0"
	},
	{
		emoji: "🫃",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "14.0",
		name: "pregnant man",
		slug: "pregnant_man",
		unicode_version: "14.0",
		emoji_version: "14.0"
	},
	{
		emoji: "🫄",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "14.0",
		name: "pregnant person",
		slug: "pregnant_person",
		unicode_version: "14.0",
		emoji_version: "14.0"
	},
	{
		emoji: "🤱",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "5.0",
		name: "breast-feeding",
		slug: "breast_feeding",
		unicode_version: "5.0",
		emoji_version: "5.0"
	},
	{
		emoji: "👩‍🍼",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "13.0",
		name: "woman feeding baby",
		slug: "woman_feeding_baby",
		unicode_version: "13.0",
		emoji_version: "13.0"
	},
	{
		emoji: "👨‍🍼",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "13.0",
		name: "man feeding baby",
		slug: "man_feeding_baby",
		unicode_version: "13.0",
		emoji_version: "13.0"
	},
	{
		emoji: "🧑‍🍼",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "13.0",
		name: "person feeding baby",
		slug: "person_feeding_baby",
		unicode_version: "13.0",
		emoji_version: "13.0"
	},
	{
		emoji: "👼",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "1.0",
		name: "baby angel",
		slug: "baby_angel",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🎅",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "1.0",
		name: "Santa Claus",
		slug: "santa_claus",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🤶",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "3.0",
		name: "Mrs. Claus",
		slug: "mrs_claus",
		unicode_version: "3.0",
		emoji_version: "3.0"
	},
	{
		emoji: "🧑‍🎄",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "13.0",
		name: "mx claus",
		slug: "mx_claus",
		unicode_version: "13.0",
		emoji_version: "13.0"
	},
	{
		emoji: "🦸",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "11.0",
		name: "superhero",
		slug: "superhero",
		unicode_version: "11.0",
		emoji_version: "11.0"
	},
	{
		emoji: "🦸‍♂️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "11.0",
		name: "man superhero",
		slug: "man_superhero",
		unicode_version: "11.0",
		emoji_version: "11.0"
	},
	{
		emoji: "🦸‍♀️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "11.0",
		name: "woman superhero",
		slug: "woman_superhero",
		unicode_version: "11.0",
		emoji_version: "11.0"
	},
	{
		emoji: "🦹",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "11.0",
		name: "supervillain",
		slug: "supervillain",
		unicode_version: "11.0",
		emoji_version: "11.0"
	},
	{
		emoji: "🦹‍♂️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "11.0",
		name: "man supervillain",
		slug: "man_supervillain",
		unicode_version: "11.0",
		emoji_version: "11.0"
	},
	{
		emoji: "🦹‍♀️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "11.0",
		name: "woman supervillain",
		slug: "woman_supervillain",
		unicode_version: "11.0",
		emoji_version: "11.0"
	},
	{
		emoji: "🧙",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "5.0",
		name: "mage",
		slug: "mage",
		unicode_version: "5.0",
		emoji_version: "5.0"
	},
	{
		emoji: "🧙‍♂️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "5.0",
		name: "man mage",
		slug: "man_mage",
		unicode_version: "5.0",
		emoji_version: "5.0"
	},
	{
		emoji: "🧙‍♀️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "5.0",
		name: "woman mage",
		slug: "woman_mage",
		unicode_version: "5.0",
		emoji_version: "5.0"
	},
	{
		emoji: "🧚",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "5.0",
		name: "fairy",
		slug: "fairy",
		unicode_version: "5.0",
		emoji_version: "5.0"
	},
	{
		emoji: "🧚‍♂️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "5.0",
		name: "man fairy",
		slug: "man_fairy",
		unicode_version: "5.0",
		emoji_version: "5.0"
	},
	{
		emoji: "🧚‍♀️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "5.0",
		name: "woman fairy",
		slug: "woman_fairy",
		unicode_version: "5.0",
		emoji_version: "5.0"
	},
	{
		emoji: "🧛",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "5.0",
		name: "vampire",
		slug: "vampire",
		unicode_version: "5.0",
		emoji_version: "5.0"
	},
	{
		emoji: "🧛‍♂️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "5.0",
		name: "man vampire",
		slug: "man_vampire",
		unicode_version: "5.0",
		emoji_version: "5.0"
	},
	{
		emoji: "🧛‍♀️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "5.0",
		name: "woman vampire",
		slug: "woman_vampire",
		unicode_version: "5.0",
		emoji_version: "5.0"
	},
	{
		emoji: "🧜",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "5.0",
		name: "merperson",
		slug: "merperson",
		unicode_version: "5.0",
		emoji_version: "5.0"
	},
	{
		emoji: "🧜‍♂️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "5.0",
		name: "merman",
		slug: "merman",
		unicode_version: "5.0",
		emoji_version: "5.0"
	},
	{
		emoji: "🧜‍♀️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "5.0",
		name: "mermaid",
		slug: "mermaid",
		unicode_version: "5.0",
		emoji_version: "5.0"
	},
	{
		emoji: "🧝",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "5.0",
		name: "elf",
		slug: "elf",
		unicode_version: "5.0",
		emoji_version: "5.0"
	},
	{
		emoji: "🧝‍♂️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "5.0",
		name: "man elf",
		slug: "man_elf",
		unicode_version: "5.0",
		emoji_version: "5.0"
	},
	{
		emoji: "🧝‍♀️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "5.0",
		name: "woman elf",
		slug: "woman_elf",
		unicode_version: "5.0",
		emoji_version: "5.0"
	},
	{
		emoji: "🧞",
		skin_tone_support: false,
		name: "genie",
		slug: "genie",
		unicode_version: "5.0",
		emoji_version: "5.0"
	},
	{
		emoji: "🧞‍♂️",
		skin_tone_support: false,
		name: "man genie",
		slug: "man_genie",
		unicode_version: "5.0",
		emoji_version: "5.0"
	},
	{
		emoji: "🧞‍♀️",
		skin_tone_support: false,
		name: "woman genie",
		slug: "woman_genie",
		unicode_version: "5.0",
		emoji_version: "5.0"
	},
	{
		emoji: "🧟",
		skin_tone_support: false,
		name: "zombie",
		slug: "zombie",
		unicode_version: "5.0",
		emoji_version: "5.0"
	},
	{
		emoji: "🧟‍♂️",
		skin_tone_support: false,
		name: "man zombie",
		slug: "man_zombie",
		unicode_version: "5.0",
		emoji_version: "5.0"
	},
	{
		emoji: "🧟‍♀️",
		skin_tone_support: false,
		name: "woman zombie",
		slug: "woman_zombie",
		unicode_version: "5.0",
		emoji_version: "5.0"
	},
	{
		emoji: "🧌",
		skin_tone_support: false,
		name: "troll",
		slug: "troll",
		unicode_version: "14.0",
		emoji_version: "14.0"
	},
	{
		emoji: "💆",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "1.0",
		name: "person getting massage",
		slug: "person_getting_massage",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "💆‍♂️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "man getting massage",
		slug: "man_getting_massage",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "💆‍♀️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "woman getting massage",
		slug: "woman_getting_massage",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "💇",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "1.0",
		name: "person getting haircut",
		slug: "person_getting_haircut",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "💇‍♂️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "man getting haircut",
		slug: "man_getting_haircut",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "💇‍♀️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "woman getting haircut",
		slug: "woman_getting_haircut",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "🚶",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "1.0",
		name: "person walking",
		slug: "person_walking",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🚶‍♂️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "man walking",
		slug: "man_walking",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "🚶‍♀️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "woman walking",
		slug: "woman_walking",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "🧍",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "12.0",
		name: "person standing",
		slug: "person_standing",
		unicode_version: "12.0",
		emoji_version: "12.0"
	},
	{
		emoji: "🧍‍♂️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "12.0",
		name: "man standing",
		slug: "man_standing",
		unicode_version: "12.0",
		emoji_version: "12.0"
	},
	{
		emoji: "🧍‍♀️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "12.0",
		name: "woman standing",
		slug: "woman_standing",
		unicode_version: "12.0",
		emoji_version: "12.0"
	},
	{
		emoji: "🧎",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "12.0",
		name: "person kneeling",
		slug: "person_kneeling",
		unicode_version: "12.0",
		emoji_version: "12.0"
	},
	{
		emoji: "🧎‍♂️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "12.0",
		name: "man kneeling",
		slug: "man_kneeling",
		unicode_version: "12.0",
		emoji_version: "12.0"
	},
	{
		emoji: "🧎‍♀️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "12.0",
		name: "woman kneeling",
		slug: "woman_kneeling",
		unicode_version: "12.0",
		emoji_version: "12.0"
	},
	{
		emoji: "🧑‍🦯",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "12.1",
		name: "person with white cane",
		slug: "person_with_white_cane",
		unicode_version: "12.1",
		emoji_version: "12.1"
	},
	{
		emoji: "👨‍🦯",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "12.0",
		name: "man with white cane",
		slug: "man_with_white_cane",
		unicode_version: "12.0",
		emoji_version: "12.0"
	},
	{
		emoji: "👩‍🦯",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "12.0",
		name: "woman with white cane",
		slug: "woman_with_white_cane",
		unicode_version: "12.0",
		emoji_version: "12.0"
	},
	{
		emoji: "🧑‍🦼",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "12.1",
		name: "person in motorized wheelchair",
		slug: "person_in_motorized_wheelchair",
		unicode_version: "12.1",
		emoji_version: "12.1"
	},
	{
		emoji: "👨‍🦼",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "12.0",
		name: "man in motorized wheelchair",
		slug: "man_in_motorized_wheelchair",
		unicode_version: "12.0",
		emoji_version: "12.0"
	},
	{
		emoji: "👩‍🦼",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "12.0",
		name: "woman in motorized wheelchair",
		slug: "woman_in_motorized_wheelchair",
		unicode_version: "12.0",
		emoji_version: "12.0"
	},
	{
		emoji: "🧑‍🦽",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "12.1",
		name: "person in manual wheelchair",
		slug: "person_in_manual_wheelchair",
		unicode_version: "12.1",
		emoji_version: "12.1"
	},
	{
		emoji: "👨‍🦽",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "12.0",
		name: "man in manual wheelchair",
		slug: "man_in_manual_wheelchair",
		unicode_version: "12.0",
		emoji_version: "12.0"
	},
	{
		emoji: "👩‍🦽",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "12.0",
		name: "woman in manual wheelchair",
		slug: "woman_in_manual_wheelchair",
		unicode_version: "12.0",
		emoji_version: "12.0"
	},
	{
		emoji: "🏃",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "1.0",
		name: "person running",
		slug: "person_running",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🏃‍♂️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "man running",
		slug: "man_running",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "🏃‍♀️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "woman running",
		slug: "woman_running",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "💃",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "1.0",
		name: "woman dancing",
		slug: "woman_dancing",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🕺",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "3.0",
		name: "man dancing",
		slug: "man_dancing",
		unicode_version: "3.0",
		emoji_version: "3.0"
	},
	{
		emoji: "🕴️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "person in suit levitating",
		slug: "person_in_suit_levitating",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "👯",
		skin_tone_support: false,
		name: "people with bunny ears",
		slug: "people_with_bunny_ears",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "👯‍♂️",
		skin_tone_support: false,
		name: "men with bunny ears",
		slug: "men_with_bunny_ears",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "👯‍♀️",
		skin_tone_support: false,
		name: "women with bunny ears",
		slug: "women_with_bunny_ears",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "🧖",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "5.0",
		name: "person in steamy room",
		slug: "person_in_steamy_room",
		unicode_version: "5.0",
		emoji_version: "5.0"
	},
	{
		emoji: "🧖‍♂️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "5.0",
		name: "man in steamy room",
		slug: "man_in_steamy_room",
		unicode_version: "5.0",
		emoji_version: "5.0"
	},
	{
		emoji: "🧖‍♀️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "5.0",
		name: "woman in steamy room",
		slug: "woman_in_steamy_room",
		unicode_version: "5.0",
		emoji_version: "5.0"
	},
	{
		emoji: "🧗",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "5.0",
		name: "person climbing",
		slug: "person_climbing",
		unicode_version: "5.0",
		emoji_version: "5.0"
	},
	{
		emoji: "🧗‍♂️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "5.0",
		name: "man climbing",
		slug: "man_climbing",
		unicode_version: "5.0",
		emoji_version: "5.0"
	},
	{
		emoji: "🧗‍♀️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "5.0",
		name: "woman climbing",
		slug: "woman_climbing",
		unicode_version: "5.0",
		emoji_version: "5.0"
	},
	{
		emoji: "🤺",
		skin_tone_support: false,
		name: "person fencing",
		slug: "person_fencing",
		unicode_version: "3.0",
		emoji_version: "3.0"
	},
	{
		emoji: "🏇",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "1.0",
		name: "horse racing",
		slug: "horse_racing",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "⛷️",
		skin_tone_support: false,
		name: "skier",
		slug: "skier",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🏂",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "1.0",
		name: "snowboarder",
		slug: "snowboarder",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🏌️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "person golfing",
		slug: "person_golfing",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🏌️‍♂️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "man golfing",
		slug: "man_golfing",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "🏌️‍♀️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "woman golfing",
		slug: "woman_golfing",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "🏄",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "1.0",
		name: "person surfing",
		slug: "person_surfing",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🏄‍♂️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "man surfing",
		slug: "man_surfing",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "🏄‍♀️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "woman surfing",
		slug: "woman_surfing",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "🚣",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "1.0",
		name: "person rowing boat",
		slug: "person_rowing_boat",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🚣‍♂️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "man rowing boat",
		slug: "man_rowing_boat",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "🚣‍♀️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "woman rowing boat",
		slug: "woman_rowing_boat",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "🏊",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "1.0",
		name: "person swimming",
		slug: "person_swimming",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🏊‍♂️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "man swimming",
		slug: "man_swimming",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "🏊‍♀️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "woman swimming",
		slug: "woman_swimming",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "⛹️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "2.0",
		name: "person bouncing ball",
		slug: "person_bouncing_ball",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "⛹️‍♂️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "man bouncing ball",
		slug: "man_bouncing_ball",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "⛹️‍♀️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "woman bouncing ball",
		slug: "woman_bouncing_ball",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "🏋️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "2.0",
		name: "person lifting weights",
		slug: "person_lifting_weights",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🏋️‍♂️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "man lifting weights",
		slug: "man_lifting_weights",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "🏋️‍♀️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "woman lifting weights",
		slug: "woman_lifting_weights",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "🚴",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "1.0",
		name: "person biking",
		slug: "person_biking",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🚴‍♂️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "man biking",
		slug: "man_biking",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "🚴‍♀️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "woman biking",
		slug: "woman_biking",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "🚵",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "1.0",
		name: "person mountain biking",
		slug: "person_mountain_biking",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🚵‍♂️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "man mountain biking",
		slug: "man_mountain_biking",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "🚵‍♀️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "woman mountain biking",
		slug: "woman_mountain_biking",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "🤸",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "3.0",
		name: "person cartwheeling",
		slug: "person_cartwheeling",
		unicode_version: "3.0",
		emoji_version: "3.0"
	},
	{
		emoji: "🤸‍♂️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "man cartwheeling",
		slug: "man_cartwheeling",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "🤸‍♀️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "woman cartwheeling",
		slug: "woman_cartwheeling",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "🤼",
		skin_tone_support: false,
		name: "people wrestling",
		slug: "people_wrestling",
		unicode_version: "3.0",
		emoji_version: "3.0"
	},
	{
		emoji: "🤼‍♂️",
		skin_tone_support: false,
		name: "men wrestling",
		slug: "men_wrestling",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "🤼‍♀️",
		skin_tone_support: false,
		name: "women wrestling",
		slug: "women_wrestling",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "🤽",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "3.0",
		name: "person playing water polo",
		slug: "person_playing_water_polo",
		unicode_version: "3.0",
		emoji_version: "3.0"
	},
	{
		emoji: "🤽‍♂️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "man playing water polo",
		slug: "man_playing_water_polo",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "🤽‍♀️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "woman playing water polo",
		slug: "woman_playing_water_polo",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "🤾",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "3.0",
		name: "person playing handball",
		slug: "person_playing_handball",
		unicode_version: "3.0",
		emoji_version: "3.0"
	},
	{
		emoji: "🤾‍♂️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "man playing handball",
		slug: "man_playing_handball",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "🤾‍♀️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "woman playing handball",
		slug: "woman_playing_handball",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "🤹",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "3.0",
		name: "person juggling",
		slug: "person_juggling",
		unicode_version: "3.0",
		emoji_version: "3.0"
	},
	{
		emoji: "🤹‍♂️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "man juggling",
		slug: "man_juggling",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "🤹‍♀️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "woman juggling",
		slug: "woman_juggling",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "🧘",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "5.0",
		name: "person in lotus position",
		slug: "person_in_lotus_position",
		unicode_version: "5.0",
		emoji_version: "5.0"
	},
	{
		emoji: "🧘‍♂️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "5.0",
		name: "man in lotus position",
		slug: "man_in_lotus_position",
		unicode_version: "5.0",
		emoji_version: "5.0"
	},
	{
		emoji: "🧘‍♀️",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "5.0",
		name: "woman in lotus position",
		slug: "woman_in_lotus_position",
		unicode_version: "5.0",
		emoji_version: "5.0"
	},
	{
		emoji: "🛀",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "1.0",
		name: "person taking bath",
		slug: "person_taking_bath",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🛌",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "4.0",
		name: "person in bed",
		slug: "person_in_bed",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🧑‍🤝‍🧑",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "12.0",
		name: "people holding hands",
		slug: "people_holding_hands",
		unicode_version: "12.0",
		emoji_version: "12.0"
	},
	{
		emoji: "👭",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "12.0",
		name: "women holding hands",
		slug: "women_holding_hands",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "👫",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "12.0",
		name: "woman and man holding hands",
		slug: "woman_and_man_holding_hands",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "👬",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "12.0",
		name: "men holding hands",
		slug: "men_holding_hands",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "💏",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "13.1",
		name: "kiss",
		slug: "kiss",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "👩‍❤️‍💋‍👨",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "13.1",
		name: "kiss woman, man",
		slug: "kiss_woman_man",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "👨‍❤️‍💋‍👨",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "13.1",
		name: "kiss man, man",
		slug: "kiss_man_man",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "👩‍❤️‍💋‍👩",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "13.1",
		name: "kiss woman, woman",
		slug: "kiss_woman_woman",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "💑",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "13.1",
		name: "couple with heart",
		slug: "couple_with_heart",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "👩‍❤️‍👨",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "13.1",
		name: "couple with heart woman, man",
		slug: "couple_with_heart_woman_man",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "👨‍❤️‍👨",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "13.1",
		name: "couple with heart man, man",
		slug: "couple_with_heart_man_man",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "👩‍❤️‍👩",
		skin_tone_support: true,
		skin_tone_support_unicode_version: "13.1",
		name: "couple with heart woman, woman",
		slug: "couple_with_heart_woman_woman",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "👪",
		skin_tone_support: false,
		name: "family",
		slug: "family",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "👨‍👩‍👦",
		skin_tone_support: false,
		name: "family man, woman, boy",
		slug: "family_man_woman_boy",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "👨‍👩‍👧",
		skin_tone_support: false,
		name: "family man, woman, girl",
		slug: "family_man_woman_girl",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "👨‍👩‍👧‍👦",
		skin_tone_support: false,
		name: "family man, woman, girl, boy",
		slug: "family_man_woman_girl_boy",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "👨‍👩‍👦‍👦",
		skin_tone_support: false,
		name: "family man, woman, boy, boy",
		slug: "family_man_woman_boy_boy",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "👨‍👩‍👧‍👧",
		skin_tone_support: false,
		name: "family man, woman, girl, girl",
		slug: "family_man_woman_girl_girl",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "👨‍👨‍👦",
		skin_tone_support: false,
		name: "family man, man, boy",
		slug: "family_man_man_boy",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "👨‍👨‍👧",
		skin_tone_support: false,
		name: "family man, man, girl",
		slug: "family_man_man_girl",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "👨‍👨‍👧‍👦",
		skin_tone_support: false,
		name: "family man, man, girl, boy",
		slug: "family_man_man_girl_boy",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "👨‍👨‍👦‍👦",
		skin_tone_support: false,
		name: "family man, man, boy, boy",
		slug: "family_man_man_boy_boy",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "👨‍👨‍👧‍👧",
		skin_tone_support: false,
		name: "family man, man, girl, girl",
		slug: "family_man_man_girl_girl",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "👩‍👩‍👦",
		skin_tone_support: false,
		name: "family woman, woman, boy",
		slug: "family_woman_woman_boy",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "👩‍👩‍👧",
		skin_tone_support: false,
		name: "family woman, woman, girl",
		slug: "family_woman_woman_girl",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "👩‍👩‍👧‍👦",
		skin_tone_support: false,
		name: "family woman, woman, girl, boy",
		slug: "family_woman_woman_girl_boy",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "👩‍👩‍👦‍👦",
		skin_tone_support: false,
		name: "family woman, woman, boy, boy",
		slug: "family_woman_woman_boy_boy",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "👩‍👩‍👧‍👧",
		skin_tone_support: false,
		name: "family woman, woman, girl, girl",
		slug: "family_woman_woman_girl_girl",
		unicode_version: "2.0",
		emoji_version: "2.0"
	},
	{
		emoji: "👨‍👦",
		skin_tone_support: false,
		name: "family man, boy",
		slug: "family_man_boy",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "👨‍👦‍👦",
		skin_tone_support: false,
		name: "family man, boy, boy",
		slug: "family_man_boy_boy",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "👨‍👧",
		skin_tone_support: false,
		name: "family man, girl",
		slug: "family_man_girl",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "👨‍👧‍👦",
		skin_tone_support: false,
		name: "family man, girl, boy",
		slug: "family_man_girl_boy",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "👨‍👧‍👧",
		skin_tone_support: false,
		name: "family man, girl, girl",
		slug: "family_man_girl_girl",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "👩‍👦",
		skin_tone_support: false,
		name: "family woman, boy",
		slug: "family_woman_boy",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "👩‍👦‍👦",
		skin_tone_support: false,
		name: "family woman, boy, boy",
		slug: "family_woman_boy_boy",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "👩‍👧",
		skin_tone_support: false,
		name: "family woman, girl",
		slug: "family_woman_girl",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "👩‍👧‍👦",
		skin_tone_support: false,
		name: "family woman, girl, boy",
		slug: "family_woman_girl_boy",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "👩‍👧‍👧",
		skin_tone_support: false,
		name: "family woman, girl, girl",
		slug: "family_woman_girl_girl",
		unicode_version: "4.0",
		emoji_version: "4.0"
	},
	{
		emoji: "🗣️",
		skin_tone_support: false,
		name: "speaking head",
		slug: "speaking_head",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "👤",
		skin_tone_support: false,
		name: "bust in silhouette",
		slug: "bust_in_silhouette",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "👥",
		skin_tone_support: false,
		name: "busts in silhouette",
		slug: "busts_in_silhouette",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🫂",
		skin_tone_support: false,
		name: "people hugging",
		slug: "people_hugging",
		unicode_version: "13.0",
		emoji_version: "13.0"
	},
	{
		emoji: "👣",
		skin_tone_support: false,
		name: "footprints",
		slug: "footprints",
		unicode_version: "0.6",
		emoji_version: "0.6"
	}
],
	"Animals & Nature": [
	{
		emoji: "🐵",
		skin_tone_support: false,
		name: "monkey face",
		slug: "monkey_face",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🐒",
		skin_tone_support: false,
		name: "monkey",
		slug: "monkey",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🦍",
		skin_tone_support: false,
		name: "gorilla",
		slug: "gorilla",
		unicode_version: "3.0",
		emoji_version: "3.0"
	},
	{
		emoji: "🦧",
		skin_tone_support: false,
		name: "orangutan",
		slug: "orangutan",
		unicode_version: "12.0",
		emoji_version: "12.0"
	},
	{
		emoji: "🐶",
		skin_tone_support: false,
		name: "dog face",
		slug: "dog_face",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🐕",
		skin_tone_support: false,
		name: "dog",
		slug: "dog",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🦮",
		skin_tone_support: false,
		name: "guide dog",
		slug: "guide_dog",
		unicode_version: "12.0",
		emoji_version: "12.0"
	},
	{
		emoji: "🐕‍🦺",
		skin_tone_support: false,
		name: "service dog",
		slug: "service_dog",
		unicode_version: "12.0",
		emoji_version: "12.0"
	},
	{
		emoji: "🐩",
		skin_tone_support: false,
		name: "poodle",
		slug: "poodle",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🐺",
		skin_tone_support: false,
		name: "wolf",
		slug: "wolf",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🦊",
		skin_tone_support: false,
		name: "fox",
		slug: "fox",
		unicode_version: "3.0",
		emoji_version: "3.0"
	},
	{
		emoji: "🦝",
		skin_tone_support: false,
		name: "raccoon",
		slug: "raccoon",
		unicode_version: "11.0",
		emoji_version: "11.0"
	},
	{
		emoji: "🐱",
		skin_tone_support: false,
		name: "cat face",
		slug: "cat_face",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🐈",
		skin_tone_support: false,
		name: "cat",
		slug: "cat",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🐈‍⬛",
		skin_tone_support: false,
		name: "black cat",
		slug: "black_cat",
		unicode_version: "13.0",
		emoji_version: "13.0"
	},
	{
		emoji: "🦁",
		skin_tone_support: false,
		name: "lion",
		slug: "lion",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🐯",
		skin_tone_support: false,
		name: "tiger face",
		slug: "tiger_face",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🐅",
		skin_tone_support: false,
		name: "tiger",
		slug: "tiger",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🐆",
		skin_tone_support: false,
		name: "leopard",
		slug: "leopard",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🐴",
		skin_tone_support: false,
		name: "horse face",
		slug: "horse_face",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🫎",
		skin_tone_support: false,
		name: "moose",
		slug: "moose",
		unicode_version: "15.0",
		emoji_version: "15.0"
	},
	{
		emoji: "🫏",
		skin_tone_support: false,
		name: "donkey",
		slug: "donkey",
		unicode_version: "15.0",
		emoji_version: "15.0"
	},
	{
		emoji: "🐎",
		skin_tone_support: false,
		name: "horse",
		slug: "horse",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🦄",
		skin_tone_support: false,
		name: "unicorn",
		slug: "unicorn",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🦓",
		skin_tone_support: false,
		name: "zebra",
		slug: "zebra",
		unicode_version: "5.0",
		emoji_version: "5.0"
	},
	{
		emoji: "🦌",
		skin_tone_support: false,
		name: "deer",
		slug: "deer",
		unicode_version: "3.0",
		emoji_version: "3.0"
	},
	{
		emoji: "🦬",
		skin_tone_support: false,
		name: "bison",
		slug: "bison",
		unicode_version: "13.0",
		emoji_version: "13.0"
	},
	{
		emoji: "🐮",
		skin_tone_support: false,
		name: "cow face",
		slug: "cow_face",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🐂",
		skin_tone_support: false,
		name: "ox",
		slug: "ox",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🐃",
		skin_tone_support: false,
		name: "water buffalo",
		slug: "water_buffalo",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🐄",
		skin_tone_support: false,
		name: "cow",
		slug: "cow",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🐷",
		skin_tone_support: false,
		name: "pig face",
		slug: "pig_face",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🐖",
		skin_tone_support: false,
		name: "pig",
		slug: "pig",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🐗",
		skin_tone_support: false,
		name: "boar",
		slug: "boar",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🐽",
		skin_tone_support: false,
		name: "pig nose",
		slug: "pig_nose",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🐏",
		skin_tone_support: false,
		name: "ram",
		slug: "ram",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🐑",
		skin_tone_support: false,
		name: "ewe",
		slug: "ewe",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🐐",
		skin_tone_support: false,
		name: "goat",
		slug: "goat",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🐪",
		skin_tone_support: false,
		name: "camel",
		slug: "camel",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🐫",
		skin_tone_support: false,
		name: "two-hump camel",
		slug: "two_hump_camel",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🦙",
		skin_tone_support: false,
		name: "llama",
		slug: "llama",
		unicode_version: "11.0",
		emoji_version: "11.0"
	},
	{
		emoji: "🦒",
		skin_tone_support: false,
		name: "giraffe",
		slug: "giraffe",
		unicode_version: "5.0",
		emoji_version: "5.0"
	},
	{
		emoji: "🐘",
		skin_tone_support: false,
		name: "elephant",
		slug: "elephant",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🦣",
		skin_tone_support: false,
		name: "mammoth",
		slug: "mammoth",
		unicode_version: "13.0",
		emoji_version: "13.0"
	},
	{
		emoji: "🦏",
		skin_tone_support: false,
		name: "rhinoceros",
		slug: "rhinoceros",
		unicode_version: "3.0",
		emoji_version: "3.0"
	},
	{
		emoji: "🦛",
		skin_tone_support: false,
		name: "hippopotamus",
		slug: "hippopotamus",
		unicode_version: "11.0",
		emoji_version: "11.0"
	},
	{
		emoji: "🐭",
		skin_tone_support: false,
		name: "mouse face",
		slug: "mouse_face",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🐁",
		skin_tone_support: false,
		name: "mouse",
		slug: "mouse",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🐀",
		skin_tone_support: false,
		name: "rat",
		slug: "rat",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🐹",
		skin_tone_support: false,
		name: "hamster",
		slug: "hamster",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🐰",
		skin_tone_support: false,
		name: "rabbit face",
		slug: "rabbit_face",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🐇",
		skin_tone_support: false,
		name: "rabbit",
		slug: "rabbit",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🐿️",
		skin_tone_support: false,
		name: "chipmunk",
		slug: "chipmunk",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🦫",
		skin_tone_support: false,
		name: "beaver",
		slug: "beaver",
		unicode_version: "13.0",
		emoji_version: "13.0"
	},
	{
		emoji: "🦔",
		skin_tone_support: false,
		name: "hedgehog",
		slug: "hedgehog",
		unicode_version: "5.0",
		emoji_version: "5.0"
	},
	{
		emoji: "🦇",
		skin_tone_support: false,
		name: "bat",
		slug: "bat",
		unicode_version: "3.0",
		emoji_version: "3.0"
	},
	{
		emoji: "🐻",
		skin_tone_support: false,
		name: "bear",
		slug: "bear",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🐻‍❄️",
		skin_tone_support: false,
		name: "polar bear",
		slug: "polar_bear",
		unicode_version: "13.0",
		emoji_version: "13.0"
	},
	{
		emoji: "🐨",
		skin_tone_support: false,
		name: "koala",
		slug: "koala",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🐼",
		skin_tone_support: false,
		name: "panda",
		slug: "panda",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🦥",
		skin_tone_support: false,
		name: "sloth",
		slug: "sloth",
		unicode_version: "12.0",
		emoji_version: "12.0"
	},
	{
		emoji: "🦦",
		skin_tone_support: false,
		name: "otter",
		slug: "otter",
		unicode_version: "12.0",
		emoji_version: "12.0"
	},
	{
		emoji: "🦨",
		skin_tone_support: false,
		name: "skunk",
		slug: "skunk",
		unicode_version: "12.0",
		emoji_version: "12.0"
	},
	{
		emoji: "🦘",
		skin_tone_support: false,
		name: "kangaroo",
		slug: "kangaroo",
		unicode_version: "11.0",
		emoji_version: "11.0"
	},
	{
		emoji: "🦡",
		skin_tone_support: false,
		name: "badger",
		slug: "badger",
		unicode_version: "11.0",
		emoji_version: "11.0"
	},
	{
		emoji: "🐾",
		skin_tone_support: false,
		name: "paw prints",
		slug: "paw_prints",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🦃",
		skin_tone_support: false,
		name: "turkey",
		slug: "turkey",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🐔",
		skin_tone_support: false,
		name: "chicken",
		slug: "chicken",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🐓",
		skin_tone_support: false,
		name: "rooster",
		slug: "rooster",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🐣",
		skin_tone_support: false,
		name: "hatching chick",
		slug: "hatching_chick",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🐤",
		skin_tone_support: false,
		name: "baby chick",
		slug: "baby_chick",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🐥",
		skin_tone_support: false,
		name: "front-facing baby chick",
		slug: "front_facing_baby_chick",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🐦",
		skin_tone_support: false,
		name: "bird",
		slug: "bird",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🐧",
		skin_tone_support: false,
		name: "penguin",
		slug: "penguin",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🕊️",
		skin_tone_support: false,
		name: "dove",
		slug: "dove",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🦅",
		skin_tone_support: false,
		name: "eagle",
		slug: "eagle",
		unicode_version: "3.0",
		emoji_version: "3.0"
	},
	{
		emoji: "🦆",
		skin_tone_support: false,
		name: "duck",
		slug: "duck",
		unicode_version: "3.0",
		emoji_version: "3.0"
	},
	{
		emoji: "🦢",
		skin_tone_support: false,
		name: "swan",
		slug: "swan",
		unicode_version: "11.0",
		emoji_version: "11.0"
	},
	{
		emoji: "🦉",
		skin_tone_support: false,
		name: "owl",
		slug: "owl",
		unicode_version: "3.0",
		emoji_version: "3.0"
	},
	{
		emoji: "🦤",
		skin_tone_support: false,
		name: "dodo",
		slug: "dodo",
		unicode_version: "13.0",
		emoji_version: "13.0"
	},
	{
		emoji: "🪶",
		skin_tone_support: false,
		name: "feather",
		slug: "feather",
		unicode_version: "13.0",
		emoji_version: "13.0"
	},
	{
		emoji: "🦩",
		skin_tone_support: false,
		name: "flamingo",
		slug: "flamingo",
		unicode_version: "12.0",
		emoji_version: "12.0"
	},
	{
		emoji: "🦚",
		skin_tone_support: false,
		name: "peacock",
		slug: "peacock",
		unicode_version: "11.0",
		emoji_version: "11.0"
	},
	{
		emoji: "🦜",
		skin_tone_support: false,
		name: "parrot",
		slug: "parrot",
		unicode_version: "11.0",
		emoji_version: "11.0"
	},
	{
		emoji: "🪽",
		skin_tone_support: false,
		name: "wing",
		slug: "wing",
		unicode_version: "15.0",
		emoji_version: "15.0"
	},
	{
		emoji: "🐦‍⬛",
		skin_tone_support: false,
		name: "black bird",
		slug: "black_bird",
		unicode_version: "15.0",
		emoji_version: "15.0"
	},
	{
		emoji: "🪿",
		skin_tone_support: false,
		name: "goose",
		slug: "goose",
		unicode_version: "15.0",
		emoji_version: "15.0"
	},
	{
		emoji: "🐸",
		skin_tone_support: false,
		name: "frog",
		slug: "frog",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🐊",
		skin_tone_support: false,
		name: "crocodile",
		slug: "crocodile",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🐢",
		skin_tone_support: false,
		name: "turtle",
		slug: "turtle",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🦎",
		skin_tone_support: false,
		name: "lizard",
		slug: "lizard",
		unicode_version: "3.0",
		emoji_version: "3.0"
	},
	{
		emoji: "🐍",
		skin_tone_support: false,
		name: "snake",
		slug: "snake",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🐲",
		skin_tone_support: false,
		name: "dragon face",
		slug: "dragon_face",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🐉",
		skin_tone_support: false,
		name: "dragon",
		slug: "dragon",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🦕",
		skin_tone_support: false,
		name: "sauropod",
		slug: "sauropod",
		unicode_version: "5.0",
		emoji_version: "5.0"
	},
	{
		emoji: "🦖",
		skin_tone_support: false,
		name: "T-Rex",
		slug: "t_rex",
		unicode_version: "5.0",
		emoji_version: "5.0"
	},
	{
		emoji: "🐳",
		skin_tone_support: false,
		name: "spouting whale",
		slug: "spouting_whale",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🐋",
		skin_tone_support: false,
		name: "whale",
		slug: "whale",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🐬",
		skin_tone_support: false,
		name: "dolphin",
		slug: "dolphin",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🦭",
		skin_tone_support: false,
		name: "seal",
		slug: "seal",
		unicode_version: "13.0",
		emoji_version: "13.0"
	},
	{
		emoji: "🐟",
		skin_tone_support: false,
		name: "fish",
		slug: "fish",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🐠",
		skin_tone_support: false,
		name: "tropical fish",
		slug: "tropical_fish",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🐡",
		skin_tone_support: false,
		name: "blowfish",
		slug: "blowfish",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🦈",
		skin_tone_support: false,
		name: "shark",
		slug: "shark",
		unicode_version: "3.0",
		emoji_version: "3.0"
	},
	{
		emoji: "🐙",
		skin_tone_support: false,
		name: "octopus",
		slug: "octopus",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🐚",
		skin_tone_support: false,
		name: "spiral shell",
		slug: "spiral_shell",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🪸",
		skin_tone_support: false,
		name: "coral",
		slug: "coral",
		unicode_version: "14.0",
		emoji_version: "14.0"
	},
	{
		emoji: "🪼",
		skin_tone_support: false,
		name: "jellyfish",
		slug: "jellyfish",
		unicode_version: "15.0",
		emoji_version: "15.0"
	},
	{
		emoji: "🐌",
		skin_tone_support: false,
		name: "snail",
		slug: "snail",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🦋",
		skin_tone_support: false,
		name: "butterfly",
		slug: "butterfly",
		unicode_version: "3.0",
		emoji_version: "3.0"
	},
	{
		emoji: "🐛",
		skin_tone_support: false,
		name: "bug",
		slug: "bug",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🐜",
		skin_tone_support: false,
		name: "ant",
		slug: "ant",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🐝",
		skin_tone_support: false,
		name: "honeybee",
		slug: "honeybee",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🪲",
		skin_tone_support: false,
		name: "beetle",
		slug: "beetle",
		unicode_version: "13.0",
		emoji_version: "13.0"
	},
	{
		emoji: "🐞",
		skin_tone_support: false,
		name: "lady beetle",
		slug: "lady_beetle",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🦗",
		skin_tone_support: false,
		name: "cricket",
		slug: "cricket",
		unicode_version: "5.0",
		emoji_version: "5.0"
	},
	{
		emoji: "🪳",
		skin_tone_support: false,
		name: "cockroach",
		slug: "cockroach",
		unicode_version: "13.0",
		emoji_version: "13.0"
	},
	{
		emoji: "🕷️",
		skin_tone_support: false,
		name: "spider",
		slug: "spider",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🕸️",
		skin_tone_support: false,
		name: "spider web",
		slug: "spider_web",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🦂",
		skin_tone_support: false,
		name: "scorpion",
		slug: "scorpion",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🦟",
		skin_tone_support: false,
		name: "mosquito",
		slug: "mosquito",
		unicode_version: "11.0",
		emoji_version: "11.0"
	},
	{
		emoji: "🪰",
		skin_tone_support: false,
		name: "fly",
		slug: "fly",
		unicode_version: "13.0",
		emoji_version: "13.0"
	},
	{
		emoji: "🪱",
		skin_tone_support: false,
		name: "worm",
		slug: "worm",
		unicode_version: "13.0",
		emoji_version: "13.0"
	},
	{
		emoji: "🦠",
		skin_tone_support: false,
		name: "microbe",
		slug: "microbe",
		unicode_version: "11.0",
		emoji_version: "11.0"
	},
	{
		emoji: "💐",
		skin_tone_support: false,
		name: "bouquet",
		slug: "bouquet",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🌸",
		skin_tone_support: false,
		name: "cherry blossom",
		slug: "cherry_blossom",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "💮",
		skin_tone_support: false,
		name: "white flower",
		slug: "white_flower",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🪷",
		skin_tone_support: false,
		name: "lotus",
		slug: "lotus",
		unicode_version: "14.0",
		emoji_version: "14.0"
	},
	{
		emoji: "🏵️",
		skin_tone_support: false,
		name: "rosette",
		slug: "rosette",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🌹",
		skin_tone_support: false,
		name: "rose",
		slug: "rose",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🥀",
		skin_tone_support: false,
		name: "wilted flower",
		slug: "wilted_flower",
		unicode_version: "3.0",
		emoji_version: "3.0"
	},
	{
		emoji: "🌺",
		skin_tone_support: false,
		name: "hibiscus",
		slug: "hibiscus",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🌻",
		skin_tone_support: false,
		name: "sunflower",
		slug: "sunflower",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🌼",
		skin_tone_support: false,
		name: "blossom",
		slug: "blossom",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🌷",
		skin_tone_support: false,
		name: "tulip",
		slug: "tulip",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🪻",
		skin_tone_support: false,
		name: "hyacinth",
		slug: "hyacinth",
		unicode_version: "15.0",
		emoji_version: "15.0"
	},
	{
		emoji: "🌱",
		skin_tone_support: false,
		name: "seedling",
		slug: "seedling",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🪴",
		skin_tone_support: false,
		name: "potted plant",
		slug: "potted_plant",
		unicode_version: "13.0",
		emoji_version: "13.0"
	},
	{
		emoji: "🌲",
		skin_tone_support: false,
		name: "evergreen tree",
		slug: "evergreen_tree",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🌳",
		skin_tone_support: false,
		name: "deciduous tree",
		slug: "deciduous_tree",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🌴",
		skin_tone_support: false,
		name: "palm tree",
		slug: "palm_tree",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🌵",
		skin_tone_support: false,
		name: "cactus",
		slug: "cactus",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🌾",
		skin_tone_support: false,
		name: "sheaf of rice",
		slug: "sheaf_of_rice",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🌿",
		skin_tone_support: false,
		name: "herb",
		slug: "herb",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "☘️",
		skin_tone_support: false,
		name: "shamrock",
		slug: "shamrock",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🍀",
		skin_tone_support: false,
		name: "four leaf clover",
		slug: "four_leaf_clover",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🍁",
		skin_tone_support: false,
		name: "maple leaf",
		slug: "maple_leaf",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🍂",
		skin_tone_support: false,
		name: "fallen leaf",
		slug: "fallen_leaf",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🍃",
		skin_tone_support: false,
		name: "leaf fluttering in wind",
		slug: "leaf_fluttering_in_wind",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🪹",
		skin_tone_support: false,
		name: "empty nest",
		slug: "empty_nest",
		unicode_version: "14.0",
		emoji_version: "14.0"
	},
	{
		emoji: "🪺",
		skin_tone_support: false,
		name: "nest with eggs",
		slug: "nest_with_eggs",
		unicode_version: "14.0",
		emoji_version: "14.0"
	},
	{
		emoji: "🍄",
		skin_tone_support: false,
		name: "mushroom",
		slug: "mushroom",
		unicode_version: "0.6",
		emoji_version: "0.6"
	}
],
	"Food & Drink": [
	{
		emoji: "🍇",
		skin_tone_support: false,
		name: "grapes",
		slug: "grapes",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🍈",
		skin_tone_support: false,
		name: "melon",
		slug: "melon",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🍉",
		skin_tone_support: false,
		name: "watermelon",
		slug: "watermelon",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🍊",
		skin_tone_support: false,
		name: "tangerine",
		slug: "tangerine",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🍋",
		skin_tone_support: false,
		name: "lemon",
		slug: "lemon",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🍌",
		skin_tone_support: false,
		name: "banana",
		slug: "banana",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🍍",
		skin_tone_support: false,
		name: "pineapple",
		slug: "pineapple",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🥭",
		skin_tone_support: false,
		name: "mango",
		slug: "mango",
		unicode_version: "11.0",
		emoji_version: "11.0"
	},
	{
		emoji: "🍎",
		skin_tone_support: false,
		name: "red apple",
		slug: "red_apple",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🍏",
		skin_tone_support: false,
		name: "green apple",
		slug: "green_apple",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🍐",
		skin_tone_support: false,
		name: "pear",
		slug: "pear",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🍑",
		skin_tone_support: false,
		name: "peach",
		slug: "peach",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🍒",
		skin_tone_support: false,
		name: "cherries",
		slug: "cherries",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🍓",
		skin_tone_support: false,
		name: "strawberry",
		slug: "strawberry",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🫐",
		skin_tone_support: false,
		name: "blueberries",
		slug: "blueberries",
		unicode_version: "13.0",
		emoji_version: "13.0"
	},
	{
		emoji: "🥝",
		skin_tone_support: false,
		name: "kiwi fruit",
		slug: "kiwi_fruit",
		unicode_version: "3.0",
		emoji_version: "3.0"
	},
	{
		emoji: "🍅",
		skin_tone_support: false,
		name: "tomato",
		slug: "tomato",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🫒",
		skin_tone_support: false,
		name: "olive",
		slug: "olive",
		unicode_version: "13.0",
		emoji_version: "13.0"
	},
	{
		emoji: "🥥",
		skin_tone_support: false,
		name: "coconut",
		slug: "coconut",
		unicode_version: "5.0",
		emoji_version: "5.0"
	},
	{
		emoji: "🥑",
		skin_tone_support: false,
		name: "avocado",
		slug: "avocado",
		unicode_version: "3.0",
		emoji_version: "3.0"
	},
	{
		emoji: "🍆",
		skin_tone_support: false,
		name: "eggplant",
		slug: "eggplant",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🥔",
		skin_tone_support: false,
		name: "potato",
		slug: "potato",
		unicode_version: "3.0",
		emoji_version: "3.0"
	},
	{
		emoji: "🥕",
		skin_tone_support: false,
		name: "carrot",
		slug: "carrot",
		unicode_version: "3.0",
		emoji_version: "3.0"
	},
	{
		emoji: "🌽",
		skin_tone_support: false,
		name: "ear of corn",
		slug: "ear_of_corn",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🌶️",
		skin_tone_support: false,
		name: "hot pepper",
		slug: "hot_pepper",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🫑",
		skin_tone_support: false,
		name: "bell pepper",
		slug: "bell_pepper",
		unicode_version: "13.0",
		emoji_version: "13.0"
	},
	{
		emoji: "🥒",
		skin_tone_support: false,
		name: "cucumber",
		slug: "cucumber",
		unicode_version: "3.0",
		emoji_version: "3.0"
	},
	{
		emoji: "🥬",
		skin_tone_support: false,
		name: "leafy green",
		slug: "leafy_green",
		unicode_version: "11.0",
		emoji_version: "11.0"
	},
	{
		emoji: "🥦",
		skin_tone_support: false,
		name: "broccoli",
		slug: "broccoli",
		unicode_version: "5.0",
		emoji_version: "5.0"
	},
	{
		emoji: "🧄",
		skin_tone_support: false,
		name: "garlic",
		slug: "garlic",
		unicode_version: "12.0",
		emoji_version: "12.0"
	},
	{
		emoji: "🧅",
		skin_tone_support: false,
		name: "onion",
		slug: "onion",
		unicode_version: "12.0",
		emoji_version: "12.0"
	},
	{
		emoji: "🥜",
		skin_tone_support: false,
		name: "peanuts",
		slug: "peanuts",
		unicode_version: "3.0",
		emoji_version: "3.0"
	},
	{
		emoji: "🫘",
		skin_tone_support: false,
		name: "beans",
		slug: "beans",
		unicode_version: "14.0",
		emoji_version: "14.0"
	},
	{
		emoji: "🌰",
		skin_tone_support: false,
		name: "chestnut",
		slug: "chestnut",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🫚",
		skin_tone_support: false,
		name: "ginger root",
		slug: "ginger_root",
		unicode_version: "15.0",
		emoji_version: "15.0"
	},
	{
		emoji: "🫛",
		skin_tone_support: false,
		name: "pea pod",
		slug: "pea_pod",
		unicode_version: "15.0",
		emoji_version: "15.0"
	},
	{
		emoji: "🍞",
		skin_tone_support: false,
		name: "bread",
		slug: "bread",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🥐",
		skin_tone_support: false,
		name: "croissant",
		slug: "croissant",
		unicode_version: "3.0",
		emoji_version: "3.0"
	},
	{
		emoji: "🥖",
		skin_tone_support: false,
		name: "baguette bread",
		slug: "baguette_bread",
		unicode_version: "3.0",
		emoji_version: "3.0"
	},
	{
		emoji: "🫓",
		skin_tone_support: false,
		name: "flatbread",
		slug: "flatbread",
		unicode_version: "13.0",
		emoji_version: "13.0"
	},
	{
		emoji: "🥨",
		skin_tone_support: false,
		name: "pretzel",
		slug: "pretzel",
		unicode_version: "5.0",
		emoji_version: "5.0"
	},
	{
		emoji: "🥯",
		skin_tone_support: false,
		name: "bagel",
		slug: "bagel",
		unicode_version: "11.0",
		emoji_version: "11.0"
	},
	{
		emoji: "🥞",
		skin_tone_support: false,
		name: "pancakes",
		slug: "pancakes",
		unicode_version: "3.0",
		emoji_version: "3.0"
	},
	{
		emoji: "🧇",
		skin_tone_support: false,
		name: "waffle",
		slug: "waffle",
		unicode_version: "12.0",
		emoji_version: "12.0"
	},
	{
		emoji: "🧀",
		skin_tone_support: false,
		name: "cheese wedge",
		slug: "cheese_wedge",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🍖",
		skin_tone_support: false,
		name: "meat on bone",
		slug: "meat_on_bone",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🍗",
		skin_tone_support: false,
		name: "poultry leg",
		slug: "poultry_leg",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🥩",
		skin_tone_support: false,
		name: "cut of meat",
		slug: "cut_of_meat",
		unicode_version: "5.0",
		emoji_version: "5.0"
	},
	{
		emoji: "🥓",
		skin_tone_support: false,
		name: "bacon",
		slug: "bacon",
		unicode_version: "3.0",
		emoji_version: "3.0"
	},
	{
		emoji: "🍔",
		skin_tone_support: false,
		name: "hamburger",
		slug: "hamburger",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🍟",
		skin_tone_support: false,
		name: "french fries",
		slug: "french_fries",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🍕",
		skin_tone_support: false,
		name: "pizza",
		slug: "pizza",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🌭",
		skin_tone_support: false,
		name: "hot dog",
		slug: "hot_dog",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🥪",
		skin_tone_support: false,
		name: "sandwich",
		slug: "sandwich",
		unicode_version: "5.0",
		emoji_version: "5.0"
	},
	{
		emoji: "🌮",
		skin_tone_support: false,
		name: "taco",
		slug: "taco",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🌯",
		skin_tone_support: false,
		name: "burrito",
		slug: "burrito",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🫔",
		skin_tone_support: false,
		name: "tamale",
		slug: "tamale",
		unicode_version: "13.0",
		emoji_version: "13.0"
	},
	{
		emoji: "🥙",
		skin_tone_support: false,
		name: "stuffed flatbread",
		slug: "stuffed_flatbread",
		unicode_version: "3.0",
		emoji_version: "3.0"
	},
	{
		emoji: "🧆",
		skin_tone_support: false,
		name: "falafel",
		slug: "falafel",
		unicode_version: "12.0",
		emoji_version: "12.0"
	},
	{
		emoji: "🥚",
		skin_tone_support: false,
		name: "egg",
		slug: "egg",
		unicode_version: "3.0",
		emoji_version: "3.0"
	},
	{
		emoji: "🍳",
		skin_tone_support: false,
		name: "cooking",
		slug: "cooking",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🥘",
		skin_tone_support: false,
		name: "shallow pan of food",
		slug: "shallow_pan_of_food",
		unicode_version: "3.0",
		emoji_version: "3.0"
	},
	{
		emoji: "🍲",
		skin_tone_support: false,
		name: "pot of food",
		slug: "pot_of_food",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🫕",
		skin_tone_support: false,
		name: "fondue",
		slug: "fondue",
		unicode_version: "13.0",
		emoji_version: "13.0"
	},
	{
		emoji: "🥣",
		skin_tone_support: false,
		name: "bowl with spoon",
		slug: "bowl_with_spoon",
		unicode_version: "5.0",
		emoji_version: "5.0"
	},
	{
		emoji: "🥗",
		skin_tone_support: false,
		name: "green salad",
		slug: "green_salad",
		unicode_version: "3.0",
		emoji_version: "3.0"
	},
	{
		emoji: "🍿",
		skin_tone_support: false,
		name: "popcorn",
		slug: "popcorn",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🧈",
		skin_tone_support: false,
		name: "butter",
		slug: "butter",
		unicode_version: "12.0",
		emoji_version: "12.0"
	},
	{
		emoji: "🧂",
		skin_tone_support: false,
		name: "salt",
		slug: "salt",
		unicode_version: "11.0",
		emoji_version: "11.0"
	},
	{
		emoji: "🥫",
		skin_tone_support: false,
		name: "canned food",
		slug: "canned_food",
		unicode_version: "5.0",
		emoji_version: "5.0"
	},
	{
		emoji: "🍱",
		skin_tone_support: false,
		name: "bento box",
		slug: "bento_box",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🍘",
		skin_tone_support: false,
		name: "rice cracker",
		slug: "rice_cracker",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🍙",
		skin_tone_support: false,
		name: "rice ball",
		slug: "rice_ball",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🍚",
		skin_tone_support: false,
		name: "cooked rice",
		slug: "cooked_rice",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🍛",
		skin_tone_support: false,
		name: "curry rice",
		slug: "curry_rice",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🍜",
		skin_tone_support: false,
		name: "steaming bowl",
		slug: "steaming_bowl",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🍝",
		skin_tone_support: false,
		name: "spaghetti",
		slug: "spaghetti",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🍠",
		skin_tone_support: false,
		name: "roasted sweet potato",
		slug: "roasted_sweet_potato",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🍢",
		skin_tone_support: false,
		name: "oden",
		slug: "oden",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🍣",
		skin_tone_support: false,
		name: "sushi",
		slug: "sushi",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🍤",
		skin_tone_support: false,
		name: "fried shrimp",
		slug: "fried_shrimp",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🍥",
		skin_tone_support: false,
		name: "fish cake with swirl",
		slug: "fish_cake_with_swirl",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🥮",
		skin_tone_support: false,
		name: "moon cake",
		slug: "moon_cake",
		unicode_version: "11.0",
		emoji_version: "11.0"
	},
	{
		emoji: "🍡",
		skin_tone_support: false,
		name: "dango",
		slug: "dango",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🥟",
		skin_tone_support: false,
		name: "dumpling",
		slug: "dumpling",
		unicode_version: "5.0",
		emoji_version: "5.0"
	},
	{
		emoji: "🥠",
		skin_tone_support: false,
		name: "fortune cookie",
		slug: "fortune_cookie",
		unicode_version: "5.0",
		emoji_version: "5.0"
	},
	{
		emoji: "🥡",
		skin_tone_support: false,
		name: "takeout box",
		slug: "takeout_box",
		unicode_version: "5.0",
		emoji_version: "5.0"
	},
	{
		emoji: "🦀",
		skin_tone_support: false,
		name: "crab",
		slug: "crab",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🦞",
		skin_tone_support: false,
		name: "lobster",
		slug: "lobster",
		unicode_version: "11.0",
		emoji_version: "11.0"
	},
	{
		emoji: "🦐",
		skin_tone_support: false,
		name: "shrimp",
		slug: "shrimp",
		unicode_version: "3.0",
		emoji_version: "3.0"
	},
	{
		emoji: "🦑",
		skin_tone_support: false,
		name: "squid",
		slug: "squid",
		unicode_version: "3.0",
		emoji_version: "3.0"
	},
	{
		emoji: "🦪",
		skin_tone_support: false,
		name: "oyster",
		slug: "oyster",
		unicode_version: "12.0",
		emoji_version: "12.0"
	},
	{
		emoji: "🍦",
		skin_tone_support: false,
		name: "soft ice cream",
		slug: "soft_ice_cream",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🍧",
		skin_tone_support: false,
		name: "shaved ice",
		slug: "shaved_ice",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🍨",
		skin_tone_support: false,
		name: "ice cream",
		slug: "ice_cream",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🍩",
		skin_tone_support: false,
		name: "doughnut",
		slug: "doughnut",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🍪",
		skin_tone_support: false,
		name: "cookie",
		slug: "cookie",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🎂",
		skin_tone_support: false,
		name: "birthday cake",
		slug: "birthday_cake",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🍰",
		skin_tone_support: false,
		name: "shortcake",
		slug: "shortcake",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🧁",
		skin_tone_support: false,
		name: "cupcake",
		slug: "cupcake",
		unicode_version: "11.0",
		emoji_version: "11.0"
	},
	{
		emoji: "🥧",
		skin_tone_support: false,
		name: "pie",
		slug: "pie",
		unicode_version: "5.0",
		emoji_version: "5.0"
	},
	{
		emoji: "🍫",
		skin_tone_support: false,
		name: "chocolate bar",
		slug: "chocolate_bar",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🍬",
		skin_tone_support: false,
		name: "candy",
		slug: "candy",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🍭",
		skin_tone_support: false,
		name: "lollipop",
		slug: "lollipop",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🍮",
		skin_tone_support: false,
		name: "custard",
		slug: "custard",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🍯",
		skin_tone_support: false,
		name: "honey pot",
		slug: "honey_pot",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🍼",
		skin_tone_support: false,
		name: "baby bottle",
		slug: "baby_bottle",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🥛",
		skin_tone_support: false,
		name: "glass of milk",
		slug: "glass_of_milk",
		unicode_version: "3.0",
		emoji_version: "3.0"
	},
	{
		emoji: "☕",
		skin_tone_support: false,
		name: "hot beverage",
		slug: "hot_beverage",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🫖",
		skin_tone_support: false,
		name: "teapot",
		slug: "teapot",
		unicode_version: "13.0",
		emoji_version: "13.0"
	},
	{
		emoji: "🍵",
		skin_tone_support: false,
		name: "teacup without handle",
		slug: "teacup_without_handle",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🍶",
		skin_tone_support: false,
		name: "sake",
		slug: "sake",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🍾",
		skin_tone_support: false,
		name: "bottle with popping cork",
		slug: "bottle_with_popping_cork",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🍷",
		skin_tone_support: false,
		name: "wine glass",
		slug: "wine_glass",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🍸",
		skin_tone_support: false,
		name: "cocktail glass",
		slug: "cocktail_glass",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🍹",
		skin_tone_support: false,
		name: "tropical drink",
		slug: "tropical_drink",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🍺",
		skin_tone_support: false,
		name: "beer mug",
		slug: "beer_mug",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🍻",
		skin_tone_support: false,
		name: "clinking beer mugs",
		slug: "clinking_beer_mugs",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🥂",
		skin_tone_support: false,
		name: "clinking glasses",
		slug: "clinking_glasses",
		unicode_version: "3.0",
		emoji_version: "3.0"
	},
	{
		emoji: "🥃",
		skin_tone_support: false,
		name: "tumbler glass",
		slug: "tumbler_glass",
		unicode_version: "3.0",
		emoji_version: "3.0"
	},
	{
		emoji: "🫗",
		skin_tone_support: false,
		name: "pouring liquid",
		slug: "pouring_liquid",
		unicode_version: "14.0",
		emoji_version: "14.0"
	},
	{
		emoji: "🥤",
		skin_tone_support: false,
		name: "cup with straw",
		slug: "cup_with_straw",
		unicode_version: "5.0",
		emoji_version: "5.0"
	},
	{
		emoji: "🧋",
		skin_tone_support: false,
		name: "bubble tea",
		slug: "bubble_tea",
		unicode_version: "13.0",
		emoji_version: "13.0"
	},
	{
		emoji: "🧃",
		skin_tone_support: false,
		name: "beverage box",
		slug: "beverage_box",
		unicode_version: "12.0",
		emoji_version: "12.0"
	},
	{
		emoji: "🧉",
		skin_tone_support: false,
		name: "mate",
		slug: "mate",
		unicode_version: "12.0",
		emoji_version: "12.0"
	},
	{
		emoji: "🧊",
		skin_tone_support: false,
		name: "ice",
		slug: "ice",
		unicode_version: "12.0",
		emoji_version: "12.0"
	},
	{
		emoji: "🥢",
		skin_tone_support: false,
		name: "chopsticks",
		slug: "chopsticks",
		unicode_version: "5.0",
		emoji_version: "5.0"
	},
	{
		emoji: "🍽️",
		skin_tone_support: false,
		name: "fork and knife with plate",
		slug: "fork_and_knife_with_plate",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🍴",
		skin_tone_support: false,
		name: "fork and knife",
		slug: "fork_and_knife",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🥄",
		skin_tone_support: false,
		name: "spoon",
		slug: "spoon",
		unicode_version: "3.0",
		emoji_version: "3.0"
	},
	{
		emoji: "🔪",
		skin_tone_support: false,
		name: "kitchen knife",
		slug: "kitchen_knife",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🫙",
		skin_tone_support: false,
		name: "jar",
		slug: "jar",
		unicode_version: "14.0",
		emoji_version: "14.0"
	},
	{
		emoji: "🏺",
		skin_tone_support: false,
		name: "amphora",
		slug: "amphora",
		unicode_version: "1.0",
		emoji_version: "1.0"
	}
],
	"Travel & Places": [
	{
		emoji: "🌍",
		skin_tone_support: false,
		name: "globe showing Europe-Africa",
		slug: "globe_showing_europe_africa",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🌎",
		skin_tone_support: false,
		name: "globe showing Americas",
		slug: "globe_showing_americas",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🌏",
		skin_tone_support: false,
		name: "globe showing Asia-Australia",
		slug: "globe_showing_asia_australia",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🌐",
		skin_tone_support: false,
		name: "globe with meridians",
		slug: "globe_with_meridians",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🗺️",
		skin_tone_support: false,
		name: "world map",
		slug: "world_map",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🗾",
		skin_tone_support: false,
		name: "map of Japan",
		slug: "map_of_japan",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🧭",
		skin_tone_support: false,
		name: "compass",
		slug: "compass",
		unicode_version: "11.0",
		emoji_version: "11.0"
	},
	{
		emoji: "🏔️",
		skin_tone_support: false,
		name: "snow-capped mountain",
		slug: "snow_capped_mountain",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "⛰️",
		skin_tone_support: false,
		name: "mountain",
		slug: "mountain",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🌋",
		skin_tone_support: false,
		name: "volcano",
		slug: "volcano",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🗻",
		skin_tone_support: false,
		name: "mount fuji",
		slug: "mount_fuji",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🏕️",
		skin_tone_support: false,
		name: "camping",
		slug: "camping",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🏖️",
		skin_tone_support: false,
		name: "beach with umbrella",
		slug: "beach_with_umbrella",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🏜️",
		skin_tone_support: false,
		name: "desert",
		slug: "desert",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🏝️",
		skin_tone_support: false,
		name: "desert island",
		slug: "desert_island",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🏞️",
		skin_tone_support: false,
		name: "national park",
		slug: "national_park",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🏟️",
		skin_tone_support: false,
		name: "stadium",
		slug: "stadium",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🏛️",
		skin_tone_support: false,
		name: "classical building",
		slug: "classical_building",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🏗️",
		skin_tone_support: false,
		name: "building construction",
		slug: "building_construction",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🧱",
		skin_tone_support: false,
		name: "brick",
		slug: "brick",
		unicode_version: "11.0",
		emoji_version: "11.0"
	},
	{
		emoji: "🪨",
		skin_tone_support: false,
		name: "rock",
		slug: "rock",
		unicode_version: "13.0",
		emoji_version: "13.0"
	},
	{
		emoji: "🪵",
		skin_tone_support: false,
		name: "wood",
		slug: "wood",
		unicode_version: "13.0",
		emoji_version: "13.0"
	},
	{
		emoji: "🛖",
		skin_tone_support: false,
		name: "hut",
		slug: "hut",
		unicode_version: "13.0",
		emoji_version: "13.0"
	},
	{
		emoji: "🏘️",
		skin_tone_support: false,
		name: "houses",
		slug: "houses",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🏚️",
		skin_tone_support: false,
		name: "derelict house",
		slug: "derelict_house",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🏠",
		skin_tone_support: false,
		name: "house",
		slug: "house",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🏡",
		skin_tone_support: false,
		name: "house with garden",
		slug: "house_with_garden",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🏢",
		skin_tone_support: false,
		name: "office building",
		slug: "office_building",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🏣",
		skin_tone_support: false,
		name: "Japanese post office",
		slug: "japanese_post_office",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🏤",
		skin_tone_support: false,
		name: "post office",
		slug: "post_office",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🏥",
		skin_tone_support: false,
		name: "hospital",
		slug: "hospital",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🏦",
		skin_tone_support: false,
		name: "bank",
		slug: "bank",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🏨",
		skin_tone_support: false,
		name: "hotel",
		slug: "hotel",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🏩",
		skin_tone_support: false,
		name: "love hotel",
		slug: "love_hotel",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🏪",
		skin_tone_support: false,
		name: "convenience store",
		slug: "convenience_store",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🏫",
		skin_tone_support: false,
		name: "school",
		slug: "school",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🏬",
		skin_tone_support: false,
		name: "department store",
		slug: "department_store",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🏭",
		skin_tone_support: false,
		name: "factory",
		slug: "factory",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🏯",
		skin_tone_support: false,
		name: "Japanese castle",
		slug: "japanese_castle",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🏰",
		skin_tone_support: false,
		name: "castle",
		slug: "castle",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "💒",
		skin_tone_support: false,
		name: "wedding",
		slug: "wedding",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🗼",
		skin_tone_support: false,
		name: "Tokyo tower",
		slug: "tokyo_tower",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🗽",
		skin_tone_support: false,
		name: "Statue of Liberty",
		slug: "statue_of_liberty",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "⛪",
		skin_tone_support: false,
		name: "church",
		slug: "church",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🕌",
		skin_tone_support: false,
		name: "mosque",
		slug: "mosque",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🛕",
		skin_tone_support: false,
		name: "hindu temple",
		slug: "hindu_temple",
		unicode_version: "12.0",
		emoji_version: "12.0"
	},
	{
		emoji: "🕍",
		skin_tone_support: false,
		name: "synagogue",
		slug: "synagogue",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "⛩️",
		skin_tone_support: false,
		name: "shinto shrine",
		slug: "shinto_shrine",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🕋",
		skin_tone_support: false,
		name: "kaaba",
		slug: "kaaba",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "⛲",
		skin_tone_support: false,
		name: "fountain",
		slug: "fountain",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "⛺",
		skin_tone_support: false,
		name: "tent",
		slug: "tent",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🌁",
		skin_tone_support: false,
		name: "foggy",
		slug: "foggy",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🌃",
		skin_tone_support: false,
		name: "night with stars",
		slug: "night_with_stars",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🏙️",
		skin_tone_support: false,
		name: "cityscape",
		slug: "cityscape",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🌄",
		skin_tone_support: false,
		name: "sunrise over mountains",
		slug: "sunrise_over_mountains",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🌅",
		skin_tone_support: false,
		name: "sunrise",
		slug: "sunrise",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🌆",
		skin_tone_support: false,
		name: "cityscape at dusk",
		slug: "cityscape_at_dusk",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🌇",
		skin_tone_support: false,
		name: "sunset",
		slug: "sunset",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🌉",
		skin_tone_support: false,
		name: "bridge at night",
		slug: "bridge_at_night",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "♨️",
		skin_tone_support: false,
		name: "hot springs",
		slug: "hot_springs",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🎠",
		skin_tone_support: false,
		name: "carousel horse",
		slug: "carousel_horse",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🛝",
		skin_tone_support: false,
		name: "playground slide",
		slug: "playground_slide",
		unicode_version: "14.0",
		emoji_version: "14.0"
	},
	{
		emoji: "🎡",
		skin_tone_support: false,
		name: "ferris wheel",
		slug: "ferris_wheel",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🎢",
		skin_tone_support: false,
		name: "roller coaster",
		slug: "roller_coaster",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "💈",
		skin_tone_support: false,
		name: "barber pole",
		slug: "barber_pole",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🎪",
		skin_tone_support: false,
		name: "circus tent",
		slug: "circus_tent",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🚂",
		skin_tone_support: false,
		name: "locomotive",
		slug: "locomotive",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🚃",
		skin_tone_support: false,
		name: "railway car",
		slug: "railway_car",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🚄",
		skin_tone_support: false,
		name: "high-speed train",
		slug: "high_speed_train",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🚅",
		skin_tone_support: false,
		name: "bullet train",
		slug: "bullet_train",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🚆",
		skin_tone_support: false,
		name: "train",
		slug: "train",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🚇",
		skin_tone_support: false,
		name: "metro",
		slug: "metro",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🚈",
		skin_tone_support: false,
		name: "light rail",
		slug: "light_rail",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🚉",
		skin_tone_support: false,
		name: "station",
		slug: "station",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🚊",
		skin_tone_support: false,
		name: "tram",
		slug: "tram",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🚝",
		skin_tone_support: false,
		name: "monorail",
		slug: "monorail",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🚞",
		skin_tone_support: false,
		name: "mountain railway",
		slug: "mountain_railway",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🚋",
		skin_tone_support: false,
		name: "tram car",
		slug: "tram_car",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🚌",
		skin_tone_support: false,
		name: "bus",
		slug: "bus",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🚍",
		skin_tone_support: false,
		name: "oncoming bus",
		slug: "oncoming_bus",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🚎",
		skin_tone_support: false,
		name: "trolleybus",
		slug: "trolleybus",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🚐",
		skin_tone_support: false,
		name: "minibus",
		slug: "minibus",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🚑",
		skin_tone_support: false,
		name: "ambulance",
		slug: "ambulance",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🚒",
		skin_tone_support: false,
		name: "fire engine",
		slug: "fire_engine",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🚓",
		skin_tone_support: false,
		name: "police car",
		slug: "police_car",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🚔",
		skin_tone_support: false,
		name: "oncoming police car",
		slug: "oncoming_police_car",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🚕",
		skin_tone_support: false,
		name: "taxi",
		slug: "taxi",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🚖",
		skin_tone_support: false,
		name: "oncoming taxi",
		slug: "oncoming_taxi",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🚗",
		skin_tone_support: false,
		name: "automobile",
		slug: "automobile",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🚘",
		skin_tone_support: false,
		name: "oncoming automobile",
		slug: "oncoming_automobile",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🚙",
		skin_tone_support: false,
		name: "sport utility vehicle",
		slug: "sport_utility_vehicle",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🛻",
		skin_tone_support: false,
		name: "pickup truck",
		slug: "pickup_truck",
		unicode_version: "13.0",
		emoji_version: "13.0"
	},
	{
		emoji: "🚚",
		skin_tone_support: false,
		name: "delivery truck",
		slug: "delivery_truck",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🚛",
		skin_tone_support: false,
		name: "articulated lorry",
		slug: "articulated_lorry",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🚜",
		skin_tone_support: false,
		name: "tractor",
		slug: "tractor",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🏎️",
		skin_tone_support: false,
		name: "racing car",
		slug: "racing_car",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🏍️",
		skin_tone_support: false,
		name: "motorcycle",
		slug: "motorcycle",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🛵",
		skin_tone_support: false,
		name: "motor scooter",
		slug: "motor_scooter",
		unicode_version: "3.0",
		emoji_version: "3.0"
	},
	{
		emoji: "🦽",
		skin_tone_support: false,
		name: "manual wheelchair",
		slug: "manual_wheelchair",
		unicode_version: "12.0",
		emoji_version: "12.0"
	},
	{
		emoji: "🦼",
		skin_tone_support: false,
		name: "motorized wheelchair",
		slug: "motorized_wheelchair",
		unicode_version: "12.0",
		emoji_version: "12.0"
	},
	{
		emoji: "🛺",
		skin_tone_support: false,
		name: "auto rickshaw",
		slug: "auto_rickshaw",
		unicode_version: "12.0",
		emoji_version: "12.0"
	},
	{
		emoji: "🚲",
		skin_tone_support: false,
		name: "bicycle",
		slug: "bicycle",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🛴",
		skin_tone_support: false,
		name: "kick scooter",
		slug: "kick_scooter",
		unicode_version: "3.0",
		emoji_version: "3.0"
	},
	{
		emoji: "🛹",
		skin_tone_support: false,
		name: "skateboard",
		slug: "skateboard",
		unicode_version: "11.0",
		emoji_version: "11.0"
	},
	{
		emoji: "🛼",
		skin_tone_support: false,
		name: "roller skate",
		slug: "roller_skate",
		unicode_version: "13.0",
		emoji_version: "13.0"
	},
	{
		emoji: "🚏",
		skin_tone_support: false,
		name: "bus stop",
		slug: "bus_stop",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🛣️",
		skin_tone_support: false,
		name: "motorway",
		slug: "motorway",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🛤️",
		skin_tone_support: false,
		name: "railway track",
		slug: "railway_track",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🛢️",
		skin_tone_support: false,
		name: "oil drum",
		slug: "oil_drum",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "⛽",
		skin_tone_support: false,
		name: "fuel pump",
		slug: "fuel_pump",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🛞",
		skin_tone_support: false,
		name: "wheel",
		slug: "wheel",
		unicode_version: "14.0",
		emoji_version: "14.0"
	},
	{
		emoji: "🚨",
		skin_tone_support: false,
		name: "police car light",
		slug: "police_car_light",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🚥",
		skin_tone_support: false,
		name: "horizontal traffic light",
		slug: "horizontal_traffic_light",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🚦",
		skin_tone_support: false,
		name: "vertical traffic light",
		slug: "vertical_traffic_light",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🛑",
		skin_tone_support: false,
		name: "stop sign",
		slug: "stop_sign",
		unicode_version: "3.0",
		emoji_version: "3.0"
	},
	{
		emoji: "🚧",
		skin_tone_support: false,
		name: "construction",
		slug: "construction",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "⚓",
		skin_tone_support: false,
		name: "anchor",
		slug: "anchor",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🛟",
		skin_tone_support: false,
		name: "ring buoy",
		slug: "ring_buoy",
		unicode_version: "14.0",
		emoji_version: "14.0"
	},
	{
		emoji: "⛵",
		skin_tone_support: false,
		name: "sailboat",
		slug: "sailboat",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🛶",
		skin_tone_support: false,
		name: "canoe",
		slug: "canoe",
		unicode_version: "3.0",
		emoji_version: "3.0"
	},
	{
		emoji: "🚤",
		skin_tone_support: false,
		name: "speedboat",
		slug: "speedboat",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🛳️",
		skin_tone_support: false,
		name: "passenger ship",
		slug: "passenger_ship",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "⛴️",
		skin_tone_support: false,
		name: "ferry",
		slug: "ferry",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🛥️",
		skin_tone_support: false,
		name: "motor boat",
		slug: "motor_boat",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🚢",
		skin_tone_support: false,
		name: "ship",
		slug: "ship",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "✈️",
		skin_tone_support: false,
		name: "airplane",
		slug: "airplane",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🛩️",
		skin_tone_support: false,
		name: "small airplane",
		slug: "small_airplane",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🛫",
		skin_tone_support: false,
		name: "airplane departure",
		slug: "airplane_departure",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🛬",
		skin_tone_support: false,
		name: "airplane arrival",
		slug: "airplane_arrival",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🪂",
		skin_tone_support: false,
		name: "parachute",
		slug: "parachute",
		unicode_version: "12.0",
		emoji_version: "12.0"
	},
	{
		emoji: "💺",
		skin_tone_support: false,
		name: "seat",
		slug: "seat",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🚁",
		skin_tone_support: false,
		name: "helicopter",
		slug: "helicopter",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🚟",
		skin_tone_support: false,
		name: "suspension railway",
		slug: "suspension_railway",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🚠",
		skin_tone_support: false,
		name: "mountain cableway",
		slug: "mountain_cableway",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🚡",
		skin_tone_support: false,
		name: "aerial tramway",
		slug: "aerial_tramway",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🛰️",
		skin_tone_support: false,
		name: "satellite",
		slug: "satellite",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🚀",
		skin_tone_support: false,
		name: "rocket",
		slug: "rocket",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🛸",
		skin_tone_support: false,
		name: "flying saucer",
		slug: "flying_saucer",
		unicode_version: "5.0",
		emoji_version: "5.0"
	},
	{
		emoji: "🛎️",
		skin_tone_support: false,
		name: "bellhop bell",
		slug: "bellhop_bell",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🧳",
		skin_tone_support: false,
		name: "luggage",
		slug: "luggage",
		unicode_version: "11.0",
		emoji_version: "11.0"
	},
	{
		emoji: "⌛",
		skin_tone_support: false,
		name: "hourglass done",
		slug: "hourglass_done",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "⏳",
		skin_tone_support: false,
		name: "hourglass not done",
		slug: "hourglass_not_done",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "⌚",
		skin_tone_support: false,
		name: "watch",
		slug: "watch",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "⏰",
		skin_tone_support: false,
		name: "alarm clock",
		slug: "alarm_clock",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "⏱️",
		skin_tone_support: false,
		name: "stopwatch",
		slug: "stopwatch",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "⏲️",
		skin_tone_support: false,
		name: "timer clock",
		slug: "timer_clock",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🕰️",
		skin_tone_support: false,
		name: "mantelpiece clock",
		slug: "mantelpiece_clock",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🕛",
		skin_tone_support: false,
		name: "twelve o’clock",
		slug: "twelve_o_clock",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🕧",
		skin_tone_support: false,
		name: "twelve-thirty",
		slug: "twelve_thirty",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🕐",
		skin_tone_support: false,
		name: "one o’clock",
		slug: "one_o_clock",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🕜",
		skin_tone_support: false,
		name: "one-thirty",
		slug: "one_thirty",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🕑",
		skin_tone_support: false,
		name: "two o’clock",
		slug: "two_o_clock",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🕝",
		skin_tone_support: false,
		name: "two-thirty",
		slug: "two_thirty",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🕒",
		skin_tone_support: false,
		name: "three o’clock",
		slug: "three_o_clock",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🕞",
		skin_tone_support: false,
		name: "three-thirty",
		slug: "three_thirty",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🕓",
		skin_tone_support: false,
		name: "four o’clock",
		slug: "four_o_clock",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🕟",
		skin_tone_support: false,
		name: "four-thirty",
		slug: "four_thirty",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🕔",
		skin_tone_support: false,
		name: "five o’clock",
		slug: "five_o_clock",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🕠",
		skin_tone_support: false,
		name: "five-thirty",
		slug: "five_thirty",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🕕",
		skin_tone_support: false,
		name: "six o’clock",
		slug: "six_o_clock",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🕡",
		skin_tone_support: false,
		name: "six-thirty",
		slug: "six_thirty",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🕖",
		skin_tone_support: false,
		name: "seven o’clock",
		slug: "seven_o_clock",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🕢",
		skin_tone_support: false,
		name: "seven-thirty",
		slug: "seven_thirty",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🕗",
		skin_tone_support: false,
		name: "eight o’clock",
		slug: "eight_o_clock",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🕣",
		skin_tone_support: false,
		name: "eight-thirty",
		slug: "eight_thirty",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🕘",
		skin_tone_support: false,
		name: "nine o’clock",
		slug: "nine_o_clock",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🕤",
		skin_tone_support: false,
		name: "nine-thirty",
		slug: "nine_thirty",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🕙",
		skin_tone_support: false,
		name: "ten o’clock",
		slug: "ten_o_clock",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🕥",
		skin_tone_support: false,
		name: "ten-thirty",
		slug: "ten_thirty",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🕚",
		skin_tone_support: false,
		name: "eleven o’clock",
		slug: "eleven_o_clock",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🕦",
		skin_tone_support: false,
		name: "eleven-thirty",
		slug: "eleven_thirty",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🌑",
		skin_tone_support: false,
		name: "new moon",
		slug: "new_moon",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🌒",
		skin_tone_support: false,
		name: "waxing crescent moon",
		slug: "waxing_crescent_moon",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🌓",
		skin_tone_support: false,
		name: "first quarter moon",
		slug: "first_quarter_moon",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🌔",
		skin_tone_support: false,
		name: "waxing gibbous moon",
		slug: "waxing_gibbous_moon",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🌕",
		skin_tone_support: false,
		name: "full moon",
		slug: "full_moon",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🌖",
		skin_tone_support: false,
		name: "waning gibbous moon",
		slug: "waning_gibbous_moon",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🌗",
		skin_tone_support: false,
		name: "last quarter moon",
		slug: "last_quarter_moon",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🌘",
		skin_tone_support: false,
		name: "waning crescent moon",
		slug: "waning_crescent_moon",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🌙",
		skin_tone_support: false,
		name: "crescent moon",
		slug: "crescent_moon",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🌚",
		skin_tone_support: false,
		name: "new moon face",
		slug: "new_moon_face",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🌛",
		skin_tone_support: false,
		name: "first quarter moon face",
		slug: "first_quarter_moon_face",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🌜",
		skin_tone_support: false,
		name: "last quarter moon face",
		slug: "last_quarter_moon_face",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🌡️",
		skin_tone_support: false,
		name: "thermometer",
		slug: "thermometer",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "☀️",
		skin_tone_support: false,
		name: "sun",
		slug: "sun",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🌝",
		skin_tone_support: false,
		name: "full moon face",
		slug: "full_moon_face",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🌞",
		skin_tone_support: false,
		name: "sun with face",
		slug: "sun_with_face",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🪐",
		skin_tone_support: false,
		name: "ringed planet",
		slug: "ringed_planet",
		unicode_version: "12.0",
		emoji_version: "12.0"
	},
	{
		emoji: "⭐",
		skin_tone_support: false,
		name: "star",
		slug: "star",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🌟",
		skin_tone_support: false,
		name: "glowing star",
		slug: "glowing_star",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🌠",
		skin_tone_support: false,
		name: "shooting star",
		slug: "shooting_star",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🌌",
		skin_tone_support: false,
		name: "milky way",
		slug: "milky_way",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "☁️",
		skin_tone_support: false,
		name: "cloud",
		slug: "cloud",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "⛅",
		skin_tone_support: false,
		name: "sun behind cloud",
		slug: "sun_behind_cloud",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "⛈️",
		skin_tone_support: false,
		name: "cloud with lightning and rain",
		slug: "cloud_with_lightning_and_rain",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🌤️",
		skin_tone_support: false,
		name: "sun behind small cloud",
		slug: "sun_behind_small_cloud",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🌥️",
		skin_tone_support: false,
		name: "sun behind large cloud",
		slug: "sun_behind_large_cloud",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🌦️",
		skin_tone_support: false,
		name: "sun behind rain cloud",
		slug: "sun_behind_rain_cloud",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🌧️",
		skin_tone_support: false,
		name: "cloud with rain",
		slug: "cloud_with_rain",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🌨️",
		skin_tone_support: false,
		name: "cloud with snow",
		slug: "cloud_with_snow",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🌩️",
		skin_tone_support: false,
		name: "cloud with lightning",
		slug: "cloud_with_lightning",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🌪️",
		skin_tone_support: false,
		name: "tornado",
		slug: "tornado",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🌫️",
		skin_tone_support: false,
		name: "fog",
		slug: "fog",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🌬️",
		skin_tone_support: false,
		name: "wind face",
		slug: "wind_face",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "🌀",
		skin_tone_support: false,
		name: "cyclone",
		slug: "cyclone",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🌈",
		skin_tone_support: false,
		name: "rainbow",
		slug: "rainbow",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🌂",
		skin_tone_support: false,
		name: "closed umbrella",
		slug: "closed_umbrella",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "☂️",
		skin_tone_support: false,
		name: "umbrella",
		slug: "umbrella",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "☔",
		skin_tone_support: false,
		name: "umbrella with rain drops",
		slug: "umbrella_with_rain_drops",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "⛱️",
		skin_tone_support: false,
		name: "umbrella on ground",
		slug: "umbrella_on_ground",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "⚡",
		skin_tone_support: false,
		name: "high voltage",
		slug: "high_voltage",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "❄️",
		skin_tone_support: false,
		name: "snowflake",
		slug: "snowflake",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "☃️",
		skin_tone_support: false,
		name: "snowman",
		slug: "snowman",
		unicode_version: "0.7",
		emoji_version: "0.7"
	},
	{
		emoji: "⛄",
		skin_tone_support: false,
		name: "snowman without snow",
		slug: "snowman_without_snow",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "☄️",
		skin_tone_support: false,
		name: "comet",
		slug: "comet",
		unicode_version: "1.0",
		emoji_version: "1.0"
	},
	{
		emoji: "🔥",
		skin_tone_support: false,
		name: "fire",
		slug: "fire",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "💧",
		skin_tone_support: false,
		name: "droplet",
		slug: "droplet",
		unicode_version: "0.6",
		emoji_version: "0.6"
	},
	{
		emoji: "🌊",
		skin_tone_support: false,
		name: "water wave",
		slug: "water_wave",
		unicode_version: "0.6",
		emoji_version: "0.6"
	}
],
	Activities: Activities,
	Objects: Objects,
	Symbols: Symbols,
	Flags: Flags
};/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2018 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 */

var emoji_markdown_it_defs = {};
var emoji_defs_by_char = (function() {
    var result = {};

    $.each(emojiData, function (emoji, def) {
        $.each(old_emojilib, function (key, item) {
            if (emoji === item.char && key !== def.name) {
                def.char = emoji;
                def.keywords = item.keywords;
                emoji_markdown_it_defs[key] = emoji;
                return false;
            }
        });

        result[emoji] = def.name;
        emojiNameMap.emoji[def.name] = emoji;
        emoji_markdown_it_defs[def.name] = emoji;
    });

    return result;
})();

// Flatten shortcuts to simple object: { alias: emoji_name }
var shortcuts = Object.keys(emoji_shortcuts).reduce(function (acc, key) {
    if (Array.isArray(emoji_shortcuts[key])) {
        emoji_shortcuts[key].forEach(function (alias) {
            acc[alias] = key;
        });
        return acc;
    }

    acc[emoji_shortcuts[key]] = key;
    return acc;
}, {});

var getEmojiDefinitionByShortcut = function (shortcut) {
    var result = {
        name: getNameByShortcut(shortcut)
    };

    if (result.name) {
        result.emoji = getCharByName(result.name);
    }

    if (result.emoji) {
        result.$dom = getCharToDom(result.emoji);
    }

    return result;
};

var getNameByShortcut = function (shortcut) {
    return String(shortcuts[shortcut]);
};

var getCharByName = function (name) {
    return emojiNameMap.get(name);
};

var getNameByChar = function (emojiChar) {
    return String(emoji_defs_by_char[emojiChar]);
};

var getCharToDom = function (emojiChar, name) {
    name = (typeof name !== 'undefined') ? name : emoji_defs_by_char[emojiChar];
    name = String(name);

    var config = getEmojiConfig();
    var twemojiConfig = config.twemoji || {};
    twemojiConfig.attributes = function (icon, variant) {
        return {
            'data-name': name,
            'style': 'width:16px'
        };
    };

    var parsed = twemoji.parse(emojiChar, twemojiConfig);

    if (parsed && parsed.length) {
        try {
            return $(parsed).first();
        } catch (e) {
            console.error(e);
        }
        return '';
    }
};


var byCategory = {};

var getByCategory = function (category) {
    if (category === 'Search')
        { return []; }

    if (!byCategory[category]) {
        groupedEmojiData[category].forEach(function (emojiDef) {
            emojiDef.keywords = keywordSet[emojiDef.emoji];
        });
        byCategory[category] = groupedEmojiData[category];
    }

    return byCategory[category];
};

var getMarkdownItOpts = function () {
    return {defs: emoji_markdown_it_defs};
};/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2018 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 */


var EmojiQueryState = function EmojiQueryState(state, options) {
    var this$1$1 = this;

    this.state = state;
    this.provider = options.provider;
    this.provider.event.on('closed', function () {
        if (this$1$1.active) {
            var ref = this$1$1.state.schema.marks;
            var emojiQuery = ref.emojiQuery;
            this$1$1.view.dispatch(this$1$1.state.tr.removeMark(0, this$1$1.state.doc.nodeSize - 2, emojiQuery));
        }
    }).on('focus', function () {
        this$1$1.view.focus();
    });
    this.reset();
};

EmojiQueryState.prototype.findQueryNode = function findQueryNode () {
    return $(this.view.dom).find('[data-emoji-query]');
};

EmojiQueryState.prototype.update = function update (state, view) {
    this.view = view;
    this.state = state;
    var ref = state.schema.marks;
        var emojiQuery = ref.emojiQuery;
    var doc = state.doc;
        var selection = state.selection;
    var $from = selection.$from;
        var from = selection.from;
        var to = selection.to;

    this.active = doc.rangeHasMark(from - 1, to, emojiQuery);

    if (!this.active) {
        return this.reset();
    }

    var $query = this.findQueryNode();
    var $pos = doc.resolve(from - 1);

    this.queryMark = {
        start: $pos.path[$pos.path.length - 1],
        end: to
    };

    var nodeBefore = $from.nodeBefore;

    if (!nodeBefore.text.length || nodeBefore.text.length > 1) {
        this.provider.reset();
        return;
    }

    var query = nodeBefore.text.substr(1);

    if (query != this.query) {
        this.query = query;
        this.provider.query(this, $query[0]);
    }
};

EmojiQueryState.prototype.reset = function reset () {
    this.active = false;
    this.query = null;
    if (this.view) {
        this.provider.reset();
    }
};

EmojiQueryState.prototype.addEmoji = function addEmoji (item) {
    var ref = this.state.schema.nodes;
        var emoji = ref.emoji;
    var ref$1 = this.state.schema.marks;
        var emojiQuery = ref$1.emojiQuery;

    var nodes = [emoji.create({
        'data-name': String(item.name),
        alt: item.alt,
        src: item.src
    }, null)];


    var tr = this.state.tr
        .removeMark(0, this.state.doc.nodeSize - 2, emojiQuery)
        .replaceWith(this.queryMark.start, this.queryMark.end, nodes);

    if (isChromeWithSelectionBug) {
        document.getSelection().empty();
    }

    this.view.dispatch(tr);
    this.view.focus();
};

var SimpleEmojiState = function SimpleEmojiState(provider) {
    var this$1$1 = this;

    this.provider = provider;
    this.provider.event.on('focus', function () {
        if (this$1$1.view) {
            this$1$1.view.focus();
        }
    });
    this.reset();
};

SimpleEmojiState.prototype.update = function update (state, view, node) {
    this.view = view;
    this.state = state;
    this.provider.query(this, node, true);
};

SimpleEmojiState.prototype.reset = function reset () {
    if (this.view) {
        this.provider.reset();
        this.view.focus();
    }
};

SimpleEmojiState.prototype.addEmoji = function addEmoji (item) {
    var ref = this.state.schema.nodes;
        var emoji = ref.emoji;

    var node = emoji.create({
        'data-name': String(item.name),
        alt: item.alt,
        src: item.src
    }, null);

    var tr = this.state.tr.replaceSelectionWith(node);

    this.view.dispatch(tr);
    this.view.focus();
    this.reset();
};/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 */


var userFlag = undefined;
var findUserFlag = function () {
    if (userFlag) {
        return userFlag;
    }

    var directMapping = {
        'en-us': 'us',
        'en': 'us',
        'en-gb': 'uk',
        'pt-br': 'portugal',
        'fa-ir': 'iran',
        'zh-cn': 'cn',
        'zh-tw': 'cn',
        'ja': 'jp',
        'ko': 'kr',
        'ar': 'united_arab_emirates',
        'uk': 'ukraine',
        'ru': 'ru',
        'vi': 'vietnam',
        'sv': 'sweden',
        'nb-no': 'norway',
        'it': 'it',
        'fr': 'fr',
        'es': 'es',
        'de': 'de',
        'da': 'denmark',
        'cs': 'czech_republic',
        'ca': 'es', // sorry for that ;)
        'an': 'es'
    };

    var result = '\uD83C\uDDE9\uD83C\uDDEA';

    try {
        var language = getUserLocale();

        if (language && directMapping[language]) {
            return getCharByName(directMapping[language]);
        }

        $.each(getByCategory('Flags'), function (index, flag) {
            if (flag && flag.keywords && flag.keywords.indexOf(language) >= 0) {
                result = flag.emoji;
                return false;
            }
        });
    } catch (e) {
        console.error('Error while determining user flag in emoji chooser');
        console.error(e);
    }

    return userFlag = result;
};

var chooser = undefined;

var EmojiChooser = function EmojiChooser(provider) {
    this.provider = provider;
    this.categoryOrder = [
        'Smileys & Emotion',
        'People & Body',
        'Animals & Nature',
        'Food & Drink',
        'Travel & Places',
        'Activities',
        'Objects',
        'Symbols',
        'Flags',
        'Search'
    ];
    this.categories = {
        'Smileys & Emotion': {$icon: getCharToDom('\uD83D\uDE00')},
        'People & Body': {$icon: getCharToDom('\uD83D\uDC4D')},
        'Animals & Nature': {$icon: getCharToDom('\uD83D\uDC3B')},
        'Food & Drink': {$icon: getCharToDom('\uD83C\uDF82')},
        'Travel & Places': {$icon: getCharToDom('\u26BD')},
        'Activities': {$icon: getCharToDom('\u2708\uFE0F')},
        'Objects': {$icon: getCharToDom('\uD83D\uDDA5')},
        'Symbols': {$icon: getCharToDom('\u2764\uFE0F')},
        'Flags': {$icon: getCharToDom(findUserFlag())},
        'Search': {$icon: getCharToDom('\uD83D\uDD0D')}
    };
};

EmojiChooser.prototype.update = function update (provider, focus) {
    this.provider = provider;
    var position = provider.$node.offset();

    if (!this.$) {
        this.initDom();
        this.initCategory(this.categoryOrder[0]);
    }

    if (!isSmallView()) {
        this.$.css({
            top: position.top + provider.$node.outerHeight() - 5,
            left: position.left,
        }).show();
    } else {
        this.$.css({
            top: 5,
            position: 'fixed',
            left: 0,
            right: 0,
            margin: 'auto'
        }).show();
    }

    if (focus) {
        this.$.find('.humhub-emoji-chooser-search').focus();
    }
};

EmojiChooser.prototype.initDom = function initDom () {
    var that = this;
    this.$ = $('<div class="atwho-view humhub-richtext-provider humhub-emoji-chooser"><div>' +
        '<input type="text" placeholder="' + this.translate('Search') + '" class="form-control humhub-emoji-chooser-search">' +
        '</div></div>')
        .hide().appendTo($('body'))
        .on('hidden', function () {
            if (that.provider) {
                that.provider.reset();
            }
        });

    this.$.find('.humhub-emoji-chooser-search').on('keydown', function (e) {
        switch (e.which) {
            case 9:
                e.preventDefault();
                that.nextCategory();
                break;
            case 27:
                that.provider.reset();
                break;
            case 13:
                e.preventDefault();
                that.provider.select();
                break;
            case 37:
                that.prev();
                break;
            case 38:
                that.up();
                break;
            case 39:
                that.next();
                break;
            case 40:
                that.down();
                break;
        }
    }).on('keyup', function (e) {
        var keyCode = e.keyCode || e.which;
        // This line should prevent processing in case user presses down/up on desktop, android chrome does not send
        // always send keyCode 229 so we can skip this check in this case
        if (keyCode !== 229 && keyCode !== 8 && !/[a-z0-9\d]/i.test(String.fromCharCode(keyCode))) {
            return;
        }

        var val = $(this).val();
        if (!val.length && that.lastActiveCategory) {
            that.openCategory(that.lastActiveCategory);
            return;
        }

        var currentlyActive = that.getActiveCategoryMenuItem().attr('data-emoji-nav-item');
        if (currentlyActive !== 'Search') {
            that.lastActiveCategory = currentlyActive;
        }

        that.updateSearch(val);
    });

    this.initNav();
};

EmojiChooser.prototype.initNav = function initNav () {
        var this$1$1 = this;

    var $nav = $('<div class="emoji-nav">').appendTo(this.$);

    this.categoryOrder.forEach(function (categoryName, index) {
        var categoryDef = this$1$1.categories[categoryName];
        var $item = $('<span class="emoji-nav-item" title="' + this$1$1.translate(categoryName) + '">').attr('data-emoji-nav-item', categoryName).append(categoryDef.$icon).on('click', function () {
            this$1$1.openCategory(categoryName);
            this$1$1.provider.event.trigger('focus');
        });

        if (index === 0) {
            $item.addClass('cur');
        }

        $nav.append($item);
    });

    $nav.find('[data-emoji-nav-item="Search"]').hide();
};

EmojiChooser.prototype.clearSearch = function clearSearch () {
    this.$.find('[data-emoji-nav-item="Search"]').hide();
    this.$.find('.humhub-emoji-chooser-search').val('');
};

EmojiChooser.prototype.updateSearch = function updateSearch (searchStr) {
    this.$.find('[data-emoji-nav-item="Search"]').show();
    var result = [];
    var length = searchStr.length;
    this.categoryOrder.forEach(function (categoryName, index) {
        $.each(getByCategory(categoryName), function (index, emoji) {
            if (emoji && emoji.keywords) {
                $.each(emoji.keywords, function (index, keyword) {
                    if (length < 3) {
                        if (keyword.lastIndexOf(searchStr, 0) === 0) {
                            result.push(emoji);
                            return false;
                        }
                    } else if (keyword.includes(searchStr)) {
                        result.push(emoji);
                        return false;
                    }
                });
            }
        });
    });

    this.openCategory('Search');
    this.setCategoryItems('Search', result);
};

EmojiChooser.prototype.openCategory = function openCategory (categoryName) {
    this.categories[categoryName];

    if (!this.$.find('[data-emoji-category="' + categoryName + '"]').length) {
        this.initCategory(categoryName);
    }

    if (categoryName !== 'Search') {
        this.clearSearch();
    }

    this.$.find('[data-emoji-nav-item]').removeClass('cur');
    this.$.find('[data-emoji-nav-item="' + categoryName + '"]').addClass('cur');
    this.$.find('[data-emoji-category]').hide();
    this.$.find('[data-emoji-category="' + categoryName + '"]').show();
};

EmojiChooser.prototype.initCategory = function initCategory (categoryName) {
    var that = this;
    var $category = $('<div>').attr('data-emoji-category', categoryName).on('click', '.atwho-emoji-entry', function () {
        that.getSelectionNode().removeClass('cur');
        $(this).addClass('cur');
        that.provider.select();
    }).prependTo(this.$);

    $('<ul class="atwo-view-ul humhub-emoji-chooser-item-list">').appendTo($category);
    this.categories[categoryName].$ = $category;
    this.setCategoryItems(categoryName);
};

EmojiChooser.prototype.setCategoryItems = function setCategoryItems (categoryName, items) {
    if (!items && categoryName !== 'Search') {
        items = getByCategory(categoryName);
    }

    if (!items) {
        items = [];
    }

    var $list = this.categories[categoryName].$.find('.humhub-emoji-chooser-item-list').empty();

    items.forEach(function (emojiDef) {
        var $img = getCharToDom(emojiDef.emoji, emojiDef.name);

        if ($img && $img !== '' && $img.length) {
            var $li = $('<li class="atwho-emoji-entry">').append($img);

            if (categoryName === 'Flags' && emojiDef.emoji === findUserFlag()) {
                $list.prepend($li);
            } else {
                $list.append($li);
            }
        }
    });

    $list.children().first().addClass('cur');
};

EmojiChooser.prototype.reset = function reset () {
    this.provder = undefined;
    this.$.remove();
    this.$ = undefined;
};

EmojiChooser.prototype.getSelection = function getSelection () {
    var $selection = this.getSelectionNode().find('img');
    return {
        name: $selection.data('name'),
        alt: $selection.attr('alt'),
        src: $selection.attr('src'),
    }
};

EmojiChooser.prototype.translate = function translate (key) {
    return this.provider.context.translate(key);
};

EmojiChooser.prototype.getSelectionNode = function getSelectionNode () {
    return this.getActiveCategoryTab().find('.cur');
};

EmojiChooser.prototype.getActiveCategoryTab = function getActiveCategoryTab () {
    return this.$.find('[data-emoji-category]:visible');
};

EmojiChooser.prototype.getActiveCategoryMenuItem = function getActiveCategoryMenuItem () {
    return this.$.find('[data-emoji-nav-item].cur');
};

EmojiChooser.prototype.nextCategory = function nextCategory () {
    var $next = this.getActiveCategoryMenuItem().next('[data-emoji-nav-item]:not([data-emoji-nav-item="Search"])');
    if (!$next.length) {
        $next = this.$.find('[data-emoji-nav-item]:first');
    }

    this.openCategory($next.attr('data-emoji-nav-item'));
};

EmojiChooser.prototype.prev = function prev () {
    var $cur = this.getSelectionNode();
    var $prev = $cur.prev();
    if ($prev.length) {
        $prev.addClass('cur');
        $cur.removeClass('cur');
        this.alignScroll();
    }
};

EmojiChooser.prototype.next = function next () {
    var $cur = this.getSelectionNode();
    var $next = $cur.next();
    if ($next.length) {
        $next.addClass('cur');
        $cur.removeClass('cur');
        this.alignScroll();
    }
};

EmojiChooser.prototype.up = function up () {
    var $cur = this.getSelectionNode();
    var curPosition = $cur.position();

    for (var $prev = $cur.prev(); $prev.length; $prev = $prev.prev()) {
        var nextPosition = $prev.position();

        if (nextPosition.top < curPosition.top && nextPosition.left === curPosition.left) {
            $prev.addClass('cur');
            $cur.removeClass('cur');
            this.alignScroll();
            return;
        }
    }
};

EmojiChooser.prototype.down = function down () {
    var $cur = this.getSelectionNode();
    var curPosition = $cur.position();

    for (var $next = $cur.next(); $next.length; $next = $next.next()) {
        var nextPosition = $next.position();
        if (nextPosition.top > curPosition.top && nextPosition.left === curPosition.left) {
            $next.addClass('cur');
            $cur.removeClass('cur');
            this.alignScroll();
            return;
        }
    }

    // If we did not find a match the line below is probably the last line.
    var $last = this.getActiveCategoryTab().find('.atwho-emoji-entry:last');
    if ($last.position().top !== curPosition.top) {
        $last.addClass('cur');
        $cur.removeClass('cur');
        this.alignScroll();
    }
};

EmojiChooser.prototype.alignScroll = function alignScroll () {
    var $cur = this.getSelectionNode();
    var $tab = this.getActiveCategoryTab();
    var scrollTop = $tab.scrollTop();
    var scrollBottom = scrollTop + $tab.height();

    var offsetTop = $cur[0].offsetTop;
    var offsetBottom = offsetTop + $cur.height();

    if (offsetTop > scrollBottom || offsetTop < scrollTop || offsetBottom > scrollBottom || offsetBottom < scrollTop) {
        $tab[0].scrollTop = $cur[0].offsetTop;
    }
};

var EmojiProvider = function EmojiProvider(context) {
    this.event = $({});
    this.context = context;
};

EmojiProvider.prototype.query = function query (state, node, focus) {
    this.state = state;
    this.$node = $(node);
    this.update(focus);
};

EmojiProvider.prototype.reset = function reset (query, node) {
    if (this.$node) {
        this.$node = undefined;
        this.getChooser().reset();
        this.event.trigger('closed');
    }
};

EmojiProvider.prototype.next = function next () {
    this.getChooser().next();
};

EmojiProvider.prototype.prev = function prev () {
    this.getChooser().prev();
};

EmojiProvider.prototype.down = function down () {
    this.getChooser().down();
};

EmojiProvider.prototype.up = function up () {
    this.getChooser().up();
};

EmojiProvider.prototype.select = function select () {
    this.state.addEmoji(this.getChooser().getSelection());
};

EmojiProvider.prototype.update = function update (focus) {
    this.getChooser().update(this, focus);
};

EmojiProvider.prototype.getChooser = function getChooser () {
    if (!chooser) {
        chooser = new EmojiChooser(this);
    }

    return chooser;
};


function getProvider(context) {
    return (context.options.emoji && context.options.emoji.provider)
        ? context.options.emoji.provider : new EmojiProvider(context);
}/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2018 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 */


var pluginKey$2 = new PluginKey('emoji');

var emojiPlugin = function (context) {
    return new Plugin({
        props: {
            transformPastedText: function (text) {
                text = twemoji.parse(text, context.getPluginOption('emoji', 'twemoji'));

                // eslint-disable-next-line
                return text.replace(/\<img class="emoji"[^\\\>]* alt=\"([^\"]*)\"[^\\\>]*\/>/g, function (match, char) {
                    return ':' + getNameByChar(char) + ':';
                });
            },
        },
        state: {
            init: function init(config, state) {
                return new EmojiQueryState(state, {
                    provider: getProvider(context)
                });
            },
            apply: function apply(tr, prevPluginState, oldState, newState) {
                return prevPluginState;
            }
        },
        key: pluginKey$2,
        view: function (view) {
            var emojiState = pluginKey$2.getState(view.state);

            return {
                update: function update(view, prevState) {
                    emojiState.update(view.state, view);
                },
                destroy: function destroy() {}
            };
        },
    });
};var NodePos = function NodePos(node, pos, parent) {
    if ( pos === void 0 ) pos = 0;

    this.node = node;
    this.pos = pos;
    this.children = [];
    this.content = new NodePosFragment(this);
};

NodePos.prototype.push = function push (childNodePos) {
    if (!this.hasChild(childNodePos.pos)) {
        this.children.push(childNodePos);
    }
};

NodePos.prototype.hasChild = function hasChild (pos) {
    for (var i = 0; i < this.children.length; i++) {
        if (this.children[i].pos === pos) {
            return true;
        }
    }
};

NodePos.prototype.removeMark = function removeMark (mark) {
    var markInstance = this.getMark(mark);
    var index = this.node.marks.indexOf(markInstance);

    if (index > -1) {
        this.node.marks.splice(index, 1);
    }
};

NodePos.prototype.hasMark = function hasMark (mark) {
    return this.getMark(mark) != null;
};

NodePos.prototype.getMark = function getMark (mark) {
    var result = null;

    if (mark instanceof MarkType) {
        mark = mark.name;
    }

    this.node.marks.forEach(function (activeMark) {
        if (activeMark.type.name === mark) {
            result = activeMark;
        }
    });

    return result;
};

NodePos.prototype.isPlain = function isPlain () {
    return !this.node.marks.length;
};

NodePos.prototype.addMarks = function addMarks (marks) {
        var this$1$1 = this;

    if (!marks || !marks.length) {
        return;
    }

    marks.forEach(function (mark) {
        this$1$1.node.marks = mark.addToSet(this$1$1.node.marks);
    });
};

NodePos.prototype.nodesBetween = function nodesBetween (from, to, f, pos, level) {
        if ( from === void 0 ) from = 0;
        if ( pos === void 0 ) pos = 0;
        if ( level === void 0 ) level = 1;

    this.content.nodesBetween(from, to, function (childNode, childPos, parent, i, level) {
        f(childNode, childPos , parent, i, level);
    }, pos, this.node, level);
};

NodePos.prototype.start = function start () {
    return this.pos;
};

NodePos.prototype.end = function end () {
    return this.pos + this.node.nodeSize;
};

var NodePosFragment = function NodePosFragment(nodePos) {
    this.nodePos = nodePos;
    this.fragment = nodePos.node.content;
    this.size = this.fragment.size;
    this.content = this.fragment.content;
};

NodePosFragment.prototype.nodesBetween = function nodesBetween (from, to, f, nodeStart, parent, level) {
        if ( nodeStart === void 0 ) nodeStart = 0;

    for (var i = 0, pos = 0; pos < to; i++) {
        var child = this.content[i], end = pos + child.nodeSize;
        if (end > from && f(child, nodeStart + pos, parent, i, level) !== false && child.content.size) {
            var start = pos + 1;
            var childNodePos = new NodePos(child, start);

            childNodePos.nodesBetween(Math.max(0, from - start),
                                    Math.min(child.content.size, to - start),
                                    f, nodeStart + start, level + 1);
        }
        pos = end;
    }
};

var $node = function (node, pos) {
    if ( pos === void 0 ) pos = 0;

    if (!(this instanceof $node)) {
        return new $node(node,pos);
    }

    this.tree = [];
    this.flat = [];
    this.filters = [];
    this.findFlag = false;

    if (node) {
        this.push(new NodePos(node, pos));
    }
};

$node.prototype.push = function (nodePos, parentPos) {
    if (this._hasNodePos(nodePos.pos)) {
        return;
    }

    this.flat.push(nodePos);

    if (parentPos) {
        parentPos.push(nodePos);
    } else {
        this.tree.push(nodePos);
    }
};

$node.prototype.find = function (selector) {
    this.filters = [];

    if (!selector) {
        this.findFlag = true;
        return this;
    }

    return this.type(selector, false);
};

$node.prototype._hasNodePos = function(pos) {
    for (var i = 0; i < this.flat.length; i++) {
        if (this.flat[i].pos === pos) {
            return true;
        }
    }
};

$node.prototype.size = function() {
    return this.flat.length;
};

$node.prototype.type = function (selector, includeSelf) {
    var typeFilter = function (node, filter) {
        var result = false;
        if (Array.isArray(filter)) {
            filter.forEach(function (type) {
                if (typeFilter((type))) {
                    result = true;
                }
            });
        } else if (filter instanceof NodeType$2) {
            result = node.type === filter;
        } else if (typeof filter === 'string') {
            result = node.type.name === filter;
        }
        return result;
    };

    return this.where(function (node) {
        return typeFilter(node, selector);
    }, includeSelf);
};

$node.prototype.between = function (from, to) {
    return this.where(function (node, pos) {
        var $pos = node.resolve(pos);
        return from <= $pos.start && to >= $pos.end;
    });
};

$node.prototype.from = function (from) {
    return this.where(function (node, pos) {
        return from <= node.resolve(pos).start;
    });
};

$node.prototype.to = function (from, to) {
    return this.where(function (node, pos) {
        return to >= node.resolve(pos).end;
    });
};

$node.prototype.mark = function (filterMark, attributes) {
    if (!filterMark) {
        this.where(function (node) {
            return !node.marks.length;
        });
    }

    var markFilter = function (node, attributes, filter) {
        var result = false;
        if (Array.isArray(filter)) {
            result = true;
            filter.forEach(function (type) {
                result = result && markFilter(node, attributes, type);
            });
        } else {
            result = hasMark(node, filter);
        }

        return result;
    };

    return this.where(function (node) {
        return markFilter(node, attributes, filterMark);
    });
};


$node.prototype.markup = function (type, attrs, marks) {
    return this.where(function (node) {
        return node.hasMarkup(type, attrs, marks);
    });
};

$node.prototype.text = function (search) {
    return this.where(function (node) {
        return node.isText && ((search) ? node.text === search : true)
    })
};

$node.prototype.contains = function (search) {
    return this.where(function (node) {
        return node.textContent.indexOf(search) >= 0
    })
};

$node.prototype.textBlock = function () {
    return this.where(function (node) {
        return node.isTextblock
    })
};

$node.prototype.block = function () {
    return this.where(function (node) {
        return node.isBlock
    })
};

$node.prototype.inline = function () {
    return this.where(function (node) {
        return node.isInline
    })
};

$node.prototype.leaf = function () {
    return this.where(function (node) {
        return node.isLeaf
    })
};

$node.prototype.canAppend = function (node) {
    return this.where(function (node) {
        return node.canAppend(node)
    })
};

$node.prototype.sameMarkup = function (node) {
    return this.where(function (node) {
        return node.sameMarkup(node)
    })
};

$node.prototype.not = function () {
    this.notFlag = true;
    return this;
};

$node.prototype.delete = function (view) {
    var tr = view.state.tr;
    this.tree.reverse().forEach(function (nodePos) {
        tr = tr.delete(nodePos.start(), nodePos.end());
    });
    view.dispatch(tr);
};

$node.prototype.get = function (index) {
    return this.tree[index];
};

$node.prototype.append = function (node, view) {
    var tr = view.state.tr;
    var doc = view.state.doc;

    this.flat.reverse().forEach(function (nodePos) {
        tr = tr.setSelection(new TextSelection(doc.resolve(nodePos.end()))).replaceSelectionWith(node);
    });

    view.dispatch(tr);
};

$node.prototype.replaceWith = function (node, view, dispatch) {
    if ( dispatch === void 0 ) dispatch = true;

    var tr = view.state.tr;
    var doc = view.state.doc;

    this.flat.reverse().forEach(function (nodePos) {
        tr = tr.setSelection(new TextSelection(doc.resolve(nodePos.start()), doc.resolve(nodePos.end()))).replaceSelectionWith(node);
    });

    if (dispatch) {
        view.dispatch(tr);
    }
};

$node.prototype.removeMark = function (mark, state) {
    var tr = state.tr;
    var doc = state.doc;
    this.flat.forEach(function (nodePos) {
        nodePos.removeMark(mark);
        tr = tr.setSelection(new TextSelection(doc.resolve(nodePos.start())), doc.resolve(nodePos.end())).replaceSelectionWith(nodePos.node, false);
    });
};

$node.prototype.getMark = function(mark) {
    if (!this.flat.length) {
        return;
    }

    return this.flat[0].getMark(mark);
};

$node.prototype.where = function (filter, includeSelf) {
    var this$1$1 = this;
    if ( includeSelf === void 0 ) includeSelf = true;

    var addFilter = (this.notFlag)
                    ? function (node, pos, parent, searchRoot) {
                        return !filter(node, pos, parent, searchRoot)
                    }
                    : filter;

    this.filters.push(addFilter);

    var $result = new $node();
    $result.filters = this.filters;

    this.tree.forEach(function (rootNodePos) {
        var branchMatch = [];

        if (!this$1$1.findFlag && includeSelf && checkFilter(this$1$1.filters, rootNodePos.node, rootNodePos.pos)) {
            branchMatch[0] = new NodePos(rootNodePos.node, rootNodePos.pos);
            $result.push(branchMatch[0]);
        }

        var lastLevel = 1;
        var startPos = rootNodePos.node.type.name === 'doc' ? 0 : rootNodePos.pos + 1;

        rootNodePos.nodesBetween(0, rootNodePos.content.size, function (childNode, pos, parent, i, level) {
            // We moved one tree level back or switched to another branch
            if (lastLevel >= level) {
                branchMatch = clearLevelBranch(branchMatch, level);
            }

            if (checkFilter(this$1$1.filters, childNode, pos, parent)) {
                var nodePos = new NodePos(childNode, pos);
                $result.push(nodePos, findBranchMatch(branchMatch, level));
                branchMatch[level] = nodePos;
            }

            lastLevel = level;
        }, startPos);

    });

    this.notFlag = false;
    this.findFlag = false;
    return $result;
};

var clearLevelBranch = function(branchMatches, level) {
    var result = [];
    branchMatches.forEach(function (val, index) {
        result[index] = (index >= level) ? null : branchMatches[index];
    });
    return result;
};

var findBranchMatch = function(branchMatches, level) {
    for (var i = level - 1; i >= 0; i--) {
        if (branchMatches[i]) {
            return branchMatches[i];
        }
    }
};

var checkFilter = function (filters, node, pos, parent, searchRoot) {
    for (var i = 0; i < filters.length; i++) {
        if (!filters[i](node, pos, parent, searchRoot)) {
            return false;
        }
    }
    return true;
};

var hasMark = function (node, markType) {
    var result = false;

    if (!node) {
        return false;
    }

    node.marks.forEach(function (mark) {
        if (markType instanceof Mark && mark.eq(markType)) {
            result = true;
        } else if (markType instanceof MarkType && ((mark.type.name === markType.name) || mark.eq(markType))) {
            result = true;
        } else if (typeof markType === 'string' && mark.type.name === markType) {
            result = true;
        }
    });

    return result;
};function quoteRE(str) {
    return str.replace(/[.?*+^$[\]\\(){}|-]/g, '\\$&');
}

// all emoji shortcuts in string seperated by |
var shortcutStr = Object.keys(shortcuts)
    .sort()
    .reverse()
    .map(function (shortcut) {
        return quoteRE(shortcut);
    })
    .join('|');

var scanRE = new RegExp('(?:^|\\ )(' + shortcutStr + ')$');

var emojiAutoCompleteRule = function (schema) {
    return new InputRule(scanRE, function (state, match, start, end) {
        // Only handle match if match is at the end of the match input
        if (match.index !== (match.input.length - match[0].length)) {
            return false;
        }

        // Match e.g. :) => smiley
        var emojiDef = getEmojiDefinitionByShortcut(match[1]);
        if (emojiDef.name && emojiDef.emoji && emojiDef.$dom) {
            var node = state.schema.nodes.emoji.create({
                'data-name': emojiDef.name,
                alt: emojiDef.$dom.attr('alt'),
                src: emojiDef.$dom.attr('src')
            });

            start = start + (match[0].length - match[1].length);

            return state.tr.delete(start, end).replaceSelectionWith(node, false);
        }

        return false;
    })
};

var emojiChooser = function (schema) {
    return new InputRule(new RegExp('(^|\\ +)(:$)'), function (state, match, start, end) {
        if (isSmallView()) {
            return;
        }

        var mark = schema.mark('emojiQuery');
        var emojiText = schema.text(':', [mark]);

        // Prevents an error log when using IME
        if (hasMark(state.selection.$anchor.nodeBefore, mark)) {
            return;
        }

        start = start + (match[0].length - 1);

        return state.tr
            .removeMark(0, state.doc.nodeSize - 2, mark)
            .setSelection(TextSelection.create(state.doc, start, end))
            .replaceSelectionWith(emojiText, false);
    })
};/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2018 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 */


var keymap$2 = function () {
    return {
        'ArrowLeft': function (state, dispatch) {
            var emojiState = pluginKey$2.getState(state);

            if (emojiState && emojiState.active) {
                emojiState.provider.prev();
                return true;
            }

            return false;
        },
        'ArrowDown': function (state, dispatch) {
            var emojiState = pluginKey$2.getState(state);

            if (emojiState && emojiState.active) {
                emojiState.provider.down();
                return true;
            }

            return false;
        },
        'ArrowRight': function (state, dispatch) {
            var emojiState = pluginKey$2.getState(state);

            if (emojiState && emojiState.active) {
                emojiState.provider.next();
                return true;
            }

            return false;
        },
        'ArrowUp': function (state, dispatch) {
            var emojiState = pluginKey$2.getState(state);

            if (emojiState && emojiState.active) {
                emojiState.provider.up();
                return true;
            }

            return false;
        },
        'Tab': function (state, dispatch) {
            var emojiState = pluginKey$2.getState(state);

            if (emojiState && emojiState.active) {
                emojiState.provider.getChooser().nextCategory();
                return true;
            }

            return false;
        },
        'Enter': function (state, dispatch) {
            var emojiState = pluginKey$2.getState(state);

            if (emojiState && emojiState.active) {
                emojiState.provider.select();
                return true;
            }

            return false;
        },
        'Escape': function (state, dispatch) {
            var emojiState = pluginKey$2.getState(state);

            if (emojiState && emojiState.active) {
                emojiState.provider.reset();
                return true;
            }

            return false;
        }
    };
};/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 */


function insertEmoji(context) {
    return new MenuItem({
        title: context.translate("Insert Emoji"),
        icon: icons.emoji,
        sortOrder: 350,
        enable: function enable(state) {
            return canInsert(state, context.schema.nodes.image) && canInsertLink(state);
        },
        run: function run(state, _, view, e) {
            if (!$('.humhub-richtext-provider:visible').length) {
                setTimeout(function () {
                    new SimpleEmojiState(getProvider(context)).update(state, view, e.target);
                }, 50);
            }
        }
    })
}

function menu$e(context) {
    return [{
        id: 'insertEmoji',
        node: 'emoji',
        item: insertEmoji(context)
    }];
}/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 */


var emoji = {
    id: 'emoji',
    schema: schema$h,
    menu: function (context) { return menu$e(context); },
    inputRules: function (schema) {
        return [
            emojiAutoCompleteRule(),
            emojiChooser(schema)
        ];
    },
    keymap: function (context) { return keymap$2(); },
    plugins: function (context) {
        return [
            emojiPlugin(context)
        ];
    },
    registerMarkdownIt: function (markdownIt) {
        markdownIt.use(emoji_plugin, getMarkdownItOpts());
        markdownIt.renderer.rules.emoji = function (token, idx) {
            var emojiToken = token[idx];

            // Not that clean but unfortunately we don't have access to the editor context here...
            var config = getEmojiConfig();
            var twemojiConfig = config.twemoji || {};
            twemojiConfig.attributes = function (icon, variant) {
                return {
                    'data-name': emojiToken.markup
                };
            };

            return twemoji.parse(emojiToken.content, twemojiConfig);
        };
    }
};/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 *
 */

var schema$g = {
    nodes: {
        hard_break: {
            sortOrder: 1100,
            inline: true,
            group: "inline",
            selectable: false,
            parseDOM: [{tag: "br"}],
            toDOM: function () {
                return ["br"]
            },
            parseMarkdown: {hardbreak: {node: "hard_break"}},
            toMarkdown: function (state, node, parent, index) {
                for (var i = index + 1; i < parent.childCount; i++) {
                    if (parent.child(i).type !== node.type) {
                        (state.table) ? state.write('<br>') : state.write("  \n");
                        return;
                    }
                }
            }
        }
    }
};var utils$1 = {};var Aacute = "Á";
var aacute = "á";
var Abreve = "Ă";
var abreve = "ă";
var ac = "∾";
var acd = "∿";
var acE = "∾̳";
var Acirc = "Â";
var acirc = "â";
var acute = "´";
var Acy = "А";
var acy = "а";
var AElig = "Æ";
var aelig = "æ";
var af = "⁡";
var Afr = "𝔄";
var afr = "𝔞";
var Agrave = "À";
var agrave = "à";
var alefsym = "ℵ";
var aleph = "ℵ";
var Alpha = "Α";
var alpha = "α";
var Amacr = "Ā";
var amacr = "ā";
var amalg = "⨿";
var amp = "&";
var AMP = "&";
var andand = "⩕";
var And = "⩓";
var and = "∧";
var andd = "⩜";
var andslope = "⩘";
var andv = "⩚";
var ang = "∠";
var ange = "⦤";
var angle = "∠";
var angmsdaa = "⦨";
var angmsdab = "⦩";
var angmsdac = "⦪";
var angmsdad = "⦫";
var angmsdae = "⦬";
var angmsdaf = "⦭";
var angmsdag = "⦮";
var angmsdah = "⦯";
var angmsd = "∡";
var angrt = "∟";
var angrtvb = "⊾";
var angrtvbd = "⦝";
var angsph = "∢";
var angst = "Å";
var angzarr = "⍼";
var Aogon = "Ą";
var aogon = "ą";
var Aopf = "𝔸";
var aopf = "𝕒";
var apacir = "⩯";
var ap = "≈";
var apE = "⩰";
var ape = "≊";
var apid = "≋";
var apos = "'";
var ApplyFunction = "⁡";
var approx = "≈";
var approxeq = "≊";
var Aring = "Å";
var aring = "å";
var Ascr = "𝒜";
var ascr = "𝒶";
var Assign = "≔";
var ast = "*";
var asymp = "≈";
var asympeq = "≍";
var Atilde = "Ã";
var atilde = "ã";
var Auml = "Ä";
var auml = "ä";
var awconint = "∳";
var awint = "⨑";
var backcong = "≌";
var backepsilon = "϶";
var backprime = "‵";
var backsim = "∽";
var backsimeq = "⋍";
var Backslash = "∖";
var Barv = "⫧";
var barvee = "⊽";
var barwed = "⌅";
var Barwed = "⌆";
var barwedge = "⌅";
var bbrk = "⎵";
var bbrktbrk = "⎶";
var bcong = "≌";
var Bcy = "Б";
var bcy = "б";
var bdquo = "„";
var becaus = "∵";
var because = "∵";
var Because = "∵";
var bemptyv = "⦰";
var bepsi = "϶";
var bernou = "ℬ";
var Bernoullis = "ℬ";
var Beta = "Β";
var beta = "β";
var beth = "ℶ";
var between = "≬";
var Bfr = "𝔅";
var bfr = "𝔟";
var bigcap = "⋂";
var bigcirc = "◯";
var bigcup = "⋃";
var bigodot = "⨀";
var bigoplus = "⨁";
var bigotimes = "⨂";
var bigsqcup = "⨆";
var bigstar = "★";
var bigtriangledown = "▽";
var bigtriangleup = "△";
var biguplus = "⨄";
var bigvee = "⋁";
var bigwedge = "⋀";
var bkarow = "⤍";
var blacklozenge = "⧫";
var blacksquare = "▪";
var blacktriangle = "▴";
var blacktriangledown = "▾";
var blacktriangleleft = "◂";
var blacktriangleright = "▸";
var blank = "␣";
var blk12 = "▒";
var blk14 = "░";
var blk34 = "▓";
var block$1 = "█";
var bne = "=⃥";
var bnequiv = "≡⃥";
var bNot = "⫭";
var bnot = "⌐";
var Bopf = "𝔹";
var bopf = "𝕓";
var bot = "⊥";
var bottom = "⊥";
var bowtie = "⋈";
var boxbox = "⧉";
var boxdl = "┐";
var boxdL = "╕";
var boxDl = "╖";
var boxDL = "╗";
var boxdr = "┌";
var boxdR = "╒";
var boxDr = "╓";
var boxDR = "╔";
var boxh = "─";
var boxH = "═";
var boxhd = "┬";
var boxHd = "╤";
var boxhD = "╥";
var boxHD = "╦";
var boxhu = "┴";
var boxHu = "╧";
var boxhU = "╨";
var boxHU = "╩";
var boxminus = "⊟";
var boxplus = "⊞";
var boxtimes = "⊠";
var boxul = "┘";
var boxuL = "╛";
var boxUl = "╜";
var boxUL = "╝";
var boxur = "└";
var boxuR = "╘";
var boxUr = "╙";
var boxUR = "╚";
var boxv = "│";
var boxV = "║";
var boxvh = "┼";
var boxvH = "╪";
var boxVh = "╫";
var boxVH = "╬";
var boxvl = "┤";
var boxvL = "╡";
var boxVl = "╢";
var boxVL = "╣";
var boxvr = "├";
var boxvR = "╞";
var boxVr = "╟";
var boxVR = "╠";
var bprime = "‵";
var breve = "˘";
var Breve = "˘";
var brvbar = "¦";
var bscr = "𝒷";
var Bscr = "ℬ";
var bsemi = "⁏";
var bsim = "∽";
var bsime = "⋍";
var bsolb = "⧅";
var bsol = "\\";
var bsolhsub = "⟈";
var bull = "•";
var bullet = "•";
var bump = "≎";
var bumpE = "⪮";
var bumpe = "≏";
var Bumpeq = "≎";
var bumpeq = "≏";
var Cacute = "Ć";
var cacute = "ć";
var capand = "⩄";
var capbrcup = "⩉";
var capcap = "⩋";
var cap = "∩";
var Cap = "⋒";
var capcup = "⩇";
var capdot = "⩀";
var CapitalDifferentialD = "ⅅ";
var caps = "∩︀";
var caret = "⁁";
var caron = "ˇ";
var Cayleys = "ℭ";
var ccaps = "⩍";
var Ccaron = "Č";
var ccaron = "č";
var Ccedil = "Ç";
var ccedil = "ç";
var Ccirc = "Ĉ";
var ccirc = "ĉ";
var Cconint = "∰";
var ccups = "⩌";
var ccupssm = "⩐";
var Cdot = "Ċ";
var cdot = "ċ";
var cedil = "¸";
var Cedilla = "¸";
var cemptyv = "⦲";
var cent = "¢";
var centerdot = "·";
var CenterDot = "·";
var cfr = "𝔠";
var Cfr = "ℭ";
var CHcy = "Ч";
var chcy = "ч";
var check = "✓";
var checkmark = "✓";
var Chi = "Χ";
var chi = "χ";
var circ = "ˆ";
var circeq = "≗";
var circlearrowleft = "↺";
var circlearrowright = "↻";
var circledast = "⊛";
var circledcirc = "⊚";
var circleddash = "⊝";
var CircleDot = "⊙";
var circledR = "®";
var circledS = "Ⓢ";
var CircleMinus = "⊖";
var CirclePlus = "⊕";
var CircleTimes = "⊗";
var cir = "○";
var cirE = "⧃";
var cire = "≗";
var cirfnint = "⨐";
var cirmid = "⫯";
var cirscir = "⧂";
var ClockwiseContourIntegral = "∲";
var CloseCurlyDoubleQuote = "”";
var CloseCurlyQuote = "’";
var clubs = "♣";
var clubsuit = "♣";
var colon = ":";
var Colon = "∷";
var Colone = "⩴";
var colone = "≔";
var coloneq = "≔";
var comma = ",";
var commat = "@";
var comp = "∁";
var compfn = "∘";
var complement = "∁";
var complexes = "ℂ";
var cong = "≅";
var congdot = "⩭";
var Congruent = "≡";
var conint = "∮";
var Conint = "∯";
var ContourIntegral = "∮";
var copf = "𝕔";
var Copf = "ℂ";
var coprod = "∐";
var Coproduct = "∐";
var copy = "©";
var COPY = "©";
var copysr = "℗";
var CounterClockwiseContourIntegral = "∳";
var crarr = "↵";
var cross = "✗";
var Cross = "⨯";
var Cscr = "𝒞";
var cscr = "𝒸";
var csub = "⫏";
var csube = "⫑";
var csup = "⫐";
var csupe = "⫒";
var ctdot = "⋯";
var cudarrl = "⤸";
var cudarrr = "⤵";
var cuepr = "⋞";
var cuesc = "⋟";
var cularr = "↶";
var cularrp = "⤽";
var cupbrcap = "⩈";
var cupcap = "⩆";
var CupCap = "≍";
var cup = "∪";
var Cup = "⋓";
var cupcup = "⩊";
var cupdot = "⊍";
var cupor = "⩅";
var cups = "∪︀";
var curarr = "↷";
var curarrm = "⤼";
var curlyeqprec = "⋞";
var curlyeqsucc = "⋟";
var curlyvee = "⋎";
var curlywedge = "⋏";
var curren = "¤";
var curvearrowleft = "↶";
var curvearrowright = "↷";
var cuvee = "⋎";
var cuwed = "⋏";
var cwconint = "∲";
var cwint = "∱";
var cylcty = "⌭";
var dagger = "†";
var Dagger = "‡";
var daleth = "ℸ";
var darr = "↓";
var Darr = "↡";
var dArr = "⇓";
var dash = "‐";
var Dashv = "⫤";
var dashv = "⊣";
var dbkarow = "⤏";
var dblac = "˝";
var Dcaron = "Ď";
var dcaron = "ď";
var Dcy = "Д";
var dcy = "д";
var ddagger = "‡";
var ddarr = "⇊";
var DD = "ⅅ";
var dd = "ⅆ";
var DDotrahd = "⤑";
var ddotseq = "⩷";
var deg = "°";
var Del = "∇";
var Delta = "Δ";
var delta = "δ";
var demptyv = "⦱";
var dfisht = "⥿";
var Dfr = "𝔇";
var dfr = "𝔡";
var dHar = "⥥";
var dharl = "⇃";
var dharr = "⇂";
var DiacriticalAcute = "´";
var DiacriticalDot = "˙";
var DiacriticalDoubleAcute = "˝";
var DiacriticalGrave = "`";
var DiacriticalTilde = "˜";
var diam = "⋄";
var diamond = "⋄";
var Diamond = "⋄";
var diamondsuit = "♦";
var diams = "♦";
var die = "¨";
var DifferentialD = "ⅆ";
var digamma = "ϝ";
var disin = "⋲";
var div = "÷";
var divide = "÷";
var divideontimes = "⋇";
var divonx = "⋇";
var DJcy = "Ђ";
var djcy = "ђ";
var dlcorn = "⌞";
var dlcrop = "⌍";
var dollar = "$";
var Dopf = "𝔻";
var dopf = "𝕕";
var Dot = "¨";
var dot = "˙";
var DotDot = "⃜";
var doteq = "≐";
var doteqdot = "≑";
var DotEqual = "≐";
var dotminus = "∸";
var dotplus = "∔";
var dotsquare = "⊡";
var doublebarwedge = "⌆";
var DoubleContourIntegral = "∯";
var DoubleDot = "¨";
var DoubleDownArrow = "⇓";
var DoubleLeftArrow = "⇐";
var DoubleLeftRightArrow = "⇔";
var DoubleLeftTee = "⫤";
var DoubleLongLeftArrow = "⟸";
var DoubleLongLeftRightArrow = "⟺";
var DoubleLongRightArrow = "⟹";
var DoubleRightArrow = "⇒";
var DoubleRightTee = "⊨";
var DoubleUpArrow = "⇑";
var DoubleUpDownArrow = "⇕";
var DoubleVerticalBar = "∥";
var DownArrowBar = "⤓";
var downarrow = "↓";
var DownArrow = "↓";
var Downarrow = "⇓";
var DownArrowUpArrow = "⇵";
var DownBreve = "̑";
var downdownarrows = "⇊";
var downharpoonleft = "⇃";
var downharpoonright = "⇂";
var DownLeftRightVector = "⥐";
var DownLeftTeeVector = "⥞";
var DownLeftVectorBar = "⥖";
var DownLeftVector = "↽";
var DownRightTeeVector = "⥟";
var DownRightVectorBar = "⥗";
var DownRightVector = "⇁";
var DownTeeArrow = "↧";
var DownTee = "⊤";
var drbkarow = "⤐";
var drcorn = "⌟";
var drcrop = "⌌";
var Dscr = "𝒟";
var dscr = "𝒹";
var DScy = "Ѕ";
var dscy = "ѕ";
var dsol = "⧶";
var Dstrok = "Đ";
var dstrok = "đ";
var dtdot = "⋱";
var dtri = "▿";
var dtrif = "▾";
var duarr = "⇵";
var duhar = "⥯";
var dwangle = "⦦";
var DZcy = "Џ";
var dzcy = "џ";
var dzigrarr = "⟿";
var Eacute = "É";
var eacute = "é";
var easter = "⩮";
var Ecaron = "Ě";
var ecaron = "ě";
var Ecirc = "Ê";
var ecirc = "ê";
var ecir = "≖";
var ecolon = "≕";
var Ecy = "Э";
var ecy = "э";
var eDDot = "⩷";
var Edot = "Ė";
var edot = "ė";
var eDot = "≑";
var ee = "ⅇ";
var efDot = "≒";
var Efr = "𝔈";
var efr = "𝔢";
var eg = "⪚";
var Egrave = "È";
var egrave = "è";
var egs = "⪖";
var egsdot = "⪘";
var el = "⪙";
var Element = "∈";
var elinters = "⏧";
var ell = "ℓ";
var els = "⪕";
var elsdot = "⪗";
var Emacr = "Ē";
var emacr = "ē";
var empty = "∅";
var emptyset = "∅";
var EmptySmallSquare = "◻";
var emptyv = "∅";
var EmptyVerySmallSquare = "▫";
var emsp13 = " ";
var emsp14 = " ";
var emsp = " ";
var ENG = "Ŋ";
var eng = "ŋ";
var ensp = " ";
var Eogon = "Ę";
var eogon = "ę";
var Eopf = "𝔼";
var eopf = "𝕖";
var epar = "⋕";
var eparsl = "⧣";
var eplus = "⩱";
var epsi = "ε";
var Epsilon = "Ε";
var epsilon = "ε";
var epsiv = "ϵ";
var eqcirc = "≖";
var eqcolon = "≕";
var eqsim = "≂";
var eqslantgtr = "⪖";
var eqslantless = "⪕";
var Equal = "⩵";
var equals = "=";
var EqualTilde = "≂";
var equest = "≟";
var Equilibrium = "⇌";
var equiv = "≡";
var equivDD = "⩸";
var eqvparsl = "⧥";
var erarr = "⥱";
var erDot = "≓";
var escr = "ℯ";
var Escr = "ℰ";
var esdot = "≐";
var Esim = "⩳";
var esim = "≂";
var Eta = "Η";
var eta = "η";
var ETH = "Ð";
var eth = "ð";
var Euml = "Ë";
var euml = "ë";
var euro = "€";
var excl = "!";
var exist = "∃";
var Exists = "∃";
var expectation = "ℰ";
var exponentiale = "ⅇ";
var ExponentialE = "ⅇ";
var fallingdotseq = "≒";
var Fcy = "Ф";
var fcy = "ф";
var female = "♀";
var ffilig = "ﬃ";
var fflig = "ﬀ";
var ffllig = "ﬄ";
var Ffr = "𝔉";
var ffr = "𝔣";
var filig = "ﬁ";
var FilledSmallSquare = "◼";
var FilledVerySmallSquare = "▪";
var fjlig = "fj";
var flat = "♭";
var fllig = "ﬂ";
var fltns = "▱";
var fnof = "ƒ";
var Fopf = "𝔽";
var fopf = "𝕗";
var forall = "∀";
var ForAll = "∀";
var fork = "⋔";
var forkv = "⫙";
var Fouriertrf = "ℱ";
var fpartint = "⨍";
var frac12 = "½";
var frac13 = "⅓";
var frac14 = "¼";
var frac15 = "⅕";
var frac16 = "⅙";
var frac18 = "⅛";
var frac23 = "⅔";
var frac25 = "⅖";
var frac34 = "¾";
var frac35 = "⅗";
var frac38 = "⅜";
var frac45 = "⅘";
var frac56 = "⅚";
var frac58 = "⅝";
var frac78 = "⅞";
var frasl = "⁄";
var frown = "⌢";
var fscr = "𝒻";
var Fscr = "ℱ";
var gacute = "ǵ";
var Gamma = "Γ";
var gamma = "γ";
var Gammad = "Ϝ";
var gammad = "ϝ";
var gap = "⪆";
var Gbreve = "Ğ";
var gbreve = "ğ";
var Gcedil = "Ģ";
var Gcirc = "Ĝ";
var gcirc = "ĝ";
var Gcy = "Г";
var gcy = "г";
var Gdot = "Ġ";
var gdot = "ġ";
var ge = "≥";
var gE = "≧";
var gEl = "⪌";
var gel = "⋛";
var geq = "≥";
var geqq = "≧";
var geqslant = "⩾";
var gescc = "⪩";
var ges = "⩾";
var gesdot = "⪀";
var gesdoto = "⪂";
var gesdotol = "⪄";
var gesl = "⋛︀";
var gesles = "⪔";
var Gfr = "𝔊";
var gfr = "𝔤";
var gg = "≫";
var Gg = "⋙";
var ggg = "⋙";
var gimel = "ℷ";
var GJcy = "Ѓ";
var gjcy = "ѓ";
var gla = "⪥";
var gl = "≷";
var glE = "⪒";
var glj = "⪤";
var gnap = "⪊";
var gnapprox = "⪊";
var gne = "⪈";
var gnE = "≩";
var gneq = "⪈";
var gneqq = "≩";
var gnsim = "⋧";
var Gopf = "𝔾";
var gopf = "𝕘";
var grave = "`";
var GreaterEqual = "≥";
var GreaterEqualLess = "⋛";
var GreaterFullEqual = "≧";
var GreaterGreater = "⪢";
var GreaterLess = "≷";
var GreaterSlantEqual = "⩾";
var GreaterTilde = "≳";
var Gscr = "𝒢";
var gscr = "ℊ";
var gsim = "≳";
var gsime = "⪎";
var gsiml = "⪐";
var gtcc = "⪧";
var gtcir = "⩺";
var gt = ">";
var GT = ">";
var Gt = "≫";
var gtdot = "⋗";
var gtlPar = "⦕";
var gtquest = "⩼";
var gtrapprox = "⪆";
var gtrarr = "⥸";
var gtrdot = "⋗";
var gtreqless = "⋛";
var gtreqqless = "⪌";
var gtrless = "≷";
var gtrsim = "≳";
var gvertneqq = "≩︀";
var gvnE = "≩︀";
var Hacek = "ˇ";
var hairsp = " ";
var half = "½";
var hamilt = "ℋ";
var HARDcy = "Ъ";
var hardcy = "ъ";
var harrcir = "⥈";
var harr = "↔";
var hArr = "⇔";
var harrw = "↭";
var Hat = "^";
var hbar = "ℏ";
var Hcirc = "Ĥ";
var hcirc = "ĥ";
var hearts = "♥";
var heartsuit = "♥";
var hellip = "…";
var hercon = "⊹";
var hfr = "𝔥";
var Hfr = "ℌ";
var HilbertSpace = "ℋ";
var hksearow = "⤥";
var hkswarow = "⤦";
var hoarr = "⇿";
var homtht = "∻";
var hookleftarrow = "↩";
var hookrightarrow = "↪";
var hopf = "𝕙";
var Hopf = "ℍ";
var horbar = "―";
var HorizontalLine = "─";
var hscr = "𝒽";
var Hscr = "ℋ";
var hslash = "ℏ";
var Hstrok = "Ħ";
var hstrok = "ħ";
var HumpDownHump = "≎";
var HumpEqual = "≏";
var hybull = "⁃";
var hyphen = "‐";
var Iacute = "Í";
var iacute = "í";
var ic = "⁣";
var Icirc = "Î";
var icirc = "î";
var Icy = "И";
var icy = "и";
var Idot = "İ";
var IEcy = "Е";
var iecy = "е";
var iexcl = "¡";
var iff = "⇔";
var ifr = "𝔦";
var Ifr = "ℑ";
var Igrave = "Ì";
var igrave = "ì";
var ii = "ⅈ";
var iiiint = "⨌";
var iiint = "∭";
var iinfin = "⧜";
var iiota = "℩";
var IJlig = "Ĳ";
var ijlig = "ĳ";
var Imacr = "Ī";
var imacr = "ī";
var image$2 = "ℑ";
var ImaginaryI = "ⅈ";
var imagline = "ℐ";
var imagpart = "ℑ";
var imath = "ı";
var Im = "ℑ";
var imof = "⊷";
var imped = "Ƶ";
var Implies = "⇒";
var incare = "℅";
var infin = "∞";
var infintie = "⧝";
var inodot = "ı";
var intcal = "⊺";
var int = "∫";
var Int = "∬";
var integers = "ℤ";
var Integral = "∫";
var intercal = "⊺";
var Intersection = "⋂";
var intlarhk = "⨗";
var intprod = "⨼";
var InvisibleComma = "⁣";
var InvisibleTimes = "⁢";
var IOcy = "Ё";
var iocy = "ё";
var Iogon = "Į";
var iogon = "į";
var Iopf = "𝕀";
var iopf = "𝕚";
var Iota = "Ι";
var iota = "ι";
var iprod = "⨼";
var iquest = "¿";
var iscr = "𝒾";
var Iscr = "ℐ";
var isin = "∈";
var isindot = "⋵";
var isinE = "⋹";
var isins = "⋴";
var isinsv = "⋳";
var isinv = "∈";
var it = "⁢";
var Itilde = "Ĩ";
var itilde = "ĩ";
var Iukcy = "І";
var iukcy = "і";
var Iuml = "Ï";
var iuml = "ï";
var Jcirc = "Ĵ";
var jcirc = "ĵ";
var Jcy = "Й";
var jcy = "й";
var Jfr = "𝔍";
var jfr = "𝔧";
var jmath = "ȷ";
var Jopf = "𝕁";
var jopf = "𝕛";
var Jscr = "𝒥";
var jscr = "𝒿";
var Jsercy = "Ј";
var jsercy = "ј";
var Jukcy = "Є";
var jukcy = "є";
var Kappa = "Κ";
var kappa = "κ";
var kappav = "ϰ";
var Kcedil = "Ķ";
var kcedil = "ķ";
var Kcy = "К";
var kcy = "к";
var Kfr = "𝔎";
var kfr = "𝔨";
var kgreen = "ĸ";
var KHcy = "Х";
var khcy = "х";
var KJcy = "Ќ";
var kjcy = "ќ";
var Kopf = "𝕂";
var kopf = "𝕜";
var Kscr = "𝒦";
var kscr = "𝓀";
var lAarr = "⇚";
var Lacute = "Ĺ";
var lacute = "ĺ";
var laemptyv = "⦴";
var lagran = "ℒ";
var Lambda = "Λ";
var lambda = "λ";
var lang = "⟨";
var Lang = "⟪";
var langd = "⦑";
var langle = "⟨";
var lap = "⪅";
var Laplacetrf = "ℒ";
var laquo = "«";
var larrb = "⇤";
var larrbfs = "⤟";
var larr = "←";
var Larr = "↞";
var lArr = "⇐";
var larrfs = "⤝";
var larrhk = "↩";
var larrlp = "↫";
var larrpl = "⤹";
var larrsim = "⥳";
var larrtl = "↢";
var latail = "⤙";
var lAtail = "⤛";
var lat = "⪫";
var late = "⪭";
var lates = "⪭︀";
var lbarr = "⤌";
var lBarr = "⤎";
var lbbrk = "❲";
var lbrace = "{";
var lbrack = "[";
var lbrke = "⦋";
var lbrksld = "⦏";
var lbrkslu = "⦍";
var Lcaron = "Ľ";
var lcaron = "ľ";
var Lcedil = "Ļ";
var lcedil = "ļ";
var lceil = "⌈";
var lcub = "{";
var Lcy = "Л";
var lcy = "л";
var ldca = "⤶";
var ldquo = "“";
var ldquor = "„";
var ldrdhar = "⥧";
var ldrushar = "⥋";
var ldsh = "↲";
var le = "≤";
var lE = "≦";
var LeftAngleBracket = "⟨";
var LeftArrowBar = "⇤";
var leftarrow = "←";
var LeftArrow = "←";
var Leftarrow = "⇐";
var LeftArrowRightArrow = "⇆";
var leftarrowtail = "↢";
var LeftCeiling = "⌈";
var LeftDoubleBracket = "⟦";
var LeftDownTeeVector = "⥡";
var LeftDownVectorBar = "⥙";
var LeftDownVector = "⇃";
var LeftFloor = "⌊";
var leftharpoondown = "↽";
var leftharpoonup = "↼";
var leftleftarrows = "⇇";
var leftrightarrow = "↔";
var LeftRightArrow = "↔";
var Leftrightarrow = "⇔";
var leftrightarrows = "⇆";
var leftrightharpoons = "⇋";
var leftrightsquigarrow = "↭";
var LeftRightVector = "⥎";
var LeftTeeArrow = "↤";
var LeftTee = "⊣";
var LeftTeeVector = "⥚";
var leftthreetimes = "⋋";
var LeftTriangleBar = "⧏";
var LeftTriangle = "⊲";
var LeftTriangleEqual = "⊴";
var LeftUpDownVector = "⥑";
var LeftUpTeeVector = "⥠";
var LeftUpVectorBar = "⥘";
var LeftUpVector = "↿";
var LeftVectorBar = "⥒";
var LeftVector = "↼";
var lEg = "⪋";
var leg = "⋚";
var leq = "≤";
var leqq = "≦";
var leqslant = "⩽";
var lescc = "⪨";
var les = "⩽";
var lesdot = "⩿";
var lesdoto = "⪁";
var lesdotor = "⪃";
var lesg = "⋚︀";
var lesges = "⪓";
var lessapprox = "⪅";
var lessdot = "⋖";
var lesseqgtr = "⋚";
var lesseqqgtr = "⪋";
var LessEqualGreater = "⋚";
var LessFullEqual = "≦";
var LessGreater = "≶";
var lessgtr = "≶";
var LessLess = "⪡";
var lesssim = "≲";
var LessSlantEqual = "⩽";
var LessTilde = "≲";
var lfisht = "⥼";
var lfloor = "⌊";
var Lfr = "𝔏";
var lfr = "𝔩";
var lg = "≶";
var lgE = "⪑";
var lHar = "⥢";
var lhard = "↽";
var lharu = "↼";
var lharul = "⥪";
var lhblk = "▄";
var LJcy = "Љ";
var ljcy = "љ";
var llarr = "⇇";
var ll = "≪";
var Ll = "⋘";
var llcorner = "⌞";
var Lleftarrow = "⇚";
var llhard = "⥫";
var lltri = "◺";
var Lmidot = "Ŀ";
var lmidot = "ŀ";
var lmoustache = "⎰";
var lmoust = "⎰";
var lnap = "⪉";
var lnapprox = "⪉";
var lne = "⪇";
var lnE = "≨";
var lneq = "⪇";
var lneqq = "≨";
var lnsim = "⋦";
var loang = "⟬";
var loarr = "⇽";
var lobrk = "⟦";
var longleftarrow = "⟵";
var LongLeftArrow = "⟵";
var Longleftarrow = "⟸";
var longleftrightarrow = "⟷";
var LongLeftRightArrow = "⟷";
var Longleftrightarrow = "⟺";
var longmapsto = "⟼";
var longrightarrow = "⟶";
var LongRightArrow = "⟶";
var Longrightarrow = "⟹";
var looparrowleft = "↫";
var looparrowright = "↬";
var lopar = "⦅";
var Lopf = "𝕃";
var lopf = "𝕝";
var loplus = "⨭";
var lotimes = "⨴";
var lowast = "∗";
var lowbar = "_";
var LowerLeftArrow = "↙";
var LowerRightArrow = "↘";
var loz = "◊";
var lozenge = "◊";
var lozf = "⧫";
var lpar = "(";
var lparlt = "⦓";
var lrarr = "⇆";
var lrcorner = "⌟";
var lrhar = "⇋";
var lrhard = "⥭";
var lrm = "‎";
var lrtri = "⊿";
var lsaquo = "‹";
var lscr = "𝓁";
var Lscr = "ℒ";
var lsh = "↰";
var Lsh = "↰";
var lsim = "≲";
var lsime = "⪍";
var lsimg = "⪏";
var lsqb = "[";
var lsquo = "‘";
var lsquor = "‚";
var Lstrok = "Ł";
var lstrok = "ł";
var ltcc = "⪦";
var ltcir = "⩹";
var lt = "<";
var LT = "<";
var Lt = "≪";
var ltdot = "⋖";
var lthree = "⋋";
var ltimes = "⋉";
var ltlarr = "⥶";
var ltquest = "⩻";
var ltri = "◃";
var ltrie = "⊴";
var ltrif = "◂";
var ltrPar = "⦖";
var lurdshar = "⥊";
var luruhar = "⥦";
var lvertneqq = "≨︀";
var lvnE = "≨︀";
var macr = "¯";
var male = "♂";
var malt = "✠";
var maltese = "✠";
var map$1 = "↦";
var mapsto = "↦";
var mapstodown = "↧";
var mapstoleft = "↤";
var mapstoup = "↥";
var marker = "▮";
var mcomma = "⨩";
var Mcy = "М";
var mcy = "м";
var mdash = "—";
var mDDot = "∺";
var measuredangle = "∡";
var MediumSpace = " ";
var Mellintrf = "ℳ";
var Mfr = "𝔐";
var mfr = "𝔪";
var mho = "℧";
var micro = "µ";
var midast = "*";
var midcir = "⫰";
var mid = "∣";
var middot = "·";
var minusb = "⊟";
var minus = "−";
var minusd = "∸";
var minusdu = "⨪";
var MinusPlus = "∓";
var mlcp = "⫛";
var mldr = "…";
var mnplus = "∓";
var models = "⊧";
var Mopf = "𝕄";
var mopf = "𝕞";
var mp = "∓";
var mscr = "𝓂";
var Mscr = "ℳ";
var mstpos = "∾";
var Mu = "Μ";
var mu = "μ";
var multimap = "⊸";
var mumap = "⊸";
var nabla = "∇";
var Nacute = "Ń";
var nacute = "ń";
var nang = "∠⃒";
var nap = "≉";
var napE = "⩰̸";
var napid = "≋̸";
var napos = "ŉ";
var napprox = "≉";
var natural = "♮";
var naturals = "ℕ";
var natur = "♮";
var nbsp = " ";
var nbump = "≎̸";
var nbumpe = "≏̸";
var ncap = "⩃";
var Ncaron = "Ň";
var ncaron = "ň";
var Ncedil = "Ņ";
var ncedil = "ņ";
var ncong = "≇";
var ncongdot = "⩭̸";
var ncup = "⩂";
var Ncy = "Н";
var ncy = "н";
var ndash = "–";
var nearhk = "⤤";
var nearr = "↗";
var neArr = "⇗";
var nearrow = "↗";
var ne = "≠";
var nedot = "≐̸";
var NegativeMediumSpace = "​";
var NegativeThickSpace = "​";
var NegativeThinSpace = "​";
var NegativeVeryThinSpace = "​";
var nequiv = "≢";
var nesear = "⤨";
var nesim = "≂̸";
var NestedGreaterGreater = "≫";
var NestedLessLess = "≪";
var NewLine = "\n";
var nexist = "∄";
var nexists = "∄";
var Nfr = "𝔑";
var nfr = "𝔫";
var ngE = "≧̸";
var nge = "≱";
var ngeq = "≱";
var ngeqq = "≧̸";
var ngeqslant = "⩾̸";
var nges = "⩾̸";
var nGg = "⋙̸";
var ngsim = "≵";
var nGt = "≫⃒";
var ngt = "≯";
var ngtr = "≯";
var nGtv = "≫̸";
var nharr = "↮";
var nhArr = "⇎";
var nhpar = "⫲";
var ni = "∋";
var nis = "⋼";
var nisd = "⋺";
var niv = "∋";
var NJcy = "Њ";
var njcy = "њ";
var nlarr = "↚";
var nlArr = "⇍";
var nldr = "‥";
var nlE = "≦̸";
var nle = "≰";
var nleftarrow = "↚";
var nLeftarrow = "⇍";
var nleftrightarrow = "↮";
var nLeftrightarrow = "⇎";
var nleq = "≰";
var nleqq = "≦̸";
var nleqslant = "⩽̸";
var nles = "⩽̸";
var nless = "≮";
var nLl = "⋘̸";
var nlsim = "≴";
var nLt = "≪⃒";
var nlt = "≮";
var nltri = "⋪";
var nltrie = "⋬";
var nLtv = "≪̸";
var nmid = "∤";
var NoBreak = "⁠";
var NonBreakingSpace = " ";
var nopf = "𝕟";
var Nopf = "ℕ";
var Not = "⫬";
var not = "¬";
var NotCongruent = "≢";
var NotCupCap = "≭";
var NotDoubleVerticalBar = "∦";
var NotElement = "∉";
var NotEqual = "≠";
var NotEqualTilde = "≂̸";
var NotExists = "∄";
var NotGreater = "≯";
var NotGreaterEqual = "≱";
var NotGreaterFullEqual = "≧̸";
var NotGreaterGreater = "≫̸";
var NotGreaterLess = "≹";
var NotGreaterSlantEqual = "⩾̸";
var NotGreaterTilde = "≵";
var NotHumpDownHump = "≎̸";
var NotHumpEqual = "≏̸";
var notin = "∉";
var notindot = "⋵̸";
var notinE = "⋹̸";
var notinva = "∉";
var notinvb = "⋷";
var notinvc = "⋶";
var NotLeftTriangleBar = "⧏̸";
var NotLeftTriangle = "⋪";
var NotLeftTriangleEqual = "⋬";
var NotLess = "≮";
var NotLessEqual = "≰";
var NotLessGreater = "≸";
var NotLessLess = "≪̸";
var NotLessSlantEqual = "⩽̸";
var NotLessTilde = "≴";
var NotNestedGreaterGreater = "⪢̸";
var NotNestedLessLess = "⪡̸";
var notni = "∌";
var notniva = "∌";
var notnivb = "⋾";
var notnivc = "⋽";
var NotPrecedes = "⊀";
var NotPrecedesEqual = "⪯̸";
var NotPrecedesSlantEqual = "⋠";
var NotReverseElement = "∌";
var NotRightTriangleBar = "⧐̸";
var NotRightTriangle = "⋫";
var NotRightTriangleEqual = "⋭";
var NotSquareSubset = "⊏̸";
var NotSquareSubsetEqual = "⋢";
var NotSquareSuperset = "⊐̸";
var NotSquareSupersetEqual = "⋣";
var NotSubset = "⊂⃒";
var NotSubsetEqual = "⊈";
var NotSucceeds = "⊁";
var NotSucceedsEqual = "⪰̸";
var NotSucceedsSlantEqual = "⋡";
var NotSucceedsTilde = "≿̸";
var NotSuperset = "⊃⃒";
var NotSupersetEqual = "⊉";
var NotTilde = "≁";
var NotTildeEqual = "≄";
var NotTildeFullEqual = "≇";
var NotTildeTilde = "≉";
var NotVerticalBar = "∤";
var nparallel = "∦";
var npar = "∦";
var nparsl = "⫽⃥";
var npart = "∂̸";
var npolint = "⨔";
var npr = "⊀";
var nprcue = "⋠";
var nprec = "⊀";
var npreceq = "⪯̸";
var npre = "⪯̸";
var nrarrc = "⤳̸";
var nrarr = "↛";
var nrArr = "⇏";
var nrarrw = "↝̸";
var nrightarrow = "↛";
var nRightarrow = "⇏";
var nrtri = "⋫";
var nrtrie = "⋭";
var nsc = "⊁";
var nsccue = "⋡";
var nsce = "⪰̸";
var Nscr = "𝒩";
var nscr = "𝓃";
var nshortmid = "∤";
var nshortparallel = "∦";
var nsim = "≁";
var nsime = "≄";
var nsimeq = "≄";
var nsmid = "∤";
var nspar = "∦";
var nsqsube = "⋢";
var nsqsupe = "⋣";
var nsub = "⊄";
var nsubE = "⫅̸";
var nsube = "⊈";
var nsubset = "⊂⃒";
var nsubseteq = "⊈";
var nsubseteqq = "⫅̸";
var nsucc = "⊁";
var nsucceq = "⪰̸";
var nsup = "⊅";
var nsupE = "⫆̸";
var nsupe = "⊉";
var nsupset = "⊃⃒";
var nsupseteq = "⊉";
var nsupseteqq = "⫆̸";
var ntgl = "≹";
var Ntilde = "Ñ";
var ntilde = "ñ";
var ntlg = "≸";
var ntriangleleft = "⋪";
var ntrianglelefteq = "⋬";
var ntriangleright = "⋫";
var ntrianglerighteq = "⋭";
var Nu = "Ν";
var nu = "ν";
var num = "#";
var numero = "№";
var numsp = " ";
var nvap = "≍⃒";
var nvdash = "⊬";
var nvDash = "⊭";
var nVdash = "⊮";
var nVDash = "⊯";
var nvge = "≥⃒";
var nvgt = ">⃒";
var nvHarr = "⤄";
var nvinfin = "⧞";
var nvlArr = "⤂";
var nvle = "≤⃒";
var nvlt = "<⃒";
var nvltrie = "⊴⃒";
var nvrArr = "⤃";
var nvrtrie = "⊵⃒";
var nvsim = "∼⃒";
var nwarhk = "⤣";
var nwarr = "↖";
var nwArr = "⇖";
var nwarrow = "↖";
var nwnear = "⤧";
var Oacute = "Ó";
var oacute = "ó";
var oast = "⊛";
var Ocirc = "Ô";
var ocirc = "ô";
var ocir = "⊚";
var Ocy = "О";
var ocy = "о";
var odash = "⊝";
var Odblac = "Ő";
var odblac = "ő";
var odiv = "⨸";
var odot = "⊙";
var odsold = "⦼";
var OElig = "Œ";
var oelig = "œ";
var ofcir = "⦿";
var Ofr = "𝔒";
var ofr = "𝔬";
var ogon = "˛";
var Ograve = "Ò";
var ograve = "ò";
var ogt = "⧁";
var ohbar = "⦵";
var ohm = "Ω";
var oint = "∮";
var olarr = "↺";
var olcir = "⦾";
var olcross = "⦻";
var oline = "‾";
var olt = "⧀";
var Omacr = "Ō";
var omacr = "ō";
var Omega = "Ω";
var omega = "ω";
var Omicron = "Ο";
var omicron = "ο";
var omid = "⦶";
var ominus = "⊖";
var Oopf = "𝕆";
var oopf = "𝕠";
var opar = "⦷";
var OpenCurlyDoubleQuote = "“";
var OpenCurlyQuote = "‘";
var operp = "⦹";
var oplus = "⊕";
var orarr = "↻";
var Or = "⩔";
var or = "∨";
var ord = "⩝";
var order = "ℴ";
var orderof = "ℴ";
var ordf = "ª";
var ordm = "º";
var origof = "⊶";
var oror = "⩖";
var orslope = "⩗";
var orv = "⩛";
var oS = "Ⓢ";
var Oscr = "𝒪";
var oscr = "ℴ";
var Oslash = "Ø";
var oslash = "ø";
var osol = "⊘";
var Otilde = "Õ";
var otilde = "õ";
var otimesas = "⨶";
var Otimes = "⨷";
var otimes = "⊗";
var Ouml = "Ö";
var ouml = "ö";
var ovbar = "⌽";
var OverBar = "‾";
var OverBrace = "⏞";
var OverBracket = "⎴";
var OverParenthesis = "⏜";
var para = "¶";
var parallel = "∥";
var par = "∥";
var parsim = "⫳";
var parsl = "⫽";
var part = "∂";
var PartialD = "∂";
var Pcy = "П";
var pcy = "п";
var percnt = "%";
var period = ".";
var permil = "‰";
var perp = "⊥";
var pertenk = "‱";
var Pfr = "𝔓";
var pfr = "𝔭";
var Phi = "Φ";
var phi = "φ";
var phiv = "ϕ";
var phmmat = "ℳ";
var phone = "☎";
var Pi = "Π";
var pi = "π";
var pitchfork = "⋔";
var piv = "ϖ";
var planck = "ℏ";
var planckh = "ℎ";
var plankv = "ℏ";
var plusacir = "⨣";
var plusb = "⊞";
var pluscir = "⨢";
var plus = "+";
var plusdo = "∔";
var plusdu = "⨥";
var pluse = "⩲";
var PlusMinus = "±";
var plusmn = "±";
var plussim = "⨦";
var plustwo = "⨧";
var pm = "±";
var Poincareplane = "ℌ";
var pointint = "⨕";
var popf = "𝕡";
var Popf = "ℙ";
var pound = "£";
var prap = "⪷";
var Pr = "⪻";
var pr = "≺";
var prcue = "≼";
var precapprox = "⪷";
var prec = "≺";
var preccurlyeq = "≼";
var Precedes = "≺";
var PrecedesEqual = "⪯";
var PrecedesSlantEqual = "≼";
var PrecedesTilde = "≾";
var preceq = "⪯";
var precnapprox = "⪹";
var precneqq = "⪵";
var precnsim = "⋨";
var pre = "⪯";
var prE = "⪳";
var precsim = "≾";
var prime = "′";
var Prime = "″";
var primes = "ℙ";
var prnap = "⪹";
var prnE = "⪵";
var prnsim = "⋨";
var prod = "∏";
var Product = "∏";
var profalar = "⌮";
var profline = "⌒";
var profsurf = "⌓";
var prop = "∝";
var Proportional = "∝";
var Proportion = "∷";
var propto = "∝";
var prsim = "≾";
var prurel = "⊰";
var Pscr = "𝒫";
var pscr = "𝓅";
var Psi = "Ψ";
var psi = "ψ";
var puncsp = " ";
var Qfr = "𝔔";
var qfr = "𝔮";
var qint = "⨌";
var qopf = "𝕢";
var Qopf = "ℚ";
var qprime = "⁗";
var Qscr = "𝒬";
var qscr = "𝓆";
var quaternions = "ℍ";
var quatint = "⨖";
var quest = "?";
var questeq = "≟";
var quot = "\"";
var QUOT = "\"";
var rAarr = "⇛";
var race = "∽̱";
var Racute = "Ŕ";
var racute = "ŕ";
var radic = "√";
var raemptyv = "⦳";
var rang = "⟩";
var Rang = "⟫";
var rangd = "⦒";
var range = "⦥";
var rangle = "⟩";
var raquo = "»";
var rarrap = "⥵";
var rarrb = "⇥";
var rarrbfs = "⤠";
var rarrc = "⤳";
var rarr = "→";
var Rarr = "↠";
var rArr = "⇒";
var rarrfs = "⤞";
var rarrhk = "↪";
var rarrlp = "↬";
var rarrpl = "⥅";
var rarrsim = "⥴";
var Rarrtl = "⤖";
var rarrtl = "↣";
var rarrw = "↝";
var ratail = "⤚";
var rAtail = "⤜";
var ratio = "∶";
var rationals = "ℚ";
var rbarr = "⤍";
var rBarr = "⤏";
var RBarr = "⤐";
var rbbrk = "❳";
var rbrace = "}";
var rbrack = "]";
var rbrke = "⦌";
var rbrksld = "⦎";
var rbrkslu = "⦐";
var Rcaron = "Ř";
var rcaron = "ř";
var Rcedil = "Ŗ";
var rcedil = "ŗ";
var rceil = "⌉";
var rcub = "}";
var Rcy = "Р";
var rcy = "р";
var rdca = "⤷";
var rdldhar = "⥩";
var rdquo = "”";
var rdquor = "”";
var rdsh = "↳";
var real = "ℜ";
var realine = "ℛ";
var realpart = "ℜ";
var reals = "ℝ";
var Re = "ℜ";
var rect = "▭";
var reg = "®";
var REG = "®";
var ReverseElement = "∋";
var ReverseEquilibrium = "⇋";
var ReverseUpEquilibrium = "⥯";
var rfisht = "⥽";
var rfloor = "⌋";
var rfr = "𝔯";
var Rfr = "ℜ";
var rHar = "⥤";
var rhard = "⇁";
var rharu = "⇀";
var rharul = "⥬";
var Rho = "Ρ";
var rho = "ρ";
var rhov = "ϱ";
var RightAngleBracket = "⟩";
var RightArrowBar = "⇥";
var rightarrow = "→";
var RightArrow = "→";
var Rightarrow = "⇒";
var RightArrowLeftArrow = "⇄";
var rightarrowtail = "↣";
var RightCeiling = "⌉";
var RightDoubleBracket = "⟧";
var RightDownTeeVector = "⥝";
var RightDownVectorBar = "⥕";
var RightDownVector = "⇂";
var RightFloor = "⌋";
var rightharpoondown = "⇁";
var rightharpoonup = "⇀";
var rightleftarrows = "⇄";
var rightleftharpoons = "⇌";
var rightrightarrows = "⇉";
var rightsquigarrow = "↝";
var RightTeeArrow = "↦";
var RightTee = "⊢";
var RightTeeVector = "⥛";
var rightthreetimes = "⋌";
var RightTriangleBar = "⧐";
var RightTriangle = "⊳";
var RightTriangleEqual = "⊵";
var RightUpDownVector = "⥏";
var RightUpTeeVector = "⥜";
var RightUpVectorBar = "⥔";
var RightUpVector = "↾";
var RightVectorBar = "⥓";
var RightVector = "⇀";
var ring = "˚";
var risingdotseq = "≓";
var rlarr = "⇄";
var rlhar = "⇌";
var rlm = "‏";
var rmoustache = "⎱";
var rmoust = "⎱";
var rnmid = "⫮";
var roang = "⟭";
var roarr = "⇾";
var robrk = "⟧";
var ropar = "⦆";
var ropf = "𝕣";
var Ropf = "ℝ";
var roplus = "⨮";
var rotimes = "⨵";
var RoundImplies = "⥰";
var rpar = ")";
var rpargt = "⦔";
var rppolint = "⨒";
var rrarr = "⇉";
var Rrightarrow = "⇛";
var rsaquo = "›";
var rscr = "𝓇";
var Rscr = "ℛ";
var rsh = "↱";
var Rsh = "↱";
var rsqb = "]";
var rsquo = "’";
var rsquor = "’";
var rthree = "⋌";
var rtimes = "⋊";
var rtri = "▹";
var rtrie = "⊵";
var rtrif = "▸";
var rtriltri = "⧎";
var RuleDelayed = "⧴";
var ruluhar = "⥨";
var rx = "℞";
var Sacute = "Ś";
var sacute = "ś";
var sbquo = "‚";
var scap = "⪸";
var Scaron = "Š";
var scaron = "š";
var Sc = "⪼";
var sc = "≻";
var sccue = "≽";
var sce = "⪰";
var scE = "⪴";
var Scedil = "Ş";
var scedil = "ş";
var Scirc = "Ŝ";
var scirc = "ŝ";
var scnap = "⪺";
var scnE = "⪶";
var scnsim = "⋩";
var scpolint = "⨓";
var scsim = "≿";
var Scy = "С";
var scy = "с";
var sdotb = "⊡";
var sdot = "⋅";
var sdote = "⩦";
var searhk = "⤥";
var searr = "↘";
var seArr = "⇘";
var searrow = "↘";
var sect = "§";
var semi = ";";
var seswar = "⤩";
var setminus = "∖";
var setmn = "∖";
var sext = "✶";
var Sfr = "𝔖";
var sfr = "𝔰";
var sfrown = "⌢";
var sharp = "♯";
var SHCHcy = "Щ";
var shchcy = "щ";
var SHcy = "Ш";
var shcy = "ш";
var ShortDownArrow = "↓";
var ShortLeftArrow = "←";
var shortmid = "∣";
var shortparallel = "∥";
var ShortRightArrow = "→";
var ShortUpArrow = "↑";
var shy = "­";
var Sigma = "Σ";
var sigma = "σ";
var sigmaf = "ς";
var sigmav = "ς";
var sim = "∼";
var simdot = "⩪";
var sime = "≃";
var simeq = "≃";
var simg = "⪞";
var simgE = "⪠";
var siml = "⪝";
var simlE = "⪟";
var simne = "≆";
var simplus = "⨤";
var simrarr = "⥲";
var slarr = "←";
var SmallCircle = "∘";
var smallsetminus = "∖";
var smashp = "⨳";
var smeparsl = "⧤";
var smid = "∣";
var smile = "⌣";
var smt = "⪪";
var smte = "⪬";
var smtes = "⪬︀";
var SOFTcy = "Ь";
var softcy = "ь";
var solbar = "⌿";
var solb = "⧄";
var sol = "/";
var Sopf = "𝕊";
var sopf = "𝕤";
var spades = "♠";
var spadesuit = "♠";
var spar = "∥";
var sqcap = "⊓";
var sqcaps = "⊓︀";
var sqcup = "⊔";
var sqcups = "⊔︀";
var Sqrt = "√";
var sqsub = "⊏";
var sqsube = "⊑";
var sqsubset = "⊏";
var sqsubseteq = "⊑";
var sqsup = "⊐";
var sqsupe = "⊒";
var sqsupset = "⊐";
var sqsupseteq = "⊒";
var square = "□";
var Square = "□";
var SquareIntersection = "⊓";
var SquareSubset = "⊏";
var SquareSubsetEqual = "⊑";
var SquareSuperset = "⊐";
var SquareSupersetEqual = "⊒";
var SquareUnion = "⊔";
var squarf = "▪";
var squ = "□";
var squf = "▪";
var srarr = "→";
var Sscr = "𝒮";
var sscr = "𝓈";
var ssetmn = "∖";
var ssmile = "⌣";
var sstarf = "⋆";
var Star = "⋆";
var star = "☆";
var starf = "★";
var straightepsilon = "ϵ";
var straightphi = "ϕ";
var strns = "¯";
var sub = "⊂";
var Sub = "⋐";
var subdot = "⪽";
var subE = "⫅";
var sube = "⊆";
var subedot = "⫃";
var submult = "⫁";
var subnE = "⫋";
var subne = "⊊";
var subplus = "⪿";
var subrarr = "⥹";
var subset = "⊂";
var Subset = "⋐";
var subseteq = "⊆";
var subseteqq = "⫅";
var SubsetEqual = "⊆";
var subsetneq = "⊊";
var subsetneqq = "⫋";
var subsim = "⫇";
var subsub = "⫕";
var subsup = "⫓";
var succapprox = "⪸";
var succ = "≻";
var succcurlyeq = "≽";
var Succeeds = "≻";
var SucceedsEqual = "⪰";
var SucceedsSlantEqual = "≽";
var SucceedsTilde = "≿";
var succeq = "⪰";
var succnapprox = "⪺";
var succneqq = "⪶";
var succnsim = "⋩";
var succsim = "≿";
var SuchThat = "∋";
var sum = "∑";
var Sum = "∑";
var sung = "♪";
var sup1 = "¹";
var sup2 = "²";
var sup3 = "³";
var sup = "⊃";
var Sup = "⋑";
var supdot = "⪾";
var supdsub = "⫘";
var supE = "⫆";
var supe = "⊇";
var supedot = "⫄";
var Superset = "⊃";
var SupersetEqual = "⊇";
var suphsol = "⟉";
var suphsub = "⫗";
var suplarr = "⥻";
var supmult = "⫂";
var supnE = "⫌";
var supne = "⊋";
var supplus = "⫀";
var supset = "⊃";
var Supset = "⋑";
var supseteq = "⊇";
var supseteqq = "⫆";
var supsetneq = "⊋";
var supsetneqq = "⫌";
var supsim = "⫈";
var supsub = "⫔";
var supsup = "⫖";
var swarhk = "⤦";
var swarr = "↙";
var swArr = "⇙";
var swarrow = "↙";
var swnwar = "⤪";
var szlig = "ß";
var Tab = "\t";
var target = "⌖";
var Tau = "Τ";
var tau = "τ";
var tbrk = "⎴";
var Tcaron = "Ť";
var tcaron = "ť";
var Tcedil = "Ţ";
var tcedil = "ţ";
var Tcy = "Т";
var tcy = "т";
var tdot = "⃛";
var telrec = "⌕";
var Tfr = "𝔗";
var tfr = "𝔱";
var there4 = "∴";
var therefore = "∴";
var Therefore = "∴";
var Theta = "Θ";
var theta = "θ";
var thetasym = "ϑ";
var thetav = "ϑ";
var thickapprox = "≈";
var thicksim = "∼";
var ThickSpace = "  ";
var ThinSpace = " ";
var thinsp = " ";
var thkap = "≈";
var thksim = "∼";
var THORN = "Þ";
var thorn = "þ";
var tilde = "˜";
var Tilde = "∼";
var TildeEqual = "≃";
var TildeFullEqual = "≅";
var TildeTilde = "≈";
var timesbar = "⨱";
var timesb = "⊠";
var times = "×";
var timesd = "⨰";
var tint = "∭";
var toea = "⤨";
var topbot = "⌶";
var topcir = "⫱";
var top = "⊤";
var Topf = "𝕋";
var topf = "𝕥";
var topfork = "⫚";
var tosa = "⤩";
var tprime = "‴";
var trade = "™";
var TRADE = "™";
var triangle = "▵";
var triangledown = "▿";
var triangleleft = "◃";
var trianglelefteq = "⊴";
var triangleq = "≜";
var triangleright = "▹";
var trianglerighteq = "⊵";
var tridot = "◬";
var trie = "≜";
var triminus = "⨺";
var TripleDot = "⃛";
var triplus = "⨹";
var trisb = "⧍";
var tritime = "⨻";
var trpezium = "⏢";
var Tscr = "𝒯";
var tscr = "𝓉";
var TScy = "Ц";
var tscy = "ц";
var TSHcy = "Ћ";
var tshcy = "ћ";
var Tstrok = "Ŧ";
var tstrok = "ŧ";
var twixt = "≬";
var twoheadleftarrow = "↞";
var twoheadrightarrow = "↠";
var Uacute = "Ú";
var uacute = "ú";
var uarr = "↑";
var Uarr = "↟";
var uArr = "⇑";
var Uarrocir = "⥉";
var Ubrcy = "Ў";
var ubrcy = "ў";
var Ubreve = "Ŭ";
var ubreve = "ŭ";
var Ucirc = "Û";
var ucirc = "û";
var Ucy = "У";
var ucy = "у";
var udarr = "⇅";
var Udblac = "Ű";
var udblac = "ű";
var udhar = "⥮";
var ufisht = "⥾";
var Ufr = "𝔘";
var ufr = "𝔲";
var Ugrave = "Ù";
var ugrave = "ù";
var uHar = "⥣";
var uharl = "↿";
var uharr = "↾";
var uhblk = "▀";
var ulcorn = "⌜";
var ulcorner = "⌜";
var ulcrop = "⌏";
var ultri = "◸";
var Umacr = "Ū";
var umacr = "ū";
var uml = "¨";
var UnderBar = "_";
var UnderBrace = "⏟";
var UnderBracket = "⎵";
var UnderParenthesis = "⏝";
var Union = "⋃";
var UnionPlus = "⊎";
var Uogon = "Ų";
var uogon = "ų";
var Uopf = "𝕌";
var uopf = "𝕦";
var UpArrowBar = "⤒";
var uparrow = "↑";
var UpArrow = "↑";
var Uparrow = "⇑";
var UpArrowDownArrow = "⇅";
var updownarrow = "↕";
var UpDownArrow = "↕";
var Updownarrow = "⇕";
var UpEquilibrium = "⥮";
var upharpoonleft = "↿";
var upharpoonright = "↾";
var uplus = "⊎";
var UpperLeftArrow = "↖";
var UpperRightArrow = "↗";
var upsi = "υ";
var Upsi = "ϒ";
var upsih = "ϒ";
var Upsilon = "Υ";
var upsilon = "υ";
var UpTeeArrow = "↥";
var UpTee = "⊥";
var upuparrows = "⇈";
var urcorn = "⌝";
var urcorner = "⌝";
var urcrop = "⌎";
var Uring = "Ů";
var uring = "ů";
var urtri = "◹";
var Uscr = "𝒰";
var uscr = "𝓊";
var utdot = "⋰";
var Utilde = "Ũ";
var utilde = "ũ";
var utri = "▵";
var utrif = "▴";
var uuarr = "⇈";
var Uuml = "Ü";
var uuml = "ü";
var uwangle = "⦧";
var vangrt = "⦜";
var varepsilon = "ϵ";
var varkappa = "ϰ";
var varnothing = "∅";
var varphi = "ϕ";
var varpi = "ϖ";
var varpropto = "∝";
var varr = "↕";
var vArr = "⇕";
var varrho = "ϱ";
var varsigma = "ς";
var varsubsetneq = "⊊︀";
var varsubsetneqq = "⫋︀";
var varsupsetneq = "⊋︀";
var varsupsetneqq = "⫌︀";
var vartheta = "ϑ";
var vartriangleleft = "⊲";
var vartriangleright = "⊳";
var vBar = "⫨";
var Vbar = "⫫";
var vBarv = "⫩";
var Vcy = "В";
var vcy = "в";
var vdash = "⊢";
var vDash = "⊨";
var Vdash = "⊩";
var VDash = "⊫";
var Vdashl = "⫦";
var veebar = "⊻";
var vee = "∨";
var Vee = "⋁";
var veeeq = "≚";
var vellip = "⋮";
var verbar = "|";
var Verbar = "‖";
var vert = "|";
var Vert = "‖";
var VerticalBar = "∣";
var VerticalLine = "|";
var VerticalSeparator = "❘";
var VerticalTilde = "≀";
var VeryThinSpace = " ";
var Vfr = "𝔙";
var vfr = "𝔳";
var vltri = "⊲";
var vnsub = "⊂⃒";
var vnsup = "⊃⃒";
var Vopf = "𝕍";
var vopf = "𝕧";
var vprop = "∝";
var vrtri = "⊳";
var Vscr = "𝒱";
var vscr = "𝓋";
var vsubnE = "⫋︀";
var vsubne = "⊊︀";
var vsupnE = "⫌︀";
var vsupne = "⊋︀";
var Vvdash = "⊪";
var vzigzag = "⦚";
var Wcirc = "Ŵ";
var wcirc = "ŵ";
var wedbar = "⩟";
var wedge = "∧";
var Wedge = "⋀";
var wedgeq = "≙";
var weierp = "℘";
var Wfr = "𝔚";
var wfr = "𝔴";
var Wopf = "𝕎";
var wopf = "𝕨";
var wp = "℘";
var wr = "≀";
var wreath = "≀";
var Wscr = "𝒲";
var wscr = "𝓌";
var xcap = "⋂";
var xcirc = "◯";
var xcup = "⋃";
var xdtri = "▽";
var Xfr = "𝔛";
var xfr = "𝔵";
var xharr = "⟷";
var xhArr = "⟺";
var Xi = "Ξ";
var xi = "ξ";
var xlarr = "⟵";
var xlArr = "⟸";
var xmap = "⟼";
var xnis = "⋻";
var xodot = "⨀";
var Xopf = "𝕏";
var xopf = "𝕩";
var xoplus = "⨁";
var xotime = "⨂";
var xrarr = "⟶";
var xrArr = "⟹";
var Xscr = "𝒳";
var xscr = "𝓍";
var xsqcup = "⨆";
var xuplus = "⨄";
var xutri = "△";
var xvee = "⋁";
var xwedge = "⋀";
var Yacute = "Ý";
var yacute = "ý";
var YAcy = "Я";
var yacy = "я";
var Ycirc = "Ŷ";
var ycirc = "ŷ";
var Ycy = "Ы";
var ycy = "ы";
var yen = "¥";
var Yfr = "𝔜";
var yfr = "𝔶";
var YIcy = "Ї";
var yicy = "ї";
var Yopf = "𝕐";
var yopf = "𝕪";
var Yscr = "𝒴";
var yscr = "𝓎";
var YUcy = "Ю";
var yucy = "ю";
var yuml = "ÿ";
var Yuml = "Ÿ";
var Zacute = "Ź";
var zacute = "ź";
var Zcaron = "Ž";
var zcaron = "ž";
var Zcy = "З";
var zcy = "з";
var Zdot = "Ż";
var zdot = "ż";
var zeetrf = "ℨ";
var ZeroWidthSpace = "​";
var Zeta = "Ζ";
var zeta = "ζ";
var zfr = "𝔷";
var Zfr = "ℨ";
var ZHcy = "Ж";
var zhcy = "ж";
var zigrarr = "⇝";
var zopf = "𝕫";
var Zopf = "ℤ";
var Zscr = "𝒵";
var zscr = "𝓏";
var zwj = "‍";
var zwnj = "‌";
var require$$0$1 = {
	Aacute: Aacute,
	aacute: aacute,
	Abreve: Abreve,
	abreve: abreve,
	ac: ac,
	acd: acd,
	acE: acE,
	Acirc: Acirc,
	acirc: acirc,
	acute: acute,
	Acy: Acy,
	acy: acy,
	AElig: AElig,
	aelig: aelig,
	af: af,
	Afr: Afr,
	afr: afr,
	Agrave: Agrave,
	agrave: agrave,
	alefsym: alefsym,
	aleph: aleph,
	Alpha: Alpha,
	alpha: alpha,
	Amacr: Amacr,
	amacr: amacr,
	amalg: amalg,
	amp: amp,
	AMP: AMP,
	andand: andand,
	And: And,
	and: and,
	andd: andd,
	andslope: andslope,
	andv: andv,
	ang: ang,
	ange: ange,
	angle: angle,
	angmsdaa: angmsdaa,
	angmsdab: angmsdab,
	angmsdac: angmsdac,
	angmsdad: angmsdad,
	angmsdae: angmsdae,
	angmsdaf: angmsdaf,
	angmsdag: angmsdag,
	angmsdah: angmsdah,
	angmsd: angmsd,
	angrt: angrt,
	angrtvb: angrtvb,
	angrtvbd: angrtvbd,
	angsph: angsph,
	angst: angst,
	angzarr: angzarr,
	Aogon: Aogon,
	aogon: aogon,
	Aopf: Aopf,
	aopf: aopf,
	apacir: apacir,
	ap: ap,
	apE: apE,
	ape: ape,
	apid: apid,
	apos: apos,
	ApplyFunction: ApplyFunction,
	approx: approx,
	approxeq: approxeq,
	Aring: Aring,
	aring: aring,
	Ascr: Ascr,
	ascr: ascr,
	Assign: Assign,
	ast: ast,
	asymp: asymp,
	asympeq: asympeq,
	Atilde: Atilde,
	atilde: atilde,
	Auml: Auml,
	auml: auml,
	awconint: awconint,
	awint: awint,
	backcong: backcong,
	backepsilon: backepsilon,
	backprime: backprime,
	backsim: backsim,
	backsimeq: backsimeq,
	Backslash: Backslash,
	Barv: Barv,
	barvee: barvee,
	barwed: barwed,
	Barwed: Barwed,
	barwedge: barwedge,
	bbrk: bbrk,
	bbrktbrk: bbrktbrk,
	bcong: bcong,
	Bcy: Bcy,
	bcy: bcy,
	bdquo: bdquo,
	becaus: becaus,
	because: because,
	Because: Because,
	bemptyv: bemptyv,
	bepsi: bepsi,
	bernou: bernou,
	Bernoullis: Bernoullis,
	Beta: Beta,
	beta: beta,
	beth: beth,
	between: between,
	Bfr: Bfr,
	bfr: bfr,
	bigcap: bigcap,
	bigcirc: bigcirc,
	bigcup: bigcup,
	bigodot: bigodot,
	bigoplus: bigoplus,
	bigotimes: bigotimes,
	bigsqcup: bigsqcup,
	bigstar: bigstar,
	bigtriangledown: bigtriangledown,
	bigtriangleup: bigtriangleup,
	biguplus: biguplus,
	bigvee: bigvee,
	bigwedge: bigwedge,
	bkarow: bkarow,
	blacklozenge: blacklozenge,
	blacksquare: blacksquare,
	blacktriangle: blacktriangle,
	blacktriangledown: blacktriangledown,
	blacktriangleleft: blacktriangleleft,
	blacktriangleright: blacktriangleright,
	blank: blank,
	blk12: blk12,
	blk14: blk14,
	blk34: blk34,
	block: block$1,
	bne: bne,
	bnequiv: bnequiv,
	bNot: bNot,
	bnot: bnot,
	Bopf: Bopf,
	bopf: bopf,
	bot: bot,
	bottom: bottom,
	bowtie: bowtie,
	boxbox: boxbox,
	boxdl: boxdl,
	boxdL: boxdL,
	boxDl: boxDl,
	boxDL: boxDL,
	boxdr: boxdr,
	boxdR: boxdR,
	boxDr: boxDr,
	boxDR: boxDR,
	boxh: boxh,
	boxH: boxH,
	boxhd: boxhd,
	boxHd: boxHd,
	boxhD: boxhD,
	boxHD: boxHD,
	boxhu: boxhu,
	boxHu: boxHu,
	boxhU: boxhU,
	boxHU: boxHU,
	boxminus: boxminus,
	boxplus: boxplus,
	boxtimes: boxtimes,
	boxul: boxul,
	boxuL: boxuL,
	boxUl: boxUl,
	boxUL: boxUL,
	boxur: boxur,
	boxuR: boxuR,
	boxUr: boxUr,
	boxUR: boxUR,
	boxv: boxv,
	boxV: boxV,
	boxvh: boxvh,
	boxvH: boxvH,
	boxVh: boxVh,
	boxVH: boxVH,
	boxvl: boxvl,
	boxvL: boxvL,
	boxVl: boxVl,
	boxVL: boxVL,
	boxvr: boxvr,
	boxvR: boxvR,
	boxVr: boxVr,
	boxVR: boxVR,
	bprime: bprime,
	breve: breve,
	Breve: Breve,
	brvbar: brvbar,
	bscr: bscr,
	Bscr: Bscr,
	bsemi: bsemi,
	bsim: bsim,
	bsime: bsime,
	bsolb: bsolb,
	bsol: bsol,
	bsolhsub: bsolhsub,
	bull: bull,
	bullet: bullet,
	bump: bump,
	bumpE: bumpE,
	bumpe: bumpe,
	Bumpeq: Bumpeq,
	bumpeq: bumpeq,
	Cacute: Cacute,
	cacute: cacute,
	capand: capand,
	capbrcup: capbrcup,
	capcap: capcap,
	cap: cap,
	Cap: Cap,
	capcup: capcup,
	capdot: capdot,
	CapitalDifferentialD: CapitalDifferentialD,
	caps: caps,
	caret: caret,
	caron: caron,
	Cayleys: Cayleys,
	ccaps: ccaps,
	Ccaron: Ccaron,
	ccaron: ccaron,
	Ccedil: Ccedil,
	ccedil: ccedil,
	Ccirc: Ccirc,
	ccirc: ccirc,
	Cconint: Cconint,
	ccups: ccups,
	ccupssm: ccupssm,
	Cdot: Cdot,
	cdot: cdot,
	cedil: cedil,
	Cedilla: Cedilla,
	cemptyv: cemptyv,
	cent: cent,
	centerdot: centerdot,
	CenterDot: CenterDot,
	cfr: cfr,
	Cfr: Cfr,
	CHcy: CHcy,
	chcy: chcy,
	check: check,
	checkmark: checkmark,
	Chi: Chi,
	chi: chi,
	circ: circ,
	circeq: circeq,
	circlearrowleft: circlearrowleft,
	circlearrowright: circlearrowright,
	circledast: circledast,
	circledcirc: circledcirc,
	circleddash: circleddash,
	CircleDot: CircleDot,
	circledR: circledR,
	circledS: circledS,
	CircleMinus: CircleMinus,
	CirclePlus: CirclePlus,
	CircleTimes: CircleTimes,
	cir: cir,
	cirE: cirE,
	cire: cire,
	cirfnint: cirfnint,
	cirmid: cirmid,
	cirscir: cirscir,
	ClockwiseContourIntegral: ClockwiseContourIntegral,
	CloseCurlyDoubleQuote: CloseCurlyDoubleQuote,
	CloseCurlyQuote: CloseCurlyQuote,
	clubs: clubs,
	clubsuit: clubsuit,
	colon: colon,
	Colon: Colon,
	Colone: Colone,
	colone: colone,
	coloneq: coloneq,
	comma: comma,
	commat: commat,
	comp: comp,
	compfn: compfn,
	complement: complement,
	complexes: complexes,
	cong: cong,
	congdot: congdot,
	Congruent: Congruent,
	conint: conint,
	Conint: Conint,
	ContourIntegral: ContourIntegral,
	copf: copf,
	Copf: Copf,
	coprod: coprod,
	Coproduct: Coproduct,
	copy: copy,
	COPY: COPY,
	copysr: copysr,
	CounterClockwiseContourIntegral: CounterClockwiseContourIntegral,
	crarr: crarr,
	cross: cross,
	Cross: Cross,
	Cscr: Cscr,
	cscr: cscr,
	csub: csub,
	csube: csube,
	csup: csup,
	csupe: csupe,
	ctdot: ctdot,
	cudarrl: cudarrl,
	cudarrr: cudarrr,
	cuepr: cuepr,
	cuesc: cuesc,
	cularr: cularr,
	cularrp: cularrp,
	cupbrcap: cupbrcap,
	cupcap: cupcap,
	CupCap: CupCap,
	cup: cup,
	Cup: Cup,
	cupcup: cupcup,
	cupdot: cupdot,
	cupor: cupor,
	cups: cups,
	curarr: curarr,
	curarrm: curarrm,
	curlyeqprec: curlyeqprec,
	curlyeqsucc: curlyeqsucc,
	curlyvee: curlyvee,
	curlywedge: curlywedge,
	curren: curren,
	curvearrowleft: curvearrowleft,
	curvearrowright: curvearrowright,
	cuvee: cuvee,
	cuwed: cuwed,
	cwconint: cwconint,
	cwint: cwint,
	cylcty: cylcty,
	dagger: dagger,
	Dagger: Dagger,
	daleth: daleth,
	darr: darr,
	Darr: Darr,
	dArr: dArr,
	dash: dash,
	Dashv: Dashv,
	dashv: dashv,
	dbkarow: dbkarow,
	dblac: dblac,
	Dcaron: Dcaron,
	dcaron: dcaron,
	Dcy: Dcy,
	dcy: dcy,
	ddagger: ddagger,
	ddarr: ddarr,
	DD: DD,
	dd: dd,
	DDotrahd: DDotrahd,
	ddotseq: ddotseq,
	deg: deg,
	Del: Del,
	Delta: Delta,
	delta: delta,
	demptyv: demptyv,
	dfisht: dfisht,
	Dfr: Dfr,
	dfr: dfr,
	dHar: dHar,
	dharl: dharl,
	dharr: dharr,
	DiacriticalAcute: DiacriticalAcute,
	DiacriticalDot: DiacriticalDot,
	DiacriticalDoubleAcute: DiacriticalDoubleAcute,
	DiacriticalGrave: DiacriticalGrave,
	DiacriticalTilde: DiacriticalTilde,
	diam: diam,
	diamond: diamond,
	Diamond: Diamond,
	diamondsuit: diamondsuit,
	diams: diams,
	die: die,
	DifferentialD: DifferentialD,
	digamma: digamma,
	disin: disin,
	div: div,
	divide: divide,
	divideontimes: divideontimes,
	divonx: divonx,
	DJcy: DJcy,
	djcy: djcy,
	dlcorn: dlcorn,
	dlcrop: dlcrop,
	dollar: dollar,
	Dopf: Dopf,
	dopf: dopf,
	Dot: Dot,
	dot: dot,
	DotDot: DotDot,
	doteq: doteq,
	doteqdot: doteqdot,
	DotEqual: DotEqual,
	dotminus: dotminus,
	dotplus: dotplus,
	dotsquare: dotsquare,
	doublebarwedge: doublebarwedge,
	DoubleContourIntegral: DoubleContourIntegral,
	DoubleDot: DoubleDot,
	DoubleDownArrow: DoubleDownArrow,
	DoubleLeftArrow: DoubleLeftArrow,
	DoubleLeftRightArrow: DoubleLeftRightArrow,
	DoubleLeftTee: DoubleLeftTee,
	DoubleLongLeftArrow: DoubleLongLeftArrow,
	DoubleLongLeftRightArrow: DoubleLongLeftRightArrow,
	DoubleLongRightArrow: DoubleLongRightArrow,
	DoubleRightArrow: DoubleRightArrow,
	DoubleRightTee: DoubleRightTee,
	DoubleUpArrow: DoubleUpArrow,
	DoubleUpDownArrow: DoubleUpDownArrow,
	DoubleVerticalBar: DoubleVerticalBar,
	DownArrowBar: DownArrowBar,
	downarrow: downarrow,
	DownArrow: DownArrow,
	Downarrow: Downarrow,
	DownArrowUpArrow: DownArrowUpArrow,
	DownBreve: DownBreve,
	downdownarrows: downdownarrows,
	downharpoonleft: downharpoonleft,
	downharpoonright: downharpoonright,
	DownLeftRightVector: DownLeftRightVector,
	DownLeftTeeVector: DownLeftTeeVector,
	DownLeftVectorBar: DownLeftVectorBar,
	DownLeftVector: DownLeftVector,
	DownRightTeeVector: DownRightTeeVector,
	DownRightVectorBar: DownRightVectorBar,
	DownRightVector: DownRightVector,
	DownTeeArrow: DownTeeArrow,
	DownTee: DownTee,
	drbkarow: drbkarow,
	drcorn: drcorn,
	drcrop: drcrop,
	Dscr: Dscr,
	dscr: dscr,
	DScy: DScy,
	dscy: dscy,
	dsol: dsol,
	Dstrok: Dstrok,
	dstrok: dstrok,
	dtdot: dtdot,
	dtri: dtri,
	dtrif: dtrif,
	duarr: duarr,
	duhar: duhar,
	dwangle: dwangle,
	DZcy: DZcy,
	dzcy: dzcy,
	dzigrarr: dzigrarr,
	Eacute: Eacute,
	eacute: eacute,
	easter: easter,
	Ecaron: Ecaron,
	ecaron: ecaron,
	Ecirc: Ecirc,
	ecirc: ecirc,
	ecir: ecir,
	ecolon: ecolon,
	Ecy: Ecy,
	ecy: ecy,
	eDDot: eDDot,
	Edot: Edot,
	edot: edot,
	eDot: eDot,
	ee: ee,
	efDot: efDot,
	Efr: Efr,
	efr: efr,
	eg: eg,
	Egrave: Egrave,
	egrave: egrave,
	egs: egs,
	egsdot: egsdot,
	el: el,
	Element: Element,
	elinters: elinters,
	ell: ell,
	els: els,
	elsdot: elsdot,
	Emacr: Emacr,
	emacr: emacr,
	empty: empty,
	emptyset: emptyset,
	EmptySmallSquare: EmptySmallSquare,
	emptyv: emptyv,
	EmptyVerySmallSquare: EmptyVerySmallSquare,
	emsp13: emsp13,
	emsp14: emsp14,
	emsp: emsp,
	ENG: ENG,
	eng: eng,
	ensp: ensp,
	Eogon: Eogon,
	eogon: eogon,
	Eopf: Eopf,
	eopf: eopf,
	epar: epar,
	eparsl: eparsl,
	eplus: eplus,
	epsi: epsi,
	Epsilon: Epsilon,
	epsilon: epsilon,
	epsiv: epsiv,
	eqcirc: eqcirc,
	eqcolon: eqcolon,
	eqsim: eqsim,
	eqslantgtr: eqslantgtr,
	eqslantless: eqslantless,
	Equal: Equal,
	equals: equals,
	EqualTilde: EqualTilde,
	equest: equest,
	Equilibrium: Equilibrium,
	equiv: equiv,
	equivDD: equivDD,
	eqvparsl: eqvparsl,
	erarr: erarr,
	erDot: erDot,
	escr: escr,
	Escr: Escr,
	esdot: esdot,
	Esim: Esim,
	esim: esim,
	Eta: Eta,
	eta: eta,
	ETH: ETH,
	eth: eth,
	Euml: Euml,
	euml: euml,
	euro: euro,
	excl: excl,
	exist: exist,
	Exists: Exists,
	expectation: expectation,
	exponentiale: exponentiale,
	ExponentialE: ExponentialE,
	fallingdotseq: fallingdotseq,
	Fcy: Fcy,
	fcy: fcy,
	female: female,
	ffilig: ffilig,
	fflig: fflig,
	ffllig: ffllig,
	Ffr: Ffr,
	ffr: ffr,
	filig: filig,
	FilledSmallSquare: FilledSmallSquare,
	FilledVerySmallSquare: FilledVerySmallSquare,
	fjlig: fjlig,
	flat: flat,
	fllig: fllig,
	fltns: fltns,
	fnof: fnof,
	Fopf: Fopf,
	fopf: fopf,
	forall: forall,
	ForAll: ForAll,
	fork: fork,
	forkv: forkv,
	Fouriertrf: Fouriertrf,
	fpartint: fpartint,
	frac12: frac12,
	frac13: frac13,
	frac14: frac14,
	frac15: frac15,
	frac16: frac16,
	frac18: frac18,
	frac23: frac23,
	frac25: frac25,
	frac34: frac34,
	frac35: frac35,
	frac38: frac38,
	frac45: frac45,
	frac56: frac56,
	frac58: frac58,
	frac78: frac78,
	frasl: frasl,
	frown: frown,
	fscr: fscr,
	Fscr: Fscr,
	gacute: gacute,
	Gamma: Gamma,
	gamma: gamma,
	Gammad: Gammad,
	gammad: gammad,
	gap: gap,
	Gbreve: Gbreve,
	gbreve: gbreve,
	Gcedil: Gcedil,
	Gcirc: Gcirc,
	gcirc: gcirc,
	Gcy: Gcy,
	gcy: gcy,
	Gdot: Gdot,
	gdot: gdot,
	ge: ge,
	gE: gE,
	gEl: gEl,
	gel: gel,
	geq: geq,
	geqq: geqq,
	geqslant: geqslant,
	gescc: gescc,
	ges: ges,
	gesdot: gesdot,
	gesdoto: gesdoto,
	gesdotol: gesdotol,
	gesl: gesl,
	gesles: gesles,
	Gfr: Gfr,
	gfr: gfr,
	gg: gg,
	Gg: Gg,
	ggg: ggg,
	gimel: gimel,
	GJcy: GJcy,
	gjcy: gjcy,
	gla: gla,
	gl: gl,
	glE: glE,
	glj: glj,
	gnap: gnap,
	gnapprox: gnapprox,
	gne: gne,
	gnE: gnE,
	gneq: gneq,
	gneqq: gneqq,
	gnsim: gnsim,
	Gopf: Gopf,
	gopf: gopf,
	grave: grave,
	GreaterEqual: GreaterEqual,
	GreaterEqualLess: GreaterEqualLess,
	GreaterFullEqual: GreaterFullEqual,
	GreaterGreater: GreaterGreater,
	GreaterLess: GreaterLess,
	GreaterSlantEqual: GreaterSlantEqual,
	GreaterTilde: GreaterTilde,
	Gscr: Gscr,
	gscr: gscr,
	gsim: gsim,
	gsime: gsime,
	gsiml: gsiml,
	gtcc: gtcc,
	gtcir: gtcir,
	gt: gt,
	GT: GT,
	Gt: Gt,
	gtdot: gtdot,
	gtlPar: gtlPar,
	gtquest: gtquest,
	gtrapprox: gtrapprox,
	gtrarr: gtrarr,
	gtrdot: gtrdot,
	gtreqless: gtreqless,
	gtreqqless: gtreqqless,
	gtrless: gtrless,
	gtrsim: gtrsim,
	gvertneqq: gvertneqq,
	gvnE: gvnE,
	Hacek: Hacek,
	hairsp: hairsp,
	half: half,
	hamilt: hamilt,
	HARDcy: HARDcy,
	hardcy: hardcy,
	harrcir: harrcir,
	harr: harr,
	hArr: hArr,
	harrw: harrw,
	Hat: Hat,
	hbar: hbar,
	Hcirc: Hcirc,
	hcirc: hcirc,
	hearts: hearts,
	heartsuit: heartsuit,
	hellip: hellip,
	hercon: hercon,
	hfr: hfr,
	Hfr: Hfr,
	HilbertSpace: HilbertSpace,
	hksearow: hksearow,
	hkswarow: hkswarow,
	hoarr: hoarr,
	homtht: homtht,
	hookleftarrow: hookleftarrow,
	hookrightarrow: hookrightarrow,
	hopf: hopf,
	Hopf: Hopf,
	horbar: horbar,
	HorizontalLine: HorizontalLine,
	hscr: hscr,
	Hscr: Hscr,
	hslash: hslash,
	Hstrok: Hstrok,
	hstrok: hstrok,
	HumpDownHump: HumpDownHump,
	HumpEqual: HumpEqual,
	hybull: hybull,
	hyphen: hyphen,
	Iacute: Iacute,
	iacute: iacute,
	ic: ic,
	Icirc: Icirc,
	icirc: icirc,
	Icy: Icy,
	icy: icy,
	Idot: Idot,
	IEcy: IEcy,
	iecy: iecy,
	iexcl: iexcl,
	iff: iff,
	ifr: ifr,
	Ifr: Ifr,
	Igrave: Igrave,
	igrave: igrave,
	ii: ii,
	iiiint: iiiint,
	iiint: iiint,
	iinfin: iinfin,
	iiota: iiota,
	IJlig: IJlig,
	ijlig: ijlig,
	Imacr: Imacr,
	imacr: imacr,
	image: image$2,
	ImaginaryI: ImaginaryI,
	imagline: imagline,
	imagpart: imagpart,
	imath: imath,
	Im: Im,
	imof: imof,
	imped: imped,
	Implies: Implies,
	incare: incare,
	"in": "∈",
	infin: infin,
	infintie: infintie,
	inodot: inodot,
	intcal: intcal,
	int: int,
	Int: Int,
	integers: integers,
	Integral: Integral,
	intercal: intercal,
	Intersection: Intersection,
	intlarhk: intlarhk,
	intprod: intprod,
	InvisibleComma: InvisibleComma,
	InvisibleTimes: InvisibleTimes,
	IOcy: IOcy,
	iocy: iocy,
	Iogon: Iogon,
	iogon: iogon,
	Iopf: Iopf,
	iopf: iopf,
	Iota: Iota,
	iota: iota,
	iprod: iprod,
	iquest: iquest,
	iscr: iscr,
	Iscr: Iscr,
	isin: isin,
	isindot: isindot,
	isinE: isinE,
	isins: isins,
	isinsv: isinsv,
	isinv: isinv,
	it: it,
	Itilde: Itilde,
	itilde: itilde,
	Iukcy: Iukcy,
	iukcy: iukcy,
	Iuml: Iuml,
	iuml: iuml,
	Jcirc: Jcirc,
	jcirc: jcirc,
	Jcy: Jcy,
	jcy: jcy,
	Jfr: Jfr,
	jfr: jfr,
	jmath: jmath,
	Jopf: Jopf,
	jopf: jopf,
	Jscr: Jscr,
	jscr: jscr,
	Jsercy: Jsercy,
	jsercy: jsercy,
	Jukcy: Jukcy,
	jukcy: jukcy,
	Kappa: Kappa,
	kappa: kappa,
	kappav: kappav,
	Kcedil: Kcedil,
	kcedil: kcedil,
	Kcy: Kcy,
	kcy: kcy,
	Kfr: Kfr,
	kfr: kfr,
	kgreen: kgreen,
	KHcy: KHcy,
	khcy: khcy,
	KJcy: KJcy,
	kjcy: kjcy,
	Kopf: Kopf,
	kopf: kopf,
	Kscr: Kscr,
	kscr: kscr,
	lAarr: lAarr,
	Lacute: Lacute,
	lacute: lacute,
	laemptyv: laemptyv,
	lagran: lagran,
	Lambda: Lambda,
	lambda: lambda,
	lang: lang,
	Lang: Lang,
	langd: langd,
	langle: langle,
	lap: lap,
	Laplacetrf: Laplacetrf,
	laquo: laquo,
	larrb: larrb,
	larrbfs: larrbfs,
	larr: larr,
	Larr: Larr,
	lArr: lArr,
	larrfs: larrfs,
	larrhk: larrhk,
	larrlp: larrlp,
	larrpl: larrpl,
	larrsim: larrsim,
	larrtl: larrtl,
	latail: latail,
	lAtail: lAtail,
	lat: lat,
	late: late,
	lates: lates,
	lbarr: lbarr,
	lBarr: lBarr,
	lbbrk: lbbrk,
	lbrace: lbrace,
	lbrack: lbrack,
	lbrke: lbrke,
	lbrksld: lbrksld,
	lbrkslu: lbrkslu,
	Lcaron: Lcaron,
	lcaron: lcaron,
	Lcedil: Lcedil,
	lcedil: lcedil,
	lceil: lceil,
	lcub: lcub,
	Lcy: Lcy,
	lcy: lcy,
	ldca: ldca,
	ldquo: ldquo,
	ldquor: ldquor,
	ldrdhar: ldrdhar,
	ldrushar: ldrushar,
	ldsh: ldsh,
	le: le,
	lE: lE,
	LeftAngleBracket: LeftAngleBracket,
	LeftArrowBar: LeftArrowBar,
	leftarrow: leftarrow,
	LeftArrow: LeftArrow,
	Leftarrow: Leftarrow,
	LeftArrowRightArrow: LeftArrowRightArrow,
	leftarrowtail: leftarrowtail,
	LeftCeiling: LeftCeiling,
	LeftDoubleBracket: LeftDoubleBracket,
	LeftDownTeeVector: LeftDownTeeVector,
	LeftDownVectorBar: LeftDownVectorBar,
	LeftDownVector: LeftDownVector,
	LeftFloor: LeftFloor,
	leftharpoondown: leftharpoondown,
	leftharpoonup: leftharpoonup,
	leftleftarrows: leftleftarrows,
	leftrightarrow: leftrightarrow,
	LeftRightArrow: LeftRightArrow,
	Leftrightarrow: Leftrightarrow,
	leftrightarrows: leftrightarrows,
	leftrightharpoons: leftrightharpoons,
	leftrightsquigarrow: leftrightsquigarrow,
	LeftRightVector: LeftRightVector,
	LeftTeeArrow: LeftTeeArrow,
	LeftTee: LeftTee,
	LeftTeeVector: LeftTeeVector,
	leftthreetimes: leftthreetimes,
	LeftTriangleBar: LeftTriangleBar,
	LeftTriangle: LeftTriangle,
	LeftTriangleEqual: LeftTriangleEqual,
	LeftUpDownVector: LeftUpDownVector,
	LeftUpTeeVector: LeftUpTeeVector,
	LeftUpVectorBar: LeftUpVectorBar,
	LeftUpVector: LeftUpVector,
	LeftVectorBar: LeftVectorBar,
	LeftVector: LeftVector,
	lEg: lEg,
	leg: leg,
	leq: leq,
	leqq: leqq,
	leqslant: leqslant,
	lescc: lescc,
	les: les,
	lesdot: lesdot,
	lesdoto: lesdoto,
	lesdotor: lesdotor,
	lesg: lesg,
	lesges: lesges,
	lessapprox: lessapprox,
	lessdot: lessdot,
	lesseqgtr: lesseqgtr,
	lesseqqgtr: lesseqqgtr,
	LessEqualGreater: LessEqualGreater,
	LessFullEqual: LessFullEqual,
	LessGreater: LessGreater,
	lessgtr: lessgtr,
	LessLess: LessLess,
	lesssim: lesssim,
	LessSlantEqual: LessSlantEqual,
	LessTilde: LessTilde,
	lfisht: lfisht,
	lfloor: lfloor,
	Lfr: Lfr,
	lfr: lfr,
	lg: lg,
	lgE: lgE,
	lHar: lHar,
	lhard: lhard,
	lharu: lharu,
	lharul: lharul,
	lhblk: lhblk,
	LJcy: LJcy,
	ljcy: ljcy,
	llarr: llarr,
	ll: ll,
	Ll: Ll,
	llcorner: llcorner,
	Lleftarrow: Lleftarrow,
	llhard: llhard,
	lltri: lltri,
	Lmidot: Lmidot,
	lmidot: lmidot,
	lmoustache: lmoustache,
	lmoust: lmoust,
	lnap: lnap,
	lnapprox: lnapprox,
	lne: lne,
	lnE: lnE,
	lneq: lneq,
	lneqq: lneqq,
	lnsim: lnsim,
	loang: loang,
	loarr: loarr,
	lobrk: lobrk,
	longleftarrow: longleftarrow,
	LongLeftArrow: LongLeftArrow,
	Longleftarrow: Longleftarrow,
	longleftrightarrow: longleftrightarrow,
	LongLeftRightArrow: LongLeftRightArrow,
	Longleftrightarrow: Longleftrightarrow,
	longmapsto: longmapsto,
	longrightarrow: longrightarrow,
	LongRightArrow: LongRightArrow,
	Longrightarrow: Longrightarrow,
	looparrowleft: looparrowleft,
	looparrowright: looparrowright,
	lopar: lopar,
	Lopf: Lopf,
	lopf: lopf,
	loplus: loplus,
	lotimes: lotimes,
	lowast: lowast,
	lowbar: lowbar,
	LowerLeftArrow: LowerLeftArrow,
	LowerRightArrow: LowerRightArrow,
	loz: loz,
	lozenge: lozenge,
	lozf: lozf,
	lpar: lpar,
	lparlt: lparlt,
	lrarr: lrarr,
	lrcorner: lrcorner,
	lrhar: lrhar,
	lrhard: lrhard,
	lrm: lrm,
	lrtri: lrtri,
	lsaquo: lsaquo,
	lscr: lscr,
	Lscr: Lscr,
	lsh: lsh,
	Lsh: Lsh,
	lsim: lsim,
	lsime: lsime,
	lsimg: lsimg,
	lsqb: lsqb,
	lsquo: lsquo,
	lsquor: lsquor,
	Lstrok: Lstrok,
	lstrok: lstrok,
	ltcc: ltcc,
	ltcir: ltcir,
	lt: lt,
	LT: LT,
	Lt: Lt,
	ltdot: ltdot,
	lthree: lthree,
	ltimes: ltimes,
	ltlarr: ltlarr,
	ltquest: ltquest,
	ltri: ltri,
	ltrie: ltrie,
	ltrif: ltrif,
	ltrPar: ltrPar,
	lurdshar: lurdshar,
	luruhar: luruhar,
	lvertneqq: lvertneqq,
	lvnE: lvnE,
	macr: macr,
	male: male,
	malt: malt,
	maltese: maltese,
	"Map": "⤅",
	map: map$1,
	mapsto: mapsto,
	mapstodown: mapstodown,
	mapstoleft: mapstoleft,
	mapstoup: mapstoup,
	marker: marker,
	mcomma: mcomma,
	Mcy: Mcy,
	mcy: mcy,
	mdash: mdash,
	mDDot: mDDot,
	measuredangle: measuredangle,
	MediumSpace: MediumSpace,
	Mellintrf: Mellintrf,
	Mfr: Mfr,
	mfr: mfr,
	mho: mho,
	micro: micro,
	midast: midast,
	midcir: midcir,
	mid: mid,
	middot: middot,
	minusb: minusb,
	minus: minus,
	minusd: minusd,
	minusdu: minusdu,
	MinusPlus: MinusPlus,
	mlcp: mlcp,
	mldr: mldr,
	mnplus: mnplus,
	models: models,
	Mopf: Mopf,
	mopf: mopf,
	mp: mp,
	mscr: mscr,
	Mscr: Mscr,
	mstpos: mstpos,
	Mu: Mu,
	mu: mu,
	multimap: multimap,
	mumap: mumap,
	nabla: nabla,
	Nacute: Nacute,
	nacute: nacute,
	nang: nang,
	nap: nap,
	napE: napE,
	napid: napid,
	napos: napos,
	napprox: napprox,
	natural: natural,
	naturals: naturals,
	natur: natur,
	nbsp: nbsp,
	nbump: nbump,
	nbumpe: nbumpe,
	ncap: ncap,
	Ncaron: Ncaron,
	ncaron: ncaron,
	Ncedil: Ncedil,
	ncedil: ncedil,
	ncong: ncong,
	ncongdot: ncongdot,
	ncup: ncup,
	Ncy: Ncy,
	ncy: ncy,
	ndash: ndash,
	nearhk: nearhk,
	nearr: nearr,
	neArr: neArr,
	nearrow: nearrow,
	ne: ne,
	nedot: nedot,
	NegativeMediumSpace: NegativeMediumSpace,
	NegativeThickSpace: NegativeThickSpace,
	NegativeThinSpace: NegativeThinSpace,
	NegativeVeryThinSpace: NegativeVeryThinSpace,
	nequiv: nequiv,
	nesear: nesear,
	nesim: nesim,
	NestedGreaterGreater: NestedGreaterGreater,
	NestedLessLess: NestedLessLess,
	NewLine: NewLine,
	nexist: nexist,
	nexists: nexists,
	Nfr: Nfr,
	nfr: nfr,
	ngE: ngE,
	nge: nge,
	ngeq: ngeq,
	ngeqq: ngeqq,
	ngeqslant: ngeqslant,
	nges: nges,
	nGg: nGg,
	ngsim: ngsim,
	nGt: nGt,
	ngt: ngt,
	ngtr: ngtr,
	nGtv: nGtv,
	nharr: nharr,
	nhArr: nhArr,
	nhpar: nhpar,
	ni: ni,
	nis: nis,
	nisd: nisd,
	niv: niv,
	NJcy: NJcy,
	njcy: njcy,
	nlarr: nlarr,
	nlArr: nlArr,
	nldr: nldr,
	nlE: nlE,
	nle: nle,
	nleftarrow: nleftarrow,
	nLeftarrow: nLeftarrow,
	nleftrightarrow: nleftrightarrow,
	nLeftrightarrow: nLeftrightarrow,
	nleq: nleq,
	nleqq: nleqq,
	nleqslant: nleqslant,
	nles: nles,
	nless: nless,
	nLl: nLl,
	nlsim: nlsim,
	nLt: nLt,
	nlt: nlt,
	nltri: nltri,
	nltrie: nltrie,
	nLtv: nLtv,
	nmid: nmid,
	NoBreak: NoBreak,
	NonBreakingSpace: NonBreakingSpace,
	nopf: nopf,
	Nopf: Nopf,
	Not: Not,
	not: not,
	NotCongruent: NotCongruent,
	NotCupCap: NotCupCap,
	NotDoubleVerticalBar: NotDoubleVerticalBar,
	NotElement: NotElement,
	NotEqual: NotEqual,
	NotEqualTilde: NotEqualTilde,
	NotExists: NotExists,
	NotGreater: NotGreater,
	NotGreaterEqual: NotGreaterEqual,
	NotGreaterFullEqual: NotGreaterFullEqual,
	NotGreaterGreater: NotGreaterGreater,
	NotGreaterLess: NotGreaterLess,
	NotGreaterSlantEqual: NotGreaterSlantEqual,
	NotGreaterTilde: NotGreaterTilde,
	NotHumpDownHump: NotHumpDownHump,
	NotHumpEqual: NotHumpEqual,
	notin: notin,
	notindot: notindot,
	notinE: notinE,
	notinva: notinva,
	notinvb: notinvb,
	notinvc: notinvc,
	NotLeftTriangleBar: NotLeftTriangleBar,
	NotLeftTriangle: NotLeftTriangle,
	NotLeftTriangleEqual: NotLeftTriangleEqual,
	NotLess: NotLess,
	NotLessEqual: NotLessEqual,
	NotLessGreater: NotLessGreater,
	NotLessLess: NotLessLess,
	NotLessSlantEqual: NotLessSlantEqual,
	NotLessTilde: NotLessTilde,
	NotNestedGreaterGreater: NotNestedGreaterGreater,
	NotNestedLessLess: NotNestedLessLess,
	notni: notni,
	notniva: notniva,
	notnivb: notnivb,
	notnivc: notnivc,
	NotPrecedes: NotPrecedes,
	NotPrecedesEqual: NotPrecedesEqual,
	NotPrecedesSlantEqual: NotPrecedesSlantEqual,
	NotReverseElement: NotReverseElement,
	NotRightTriangleBar: NotRightTriangleBar,
	NotRightTriangle: NotRightTriangle,
	NotRightTriangleEqual: NotRightTriangleEqual,
	NotSquareSubset: NotSquareSubset,
	NotSquareSubsetEqual: NotSquareSubsetEqual,
	NotSquareSuperset: NotSquareSuperset,
	NotSquareSupersetEqual: NotSquareSupersetEqual,
	NotSubset: NotSubset,
	NotSubsetEqual: NotSubsetEqual,
	NotSucceeds: NotSucceeds,
	NotSucceedsEqual: NotSucceedsEqual,
	NotSucceedsSlantEqual: NotSucceedsSlantEqual,
	NotSucceedsTilde: NotSucceedsTilde,
	NotSuperset: NotSuperset,
	NotSupersetEqual: NotSupersetEqual,
	NotTilde: NotTilde,
	NotTildeEqual: NotTildeEqual,
	NotTildeFullEqual: NotTildeFullEqual,
	NotTildeTilde: NotTildeTilde,
	NotVerticalBar: NotVerticalBar,
	nparallel: nparallel,
	npar: npar,
	nparsl: nparsl,
	npart: npart,
	npolint: npolint,
	npr: npr,
	nprcue: nprcue,
	nprec: nprec,
	npreceq: npreceq,
	npre: npre,
	nrarrc: nrarrc,
	nrarr: nrarr,
	nrArr: nrArr,
	nrarrw: nrarrw,
	nrightarrow: nrightarrow,
	nRightarrow: nRightarrow,
	nrtri: nrtri,
	nrtrie: nrtrie,
	nsc: nsc,
	nsccue: nsccue,
	nsce: nsce,
	Nscr: Nscr,
	nscr: nscr,
	nshortmid: nshortmid,
	nshortparallel: nshortparallel,
	nsim: nsim,
	nsime: nsime,
	nsimeq: nsimeq,
	nsmid: nsmid,
	nspar: nspar,
	nsqsube: nsqsube,
	nsqsupe: nsqsupe,
	nsub: nsub,
	nsubE: nsubE,
	nsube: nsube,
	nsubset: nsubset,
	nsubseteq: nsubseteq,
	nsubseteqq: nsubseteqq,
	nsucc: nsucc,
	nsucceq: nsucceq,
	nsup: nsup,
	nsupE: nsupE,
	nsupe: nsupe,
	nsupset: nsupset,
	nsupseteq: nsupseteq,
	nsupseteqq: nsupseteqq,
	ntgl: ntgl,
	Ntilde: Ntilde,
	ntilde: ntilde,
	ntlg: ntlg,
	ntriangleleft: ntriangleleft,
	ntrianglelefteq: ntrianglelefteq,
	ntriangleright: ntriangleright,
	ntrianglerighteq: ntrianglerighteq,
	Nu: Nu,
	nu: nu,
	num: num,
	numero: numero,
	numsp: numsp,
	nvap: nvap,
	nvdash: nvdash,
	nvDash: nvDash,
	nVdash: nVdash,
	nVDash: nVDash,
	nvge: nvge,
	nvgt: nvgt,
	nvHarr: nvHarr,
	nvinfin: nvinfin,
	nvlArr: nvlArr,
	nvle: nvle,
	nvlt: nvlt,
	nvltrie: nvltrie,
	nvrArr: nvrArr,
	nvrtrie: nvrtrie,
	nvsim: nvsim,
	nwarhk: nwarhk,
	nwarr: nwarr,
	nwArr: nwArr,
	nwarrow: nwarrow,
	nwnear: nwnear,
	Oacute: Oacute,
	oacute: oacute,
	oast: oast,
	Ocirc: Ocirc,
	ocirc: ocirc,
	ocir: ocir,
	Ocy: Ocy,
	ocy: ocy,
	odash: odash,
	Odblac: Odblac,
	odblac: odblac,
	odiv: odiv,
	odot: odot,
	odsold: odsold,
	OElig: OElig,
	oelig: oelig,
	ofcir: ofcir,
	Ofr: Ofr,
	ofr: ofr,
	ogon: ogon,
	Ograve: Ograve,
	ograve: ograve,
	ogt: ogt,
	ohbar: ohbar,
	ohm: ohm,
	oint: oint,
	olarr: olarr,
	olcir: olcir,
	olcross: olcross,
	oline: oline,
	olt: olt,
	Omacr: Omacr,
	omacr: omacr,
	Omega: Omega,
	omega: omega,
	Omicron: Omicron,
	omicron: omicron,
	omid: omid,
	ominus: ominus,
	Oopf: Oopf,
	oopf: oopf,
	opar: opar,
	OpenCurlyDoubleQuote: OpenCurlyDoubleQuote,
	OpenCurlyQuote: OpenCurlyQuote,
	operp: operp,
	oplus: oplus,
	orarr: orarr,
	Or: Or,
	or: or,
	ord: ord,
	order: order,
	orderof: orderof,
	ordf: ordf,
	ordm: ordm,
	origof: origof,
	oror: oror,
	orslope: orslope,
	orv: orv,
	oS: oS,
	Oscr: Oscr,
	oscr: oscr,
	Oslash: Oslash,
	oslash: oslash,
	osol: osol,
	Otilde: Otilde,
	otilde: otilde,
	otimesas: otimesas,
	Otimes: Otimes,
	otimes: otimes,
	Ouml: Ouml,
	ouml: ouml,
	ovbar: ovbar,
	OverBar: OverBar,
	OverBrace: OverBrace,
	OverBracket: OverBracket,
	OverParenthesis: OverParenthesis,
	para: para,
	parallel: parallel,
	par: par,
	parsim: parsim,
	parsl: parsl,
	part: part,
	PartialD: PartialD,
	Pcy: Pcy,
	pcy: pcy,
	percnt: percnt,
	period: period,
	permil: permil,
	perp: perp,
	pertenk: pertenk,
	Pfr: Pfr,
	pfr: pfr,
	Phi: Phi,
	phi: phi,
	phiv: phiv,
	phmmat: phmmat,
	phone: phone,
	Pi: Pi,
	pi: pi,
	pitchfork: pitchfork,
	piv: piv,
	planck: planck,
	planckh: planckh,
	plankv: plankv,
	plusacir: plusacir,
	plusb: plusb,
	pluscir: pluscir,
	plus: plus,
	plusdo: plusdo,
	plusdu: plusdu,
	pluse: pluse,
	PlusMinus: PlusMinus,
	plusmn: plusmn,
	plussim: plussim,
	plustwo: plustwo,
	pm: pm,
	Poincareplane: Poincareplane,
	pointint: pointint,
	popf: popf,
	Popf: Popf,
	pound: pound,
	prap: prap,
	Pr: Pr,
	pr: pr,
	prcue: prcue,
	precapprox: precapprox,
	prec: prec,
	preccurlyeq: preccurlyeq,
	Precedes: Precedes,
	PrecedesEqual: PrecedesEqual,
	PrecedesSlantEqual: PrecedesSlantEqual,
	PrecedesTilde: PrecedesTilde,
	preceq: preceq,
	precnapprox: precnapprox,
	precneqq: precneqq,
	precnsim: precnsim,
	pre: pre,
	prE: prE,
	precsim: precsim,
	prime: prime,
	Prime: Prime,
	primes: primes,
	prnap: prnap,
	prnE: prnE,
	prnsim: prnsim,
	prod: prod,
	Product: Product,
	profalar: profalar,
	profline: profline,
	profsurf: profsurf,
	prop: prop,
	Proportional: Proportional,
	Proportion: Proportion,
	propto: propto,
	prsim: prsim,
	prurel: prurel,
	Pscr: Pscr,
	pscr: pscr,
	Psi: Psi,
	psi: psi,
	puncsp: puncsp,
	Qfr: Qfr,
	qfr: qfr,
	qint: qint,
	qopf: qopf,
	Qopf: Qopf,
	qprime: qprime,
	Qscr: Qscr,
	qscr: qscr,
	quaternions: quaternions,
	quatint: quatint,
	quest: quest,
	questeq: questeq,
	quot: quot,
	QUOT: QUOT,
	rAarr: rAarr,
	race: race,
	Racute: Racute,
	racute: racute,
	radic: radic,
	raemptyv: raemptyv,
	rang: rang,
	Rang: Rang,
	rangd: rangd,
	range: range,
	rangle: rangle,
	raquo: raquo,
	rarrap: rarrap,
	rarrb: rarrb,
	rarrbfs: rarrbfs,
	rarrc: rarrc,
	rarr: rarr,
	Rarr: Rarr,
	rArr: rArr,
	rarrfs: rarrfs,
	rarrhk: rarrhk,
	rarrlp: rarrlp,
	rarrpl: rarrpl,
	rarrsim: rarrsim,
	Rarrtl: Rarrtl,
	rarrtl: rarrtl,
	rarrw: rarrw,
	ratail: ratail,
	rAtail: rAtail,
	ratio: ratio,
	rationals: rationals,
	rbarr: rbarr,
	rBarr: rBarr,
	RBarr: RBarr,
	rbbrk: rbbrk,
	rbrace: rbrace,
	rbrack: rbrack,
	rbrke: rbrke,
	rbrksld: rbrksld,
	rbrkslu: rbrkslu,
	Rcaron: Rcaron,
	rcaron: rcaron,
	Rcedil: Rcedil,
	rcedil: rcedil,
	rceil: rceil,
	rcub: rcub,
	Rcy: Rcy,
	rcy: rcy,
	rdca: rdca,
	rdldhar: rdldhar,
	rdquo: rdquo,
	rdquor: rdquor,
	rdsh: rdsh,
	real: real,
	realine: realine,
	realpart: realpart,
	reals: reals,
	Re: Re,
	rect: rect,
	reg: reg,
	REG: REG,
	ReverseElement: ReverseElement,
	ReverseEquilibrium: ReverseEquilibrium,
	ReverseUpEquilibrium: ReverseUpEquilibrium,
	rfisht: rfisht,
	rfloor: rfloor,
	rfr: rfr,
	Rfr: Rfr,
	rHar: rHar,
	rhard: rhard,
	rharu: rharu,
	rharul: rharul,
	Rho: Rho,
	rho: rho,
	rhov: rhov,
	RightAngleBracket: RightAngleBracket,
	RightArrowBar: RightArrowBar,
	rightarrow: rightarrow,
	RightArrow: RightArrow,
	Rightarrow: Rightarrow,
	RightArrowLeftArrow: RightArrowLeftArrow,
	rightarrowtail: rightarrowtail,
	RightCeiling: RightCeiling,
	RightDoubleBracket: RightDoubleBracket,
	RightDownTeeVector: RightDownTeeVector,
	RightDownVectorBar: RightDownVectorBar,
	RightDownVector: RightDownVector,
	RightFloor: RightFloor,
	rightharpoondown: rightharpoondown,
	rightharpoonup: rightharpoonup,
	rightleftarrows: rightleftarrows,
	rightleftharpoons: rightleftharpoons,
	rightrightarrows: rightrightarrows,
	rightsquigarrow: rightsquigarrow,
	RightTeeArrow: RightTeeArrow,
	RightTee: RightTee,
	RightTeeVector: RightTeeVector,
	rightthreetimes: rightthreetimes,
	RightTriangleBar: RightTriangleBar,
	RightTriangle: RightTriangle,
	RightTriangleEqual: RightTriangleEqual,
	RightUpDownVector: RightUpDownVector,
	RightUpTeeVector: RightUpTeeVector,
	RightUpVectorBar: RightUpVectorBar,
	RightUpVector: RightUpVector,
	RightVectorBar: RightVectorBar,
	RightVector: RightVector,
	ring: ring,
	risingdotseq: risingdotseq,
	rlarr: rlarr,
	rlhar: rlhar,
	rlm: rlm,
	rmoustache: rmoustache,
	rmoust: rmoust,
	rnmid: rnmid,
	roang: roang,
	roarr: roarr,
	robrk: robrk,
	ropar: ropar,
	ropf: ropf,
	Ropf: Ropf,
	roplus: roplus,
	rotimes: rotimes,
	RoundImplies: RoundImplies,
	rpar: rpar,
	rpargt: rpargt,
	rppolint: rppolint,
	rrarr: rrarr,
	Rrightarrow: Rrightarrow,
	rsaquo: rsaquo,
	rscr: rscr,
	Rscr: Rscr,
	rsh: rsh,
	Rsh: Rsh,
	rsqb: rsqb,
	rsquo: rsquo,
	rsquor: rsquor,
	rthree: rthree,
	rtimes: rtimes,
	rtri: rtri,
	rtrie: rtrie,
	rtrif: rtrif,
	rtriltri: rtriltri,
	RuleDelayed: RuleDelayed,
	ruluhar: ruluhar,
	rx: rx,
	Sacute: Sacute,
	sacute: sacute,
	sbquo: sbquo,
	scap: scap,
	Scaron: Scaron,
	scaron: scaron,
	Sc: Sc,
	sc: sc,
	sccue: sccue,
	sce: sce,
	scE: scE,
	Scedil: Scedil,
	scedil: scedil,
	Scirc: Scirc,
	scirc: scirc,
	scnap: scnap,
	scnE: scnE,
	scnsim: scnsim,
	scpolint: scpolint,
	scsim: scsim,
	Scy: Scy,
	scy: scy,
	sdotb: sdotb,
	sdot: sdot,
	sdote: sdote,
	searhk: searhk,
	searr: searr,
	seArr: seArr,
	searrow: searrow,
	sect: sect,
	semi: semi,
	seswar: seswar,
	setminus: setminus,
	setmn: setmn,
	sext: sext,
	Sfr: Sfr,
	sfr: sfr,
	sfrown: sfrown,
	sharp: sharp,
	SHCHcy: SHCHcy,
	shchcy: shchcy,
	SHcy: SHcy,
	shcy: shcy,
	ShortDownArrow: ShortDownArrow,
	ShortLeftArrow: ShortLeftArrow,
	shortmid: shortmid,
	shortparallel: shortparallel,
	ShortRightArrow: ShortRightArrow,
	ShortUpArrow: ShortUpArrow,
	shy: shy,
	Sigma: Sigma,
	sigma: sigma,
	sigmaf: sigmaf,
	sigmav: sigmav,
	sim: sim,
	simdot: simdot,
	sime: sime,
	simeq: simeq,
	simg: simg,
	simgE: simgE,
	siml: siml,
	simlE: simlE,
	simne: simne,
	simplus: simplus,
	simrarr: simrarr,
	slarr: slarr,
	SmallCircle: SmallCircle,
	smallsetminus: smallsetminus,
	smashp: smashp,
	smeparsl: smeparsl,
	smid: smid,
	smile: smile,
	smt: smt,
	smte: smte,
	smtes: smtes,
	SOFTcy: SOFTcy,
	softcy: softcy,
	solbar: solbar,
	solb: solb,
	sol: sol,
	Sopf: Sopf,
	sopf: sopf,
	spades: spades,
	spadesuit: spadesuit,
	spar: spar,
	sqcap: sqcap,
	sqcaps: sqcaps,
	sqcup: sqcup,
	sqcups: sqcups,
	Sqrt: Sqrt,
	sqsub: sqsub,
	sqsube: sqsube,
	sqsubset: sqsubset,
	sqsubseteq: sqsubseteq,
	sqsup: sqsup,
	sqsupe: sqsupe,
	sqsupset: sqsupset,
	sqsupseteq: sqsupseteq,
	square: square,
	Square: Square,
	SquareIntersection: SquareIntersection,
	SquareSubset: SquareSubset,
	SquareSubsetEqual: SquareSubsetEqual,
	SquareSuperset: SquareSuperset,
	SquareSupersetEqual: SquareSupersetEqual,
	SquareUnion: SquareUnion,
	squarf: squarf,
	squ: squ,
	squf: squf,
	srarr: srarr,
	Sscr: Sscr,
	sscr: sscr,
	ssetmn: ssetmn,
	ssmile: ssmile,
	sstarf: sstarf,
	Star: Star,
	star: star,
	starf: starf,
	straightepsilon: straightepsilon,
	straightphi: straightphi,
	strns: strns,
	sub: sub,
	Sub: Sub,
	subdot: subdot,
	subE: subE,
	sube: sube,
	subedot: subedot,
	submult: submult,
	subnE: subnE,
	subne: subne,
	subplus: subplus,
	subrarr: subrarr,
	subset: subset,
	Subset: Subset,
	subseteq: subseteq,
	subseteqq: subseteqq,
	SubsetEqual: SubsetEqual,
	subsetneq: subsetneq,
	subsetneqq: subsetneqq,
	subsim: subsim,
	subsub: subsub,
	subsup: subsup,
	succapprox: succapprox,
	succ: succ,
	succcurlyeq: succcurlyeq,
	Succeeds: Succeeds,
	SucceedsEqual: SucceedsEqual,
	SucceedsSlantEqual: SucceedsSlantEqual,
	SucceedsTilde: SucceedsTilde,
	succeq: succeq,
	succnapprox: succnapprox,
	succneqq: succneqq,
	succnsim: succnsim,
	succsim: succsim,
	SuchThat: SuchThat,
	sum: sum,
	Sum: Sum,
	sung: sung,
	sup1: sup1,
	sup2: sup2,
	sup3: sup3,
	sup: sup,
	Sup: Sup,
	supdot: supdot,
	supdsub: supdsub,
	supE: supE,
	supe: supe,
	supedot: supedot,
	Superset: Superset,
	SupersetEqual: SupersetEqual,
	suphsol: suphsol,
	suphsub: suphsub,
	suplarr: suplarr,
	supmult: supmult,
	supnE: supnE,
	supne: supne,
	supplus: supplus,
	supset: supset,
	Supset: Supset,
	supseteq: supseteq,
	supseteqq: supseteqq,
	supsetneq: supsetneq,
	supsetneqq: supsetneqq,
	supsim: supsim,
	supsub: supsub,
	supsup: supsup,
	swarhk: swarhk,
	swarr: swarr,
	swArr: swArr,
	swarrow: swarrow,
	swnwar: swnwar,
	szlig: szlig,
	Tab: Tab,
	target: target,
	Tau: Tau,
	tau: tau,
	tbrk: tbrk,
	Tcaron: Tcaron,
	tcaron: tcaron,
	Tcedil: Tcedil,
	tcedil: tcedil,
	Tcy: Tcy,
	tcy: tcy,
	tdot: tdot,
	telrec: telrec,
	Tfr: Tfr,
	tfr: tfr,
	there4: there4,
	therefore: therefore,
	Therefore: Therefore,
	Theta: Theta,
	theta: theta,
	thetasym: thetasym,
	thetav: thetav,
	thickapprox: thickapprox,
	thicksim: thicksim,
	ThickSpace: ThickSpace,
	ThinSpace: ThinSpace,
	thinsp: thinsp,
	thkap: thkap,
	thksim: thksim,
	THORN: THORN,
	thorn: thorn,
	tilde: tilde,
	Tilde: Tilde,
	TildeEqual: TildeEqual,
	TildeFullEqual: TildeFullEqual,
	TildeTilde: TildeTilde,
	timesbar: timesbar,
	timesb: timesb,
	times: times,
	timesd: timesd,
	tint: tint,
	toea: toea,
	topbot: topbot,
	topcir: topcir,
	top: top,
	Topf: Topf,
	topf: topf,
	topfork: topfork,
	tosa: tosa,
	tprime: tprime,
	trade: trade,
	TRADE: TRADE,
	triangle: triangle,
	triangledown: triangledown,
	triangleleft: triangleleft,
	trianglelefteq: trianglelefteq,
	triangleq: triangleq,
	triangleright: triangleright,
	trianglerighteq: trianglerighteq,
	tridot: tridot,
	trie: trie,
	triminus: triminus,
	TripleDot: TripleDot,
	triplus: triplus,
	trisb: trisb,
	tritime: tritime,
	trpezium: trpezium,
	Tscr: Tscr,
	tscr: tscr,
	TScy: TScy,
	tscy: tscy,
	TSHcy: TSHcy,
	tshcy: tshcy,
	Tstrok: Tstrok,
	tstrok: tstrok,
	twixt: twixt,
	twoheadleftarrow: twoheadleftarrow,
	twoheadrightarrow: twoheadrightarrow,
	Uacute: Uacute,
	uacute: uacute,
	uarr: uarr,
	Uarr: Uarr,
	uArr: uArr,
	Uarrocir: Uarrocir,
	Ubrcy: Ubrcy,
	ubrcy: ubrcy,
	Ubreve: Ubreve,
	ubreve: ubreve,
	Ucirc: Ucirc,
	ucirc: ucirc,
	Ucy: Ucy,
	ucy: ucy,
	udarr: udarr,
	Udblac: Udblac,
	udblac: udblac,
	udhar: udhar,
	ufisht: ufisht,
	Ufr: Ufr,
	ufr: ufr,
	Ugrave: Ugrave,
	ugrave: ugrave,
	uHar: uHar,
	uharl: uharl,
	uharr: uharr,
	uhblk: uhblk,
	ulcorn: ulcorn,
	ulcorner: ulcorner,
	ulcrop: ulcrop,
	ultri: ultri,
	Umacr: Umacr,
	umacr: umacr,
	uml: uml,
	UnderBar: UnderBar,
	UnderBrace: UnderBrace,
	UnderBracket: UnderBracket,
	UnderParenthesis: UnderParenthesis,
	Union: Union,
	UnionPlus: UnionPlus,
	Uogon: Uogon,
	uogon: uogon,
	Uopf: Uopf,
	uopf: uopf,
	UpArrowBar: UpArrowBar,
	uparrow: uparrow,
	UpArrow: UpArrow,
	Uparrow: Uparrow,
	UpArrowDownArrow: UpArrowDownArrow,
	updownarrow: updownarrow,
	UpDownArrow: UpDownArrow,
	Updownarrow: Updownarrow,
	UpEquilibrium: UpEquilibrium,
	upharpoonleft: upharpoonleft,
	upharpoonright: upharpoonright,
	uplus: uplus,
	UpperLeftArrow: UpperLeftArrow,
	UpperRightArrow: UpperRightArrow,
	upsi: upsi,
	Upsi: Upsi,
	upsih: upsih,
	Upsilon: Upsilon,
	upsilon: upsilon,
	UpTeeArrow: UpTeeArrow,
	UpTee: UpTee,
	upuparrows: upuparrows,
	urcorn: urcorn,
	urcorner: urcorner,
	urcrop: urcrop,
	Uring: Uring,
	uring: uring,
	urtri: urtri,
	Uscr: Uscr,
	uscr: uscr,
	utdot: utdot,
	Utilde: Utilde,
	utilde: utilde,
	utri: utri,
	utrif: utrif,
	uuarr: uuarr,
	Uuml: Uuml,
	uuml: uuml,
	uwangle: uwangle,
	vangrt: vangrt,
	varepsilon: varepsilon,
	varkappa: varkappa,
	varnothing: varnothing,
	varphi: varphi,
	varpi: varpi,
	varpropto: varpropto,
	varr: varr,
	vArr: vArr,
	varrho: varrho,
	varsigma: varsigma,
	varsubsetneq: varsubsetneq,
	varsubsetneqq: varsubsetneqq,
	varsupsetneq: varsupsetneq,
	varsupsetneqq: varsupsetneqq,
	vartheta: vartheta,
	vartriangleleft: vartriangleleft,
	vartriangleright: vartriangleright,
	vBar: vBar,
	Vbar: Vbar,
	vBarv: vBarv,
	Vcy: Vcy,
	vcy: vcy,
	vdash: vdash,
	vDash: vDash,
	Vdash: Vdash,
	VDash: VDash,
	Vdashl: Vdashl,
	veebar: veebar,
	vee: vee,
	Vee: Vee,
	veeeq: veeeq,
	vellip: vellip,
	verbar: verbar,
	Verbar: Verbar,
	vert: vert,
	Vert: Vert,
	VerticalBar: VerticalBar,
	VerticalLine: VerticalLine,
	VerticalSeparator: VerticalSeparator,
	VerticalTilde: VerticalTilde,
	VeryThinSpace: VeryThinSpace,
	Vfr: Vfr,
	vfr: vfr,
	vltri: vltri,
	vnsub: vnsub,
	vnsup: vnsup,
	Vopf: Vopf,
	vopf: vopf,
	vprop: vprop,
	vrtri: vrtri,
	Vscr: Vscr,
	vscr: vscr,
	vsubnE: vsubnE,
	vsubne: vsubne,
	vsupnE: vsupnE,
	vsupne: vsupne,
	Vvdash: Vvdash,
	vzigzag: vzigzag,
	Wcirc: Wcirc,
	wcirc: wcirc,
	wedbar: wedbar,
	wedge: wedge,
	Wedge: Wedge,
	wedgeq: wedgeq,
	weierp: weierp,
	Wfr: Wfr,
	wfr: wfr,
	Wopf: Wopf,
	wopf: wopf,
	wp: wp,
	wr: wr,
	wreath: wreath,
	Wscr: Wscr,
	wscr: wscr,
	xcap: xcap,
	xcirc: xcirc,
	xcup: xcup,
	xdtri: xdtri,
	Xfr: Xfr,
	xfr: xfr,
	xharr: xharr,
	xhArr: xhArr,
	Xi: Xi,
	xi: xi,
	xlarr: xlarr,
	xlArr: xlArr,
	xmap: xmap,
	xnis: xnis,
	xodot: xodot,
	Xopf: Xopf,
	xopf: xopf,
	xoplus: xoplus,
	xotime: xotime,
	xrarr: xrarr,
	xrArr: xrArr,
	Xscr: Xscr,
	xscr: xscr,
	xsqcup: xsqcup,
	xuplus: xuplus,
	xutri: xutri,
	xvee: xvee,
	xwedge: xwedge,
	Yacute: Yacute,
	yacute: yacute,
	YAcy: YAcy,
	yacy: yacy,
	Ycirc: Ycirc,
	ycirc: ycirc,
	Ycy: Ycy,
	ycy: ycy,
	yen: yen,
	Yfr: Yfr,
	yfr: yfr,
	YIcy: YIcy,
	yicy: yicy,
	Yopf: Yopf,
	yopf: yopf,
	Yscr: Yscr,
	yscr: yscr,
	YUcy: YUcy,
	yucy: yucy,
	yuml: yuml,
	Yuml: Yuml,
	Zacute: Zacute,
	zacute: zacute,
	Zcaron: Zcaron,
	zcaron: zcaron,
	Zcy: Zcy,
	zcy: zcy,
	Zdot: Zdot,
	zdot: zdot,
	zeetrf: zeetrf,
	ZeroWidthSpace: ZeroWidthSpace,
	Zeta: Zeta,
	zeta: zeta,
	zfr: zfr,
	Zfr: Zfr,
	ZHcy: ZHcy,
	zhcy: zhcy,
	zigrarr: zigrarr,
	zopf: zopf,
	Zopf: Zopf,
	Zscr: Zscr,
	zscr: zscr,
	zwj: zwj,
	zwnj: zwnj
};/*eslint quotes:0*/
var entities$1 = require$$0$1;var regex$4=/[!-#%-\*,-\/:;\?@\[-\]_\{\}\xA1\xA7\xAB\xB6\xB7\xBB\xBF\u037E\u0387\u055A-\u055F\u0589\u058A\u05BE\u05C0\u05C3\u05C6\u05F3\u05F4\u0609\u060A\u060C\u060D\u061B\u061E\u061F\u066A-\u066D\u06D4\u0700-\u070D\u07F7-\u07F9\u0830-\u083E\u085E\u0964\u0965\u0970\u09FD\u0A76\u0AF0\u0C84\u0DF4\u0E4F\u0E5A\u0E5B\u0F04-\u0F12\u0F14\u0F3A-\u0F3D\u0F85\u0FD0-\u0FD4\u0FD9\u0FDA\u104A-\u104F\u10FB\u1360-\u1368\u1400\u166D\u166E\u169B\u169C\u16EB-\u16ED\u1735\u1736\u17D4-\u17D6\u17D8-\u17DA\u1800-\u180A\u1944\u1945\u1A1E\u1A1F\u1AA0-\u1AA6\u1AA8-\u1AAD\u1B5A-\u1B60\u1BFC-\u1BFF\u1C3B-\u1C3F\u1C7E\u1C7F\u1CC0-\u1CC7\u1CD3\u2010-\u2027\u2030-\u2043\u2045-\u2051\u2053-\u205E\u207D\u207E\u208D\u208E\u2308-\u230B\u2329\u232A\u2768-\u2775\u27C5\u27C6\u27E6-\u27EF\u2983-\u2998\u29D8-\u29DB\u29FC\u29FD\u2CF9-\u2CFC\u2CFE\u2CFF\u2D70\u2E00-\u2E2E\u2E30-\u2E4E\u3001-\u3003\u3008-\u3011\u3014-\u301F\u3030\u303D\u30A0\u30FB\uA4FE\uA4FF\uA60D-\uA60F\uA673\uA67E\uA6F2-\uA6F7\uA874-\uA877\uA8CE\uA8CF\uA8F8-\uA8FA\uA8FC\uA92E\uA92F\uA95F\uA9C1-\uA9CD\uA9DE\uA9DF\uAA5C-\uAA5F\uAADE\uAADF\uAAF0\uAAF1\uABEB\uFD3E\uFD3F\uFE10-\uFE19\uFE30-\uFE52\uFE54-\uFE61\uFE63\uFE68\uFE6A\uFE6B\uFF01-\uFF03\uFF05-\uFF0A\uFF0C-\uFF0F\uFF1A\uFF1B\uFF1F\uFF20\uFF3B-\uFF3D\uFF3F\uFF5B\uFF5D\uFF5F-\uFF65]|\uD800[\uDD00-\uDD02\uDF9F\uDFD0]|\uD801\uDD6F|\uD802[\uDC57\uDD1F\uDD3F\uDE50-\uDE58\uDE7F\uDEF0-\uDEF6\uDF39-\uDF3F\uDF99-\uDF9C]|\uD803[\uDF55-\uDF59]|\uD804[\uDC47-\uDC4D\uDCBB\uDCBC\uDCBE-\uDCC1\uDD40-\uDD43\uDD74\uDD75\uDDC5-\uDDC8\uDDCD\uDDDB\uDDDD-\uDDDF\uDE38-\uDE3D\uDEA9]|\uD805[\uDC4B-\uDC4F\uDC5B\uDC5D\uDCC6\uDDC1-\uDDD7\uDE41-\uDE43\uDE60-\uDE6C\uDF3C-\uDF3E]|\uD806[\uDC3B\uDE3F-\uDE46\uDE9A-\uDE9C\uDE9E-\uDEA2]|\uD807[\uDC41-\uDC45\uDC70\uDC71\uDEF7\uDEF8]|\uD809[\uDC70-\uDC74]|\uD81A[\uDE6E\uDE6F\uDEF5\uDF37-\uDF3B\uDF44]|\uD81B[\uDE97-\uDE9A]|\uD82F\uDC9F|\uD836[\uDE87-\uDE8B]|\uD83A[\uDD5E\uDD5F]/;var mdurl$1 = {};var encodeCache = {};


// Create a lookup array where anything but characters in `chars` string
// and alphanumeric chars is percent-encoded.
//
function getEncodeCache(exclude) {
  var i, ch, cache = encodeCache[exclude];
  if (cache) { return cache; }

  cache = encodeCache[exclude] = [];

  for (i = 0; i < 128; i++) {
    ch = String.fromCharCode(i);

    if (/^[0-9a-z]$/i.test(ch)) {
      // always allow unencoded alphanumeric characters
      cache.push(ch);
    } else {
      cache.push('%' + ('0' + i.toString(16).toUpperCase()).slice(-2));
    }
  }

  for (i = 0; i < exclude.length; i++) {
    cache[exclude.charCodeAt(i)] = exclude[i];
  }

  return cache;
}


// Encode unsafe characters with percent-encoding, skipping already
// encoded sequences.
//
//  - string       - string to encode
//  - exclude      - list of characters to ignore (in addition to a-zA-Z0-9)
//  - keepEscaped  - don't encode '%' in a correct escape sequence (default: true)
//
function encode$1(string, exclude, keepEscaped) {
  var i, l, code, nextCode, cache,
      result = '';

  if (typeof exclude !== 'string') {
    // encode(string, keepEscaped)
    keepEscaped  = exclude;
    exclude = encode$1.defaultChars;
  }

  if (typeof keepEscaped === 'undefined') {
    keepEscaped = true;
  }

  cache = getEncodeCache(exclude);

  for (i = 0, l = string.length; i < l; i++) {
    code = string.charCodeAt(i);

    if (keepEscaped && code === 0x25 /* % */ && i + 2 < l) {
      if (/^[0-9a-f]{2}$/i.test(string.slice(i + 1, i + 3))) {
        result += string.slice(i, i + 3);
        i += 2;
        continue;
      }
    }

    if (code < 128) {
      result += cache[code];
      continue;
    }

    if (code >= 0xD800 && code <= 0xDFFF) {
      if (code >= 0xD800 && code <= 0xDBFF && i + 1 < l) {
        nextCode = string.charCodeAt(i + 1);
        if (nextCode >= 0xDC00 && nextCode <= 0xDFFF) {
          result += encodeURIComponent(string[i] + string[i + 1]);
          i++;
          continue;
        }
      }
      result += '%EF%BF%BD';
      continue;
    }

    result += encodeURIComponent(string[i]);
  }

  return result;
}

encode$1.defaultChars   = ";/?:@&=+$,-_.!~*'()#";
encode$1.componentChars = "-_.!~*'()";


var encode_1 = encode$1;/* eslint-disable no-bitwise */

var decodeCache = {};

function getDecodeCache(exclude) {
  var i, ch, cache = decodeCache[exclude];
  if (cache) { return cache; }

  cache = decodeCache[exclude] = [];

  for (i = 0; i < 128; i++) {
    ch = String.fromCharCode(i);
    cache.push(ch);
  }

  for (i = 0; i < exclude.length; i++) {
    ch = exclude.charCodeAt(i);
    cache[ch] = '%' + ('0' + ch.toString(16).toUpperCase()).slice(-2);
  }

  return cache;
}


// Decode percent-encoded string.
//
function decode$1(string, exclude) {
  var cache;

  if (typeof exclude !== 'string') {
    exclude = decode$1.defaultChars;
  }

  cache = getDecodeCache(exclude);

  return string.replace(/(%[a-f0-9]{2})+/gi, function(seq) {
    var i, l, b1, b2, b3, b4, chr,
        result = '';

    for (i = 0, l = seq.length; i < l; i += 3) {
      b1 = parseInt(seq.slice(i + 1, i + 3), 16);

      if (b1 < 0x80) {
        result += cache[b1];
        continue;
      }

      if ((b1 & 0xE0) === 0xC0 && (i + 3 < l)) {
        // 110xxxxx 10xxxxxx
        b2 = parseInt(seq.slice(i + 4, i + 6), 16);

        if ((b2 & 0xC0) === 0x80) {
          chr = ((b1 << 6) & 0x7C0) | (b2 & 0x3F);

          if (chr < 0x80) {
            result += '\ufffd\ufffd';
          } else {
            result += String.fromCharCode(chr);
          }

          i += 3;
          continue;
        }
      }

      if ((b1 & 0xF0) === 0xE0 && (i + 6 < l)) {
        // 1110xxxx 10xxxxxx 10xxxxxx
        b2 = parseInt(seq.slice(i + 4, i + 6), 16);
        b3 = parseInt(seq.slice(i + 7, i + 9), 16);

        if ((b2 & 0xC0) === 0x80 && (b3 & 0xC0) === 0x80) {
          chr = ((b1 << 12) & 0xF000) | ((b2 << 6) & 0xFC0) | (b3 & 0x3F);

          if (chr < 0x800 || (chr >= 0xD800 && chr <= 0xDFFF)) {
            result += '\ufffd\ufffd\ufffd';
          } else {
            result += String.fromCharCode(chr);
          }

          i += 6;
          continue;
        }
      }

      if ((b1 & 0xF8) === 0xF0 && (i + 9 < l)) {
        // 111110xx 10xxxxxx 10xxxxxx 10xxxxxx
        b2 = parseInt(seq.slice(i + 4, i + 6), 16);
        b3 = parseInt(seq.slice(i + 7, i + 9), 16);
        b4 = parseInt(seq.slice(i + 10, i + 12), 16);

        if ((b2 & 0xC0) === 0x80 && (b3 & 0xC0) === 0x80 && (b4 & 0xC0) === 0x80) {
          chr = ((b1 << 18) & 0x1C0000) | ((b2 << 12) & 0x3F000) | ((b3 << 6) & 0xFC0) | (b4 & 0x3F);

          if (chr < 0x10000 || chr > 0x10FFFF) {
            result += '\ufffd\ufffd\ufffd\ufffd';
          } else {
            chr -= 0x10000;
            result += String.fromCharCode(0xD800 + (chr >> 10), 0xDC00 + (chr & 0x3FF));
          }

          i += 9;
          continue;
        }
      }

      result += '\ufffd';
    }

    return result;
  });
}


decode$1.defaultChars   = ';/?:@&=+$,#';
decode$1.componentChars = '';


var decode_1 = decode$1;var format = function format(url) {
  var result = '';

  result += url.protocol || '';
  result += url.slashes ? '//' : '';
  result += url.auth ? url.auth + '@' : '';

  if (url.hostname && url.hostname.indexOf(':') !== -1) {
    // ipv6 address
    result += '[' + url.hostname + ']';
  } else {
    result += url.hostname || '';
  }

  result += url.port ? ':' + url.port : '';
  result += url.pathname || '';
  result += url.search || '';
  result += url.hash || '';

  return result;
};//
// Changes from joyent/node:
//
// 1. No leading slash in paths,
//    e.g. in `url.parse('http://foo?bar')` pathname is ``, not `/`
//
// 2. Backslashes are not replaced with slashes,
//    so `http:\\example.org\` is treated like a relative path
//
// 3. Trailing colon is treated like a part of the path,
//    i.e. in `http://example.org:foo` pathname is `:foo`
//
// 4. Nothing is URL-encoded in the resulting object,
//    (in joyent/node some chars in auth and paths are encoded)
//
// 5. `url.parse()` does not have `parseQueryString` argument
//
// 6. Removed extraneous result properties: `host`, `path`, `query`, etc.,
//    which can be constructed using other parts of the url.
//


function Url() {
  this.protocol = null;
  this.slashes = null;
  this.auth = null;
  this.port = null;
  this.hostname = null;
  this.hash = null;
  this.search = null;
  this.pathname = null;
}

// Reference: RFC 3986, RFC 1808, RFC 2396

// define these here so at least they only have to be
// compiled once on the first module load.
var protocolPattern = /^([a-z0-9.+-]+:)/i,
    portPattern = /:[0-9]*$/,

    // Special case for a simple path URL
    simplePathPattern = /^(\/\/?(?!\/)[^\?\s]*)(\?[^\s]*)?$/,

    // RFC 2396: characters reserved for delimiting URLs.
    // We actually just auto-escape these.
    delims = [ '<', '>', '"', '`', ' ', '\r', '\n', '\t' ],

    // RFC 2396: characters not allowed for various reasons.
    unwise = [ '{', '}', '|', '\\', '^', '`' ].concat(delims),

    // Allowed by RFCs, but cause of XSS attacks.  Always escape these.
    autoEscape = [ '\'' ].concat(unwise),
    // Characters that are never ever allowed in a hostname.
    // Note that any invalid chars are also handled, but these
    // are the ones that are *expected* to be seen, so we fast-path
    // them.
    nonHostChars = [ '%', '/', '?', ';', '#' ].concat(autoEscape),
    hostEndingChars = [ '/', '?', '#' ],
    hostnameMaxLen = 255,
    hostnamePartPattern = /^[+a-z0-9A-Z_-]{0,63}$/,
    hostnamePartStart = /^([+a-z0-9A-Z_-]{0,63})(.*)$/,
    // protocols that can allow "unsafe" and "unwise" chars.
    /* eslint-disable no-script-url */
    // protocols that never have a hostname.
    hostlessProtocol = {
      'javascript': true,
      'javascript:': true
    },
    // protocols that always contain a // bit.
    slashedProtocol = {
      'http': true,
      'https': true,
      'ftp': true,
      'gopher': true,
      'file': true,
      'http:': true,
      'https:': true,
      'ftp:': true,
      'gopher:': true,
      'file:': true
    };
    /* eslint-enable no-script-url */

function urlParse(url, slashesDenoteHost) {
  if (url && url instanceof Url) { return url; }

  var u = new Url();
  u.parse(url, slashesDenoteHost);
  return u;
}

Url.prototype.parse = function(url, slashesDenoteHost) {
  var i, l, lowerProto, hec, slashes,
      rest = url;

  // trim before proceeding.
  // This is to support parse stuff like "  http://foo.com  \n"
  rest = rest.trim();

  if (!slashesDenoteHost && url.split('#').length === 1) {
    // Try fast path regexp
    var simplePath = simplePathPattern.exec(rest);
    if (simplePath) {
      this.pathname = simplePath[1];
      if (simplePath[2]) {
        this.search = simplePath[2];
      }
      return this;
    }
  }

  var proto = protocolPattern.exec(rest);
  if (proto) {
    proto = proto[0];
    lowerProto = proto.toLowerCase();
    this.protocol = proto;
    rest = rest.substr(proto.length);
  }

  // figure out if it's got a host
  // user@server is *always* interpreted as a hostname, and url
  // resolution will treat //foo/bar as host=foo,path=bar because that's
  // how the browser resolves relative URLs.
  if (slashesDenoteHost || proto || rest.match(/^\/\/[^@\/]+@[^@\/]+/)) {
    slashes = rest.substr(0, 2) === '//';
    if (slashes && !(proto && hostlessProtocol[proto])) {
      rest = rest.substr(2);
      this.slashes = true;
    }
  }

  if (!hostlessProtocol[proto] &&
      (slashes || (proto && !slashedProtocol[proto]))) {

    // there's a hostname.
    // the first instance of /, ?, ;, or # ends the host.
    //
    // If there is an @ in the hostname, then non-host chars *are* allowed
    // to the left of the last @ sign, unless some host-ending character
    // comes *before* the @-sign.
    // URLs are obnoxious.
    //
    // ex:
    // http://a@b@c/ => user:a@b host:c
    // http://a@b?@c => user:a host:c path:/?@c

    // v0.12 TODO(isaacs): This is not quite how Chrome does things.
    // Review our test case against browsers more comprehensively.

    // find the first instance of any hostEndingChars
    var hostEnd = -1;
    for (i = 0; i < hostEndingChars.length; i++) {
      hec = rest.indexOf(hostEndingChars[i]);
      if (hec !== -1 && (hostEnd === -1 || hec < hostEnd)) {
        hostEnd = hec;
      }
    }

    // at this point, either we have an explicit point where the
    // auth portion cannot go past, or the last @ char is the decider.
    var auth, atSign;
    if (hostEnd === -1) {
      // atSign can be anywhere.
      atSign = rest.lastIndexOf('@');
    } else {
      // atSign must be in auth portion.
      // http://a@b/c@d => host:b auth:a path:/c@d
      atSign = rest.lastIndexOf('@', hostEnd);
    }

    // Now we have a portion which is definitely the auth.
    // Pull that off.
    if (atSign !== -1) {
      auth = rest.slice(0, atSign);
      rest = rest.slice(atSign + 1);
      this.auth = auth;
    }

    // the host is the remaining to the left of the first non-host char
    hostEnd = -1;
    for (i = 0; i < nonHostChars.length; i++) {
      hec = rest.indexOf(nonHostChars[i]);
      if (hec !== -1 && (hostEnd === -1 || hec < hostEnd)) {
        hostEnd = hec;
      }
    }
    // if we still have not hit it, then the entire thing is a host.
    if (hostEnd === -1) {
      hostEnd = rest.length;
    }

    if (rest[hostEnd - 1] === ':') { hostEnd--; }
    var host = rest.slice(0, hostEnd);
    rest = rest.slice(hostEnd);

    // pull out port.
    this.parseHost(host);

    // we've indicated that there is a hostname,
    // so even if it's empty, it has to be present.
    this.hostname = this.hostname || '';

    // if hostname begins with [ and ends with ]
    // assume that it's an IPv6 address.
    var ipv6Hostname = this.hostname[0] === '[' &&
        this.hostname[this.hostname.length - 1] === ']';

    // validate a little.
    if (!ipv6Hostname) {
      var hostparts = this.hostname.split(/\./);
      for (i = 0, l = hostparts.length; i < l; i++) {
        var part = hostparts[i];
        if (!part) { continue; }
        if (!part.match(hostnamePartPattern)) {
          var newpart = '';
          for (var j = 0, k = part.length; j < k; j++) {
            if (part.charCodeAt(j) > 127) {
              // we replace non-ASCII char with a temporary placeholder
              // we need this to make sure size of hostname is not
              // broken by replacing non-ASCII by nothing
              newpart += 'x';
            } else {
              newpart += part[j];
            }
          }
          // we test again with ASCII char only
          if (!newpart.match(hostnamePartPattern)) {
            var validParts = hostparts.slice(0, i);
            var notHost = hostparts.slice(i + 1);
            var bit = part.match(hostnamePartStart);
            if (bit) {
              validParts.push(bit[1]);
              notHost.unshift(bit[2]);
            }
            if (notHost.length) {
              rest = notHost.join('.') + rest;
            }
            this.hostname = validParts.join('.');
            break;
          }
        }
      }
    }

    if (this.hostname.length > hostnameMaxLen) {
      this.hostname = '';
    }

    // strip [ and ] from the hostname
    // the host field still retains them, though
    if (ipv6Hostname) {
      this.hostname = this.hostname.substr(1, this.hostname.length - 2);
    }
  }

  // chop off from the tail first.
  var hash = rest.indexOf('#');
  if (hash !== -1) {
    // got a fragment string.
    this.hash = rest.substr(hash);
    rest = rest.slice(0, hash);
  }
  var qm = rest.indexOf('?');
  if (qm !== -1) {
    this.search = rest.substr(qm);
    rest = rest.slice(0, qm);
  }
  if (rest) { this.pathname = rest; }
  if (slashedProtocol[lowerProto] &&
      this.hostname && !this.pathname) {
    this.pathname = '';
  }

  return this;
};

Url.prototype.parseHost = function(host) {
  var port = portPattern.exec(host);
  if (port) {
    port = port[0];
    if (port !== ':') {
      this.port = port.substr(1);
    }
    host = host.substr(0, host.length - port.length);
  }
  if (host) { this.hostname = host; }
};

var parse = urlParse;mdurl$1.encode = encode_1;
mdurl$1.decode = decode_1;
mdurl$1.format = format;
mdurl$1.parse  = parse;var uc_micro = {};var regex$3;
var hasRequiredRegex$3;

function requireRegex$3 () {
	if (hasRequiredRegex$3) { return regex$3; }
	hasRequiredRegex$3 = 1;
	regex$3=/[\0-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]/;
	return regex$3;
}var regex$2;
var hasRequiredRegex$2;

function requireRegex$2 () {
	if (hasRequiredRegex$2) { return regex$2; }
	hasRequiredRegex$2 = 1;
	regex$2=/[\0-\x1F\x7F-\x9F]/;
	return regex$2;
}var regex$1;
var hasRequiredRegex$1;

function requireRegex$1 () {
	if (hasRequiredRegex$1) { return regex$1; }
	hasRequiredRegex$1 = 1;
	regex$1=/[\xAD\u0600-\u0605\u061C\u06DD\u070F\u08E2\u180E\u200B-\u200F\u202A-\u202E\u2060-\u2064\u2066-\u206F\uFEFF\uFFF9-\uFFFB]|\uD804[\uDCBD\uDCCD]|\uD82F[\uDCA0-\uDCA3]|\uD834[\uDD73-\uDD7A]|\uDB40[\uDC01\uDC20-\uDC7F]/;
	return regex$1;
}var regex;
var hasRequiredRegex;

function requireRegex () {
	if (hasRequiredRegex) { return regex; }
	hasRequiredRegex = 1;
	regex=/[ \xA0\u1680\u2000-\u200A\u2028\u2029\u202F\u205F\u3000]/;
	return regex;
}var hasRequiredUc_micro;

function requireUc_micro () {
	if (hasRequiredUc_micro) { return uc_micro; }
	hasRequiredUc_micro = 1;

	uc_micro.Any = requireRegex$3();
	uc_micro.Cc  = requireRegex$2();
	uc_micro.Cf  = requireRegex$1();
	uc_micro.P   = regex$4;
	uc_micro.Z   = requireRegex();
	return uc_micro;
}(function (exports) {


	function _class(obj) { return Object.prototype.toString.call(obj); }

	function isString(obj) { return _class(obj) === '[object String]'; }

	var _hasOwnProperty = Object.prototype.hasOwnProperty;

	function has(object, key) {
	  return _hasOwnProperty.call(object, key);
	}

	// Merge objects
	//
	function assign(obj /*from1, from2, from3, ...*/) {
	  var sources = Array.prototype.slice.call(arguments, 1);

	  sources.forEach(function (source) {
	    if (!source) { return; }

	    if (typeof source !== 'object') {
	      throw new TypeError(source + 'must be object');
	    }

	    Object.keys(source).forEach(function (key) {
	      obj[key] = source[key];
	    });
	  });

	  return obj;
	}

	// Remove element from array and put another array at those position.
	// Useful for some operations with tokens
	function arrayReplaceAt(src, pos, newElements) {
	  return [].concat(src.slice(0, pos), newElements, src.slice(pos + 1));
	}

	////////////////////////////////////////////////////////////////////////////////

	function isValidEntityCode(c) {
	  /*eslint no-bitwise:0*/
	  // broken sequence
	  if (c >= 0xD800 && c <= 0xDFFF) { return false; }
	  // never used
	  if (c >= 0xFDD0 && c <= 0xFDEF) { return false; }
	  if ((c & 0xFFFF) === 0xFFFF || (c & 0xFFFF) === 0xFFFE) { return false; }
	  // control codes
	  if (c >= 0x00 && c <= 0x08) { return false; }
	  if (c === 0x0B) { return false; }
	  if (c >= 0x0E && c <= 0x1F) { return false; }
	  if (c >= 0x7F && c <= 0x9F) { return false; }
	  // out of range
	  if (c > 0x10FFFF) { return false; }
	  return true;
	}

	function fromCodePoint(c) {
	  /*eslint no-bitwise:0*/
	  if (c > 0xffff) {
	    c -= 0x10000;
	    var surrogate1 = 0xd800 + (c >> 10),
	        surrogate2 = 0xdc00 + (c & 0x3ff);

	    return String.fromCharCode(surrogate1, surrogate2);
	  }
	  return String.fromCharCode(c);
	}


	var UNESCAPE_MD_RE  = /\\([!"#$%&'()*+,\-.\/:;<=>?@[\\\]^_`{|}~])/g;
	var ENTITY_RE       = /&([a-z#][a-z0-9]{1,31});/gi;
	var UNESCAPE_ALL_RE = new RegExp(UNESCAPE_MD_RE.source + '|' + ENTITY_RE.source, 'gi');

	var DIGITAL_ENTITY_TEST_RE = /^#((?:x[a-f0-9]{1,8}|[0-9]{1,8}))$/i;

	var entities = entities$1;

	function replaceEntityPattern(match, name) {
	  var code;

	  if (has(entities, name)) {
	    return entities[name];
	  }

	  if (name.charCodeAt(0) === 0x23/* # */ && DIGITAL_ENTITY_TEST_RE.test(name)) {
	    code = name[1].toLowerCase() === 'x' ?
	      parseInt(name.slice(2), 16) : parseInt(name.slice(1), 10);

	    if (isValidEntityCode(code)) {
	      return fromCodePoint(code);
	    }
	  }

	  return match;
	}

	/*function replaceEntities(str) {
	  if (str.indexOf('&') < 0) { return str; }

	  return str.replace(ENTITY_RE, replaceEntityPattern);
	}*/

	function unescapeMd(str) {
	  if (str.indexOf('\\') < 0) { return str; }
	  return str.replace(UNESCAPE_MD_RE, '$1');
	}

	function unescapeAll(str) {
	  if (str.indexOf('\\') < 0 && str.indexOf('&') < 0) { return str; }

	  return str.replace(UNESCAPE_ALL_RE, function (match, escaped, entity) {
	    if (escaped) { return escaped; }
	    return replaceEntityPattern(match, entity);
	  });
	}

	////////////////////////////////////////////////////////////////////////////////

	var HTML_ESCAPE_TEST_RE = /[&<>"]/;
	var HTML_ESCAPE_REPLACE_RE = /[&<>"]/g;
	var HTML_REPLACEMENTS = {
	  '&': '&amp;',
	  '<': '&lt;',
	  '>': '&gt;',
	  '"': '&quot;'
	};

	function replaceUnsafeChar(ch) {
	  return HTML_REPLACEMENTS[ch];
	}

	function escapeHtml(str) {
	  if (HTML_ESCAPE_TEST_RE.test(str)) {
	    return str.replace(HTML_ESCAPE_REPLACE_RE, replaceUnsafeChar);
	  }
	  return str;
	}

	////////////////////////////////////////////////////////////////////////////////

	var REGEXP_ESCAPE_RE = /[.?*+^$[\]\\(){}|-]/g;

	function escapeRE(str) {
	  return str.replace(REGEXP_ESCAPE_RE, '\\$&');
	}

	////////////////////////////////////////////////////////////////////////////////

	function isSpace(code) {
	  switch (code) {
	    case 0x09:
	    case 0x20:
	      return true;
	  }
	  return false;
	}

	// Zs (unicode class) || [\t\f\v\r\n]
	function isWhiteSpace(code) {
	  if (code >= 0x2000 && code <= 0x200A) { return true; }
	  switch (code) {
	    case 0x09: // \t
	    case 0x0A: // \n
	    case 0x0B: // \v
	    case 0x0C: // \f
	    case 0x0D: // \r
	    case 0x20:
	    case 0xA0:
	    case 0x1680:
	    case 0x202F:
	    case 0x205F:
	    case 0x3000:
	      return true;
	  }
	  return false;
	}

	////////////////////////////////////////////////////////////////////////////////

	/*eslint-disable max-len*/
	var UNICODE_PUNCT_RE = regex$4;

	// Currently without astral characters support.
	function isPunctChar(ch) {
	  return UNICODE_PUNCT_RE.test(ch);
	}


	// Markdown ASCII punctuation characters.
	//
	// !, ", #, $, %, &, ', (, ), *, +, ,, -, ., /, :, ;, <, =, >, ?, @, [, \, ], ^, _, `, {, |, }, or ~
	// http://spec.commonmark.org/0.15/#ascii-punctuation-character
	//
	// Don't confuse with unicode punctuation !!! It lacks some chars in ascii range.
	//
	function isMdAsciiPunct(ch) {
	  switch (ch) {
	    case 0x21/* ! */:
	    case 0x22/* " */:
	    case 0x23/* # */:
	    case 0x24/* $ */:
	    case 0x25/* % */:
	    case 0x26/* & */:
	    case 0x27/* ' */:
	    case 0x28/* ( */:
	    case 0x29/* ) */:
	    case 0x2A/* * */:
	    case 0x2B/* + */:
	    case 0x2C/* , */:
	    case 0x2D/* - */:
	    case 0x2E/* . */:
	    case 0x2F/* / */:
	    case 0x3A/* : */:
	    case 0x3B/* ; */:
	    case 0x3C/* < */:
	    case 0x3D/* = */:
	    case 0x3E/* > */:
	    case 0x3F/* ? */:
	    case 0x40/* @ */:
	    case 0x5B/* [ */:
	    case 0x5C/* \ */:
	    case 0x5D/* ] */:
	    case 0x5E/* ^ */:
	    case 0x5F/* _ */:
	    case 0x60/* ` */:
	    case 0x7B/* { */:
	    case 0x7C/* | */:
	    case 0x7D/* } */:
	    case 0x7E/* ~ */:
	      return true;
	    default:
	      return false;
	  }
	}

	// Hepler to unify [reference labels].
	//
	function normalizeReference(str) {
	  // Trim and collapse whitespace
	  //
	  str = str.trim().replace(/\s+/g, ' ');

	  // In node v10 'ẞ'.toLowerCase() === 'Ṿ', which is presumed to be a bug
	  // fixed in v12 (couldn't find any details).
	  //
	  // So treat this one as a special case
	  // (remove this when node v10 is no longer supported).
	  //
	  if ('ẞ'.toLowerCase() === 'Ṿ') {
	    str = str.replace(/ẞ/g, 'ß');
	  }

	  // .toLowerCase().toUpperCase() should get rid of all differences
	  // between letter variants.
	  //
	  // Simple .toLowerCase() doesn't normalize 125 code points correctly,
	  // and .toUpperCase doesn't normalize 6 of them (list of exceptions:
	  // İ, ϴ, ẞ, Ω, K, Å - those are already uppercased, but have differently
	  // uppercased versions).
	  //
	  // Here's an example showing how it happens. Lets take greek letter omega:
	  // uppercase U+0398 (Θ), U+03f4 (ϴ) and lowercase U+03b8 (θ), U+03d1 (ϑ)
	  //
	  // Unicode entries:
	  // 0398;GREEK CAPITAL LETTER THETA;Lu;0;L;;;;;N;;;;03B8;
	  // 03B8;GREEK SMALL LETTER THETA;Ll;0;L;;;;;N;;;0398;;0398
	  // 03D1;GREEK THETA SYMBOL;Ll;0;L;<compat> 03B8;;;;N;GREEK SMALL LETTER SCRIPT THETA;;0398;;0398
	  // 03F4;GREEK CAPITAL THETA SYMBOL;Lu;0;L;<compat> 0398;;;;N;;;;03B8;
	  //
	  // Case-insensitive comparison should treat all of them as equivalent.
	  //
	  // But .toLowerCase() doesn't change ϑ (it's already lowercase),
	  // and .toUpperCase() doesn't change ϴ (already uppercase).
	  //
	  // Applying first lower then upper case normalizes any character:
	  // '\u0398\u03f4\u03b8\u03d1'.toLowerCase().toUpperCase() === '\u0398\u0398\u0398\u0398'
	  //
	  // Note: this is equivalent to unicode case folding; unicode normalization
	  // is a different step that is not required here.
	  //
	  // Final result should be uppercased, because it's later stored in an object
	  // (this avoid a conflict with Object.prototype members,
	  // most notably, `__proto__`)
	  //
	  return str.toLowerCase().toUpperCase();
	}

	////////////////////////////////////////////////////////////////////////////////

	// Re-export libraries commonly used in both markdown-it and its plugins,
	// so plugins won't have to depend on them explicitly, which reduces their
	// bundled size (e.g. a browser build).
	//
	exports.lib                 = {};
	exports.lib.mdurl           = mdurl$1;
	exports.lib.ucmicro         = requireUc_micro();

	exports.assign              = assign;
	exports.isString            = isString;
	exports.has                 = has;
	exports.unescapeMd          = unescapeMd;
	exports.unescapeAll         = unescapeAll;
	exports.isValidEntityCode   = isValidEntityCode;
	exports.fromCodePoint       = fromCodePoint;
	// exports.replaceEntities     = replaceEntities;
	exports.escapeHtml          = escapeHtml;
	exports.arrayReplaceAt      = arrayReplaceAt;
	exports.isSpace             = isSpace;
	exports.isWhiteSpace        = isWhiteSpace;
	exports.isMdAsciiPunct      = isMdAsciiPunct;
	exports.isPunctChar         = isPunctChar;
	exports.escapeRE            = escapeRE;
	exports.normalizeReference  = normalizeReference; 
} (utils$1));var helpers$1 = {};var parse_link_label = function parseLinkLabel(state, start, disableNested) {
  var level, found, marker, prevPos,
      labelEnd = -1,
      max = state.posMax,
      oldPos = state.pos;

  state.pos = start + 1;
  level = 1;

  while (state.pos < max) {
    marker = state.src.charCodeAt(state.pos);
    if (marker === 0x5D /* ] */) {
      level--;
      if (level === 0) {
        found = true;
        break;
      }
    }

    prevPos = state.pos;
    state.md.inline.skipToken(state);
    if (marker === 0x5B /* [ */) {
      if (prevPos === state.pos - 1) {
        // increase level if we find text `[`, which is not a part of any token
        level++;
      } else if (disableNested) {
        state.pos = oldPos;
        return -1;
      }
    }
  }

  if (found) {
    labelEnd = state.pos;
  }

  // restore old state
  state.pos = oldPos;

  return labelEnd;
};var unescapeAll$2 = utils$1.unescapeAll;


var parse_link_destination = function parseLinkDestination(str, start, max) {
  var code, level,
      pos = start,
      result = {
        ok: false,
        pos: 0,
        lines: 0,
        str: ''
      };

  if (str.charCodeAt(pos) === 0x3C /* < */) {
    pos++;
    while (pos < max) {
      code = str.charCodeAt(pos);
      if (code === 0x0A /* \n */) { return result; }
      if (code === 0x3C /* < */) { return result; }
      if (code === 0x3E /* > */) {
        result.pos = pos + 1;
        result.str = unescapeAll$2(str.slice(start + 1, pos));
        result.ok = true;
        return result;
      }
      if (code === 0x5C /* \ */ && pos + 1 < max) {
        pos += 2;
        continue;
      }

      pos++;
    }

    // no closing '>'
    return result;
  }

  // this should be ... } else { ... branch

  level = 0;
  while (pos < max) {
    code = str.charCodeAt(pos);

    if (code === 0x20) { break; }

    // ascii control characters
    if (code < 0x20 || code === 0x7F) { break; }

    if (code === 0x5C /* \ */ && pos + 1 < max) {
      if (str.charCodeAt(pos + 1) === 0x20) { break; }
      pos += 2;
      continue;
    }

    if (code === 0x28 /* ( */) {
      level++;
      if (level > 32) { return result; }
    }

    if (code === 0x29 /* ) */) {
      if (level === 0) { break; }
      level--;
    }

    pos++;
  }

  if (start === pos) { return result; }
  if (level !== 0) { return result; }

  result.str = unescapeAll$2(str.slice(start, pos));
  result.pos = pos;
  result.ok = true;
  return result;
};var unescapeAll$1 = utils$1.unescapeAll;


var parse_link_title = function parseLinkTitle(str, start, max) {
  var code,
      marker,
      lines = 0,
      pos = start,
      result = {
        ok: false,
        pos: 0,
        lines: 0,
        str: ''
      };

  if (pos >= max) { return result; }

  marker = str.charCodeAt(pos);

  if (marker !== 0x22 /* " */ && marker !== 0x27 /* ' */ && marker !== 0x28 /* ( */) { return result; }

  pos++;

  // if opening marker is "(", switch it to closing marker ")"
  if (marker === 0x28) { marker = 0x29; }

  while (pos < max) {
    code = str.charCodeAt(pos);
    if (code === marker) {
      result.pos = pos + 1;
      result.lines = lines;
      result.str = unescapeAll$1(str.slice(start + 1, pos));
      result.ok = true;
      return result;
    } else if (code === 0x28 /* ( */ && marker === 0x29 /* ) */) {
      return result;
    } else if (code === 0x0A) {
      lines++;
    } else if (code === 0x5C /* \ */ && pos + 1 < max) {
      pos++;
      if (str.charCodeAt(pos) === 0x0A) {
        lines++;
      }
    }

    pos++;
  }

  return result;
};helpers$1.parseLinkLabel       = parse_link_label;
helpers$1.parseLinkDestination = parse_link_destination;
helpers$1.parseLinkTitle       = parse_link_title;/**
 * class Renderer
 *
 * Generates HTML from parsed token stream. Each instance has independent
 * copy of rules. Those can be rewritten with ease. Also, you can add new
 * rules if you create plugin and adds new token types.
 **/


var assign$1          = utils$1.assign;
var unescapeAll     = utils$1.unescapeAll;
var escapeHtml      = utils$1.escapeHtml;


////////////////////////////////////////////////////////////////////////////////

var default_rules = {};


default_rules.code_inline = function (tokens, idx, options, env, slf) {
  var token = tokens[idx];

  return  '<code' + slf.renderAttrs(token) + '>' +
          escapeHtml(token.content) +
          '</code>';
};


default_rules.code_block = function (tokens, idx, options, env, slf) {
  var token = tokens[idx];

  return  '<pre' + slf.renderAttrs(token) + '><code>' +
          escapeHtml(tokens[idx].content) +
          '</code></pre>\n';
};


default_rules.fence = function (tokens, idx, options, env, slf) {
  var token = tokens[idx],
      info = token.info ? unescapeAll(token.info).trim() : '',
      langName = '',
      langAttrs = '',
      highlighted, i, arr, tmpAttrs, tmpToken;

  if (info) {
    arr = info.split(/(\s+)/g);
    langName = arr[0];
    langAttrs = arr.slice(2).join('');
  }

  if (options.highlight) {
    highlighted = options.highlight(token.content, langName, langAttrs) || escapeHtml(token.content);
  } else {
    highlighted = escapeHtml(token.content);
  }

  if (highlighted.indexOf('<pre') === 0) {
    return highlighted + '\n';
  }

  // If language exists, inject class gently, without modifying original token.
  // May be, one day we will add .deepClone() for token and simplify this part, but
  // now we prefer to keep things local.
  if (info) {
    i        = token.attrIndex('class');
    tmpAttrs = token.attrs ? token.attrs.slice() : [];

    if (i < 0) {
      tmpAttrs.push([ 'class', options.langPrefix + langName ]);
    } else {
      tmpAttrs[i] = tmpAttrs[i].slice();
      tmpAttrs[i][1] += ' ' + options.langPrefix + langName;
    }

    // Fake token just to render attributes
    tmpToken = {
      attrs: tmpAttrs
    };

    return  '<pre><code' + slf.renderAttrs(tmpToken) + '>'
          + highlighted
          + '</code></pre>\n';
  }


  return  '<pre><code' + slf.renderAttrs(token) + '>'
        + highlighted
        + '</code></pre>\n';
};


default_rules.image = function (tokens, idx, options, env, slf) {
  var token = tokens[idx];

  // "alt" attr MUST be set, even if empty. Because it's mandatory and
  // should be placed on proper position for tests.
  //
  // Replace content with actual value

  token.attrs[token.attrIndex('alt')][1] =
    slf.renderInlineAsText(token.children, options, env);

  return slf.renderToken(tokens, idx, options);
};


default_rules.hardbreak = function (tokens, idx, options /*, env */) {
  return options.xhtmlOut ? '<br />\n' : '<br>\n';
};
default_rules.softbreak = function (tokens, idx, options /*, env */) {
  return options.breaks ? (options.xhtmlOut ? '<br />\n' : '<br>\n') : '\n';
};


default_rules.text = function (tokens, idx /*, options, env */) {
  return escapeHtml(tokens[idx].content);
};


default_rules.html_block = function (tokens, idx /*, options, env */) {
  return tokens[idx].content;
};
default_rules.html_inline = function (tokens, idx /*, options, env */) {
  return tokens[idx].content;
};


/**
 * new Renderer()
 *
 * Creates new [[Renderer]] instance and fill [[Renderer#rules]] with defaults.
 **/
function Renderer$1() {

  /**
   * Renderer#rules -> Object
   *
   * Contains render rules for tokens. Can be updated and extended.
   *
   * ##### Example
   *
   * ```javascript
   * var md = require('markdown-it')();
   *
   * md.renderer.rules.strong_open  = function () { return '<b>'; };
   * md.renderer.rules.strong_close = function () { return '</b>'; };
   *
   * var result = md.renderInline(...);
   * ```
   *
   * Each rule is called as independent static function with fixed signature:
   *
   * ```javascript
   * function my_token_render(tokens, idx, options, env, renderer) {
   *   // ...
   *   return renderedHTML;
   * }
   * ```
   *
   * See [source code](https://github.com/markdown-it/markdown-it/blob/master/lib/renderer.js)
   * for more details and examples.
   **/
  this.rules = assign$1({}, default_rules);
}


/**
 * Renderer.renderAttrs(token) -> String
 *
 * Render token attributes to string.
 **/
Renderer$1.prototype.renderAttrs = function renderAttrs(token) {
  var i, l, result;

  if (!token.attrs) { return ''; }

  result = '';

  for (i = 0, l = token.attrs.length; i < l; i++) {
    result += ' ' + escapeHtml(token.attrs[i][0]) + '="' + escapeHtml(token.attrs[i][1]) + '"';
  }

  return result;
};


/**
 * Renderer.renderToken(tokens, idx, options) -> String
 * - tokens (Array): list of tokens
 * - idx (Numbed): token index to render
 * - options (Object): params of parser instance
 *
 * Default token renderer. Can be overriden by custom function
 * in [[Renderer#rules]].
 **/
Renderer$1.prototype.renderToken = function renderToken(tokens, idx, options) {
  var nextToken,
      result = '',
      needLf = false,
      token = tokens[idx];

  // Tight list paragraphs
  if (token.hidden) {
    return '';
  }

  // Insert a newline between hidden paragraph and subsequent opening
  // block-level tag.
  //
  // For example, here we should insert a newline before blockquote:
  //  - a
  //    >
  //
  if (token.block && token.nesting !== -1 && idx && tokens[idx - 1].hidden) {
    result += '\n';
  }

  // Add token name, e.g. `<img`
  result += (token.nesting === -1 ? '</' : '<') + token.tag;

  // Encode attributes, e.g. `<img src="foo"`
  result += this.renderAttrs(token);

  // Add a slash for self-closing tags, e.g. `<img src="foo" /`
  if (token.nesting === 0 && options.xhtmlOut) {
    result += ' /';
  }

  // Check if we need to add a newline after this tag
  if (token.block) {
    needLf = true;

    if (token.nesting === 1) {
      if (idx + 1 < tokens.length) {
        nextToken = tokens[idx + 1];

        if (nextToken.type === 'inline' || nextToken.hidden) {
          // Block-level tag containing an inline tag.
          //
          needLf = false;

        } else if (nextToken.nesting === -1 && nextToken.tag === token.tag) {
          // Opening tag + closing tag of the same type. E.g. `<li></li>`.
          //
          needLf = false;
        }
      }
    }
  }

  result += needLf ? '>\n' : '>';

  return result;
};


/**
 * Renderer.renderInline(tokens, options, env) -> String
 * - tokens (Array): list on block tokens to render
 * - options (Object): params of parser instance
 * - env (Object): additional data from parsed input (references, for example)
 *
 * The same as [[Renderer.render]], but for single token of `inline` type.
 **/
Renderer$1.prototype.renderInline = function (tokens, options, env) {
  var type,
      result = '',
      rules = this.rules;

  for (var i = 0, len = tokens.length; i < len; i++) {
    type = tokens[i].type;

    if (typeof rules[type] !== 'undefined') {
      result += rules[type](tokens, i, options, env, this);
    } else {
      result += this.renderToken(tokens, i, options);
    }
  }

  return result;
};


/** internal
 * Renderer.renderInlineAsText(tokens, options, env) -> String
 * - tokens (Array): list on block tokens to render
 * - options (Object): params of parser instance
 * - env (Object): additional data from parsed input (references, for example)
 *
 * Special kludge for image `alt` attributes to conform CommonMark spec.
 * Don't try to use it! Spec requires to show `alt` content with stripped markup,
 * instead of simple escaping.
 **/
Renderer$1.prototype.renderInlineAsText = function (tokens, options, env) {
  var result = '';

  for (var i = 0, len = tokens.length; i < len; i++) {
    if (tokens[i].type === 'text') {
      result += tokens[i].content;
    } else if (tokens[i].type === 'image') {
      result += this.renderInlineAsText(tokens[i].children, options, env);
    } else if (tokens[i].type === 'softbreak') {
      result += '\n';
    }
  }

  return result;
};


/**
 * Renderer.render(tokens, options, env) -> String
 * - tokens (Array): list on block tokens to render
 * - options (Object): params of parser instance
 * - env (Object): additional data from parsed input (references, for example)
 *
 * Takes token stream and generates HTML. Probably, you will never need to call
 * this method directly.
 **/
Renderer$1.prototype.render = function (tokens, options, env) {
  var i, len, type,
      result = '',
      rules = this.rules;

  for (i = 0, len = tokens.length; i < len; i++) {
    type = tokens[i].type;

    if (type === 'inline') {
      result += this.renderInline(tokens[i].children, options, env);
    } else if (typeof rules[type] !== 'undefined') {
      result += rules[type](tokens, i, options, env, this);
    } else {
      result += this.renderToken(tokens, i, options, env);
    }
  }

  return result;
};

var renderer = Renderer$1;/**
 * class Ruler
 *
 * Helper class, used by [[MarkdownIt#core]], [[MarkdownIt#block]] and
 * [[MarkdownIt#inline]] to manage sequences of functions (rules):
 *
 * - keep rules in defined order
 * - assign the name to each rule
 * - enable/disable rules
 * - add/replace rules
 * - allow assign rules to additional named chains (in the same)
 * - cacheing lists of active rules
 *
 * You will not need use this class directly until write plugins. For simple
 * rules control use [[MarkdownIt.disable]], [[MarkdownIt.enable]] and
 * [[MarkdownIt.use]].
 **/


/**
 * new Ruler()
 **/
function Ruler$3() {
  // List of added rules. Each element is:
  //
  // {
  //   name: XXX,
  //   enabled: Boolean,
  //   fn: Function(),
  //   alt: [ name2, name3 ]
  // }
  //
  this.__rules__ = [];

  // Cached rule chains.
  //
  // First level - chain name, '' for default.
  // Second level - diginal anchor for fast filtering by charcodes.
  //
  this.__cache__ = null;
}

////////////////////////////////////////////////////////////////////////////////
// Helper methods, should not be used directly


// Find rule index by name
//
Ruler$3.prototype.__find__ = function (name) {
  for (var i = 0; i < this.__rules__.length; i++) {
    if (this.__rules__[i].name === name) {
      return i;
    }
  }
  return -1;
};


// Build rules lookup cache
//
Ruler$3.prototype.__compile__ = function () {
  var self = this;
  var chains = [ '' ];

  // collect unique names
  self.__rules__.forEach(function (rule) {
    if (!rule.enabled) { return; }

    rule.alt.forEach(function (altName) {
      if (chains.indexOf(altName) < 0) {
        chains.push(altName);
      }
    });
  });

  self.__cache__ = {};

  chains.forEach(function (chain) {
    self.__cache__[chain] = [];
    self.__rules__.forEach(function (rule) {
      if (!rule.enabled) { return; }

      if (chain && rule.alt.indexOf(chain) < 0) { return; }

      self.__cache__[chain].push(rule.fn);
    });
  });
};


/**
 * Ruler.at(name, fn [, options])
 * - name (String): rule name to replace.
 * - fn (Function): new rule function.
 * - options (Object): new rule options (not mandatory).
 *
 * Replace rule by name with new function & options. Throws error if name not
 * found.
 *
 * ##### Options:
 *
 * - __alt__ - array with names of "alternate" chains.
 *
 * ##### Example
 *
 * Replace existing typographer replacement rule with new one:
 *
 * ```javascript
 * var md = require('markdown-it')();
 *
 * md.core.ruler.at('replacements', function replace(state) {
 *   //...
 * });
 * ```
 **/
Ruler$3.prototype.at = function (name, fn, options) {
  var index = this.__find__(name);
  var opt = options || {};

  if (index === -1) { throw new Error('Parser rule not found: ' + name); }

  this.__rules__[index].fn = fn;
  this.__rules__[index].alt = opt.alt || [];
  this.__cache__ = null;
};


/**
 * Ruler.before(beforeName, ruleName, fn [, options])
 * - beforeName (String): new rule will be added before this one.
 * - ruleName (String): name of added rule.
 * - fn (Function): rule function.
 * - options (Object): rule options (not mandatory).
 *
 * Add new rule to chain before one with given name. See also
 * [[Ruler.after]], [[Ruler.push]].
 *
 * ##### Options:
 *
 * - __alt__ - array with names of "alternate" chains.
 *
 * ##### Example
 *
 * ```javascript
 * var md = require('markdown-it')();
 *
 * md.block.ruler.before('paragraph', 'my_rule', function replace(state) {
 *   //...
 * });
 * ```
 **/
Ruler$3.prototype.before = function (beforeName, ruleName, fn, options) {
  var index = this.__find__(beforeName);
  var opt = options || {};

  if (index === -1) { throw new Error('Parser rule not found: ' + beforeName); }

  this.__rules__.splice(index, 0, {
    name: ruleName,
    enabled: true,
    fn: fn,
    alt: opt.alt || []
  });

  this.__cache__ = null;
};


/**
 * Ruler.after(afterName, ruleName, fn [, options])
 * - afterName (String): new rule will be added after this one.
 * - ruleName (String): name of added rule.
 * - fn (Function): rule function.
 * - options (Object): rule options (not mandatory).
 *
 * Add new rule to chain after one with given name. See also
 * [[Ruler.before]], [[Ruler.push]].
 *
 * ##### Options:
 *
 * - __alt__ - array with names of "alternate" chains.
 *
 * ##### Example
 *
 * ```javascript
 * var md = require('markdown-it')();
 *
 * md.inline.ruler.after('text', 'my_rule', function replace(state) {
 *   //...
 * });
 * ```
 **/
Ruler$3.prototype.after = function (afterName, ruleName, fn, options) {
  var index = this.__find__(afterName);
  var opt = options || {};

  if (index === -1) { throw new Error('Parser rule not found: ' + afterName); }

  this.__rules__.splice(index + 1, 0, {
    name: ruleName,
    enabled: true,
    fn: fn,
    alt: opt.alt || []
  });

  this.__cache__ = null;
};

/**
 * Ruler.push(ruleName, fn [, options])
 * - ruleName (String): name of added rule.
 * - fn (Function): rule function.
 * - options (Object): rule options (not mandatory).
 *
 * Push new rule to the end of chain. See also
 * [[Ruler.before]], [[Ruler.after]].
 *
 * ##### Options:
 *
 * - __alt__ - array with names of "alternate" chains.
 *
 * ##### Example
 *
 * ```javascript
 * var md = require('markdown-it')();
 *
 * md.core.ruler.push('my_rule', function replace(state) {
 *   //...
 * });
 * ```
 **/
Ruler$3.prototype.push = function (ruleName, fn, options) {
  var opt = options || {};

  this.__rules__.push({
    name: ruleName,
    enabled: true,
    fn: fn,
    alt: opt.alt || []
  });

  this.__cache__ = null;
};


/**
 * Ruler.enable(list [, ignoreInvalid]) -> Array
 * - list (String|Array): list of rule names to enable.
 * - ignoreInvalid (Boolean): set `true` to ignore errors when rule not found.
 *
 * Enable rules with given names. If any rule name not found - throw Error.
 * Errors can be disabled by second param.
 *
 * Returns list of found rule names (if no exception happened).
 *
 * See also [[Ruler.disable]], [[Ruler.enableOnly]].
 **/
Ruler$3.prototype.enable = function (list, ignoreInvalid) {
  if (!Array.isArray(list)) { list = [ list ]; }

  var result = [];

  // Search by name and enable
  list.forEach(function (name) {
    var idx = this.__find__(name);

    if (idx < 0) {
      if (ignoreInvalid) { return; }
      throw new Error('Rules manager: invalid rule name ' + name);
    }
    this.__rules__[idx].enabled = true;
    result.push(name);
  }, this);

  this.__cache__ = null;
  return result;
};


/**
 * Ruler.enableOnly(list [, ignoreInvalid])
 * - list (String|Array): list of rule names to enable (whitelist).
 * - ignoreInvalid (Boolean): set `true` to ignore errors when rule not found.
 *
 * Enable rules with given names, and disable everything else. If any rule name
 * not found - throw Error. Errors can be disabled by second param.
 *
 * See also [[Ruler.disable]], [[Ruler.enable]].
 **/
Ruler$3.prototype.enableOnly = function (list, ignoreInvalid) {
  if (!Array.isArray(list)) { list = [ list ]; }

  this.__rules__.forEach(function (rule) { rule.enabled = false; });

  this.enable(list, ignoreInvalid);
};


/**
 * Ruler.disable(list [, ignoreInvalid]) -> Array
 * - list (String|Array): list of rule names to disable.
 * - ignoreInvalid (Boolean): set `true` to ignore errors when rule not found.
 *
 * Disable rules with given names. If any rule name not found - throw Error.
 * Errors can be disabled by second param.
 *
 * Returns list of found rule names (if no exception happened).
 *
 * See also [[Ruler.enable]], [[Ruler.enableOnly]].
 **/
Ruler$3.prototype.disable = function (list, ignoreInvalid) {
  if (!Array.isArray(list)) { list = [ list ]; }

  var result = [];

  // Search by name and disable
  list.forEach(function (name) {
    var idx = this.__find__(name);

    if (idx < 0) {
      if (ignoreInvalid) { return; }
      throw new Error('Rules manager: invalid rule name ' + name);
    }
    this.__rules__[idx].enabled = false;
    result.push(name);
  }, this);

  this.__cache__ = null;
  return result;
};


/**
 * Ruler.getRules(chainName) -> Array
 *
 * Return array of active functions (rules) for given chain name. It analyzes
 * rules configuration, compiles caches if not exists and returns result.
 *
 * Default chain name is `''` (empty string). It can't be skipped. That's
 * done intentionally, to keep signature monomorphic for high speed.
 **/
Ruler$3.prototype.getRules = function (chainName) {
  if (this.__cache__ === null) {
    this.__compile__();
  }

  // Chain can be empty, if rules disabled. But we still have to return Array.
  return this.__cache__[chainName] || [];
};

var ruler = Ruler$3;// https://spec.commonmark.org/0.29/#line-ending
var NEWLINES_RE  = /\r\n?|\n/g;
var NULL_RE      = /\0/g;


var normalize = function normalize(state) {
  var str;

  // Normalize newlines
  str = state.src.replace(NEWLINES_RE, '\n');

  // Replace NULL characters
  str = str.replace(NULL_RE, '\uFFFD');

  state.src = str;
};var block = function block(state) {
  var token;

  if (state.inlineMode) {
    token          = new state.Token('inline', '', 0);
    token.content  = state.src;
    token.map      = [ 0, 1 ];
    token.children = [];
    state.tokens.push(token);
  } else {
    state.md.block.parse(state.src, state.md, state.env, state.tokens);
  }
};var inline = function inline(state) {
  var tokens = state.tokens, tok, i, l;

  // Parse inlines
  for (i = 0, l = tokens.length; i < l; i++) {
    tok = tokens[i];
    if (tok.type === 'inline') {
      state.md.inline.parse(tok.content, state.md, state.env, tok.children);
    }
  }
};var arrayReplaceAt = utils$1.arrayReplaceAt;


function isLinkOpen$1(str) {
  return /^<a[>\s]/i.test(str);
}
function isLinkClose$1(str) {
  return /^<\/a\s*>/i.test(str);
}


var linkify$2 = function linkify(state) {
  var i, j, l, tokens, token, currentToken, nodes, ln, text, pos, lastPos,
      level, htmlLinkLevel, url, fullUrl, urlText,
      blockTokens = state.tokens,
      links;

  if (!state.md.options.linkify) { return; }

  for (j = 0, l = blockTokens.length; j < l; j++) {
    if (blockTokens[j].type !== 'inline' ||
        !state.md.linkify.pretest(blockTokens[j].content)) {
      continue;
    }

    tokens = blockTokens[j].children;

    htmlLinkLevel = 0;

    // We scan from the end, to keep position when new tags added.
    // Use reversed logic in links start/end match
    for (i = tokens.length - 1; i >= 0; i--) {
      currentToken = tokens[i];

      // Skip content of markdown links
      if (currentToken.type === 'link_close') {
        i--;
        while (tokens[i].level !== currentToken.level && tokens[i].type !== 'link_open') {
          i--;
        }
        continue;
      }

      // Skip content of html tag links
      if (currentToken.type === 'html_inline') {
        if (isLinkOpen$1(currentToken.content) && htmlLinkLevel > 0) {
          htmlLinkLevel--;
        }
        if (isLinkClose$1(currentToken.content)) {
          htmlLinkLevel++;
        }
      }
      if (htmlLinkLevel > 0) { continue; }

      if (currentToken.type === 'text' && state.md.linkify.test(currentToken.content)) {

        text = currentToken.content;
        links = state.md.linkify.match(text);

        // Now split string to nodes
        nodes = [];
        level = currentToken.level;
        lastPos = 0;

        // forbid escape sequence at the start of the string,
        // this avoids http\://example.com/ from being linkified as
        // http:<a href="//example.com/">//example.com/</a>
        if (links.length > 0 &&
            links[0].index === 0 &&
            i > 0 &&
            tokens[i - 1].type === 'text_special') {
          links = links.slice(1);
        }

        for (ln = 0; ln < links.length; ln++) {
          url = links[ln].url;
          fullUrl = state.md.normalizeLink(url);
          if (!state.md.validateLink(fullUrl)) { continue; }

          urlText = links[ln].text;

          // Linkifier might send raw hostnames like "example.com", where url
          // starts with domain name. So we prepend http:// in those cases,
          // and remove it afterwards.
          //
          if (!links[ln].schema) {
            urlText = state.md.normalizeLinkText('http://' + urlText).replace(/^http:\/\//, '');
          } else if (links[ln].schema === 'mailto:' && !/^mailto:/i.test(urlText)) {
            urlText = state.md.normalizeLinkText('mailto:' + urlText).replace(/^mailto:/, '');
          } else {
            urlText = state.md.normalizeLinkText(urlText);
          }

          pos = links[ln].index;

          if (pos > lastPos) {
            token         = new state.Token('text', '', 0);
            token.content = text.slice(lastPos, pos);
            token.level   = level;
            nodes.push(token);
          }

          token         = new state.Token('link_open', 'a', 1);
          token.attrs   = [ [ 'href', fullUrl ] ];
          token.level   = level++;
          token.markup  = 'linkify';
          token.info    = 'auto';
          nodes.push(token);

          token         = new state.Token('text', '', 0);
          token.content = urlText;
          token.level   = level;
          nodes.push(token);

          token         = new state.Token('link_close', 'a', -1);
          token.level   = --level;
          token.markup  = 'linkify';
          token.info    = 'auto';
          nodes.push(token);

          lastPos = links[ln].lastIndex;
        }
        if (lastPos < text.length) {
          token         = new state.Token('text', '', 0);
          token.content = text.slice(lastPos);
          token.level   = level;
          nodes.push(token);
        }

        // replace current node
        blockTokens[j].children = tokens = arrayReplaceAt(tokens, i, nodes);
      }
    }
  }
};// TODO:
// - fractionals 1/2, 1/4, 3/4 -> ½, ¼, ¾
// - multiplications 2 x 4 -> 2 × 4

var RARE_RE = /\+-|\.\.|\?\?\?\?|!!!!|,,|--/;

// Workaround for phantomjs - need regex without /g flag,
// or root check will fail every second time
var SCOPED_ABBR_TEST_RE = /\((c|tm|r)\)/i;

var SCOPED_ABBR_RE = /\((c|tm|r)\)/ig;
var SCOPED_ABBR = {
  c: '©',
  r: '®',
  tm: '™'
};

function replaceFn(match, name) {
  return SCOPED_ABBR[name.toLowerCase()];
}

function replace_scoped(inlineTokens) {
  var i, token, inside_autolink = 0;

  for (i = inlineTokens.length - 1; i >= 0; i--) {
    token = inlineTokens[i];

    if (token.type === 'text' && !inside_autolink) {
      token.content = token.content.replace(SCOPED_ABBR_RE, replaceFn);
    }

    if (token.type === 'link_open' && token.info === 'auto') {
      inside_autolink--;
    }

    if (token.type === 'link_close' && token.info === 'auto') {
      inside_autolink++;
    }
  }
}

function replace_rare(inlineTokens) {
  var i, token, inside_autolink = 0;

  for (i = inlineTokens.length - 1; i >= 0; i--) {
    token = inlineTokens[i];

    if (token.type === 'text' && !inside_autolink) {
      if (RARE_RE.test(token.content)) {
        token.content = token.content
          .replace(/\+-/g, '±')
          // .., ..., ....... -> …
          // but ?..... & !..... -> ?.. & !..
          .replace(/\.{2,}/g, '…').replace(/([?!])…/g, '$1..')
          .replace(/([?!]){4,}/g, '$1$1$1').replace(/,{2,}/g, ',')
          // em-dash
          .replace(/(^|[^-])---(?=[^-]|$)/mg, '$1\u2014')
          // en-dash
          .replace(/(^|\s)--(?=\s|$)/mg, '$1\u2013')
          .replace(/(^|[^-\s])--(?=[^-\s]|$)/mg, '$1\u2013');
      }
    }

    if (token.type === 'link_open' && token.info === 'auto') {
      inside_autolink--;
    }

    if (token.type === 'link_close' && token.info === 'auto') {
      inside_autolink++;
    }
  }
}


var replacements = function replace(state) {
  var blkIdx;

  if (!state.md.options.typographer) { return; }

  for (blkIdx = state.tokens.length - 1; blkIdx >= 0; blkIdx--) {

    if (state.tokens[blkIdx].type !== 'inline') { continue; }

    if (SCOPED_ABBR_TEST_RE.test(state.tokens[blkIdx].content)) {
      replace_scoped(state.tokens[blkIdx].children);
    }

    if (RARE_RE.test(state.tokens[blkIdx].content)) {
      replace_rare(state.tokens[blkIdx].children);
    }

  }
};var isWhiteSpace$1   = utils$1.isWhiteSpace;
var isPunctChar$1    = utils$1.isPunctChar;
var isMdAsciiPunct$1 = utils$1.isMdAsciiPunct;

var QUOTE_TEST_RE = /['"]/;
var QUOTE_RE = /['"]/g;
var APOSTROPHE = '\u2019'; /* ’ */


function replaceAt(str, index, ch) {
  return str.slice(0, index) + ch + str.slice(index + 1);
}

function process_inlines(tokens, state) {
  var i, token, text, t, pos, max, thisLevel, item, lastChar, nextChar,
      isLastPunctChar, isNextPunctChar, isLastWhiteSpace, isNextWhiteSpace,
      canOpen, canClose, j, isSingle, stack, openQuote, closeQuote;

  stack = [];

  for (i = 0; i < tokens.length; i++) {
    token = tokens[i];

    thisLevel = tokens[i].level;

    for (j = stack.length - 1; j >= 0; j--) {
      if (stack[j].level <= thisLevel) { break; }
    }
    stack.length = j + 1;

    if (token.type !== 'text') { continue; }

    text = token.content;
    pos = 0;
    max = text.length;

    /*eslint no-labels:0,block-scoped-var:0*/
    OUTER:
    while (pos < max) {
      QUOTE_RE.lastIndex = pos;
      t = QUOTE_RE.exec(text);
      if (!t) { break; }

      canOpen = canClose = true;
      pos = t.index + 1;
      isSingle = (t[0] === "'");

      // Find previous character,
      // default to space if it's the beginning of the line
      //
      lastChar = 0x20;

      if (t.index - 1 >= 0) {
        lastChar = text.charCodeAt(t.index - 1);
      } else {
        for (j = i - 1; j >= 0; j--) {
          if (tokens[j].type === 'softbreak' || tokens[j].type === 'hardbreak') { break; } // lastChar defaults to 0x20
          if (!tokens[j].content) { continue; } // should skip all tokens except 'text', 'html_inline' or 'code_inline'

          lastChar = tokens[j].content.charCodeAt(tokens[j].content.length - 1);
          break;
        }
      }

      // Find next character,
      // default to space if it's the end of the line
      //
      nextChar = 0x20;

      if (pos < max) {
        nextChar = text.charCodeAt(pos);
      } else {
        for (j = i + 1; j < tokens.length; j++) {
          if (tokens[j].type === 'softbreak' || tokens[j].type === 'hardbreak') { break; } // nextChar defaults to 0x20
          if (!tokens[j].content) { continue; } // should skip all tokens except 'text', 'html_inline' or 'code_inline'

          nextChar = tokens[j].content.charCodeAt(0);
          break;
        }
      }

      isLastPunctChar = isMdAsciiPunct$1(lastChar) || isPunctChar$1(String.fromCharCode(lastChar));
      isNextPunctChar = isMdAsciiPunct$1(nextChar) || isPunctChar$1(String.fromCharCode(nextChar));

      isLastWhiteSpace = isWhiteSpace$1(lastChar);
      isNextWhiteSpace = isWhiteSpace$1(nextChar);

      if (isNextWhiteSpace) {
        canOpen = false;
      } else if (isNextPunctChar) {
        if (!(isLastWhiteSpace || isLastPunctChar)) {
          canOpen = false;
        }
      }

      if (isLastWhiteSpace) {
        canClose = false;
      } else if (isLastPunctChar) {
        if (!(isNextWhiteSpace || isNextPunctChar)) {
          canClose = false;
        }
      }

      if (nextChar === 0x22 /* " */ && t[0] === '"') {
        if (lastChar >= 0x30 /* 0 */ && lastChar <= 0x39 /* 9 */) {
          // special case: 1"" - count first quote as an inch
          canClose = canOpen = false;
        }
      }

      if (canOpen && canClose) {
        // Replace quotes in the middle of punctuation sequence, but not
        // in the middle of the words, i.e.:
        //
        // 1. foo " bar " baz - not replaced
        // 2. foo-"-bar-"-baz - replaced
        // 3. foo"bar"baz     - not replaced
        //
        canOpen = isLastPunctChar;
        canClose = isNextPunctChar;
      }

      if (!canOpen && !canClose) {
        // middle of word
        if (isSingle) {
          token.content = replaceAt(token.content, t.index, APOSTROPHE);
        }
        continue;
      }

      if (canClose) {
        // this could be a closing quote, rewind the stack to get a match
        for (j = stack.length - 1; j >= 0; j--) {
          item = stack[j];
          if (stack[j].level < thisLevel) { break; }
          if (item.single === isSingle && stack[j].level === thisLevel) {
            item = stack[j];

            if (isSingle) {
              openQuote = state.md.options.quotes[2];
              closeQuote = state.md.options.quotes[3];
            } else {
              openQuote = state.md.options.quotes[0];
              closeQuote = state.md.options.quotes[1];
            }

            // replace token.content *before* tokens[item.token].content,
            // because, if they are pointing at the same token, replaceAt
            // could mess up indices when quote length != 1
            token.content = replaceAt(token.content, t.index, closeQuote);
            tokens[item.token].content = replaceAt(
              tokens[item.token].content, item.pos, openQuote);

            pos += closeQuote.length - 1;
            if (item.token === i) { pos += openQuote.length - 1; }

            text = token.content;
            max = text.length;

            stack.length = j;
            continue OUTER;
          }
        }
      }

      if (canOpen) {
        stack.push({
          token: i,
          pos: t.index,
          single: isSingle,
          level: thisLevel
        });
      } else if (canClose && isSingle) {
        token.content = replaceAt(token.content, t.index, APOSTROPHE);
      }
    }
  }
}


var smartquotes = function smartquotes(state) {
  /*eslint max-depth:0*/
  var blkIdx;

  if (!state.md.options.typographer) { return; }

  for (blkIdx = state.tokens.length - 1; blkIdx >= 0; blkIdx--) {

    if (state.tokens[blkIdx].type !== 'inline' ||
        !QUOTE_TEST_RE.test(state.tokens[blkIdx].content)) {
      continue;
    }

    process_inlines(state.tokens[blkIdx].children, state);
  }
};var text_join = function text_join(state) {
  var j, l, tokens, curr, max, last,
      blockTokens = state.tokens;

  for (j = 0, l = blockTokens.length; j < l; j++) {
    if (blockTokens[j].type !== 'inline') { continue; }

    tokens = blockTokens[j].children;
    max = tokens.length;

    for (curr = 0; curr < max; curr++) {
      if (tokens[curr].type === 'text_special') {
        tokens[curr].type = 'text';
      }
    }

    for (curr = last = 0; curr < max; curr++) {
      if (tokens[curr].type === 'text' &&
          curr + 1 < max &&
          tokens[curr + 1].type === 'text') {

        // collapse two adjacent text nodes
        tokens[curr + 1].content = tokens[curr].content + tokens[curr + 1].content;
      } else {
        if (curr !== last) { tokens[last] = tokens[curr]; }

        last++;
      }
    }

    if (curr !== last) {
      tokens.length = last;
    }
  }
};/**
 * class Token
 **/

/**
 * new Token(type, tag, nesting)
 *
 * Create new token and fill passed properties.
 **/
function Token$3(type, tag, nesting) {
  /**
   * Token#type -> String
   *
   * Type of the token (string, e.g. "paragraph_open")
   **/
  this.type     = type;

  /**
   * Token#tag -> String
   *
   * html tag name, e.g. "p"
   **/
  this.tag      = tag;

  /**
   * Token#attrs -> Array
   *
   * Html attributes. Format: `[ [ name1, value1 ], [ name2, value2 ] ]`
   **/
  this.attrs    = null;

  /**
   * Token#map -> Array
   *
   * Source map info. Format: `[ line_begin, line_end ]`
   **/
  this.map      = null;

  /**
   * Token#nesting -> Number
   *
   * Level change (number in {-1, 0, 1} set), where:
   *
   * -  `1` means the tag is opening
   * -  `0` means the tag is self-closing
   * - `-1` means the tag is closing
   **/
  this.nesting  = nesting;

  /**
   * Token#level -> Number
   *
   * nesting level, the same as `state.level`
   **/
  this.level    = 0;

  /**
   * Token#children -> Array
   *
   * An array of child nodes (inline and img tokens)
   **/
  this.children = null;

  /**
   * Token#content -> String
   *
   * In a case of self-closing tag (code, html, fence, etc.),
   * it has contents of this tag.
   **/
  this.content  = '';

  /**
   * Token#markup -> String
   *
   * '*' or '_' for emphasis, fence string for fence, etc.
   **/
  this.markup   = '';

  /**
   * Token#info -> String
   *
   * Additional information:
   *
   * - Info string for "fence" tokens
   * - The value "auto" for autolink "link_open" and "link_close" tokens
   * - The string value of the item marker for ordered-list "list_item_open" tokens
   **/
  this.info     = '';

  /**
   * Token#meta -> Object
   *
   * A place for plugins to store an arbitrary data
   **/
  this.meta     = null;

  /**
   * Token#block -> Boolean
   *
   * True for block-level tokens, false for inline tokens.
   * Used in renderer to calculate line breaks
   **/
  this.block    = false;

  /**
   * Token#hidden -> Boolean
   *
   * If it's true, ignore this element when rendering. Used for tight lists
   * to hide paragraphs.
   **/
  this.hidden   = false;
}


/**
 * Token.attrIndex(name) -> Number
 *
 * Search attribute index by name.
 **/
Token$3.prototype.attrIndex = function attrIndex(name) {
  var attrs, i, len;

  if (!this.attrs) { return -1; }

  attrs = this.attrs;

  for (i = 0, len = attrs.length; i < len; i++) {
    if (attrs[i][0] === name) { return i; }
  }
  return -1;
};


/**
 * Token.attrPush(attrData)
 *
 * Add `[ name, value ]` attribute to list. Init attrs if necessary
 **/
Token$3.prototype.attrPush = function attrPush(attrData) {
  if (this.attrs) {
    this.attrs.push(attrData);
  } else {
    this.attrs = [ attrData ];
  }
};


/**
 * Token.attrSet(name, value)
 *
 * Set `name` attribute to `value`. Override old value if exists.
 **/
Token$3.prototype.attrSet = function attrSet(name, value) {
  var idx = this.attrIndex(name),
      attrData = [ name, value ];

  if (idx < 0) {
    this.attrPush(attrData);
  } else {
    this.attrs[idx] = attrData;
  }
};


/**
 * Token.attrGet(name)
 *
 * Get the value of attribute `name`, or null if it does not exist.
 **/
Token$3.prototype.attrGet = function attrGet(name) {
  var idx = this.attrIndex(name), value = null;
  if (idx >= 0) {
    value = this.attrs[idx][1];
  }
  return value;
};


/**
 * Token.attrJoin(name, value)
 *
 * Join value to existing attribute via space. Or create new attribute if not
 * exists. Useful to operate with token classes.
 **/
Token$3.prototype.attrJoin = function attrJoin(name, value) {
  var idx = this.attrIndex(name);

  if (idx < 0) {
    this.attrPush([ name, value ]);
  } else {
    this.attrs[idx][1] = this.attrs[idx][1] + ' ' + value;
  }
};


var token = Token$3;var Token$2 = token;


function StateCore(src, md, env) {
  this.src = src;
  this.env = env;
  this.tokens = [];
  this.inlineMode = false;
  this.md = md; // link to parser instance
}

// re-export Token class to use in core rules
StateCore.prototype.Token = Token$2;


var state_core = StateCore;/** internal
 * class Core
 *
 * Top-level rules executor. Glues block/inline parsers and does intermediate
 * transformations.
 **/


var Ruler$2  = ruler;


var _rules$2 = [
  [ 'normalize',      normalize      ],
  [ 'block',          block          ],
  [ 'inline',         inline         ],
  [ 'linkify',        linkify$2        ],
  [ 'replacements',   replacements   ],
  [ 'smartquotes',    smartquotes    ],
  // `text_join` finds `text_special` tokens (for escape sequences)
  // and joins them with the rest of the text
  [ 'text_join',      text_join      ]
];


/**
 * new Core()
 **/
function Core() {
  /**
   * Core#ruler -> Ruler
   *
   * [[Ruler]] instance. Keep configuration of core rules.
   **/
  this.ruler = new Ruler$2();

  for (var i = 0; i < _rules$2.length; i++) {
    this.ruler.push(_rules$2[i][0], _rules$2[i][1]);
  }
}


/**
 * Core.process(state)
 *
 * Executes core chain rules.
 **/
Core.prototype.process = function (state) {
  var i, l, rules;

  rules = this.ruler.getRules('');

  for (i = 0, l = rules.length; i < l; i++) {
    rules[i](state);
  }
};

Core.prototype.State = state_core;


var parser_core = Core;var isSpace$d = utils$1.isSpace;


function getLine$1(state, line) {
  var pos = state.bMarks[line] + state.tShift[line],
      max = state.eMarks[line];

  return state.src.slice(pos, max);
}

function escapedSplit$1(str) {
  var result = [],
      pos = 0,
      max = str.length,
      ch,
      isEscaped = false,
      lastPos = 0,
      current = '';

  ch  = str.charCodeAt(pos);

  while (pos < max) {
    if (ch === 0x7c/* | */) {
      if (!isEscaped) {
        // pipe separating cells, '|'
        result.push(current + str.substring(lastPos, pos));
        current = '';
        lastPos = pos + 1;
      } else {
        // escaped pipe, '\|'
        current += str.substring(lastPos, pos - 1);
        lastPos = pos;
      }
    }

    isEscaped = (ch === 0x5c/* \ */);
    pos++;

    ch = str.charCodeAt(pos);
  }

  result.push(current + str.substring(lastPos));

  return result;
}


var table$1 = function table(state, startLine, endLine, silent) {
  var ch, lineText, pos, i, l, nextLine, columns, columnCount, token,
      aligns, t, tableLines, tbodyLines, oldParentType, terminate,
      terminatorRules, firstCh, secondCh;

  // should have at least two lines
  if (startLine + 2 > endLine) { return false; }

  nextLine = startLine + 1;

  if (state.sCount[nextLine] < state.blkIndent) { return false; }

  // if it's indented more than 3 spaces, it should be a code block
  if (state.sCount[nextLine] - state.blkIndent >= 4) { return false; }

  // first character of the second line should be '|', '-', ':',
  // and no other characters are allowed but spaces;
  // basically, this is the equivalent of /^[-:|][-:|\s]*$/ regexp

  pos = state.bMarks[nextLine] + state.tShift[nextLine];
  if (pos >= state.eMarks[nextLine]) { return false; }

  firstCh = state.src.charCodeAt(pos++);
  if (firstCh !== 0x7C/* | */ && firstCh !== 0x2D/* - */ && firstCh !== 0x3A/* : */) { return false; }

  if (pos >= state.eMarks[nextLine]) { return false; }

  secondCh = state.src.charCodeAt(pos++);
  if (secondCh !== 0x7C/* | */ && secondCh !== 0x2D/* - */ && secondCh !== 0x3A/* : */ && !isSpace$d(secondCh)) {
    return false;
  }

  // if first character is '-', then second character must not be a space
  // (due to parsing ambiguity with list)
  if (firstCh === 0x2D/* - */ && isSpace$d(secondCh)) { return false; }

  while (pos < state.eMarks[nextLine]) {
    ch = state.src.charCodeAt(pos);

    if (ch !== 0x7C/* | */ && ch !== 0x2D/* - */ && ch !== 0x3A/* : */ && !isSpace$d(ch)) { return false; }

    pos++;
  }

  lineText = getLine$1(state, startLine + 1);

  columns = lineText.split('|');
  aligns = [];
  for (i = 0; i < columns.length; i++) {
    t = columns[i].trim();
    if (!t) {
      // allow empty columns before and after table, but not in between columns;
      // e.g. allow ` |---| `, disallow ` ---||--- `
      if (i === 0 || i === columns.length - 1) {
        continue;
      } else {
        return false;
      }
    }

    if (!/^:?-+:?$/.test(t)) { return false; }
    if (t.charCodeAt(t.length - 1) === 0x3A/* : */) {
      aligns.push(t.charCodeAt(0) === 0x3A/* : */ ? 'center' : 'right');
    } else if (t.charCodeAt(0) === 0x3A/* : */) {
      aligns.push('left');
    } else {
      aligns.push('');
    }
  }

  lineText = getLine$1(state, startLine).trim();
  if (lineText.indexOf('|') === -1) { return false; }
  if (state.sCount[startLine] - state.blkIndent >= 4) { return false; }
  columns = escapedSplit$1(lineText);
  if (columns.length && columns[0] === '') { columns.shift(); }
  if (columns.length && columns[columns.length - 1] === '') { columns.pop(); }

  // header row will define an amount of columns in the entire table,
  // and align row should be exactly the same (the rest of the rows can differ)
  columnCount = columns.length;
  if (columnCount === 0 || columnCount !== aligns.length) { return false; }

  if (silent) { return true; }

  oldParentType = state.parentType;
  state.parentType = 'table';

  // use 'blockquote' lists for termination because it's
  // the most similar to tables
  terminatorRules = state.md.block.ruler.getRules('blockquote');

  token     = state.push('table_open', 'table', 1);
  token.map = tableLines = [ startLine, 0 ];

  token     = state.push('thead_open', 'thead', 1);
  token.map = [ startLine, startLine + 1 ];

  token     = state.push('tr_open', 'tr', 1);
  token.map = [ startLine, startLine + 1 ];

  for (i = 0; i < columns.length; i++) {
    token          = state.push('th_open', 'th', 1);
    if (aligns[i]) {
      token.attrs  = [ [ 'style', 'text-align:' + aligns[i] ] ];
    }

    token          = state.push('inline', '', 0);
    token.content  = columns[i].trim();
    token.children = [];

    token          = state.push('th_close', 'th', -1);
  }

  token     = state.push('tr_close', 'tr', -1);
  token     = state.push('thead_close', 'thead', -1);

  for (nextLine = startLine + 2; nextLine < endLine; nextLine++) {
    if (state.sCount[nextLine] < state.blkIndent) { break; }

    terminate = false;
    for (i = 0, l = terminatorRules.length; i < l; i++) {
      if (terminatorRules[i](state, nextLine, endLine, true)) {
        terminate = true;
        break;
      }
    }

    if (terminate) { break; }
    lineText = getLine$1(state, nextLine).trim();
    if (!lineText) { break; }
    if (state.sCount[nextLine] - state.blkIndent >= 4) { break; }
    columns = escapedSplit$1(lineText);
    if (columns.length && columns[0] === '') { columns.shift(); }
    if (columns.length && columns[columns.length - 1] === '') { columns.pop(); }

    if (nextLine === startLine + 2) {
      token     = state.push('tbody_open', 'tbody', 1);
      token.map = tbodyLines = [ startLine + 2, 0 ];
    }

    token     = state.push('tr_open', 'tr', 1);
    token.map = [ nextLine, nextLine + 1 ];

    for (i = 0; i < columnCount; i++) {
      token          = state.push('td_open', 'td', 1);
      if (aligns[i]) {
        token.attrs  = [ [ 'style', 'text-align:' + aligns[i] ] ];
      }

      token          = state.push('inline', '', 0);
      token.content  = columns[i] ? columns[i].trim() : '';
      token.children = [];

      token          = state.push('td_close', 'td', -1);
    }
    token = state.push('tr_close', 'tr', -1);
  }

  if (tbodyLines) {
    token = state.push('tbody_close', 'tbody', -1);
    tbodyLines[1] = nextLine;
  }

  token = state.push('table_close', 'table', -1);
  tableLines[1] = nextLine;

  state.parentType = oldParentType;
  state.line = nextLine;
  return true;
};var code = function code(state, startLine, endLine/*, silent*/) {
  var nextLine, last, token;

  if (state.sCount[startLine] - state.blkIndent < 4) { return false; }

  last = nextLine = startLine + 1;

  while (nextLine < endLine) {
    if (state.isEmpty(nextLine)) {
      nextLine++;
      continue;
    }

    if (state.sCount[nextLine] - state.blkIndent >= 4) {
      nextLine++;
      last = nextLine;
      continue;
    }
    break;
  }

  state.line = last;

  token         = state.push('code_block', 'code', 0);
  token.content = state.getLines(startLine, last, 4 + state.blkIndent, false) + '\n';
  token.map     = [ startLine, state.line ];

  return true;
};var fence = function fence(state, startLine, endLine, silent) {
  var marker, len, params, nextLine, mem, token, markup,
      haveEndMarker = false,
      pos = state.bMarks[startLine] + state.tShift[startLine],
      max = state.eMarks[startLine];

  // if it's indented more than 3 spaces, it should be a code block
  if (state.sCount[startLine] - state.blkIndent >= 4) { return false; }

  if (pos + 3 > max) { return false; }

  marker = state.src.charCodeAt(pos);

  if (marker !== 0x7E/* ~ */ && marker !== 0x60 /* ` */) {
    return false;
  }

  // scan marker length
  mem = pos;
  pos = state.skipChars(pos, marker);

  len = pos - mem;

  if (len < 3) { return false; }

  markup = state.src.slice(mem, pos);
  params = state.src.slice(pos, max);

  if (marker === 0x60 /* ` */) {
    if (params.indexOf(String.fromCharCode(marker)) >= 0) {
      return false;
    }
  }

  // Since start is found, we can report success here in validation mode
  if (silent) { return true; }

  // search end of block
  nextLine = startLine;

  for (;;) {
    nextLine++;
    if (nextLine >= endLine) {
      // unclosed block should be autoclosed by end of document.
      // also block seems to be autoclosed by end of parent
      break;
    }

    pos = mem = state.bMarks[nextLine] + state.tShift[nextLine];
    max = state.eMarks[nextLine];

    if (pos < max && state.sCount[nextLine] < state.blkIndent) {
      // non-empty line with negative indent should stop the list:
      // - ```
      //  test
      break;
    }

    if (state.src.charCodeAt(pos) !== marker) { continue; }

    if (state.sCount[nextLine] - state.blkIndent >= 4) {
      // closing fence should be indented less than 4 spaces
      continue;
    }

    pos = state.skipChars(pos, marker);

    // closing code fence must be at least as long as the opening one
    if (pos - mem < len) { continue; }

    // make sure tail has spaces only
    pos = state.skipSpaces(pos);

    if (pos < max) { continue; }

    haveEndMarker = true;
    // found!
    break;
  }

  // If a fence has heading spaces, they should be removed from its inner block
  len = state.sCount[startLine];

  state.line = nextLine + (haveEndMarker ? 1 : 0);

  token         = state.push('fence', 'code', 0);
  token.info    = params;
  token.content = state.getLines(startLine + 1, nextLine, len, true);
  token.markup  = markup;
  token.map     = [ startLine, state.line ];

  return true;
};var isSpace$c = utils$1.isSpace;


var blockquote = function blockquote(state, startLine, endLine, silent) {
  var adjustTab,
      ch,
      i,
      initial,
      l,
      lastLineEmpty,
      lines,
      nextLine,
      offset,
      oldBMarks,
      oldBSCount,
      oldIndent,
      oldParentType,
      oldSCount,
      oldTShift,
      spaceAfterMarker,
      terminate,
      terminatorRules,
      token,
      isOutdented,
      oldLineMax = state.lineMax,
      pos = state.bMarks[startLine] + state.tShift[startLine],
      max = state.eMarks[startLine];

  // if it's indented more than 3 spaces, it should be a code block
  if (state.sCount[startLine] - state.blkIndent >= 4) { return false; }

  // check the block quote marker
  if (state.src.charCodeAt(pos) !== 0x3E/* > */) { return false; }

  // we know that it's going to be a valid blockquote,
  // so no point trying to find the end of it in silent mode
  if (silent) { return true; }

  oldBMarks  = [];
  oldBSCount = [];
  oldSCount  = [];
  oldTShift  = [];

  terminatorRules = state.md.block.ruler.getRules('blockquote');

  oldParentType = state.parentType;
  state.parentType = 'blockquote';

  // Search the end of the block
  //
  // Block ends with either:
  //  1. an empty line outside:
  //     ```
  //     > test
  //
  //     ```
  //  2. an empty line inside:
  //     ```
  //     >
  //     test
  //     ```
  //  3. another tag:
  //     ```
  //     > test
  //      - - -
  //     ```
  for (nextLine = startLine; nextLine < endLine; nextLine++) {
    // check if it's outdented, i.e. it's inside list item and indented
    // less than said list item:
    //
    // ```
    // 1. anything
    //    > current blockquote
    // 2. checking this line
    // ```
    isOutdented = state.sCount[nextLine] < state.blkIndent;

    pos = state.bMarks[nextLine] + state.tShift[nextLine];
    max = state.eMarks[nextLine];

    if (pos >= max) {
      // Case 1: line is not inside the blockquote, and this line is empty.
      break;
    }

    if (state.src.charCodeAt(pos++) === 0x3E/* > */ && !isOutdented) {
      // This line is inside the blockquote.

      // set offset past spaces and ">"
      initial = state.sCount[nextLine] + 1;

      // skip one optional space after '>'
      if (state.src.charCodeAt(pos) === 0x20 /* space */) {
        // ' >   test '
        //     ^ -- position start of line here:
        pos++;
        initial++;
        adjustTab = false;
        spaceAfterMarker = true;
      } else if (state.src.charCodeAt(pos) === 0x09 /* tab */) {
        spaceAfterMarker = true;

        if ((state.bsCount[nextLine] + initial) % 4 === 3) {
          // '  >\t  test '
          //       ^ -- position start of line here (tab has width===1)
          pos++;
          initial++;
          adjustTab = false;
        } else {
          // ' >\t  test '
          //    ^ -- position start of line here + shift bsCount slightly
          //         to make extra space appear
          adjustTab = true;
        }
      } else {
        spaceAfterMarker = false;
      }

      offset = initial;
      oldBMarks.push(state.bMarks[nextLine]);
      state.bMarks[nextLine] = pos;

      while (pos < max) {
        ch = state.src.charCodeAt(pos);

        if (isSpace$c(ch)) {
          if (ch === 0x09) {
            offset += 4 - (offset + state.bsCount[nextLine] + (adjustTab ? 1 : 0)) % 4;
          } else {
            offset++;
          }
        } else {
          break;
        }

        pos++;
      }

      lastLineEmpty = pos >= max;

      oldBSCount.push(state.bsCount[nextLine]);
      state.bsCount[nextLine] = state.sCount[nextLine] + 1 + (spaceAfterMarker ? 1 : 0);

      oldSCount.push(state.sCount[nextLine]);
      state.sCount[nextLine] = offset - initial;

      oldTShift.push(state.tShift[nextLine]);
      state.tShift[nextLine] = pos - state.bMarks[nextLine];
      continue;
    }

    // Case 2: line is not inside the blockquote, and the last line was empty.
    if (lastLineEmpty) { break; }

    // Case 3: another tag found.
    terminate = false;
    for (i = 0, l = terminatorRules.length; i < l; i++) {
      if (terminatorRules[i](state, nextLine, endLine, true)) {
        terminate = true;
        break;
      }
    }

    if (terminate) {
      // Quirk to enforce "hard termination mode" for paragraphs;
      // normally if you call `tokenize(state, startLine, nextLine)`,
      // paragraphs will look below nextLine for paragraph continuation,
      // but if blockquote is terminated by another tag, they shouldn't
      state.lineMax = nextLine;

      if (state.blkIndent !== 0) {
        // state.blkIndent was non-zero, we now set it to zero,
        // so we need to re-calculate all offsets to appear as
        // if indent wasn't changed
        oldBMarks.push(state.bMarks[nextLine]);
        oldBSCount.push(state.bsCount[nextLine]);
        oldTShift.push(state.tShift[nextLine]);
        oldSCount.push(state.sCount[nextLine]);
        state.sCount[nextLine] -= state.blkIndent;
      }

      break;
    }

    oldBMarks.push(state.bMarks[nextLine]);
    oldBSCount.push(state.bsCount[nextLine]);
    oldTShift.push(state.tShift[nextLine]);
    oldSCount.push(state.sCount[nextLine]);

    // A negative indentation means that this is a paragraph continuation
    //
    state.sCount[nextLine] = -1;
  }

  oldIndent = state.blkIndent;
  state.blkIndent = 0;

  token        = state.push('blockquote_open', 'blockquote', 1);
  token.markup = '>';
  token.map    = lines = [ startLine, 0 ];

  state.md.block.tokenize(state, startLine, nextLine);

  token        = state.push('blockquote_close', 'blockquote', -1);
  token.markup = '>';

  state.lineMax = oldLineMax;
  state.parentType = oldParentType;
  lines[1] = state.line;

  // Restore original tShift; this might not be necessary since the parser
  // has already been here, but just to make sure we can do that.
  for (i = 0; i < oldTShift.length; i++) {
    state.bMarks[i + startLine] = oldBMarks[i];
    state.tShift[i + startLine] = oldTShift[i];
    state.sCount[i + startLine] = oldSCount[i];
    state.bsCount[i + startLine] = oldBSCount[i];
  }
  state.blkIndent = oldIndent;

  return true;
};var isSpace$b = utils$1.isSpace;


var hr = function hr(state, startLine, endLine, silent) {
  var marker, cnt, ch, token,
      pos = state.bMarks[startLine] + state.tShift[startLine],
      max = state.eMarks[startLine];

  // if it's indented more than 3 spaces, it should be a code block
  if (state.sCount[startLine] - state.blkIndent >= 4) { return false; }

  marker = state.src.charCodeAt(pos++);

  // Check hr marker
  if (marker !== 0x2A/* * */ &&
      marker !== 0x2D/* - */ &&
      marker !== 0x5F/* _ */) {
    return false;
  }

  // markers can be mixed with spaces, but there should be at least 3 of them

  cnt = 1;
  while (pos < max) {
    ch = state.src.charCodeAt(pos++);
    if (ch !== marker && !isSpace$b(ch)) { return false; }
    if (ch === marker) { cnt++; }
  }

  if (cnt < 3) { return false; }

  if (silent) { return true; }

  state.line = startLine + 1;

  token        = state.push('hr', 'hr', 0);
  token.map    = [ startLine, state.line ];
  token.markup = Array(cnt + 1).join(String.fromCharCode(marker));

  return true;
};var isSpace$a = utils$1.isSpace;


// Search `[-+*][\n ]`, returns next pos after marker on success
// or -1 on fail.
function skipBulletListMarker(state, startLine) {
  var marker, pos, max, ch;

  pos = state.bMarks[startLine] + state.tShift[startLine];
  max = state.eMarks[startLine];

  marker = state.src.charCodeAt(pos++);
  // Check bullet
  if (marker !== 0x2A/* * */ &&
      marker !== 0x2D/* - */ &&
      marker !== 0x2B/* + */) {
    return -1;
  }

  if (pos < max) {
    ch = state.src.charCodeAt(pos);

    if (!isSpace$a(ch)) {
      // " -test " - is not a list item
      return -1;
    }
  }

  return pos;
}

// Search `\d+[.)][\n ]`, returns next pos after marker on success
// or -1 on fail.
function skipOrderedListMarker(state, startLine) {
  var ch,
      start = state.bMarks[startLine] + state.tShift[startLine],
      pos = start,
      max = state.eMarks[startLine];

  // List marker should have at least 2 chars (digit + dot)
  if (pos + 1 >= max) { return -1; }

  ch = state.src.charCodeAt(pos++);

  if (ch < 0x30/* 0 */ || ch > 0x39/* 9 */) { return -1; }

  for (;;) {
    // EOL -> fail
    if (pos >= max) { return -1; }

    ch = state.src.charCodeAt(pos++);

    if (ch >= 0x30/* 0 */ && ch <= 0x39/* 9 */) {

      // List marker should have no more than 9 digits
      // (prevents integer overflow in browsers)
      if (pos - start >= 10) { return -1; }

      continue;
    }

    // found valid marker
    if (ch === 0x29/* ) */ || ch === 0x2e/* . */) {
      break;
    }

    return -1;
  }


  if (pos < max) {
    ch = state.src.charCodeAt(pos);

    if (!isSpace$a(ch)) {
      // " 1.test " - is not a list item
      return -1;
    }
  }
  return pos;
}

function markTightParagraphs(state, idx) {
  var i, l,
      level = state.level + 2;

  for (i = idx + 2, l = state.tokens.length - 2; i < l; i++) {
    if (state.tokens[i].level === level && state.tokens[i].type === 'paragraph_open') {
      state.tokens[i + 2].hidden = true;
      state.tokens[i].hidden = true;
      i += 2;
    }
  }
}


var list = function list(state, startLine, endLine, silent) {
  var ch,
      contentStart,
      i,
      indent,
      indentAfterMarker,
      initial,
      isOrdered,
      itemLines,
      l,
      listLines,
      listTokIdx,
      markerCharCode,
      markerValue,
      max,
      offset,
      oldListIndent,
      oldParentType,
      oldSCount,
      oldTShift,
      oldTight,
      pos,
      posAfterMarker,
      prevEmptyEnd,
      start,
      terminate,
      terminatorRules,
      token,
      nextLine = startLine,
      isTerminatingParagraph = false,
      tight = true;

  // if it's indented more than 3 spaces, it should be a code block
  if (state.sCount[nextLine] - state.blkIndent >= 4) { return false; }

  // Special case:
  //  - item 1
  //   - item 2
  //    - item 3
  //     - item 4
  //      - this one is a paragraph continuation
  if (state.listIndent >= 0 &&
      state.sCount[nextLine] - state.listIndent >= 4 &&
      state.sCount[nextLine] < state.blkIndent) {
    return false;
  }

  // limit conditions when list can interrupt
  // a paragraph (validation mode only)
  if (silent && state.parentType === 'paragraph') {
    // Next list item should still terminate previous list item;
    //
    // This code can fail if plugins use blkIndent as well as lists,
    // but I hope the spec gets fixed long before that happens.
    //
    if (state.sCount[nextLine] >= state.blkIndent) {
      isTerminatingParagraph = true;
    }
  }

  // Detect list type and position after marker
  if ((posAfterMarker = skipOrderedListMarker(state, nextLine)) >= 0) {
    isOrdered = true;
    start = state.bMarks[nextLine] + state.tShift[nextLine];
    markerValue = Number(state.src.slice(start, posAfterMarker - 1));

    // If we're starting a new ordered list right after
    // a paragraph, it should start with 1.
    if (isTerminatingParagraph && markerValue !== 1) { return false; }

  } else if ((posAfterMarker = skipBulletListMarker(state, nextLine)) >= 0) {
    isOrdered = false;

  } else {
    return false;
  }

  // If we're starting a new unordered list right after
  // a paragraph, first line should not be empty.
  if (isTerminatingParagraph) {
    if (state.skipSpaces(posAfterMarker) >= state.eMarks[nextLine]) { return false; }
  }

  // For validation mode we can terminate immediately
  if (silent) { return true; }

  // We should terminate list on style change. Remember first one to compare.
  markerCharCode = state.src.charCodeAt(posAfterMarker - 1);

  // Start list
  listTokIdx = state.tokens.length;

  if (isOrdered) {
    token       = state.push('ordered_list_open', 'ol', 1);
    if (markerValue !== 1) {
      token.attrs = [ [ 'start', markerValue ] ];
    }

  } else {
    token       = state.push('bullet_list_open', 'ul', 1);
  }

  token.map    = listLines = [ nextLine, 0 ];
  token.markup = String.fromCharCode(markerCharCode);

  //
  // Iterate list items
  //

  prevEmptyEnd = false;
  terminatorRules = state.md.block.ruler.getRules('list');

  oldParentType = state.parentType;
  state.parentType = 'list';

  while (nextLine < endLine) {
    pos = posAfterMarker;
    max = state.eMarks[nextLine];

    initial = offset = state.sCount[nextLine] + posAfterMarker - (state.bMarks[nextLine] + state.tShift[nextLine]);

    while (pos < max) {
      ch = state.src.charCodeAt(pos);

      if (ch === 0x09) {
        offset += 4 - (offset + state.bsCount[nextLine]) % 4;
      } else if (ch === 0x20) {
        offset++;
      } else {
        break;
      }

      pos++;
    }

    contentStart = pos;

    if (contentStart >= max) {
      // trimming space in "-    \n  3" case, indent is 1 here
      indentAfterMarker = 1;
    } else {
      indentAfterMarker = offset - initial;
    }

    // If we have more than 4 spaces, the indent is 1
    // (the rest is just indented code block)
    if (indentAfterMarker > 4) { indentAfterMarker = 1; }

    // "  -  test"
    //  ^^^^^ - calculating total length of this thing
    indent = initial + indentAfterMarker;

    // Run subparser & write tokens
    token        = state.push('list_item_open', 'li', 1);
    token.markup = String.fromCharCode(markerCharCode);
    token.map    = itemLines = [ nextLine, 0 ];
    if (isOrdered) {
      token.info = state.src.slice(start, posAfterMarker - 1);
    }

    // change current state, then restore it after parser subcall
    oldTight = state.tight;
    oldTShift = state.tShift[nextLine];
    oldSCount = state.sCount[nextLine];

    //  - example list
    // ^ listIndent position will be here
    //   ^ blkIndent position will be here
    //
    oldListIndent = state.listIndent;
    state.listIndent = state.blkIndent;
    state.blkIndent = indent;

    state.tight = true;
    state.tShift[nextLine] = contentStart - state.bMarks[nextLine];
    state.sCount[nextLine] = offset;

    if (contentStart >= max && state.isEmpty(nextLine + 1)) {
      // workaround for this case
      // (list item is empty, list terminates before "foo"):
      // ~~~~~~~~
      //   -
      //
      //     foo
      // ~~~~~~~~
      state.line = Math.min(state.line + 2, endLine);
    } else {
      state.md.block.tokenize(state, nextLine, endLine, true);
    }

    // If any of list item is tight, mark list as tight
    if (!state.tight || prevEmptyEnd) {
      tight = false;
    }
    // Item become loose if finish with empty line,
    // but we should filter last element, because it means list finish
    prevEmptyEnd = (state.line - nextLine) > 1 && state.isEmpty(state.line - 1);

    state.blkIndent = state.listIndent;
    state.listIndent = oldListIndent;
    state.tShift[nextLine] = oldTShift;
    state.sCount[nextLine] = oldSCount;
    state.tight = oldTight;

    token        = state.push('list_item_close', 'li', -1);
    token.markup = String.fromCharCode(markerCharCode);

    nextLine = state.line;
    itemLines[1] = nextLine;

    if (nextLine >= endLine) { break; }

    //
    // Try to check if list is terminated or continued.
    //
    if (state.sCount[nextLine] < state.blkIndent) { break; }

    // if it's indented more than 3 spaces, it should be a code block
    if (state.sCount[nextLine] - state.blkIndent >= 4) { break; }

    // fail if terminating block found
    terminate = false;
    for (i = 0, l = terminatorRules.length; i < l; i++) {
      if (terminatorRules[i](state, nextLine, endLine, true)) {
        terminate = true;
        break;
      }
    }
    if (terminate) { break; }

    // fail if list has another type
    if (isOrdered) {
      posAfterMarker = skipOrderedListMarker(state, nextLine);
      if (posAfterMarker < 0) { break; }
      start = state.bMarks[nextLine] + state.tShift[nextLine];
    } else {
      posAfterMarker = skipBulletListMarker(state, nextLine);
      if (posAfterMarker < 0) { break; }
    }

    if (markerCharCode !== state.src.charCodeAt(posAfterMarker - 1)) { break; }
  }

  // Finalize list
  if (isOrdered) {
    token = state.push('ordered_list_close', 'ol', -1);
  } else {
    token = state.push('bullet_list_close', 'ul', -1);
  }
  token.markup = String.fromCharCode(markerCharCode);

  listLines[1] = nextLine;
  state.line = nextLine;

  state.parentType = oldParentType;

  // mark paragraphs tight if needed
  if (tight) {
    markTightParagraphs(state, listTokIdx);
  }

  return true;
};var normalizeReference$2   = utils$1.normalizeReference;
var isSpace$9              = utils$1.isSpace;


var reference = function reference(state, startLine, _endLine, silent) {
  var ch,
      destEndPos,
      destEndLineNo,
      endLine,
      href,
      i,
      l,
      label,
      labelEnd,
      oldParentType,
      res,
      start,
      str,
      terminate,
      terminatorRules,
      title,
      lines = 0,
      pos = state.bMarks[startLine] + state.tShift[startLine],
      max = state.eMarks[startLine],
      nextLine = startLine + 1;

  // if it's indented more than 3 spaces, it should be a code block
  if (state.sCount[startLine] - state.blkIndent >= 4) { return false; }

  if (state.src.charCodeAt(pos) !== 0x5B/* [ */) { return false; }

  // Simple check to quickly interrupt scan on [link](url) at the start of line.
  // Can be useful on practice: https://github.com/markdown-it/markdown-it/issues/54
  while (++pos < max) {
    if (state.src.charCodeAt(pos) === 0x5D /* ] */ &&
        state.src.charCodeAt(pos - 1) !== 0x5C/* \ */) {
      if (pos + 1 === max) { return false; }
      if (state.src.charCodeAt(pos + 1) !== 0x3A/* : */) { return false; }
      break;
    }
  }

  endLine = state.lineMax;

  // jump line-by-line until empty one or EOF
  terminatorRules = state.md.block.ruler.getRules('reference');

  oldParentType = state.parentType;
  state.parentType = 'reference';

  for (; nextLine < endLine && !state.isEmpty(nextLine); nextLine++) {
    // this would be a code block normally, but after paragraph
    // it's considered a lazy continuation regardless of what's there
    if (state.sCount[nextLine] - state.blkIndent > 3) { continue; }

    // quirk for blockquotes, this line should already be checked by that rule
    if (state.sCount[nextLine] < 0) { continue; }

    // Some tags can terminate paragraph without empty line.
    terminate = false;
    for (i = 0, l = terminatorRules.length; i < l; i++) {
      if (terminatorRules[i](state, nextLine, endLine, true)) {
        terminate = true;
        break;
      }
    }
    if (terminate) { break; }
  }

  str = state.getLines(startLine, nextLine, state.blkIndent, false).trim();
  max = str.length;

  for (pos = 1; pos < max; pos++) {
    ch = str.charCodeAt(pos);
    if (ch === 0x5B /* [ */) {
      return false;
    } else if (ch === 0x5D /* ] */) {
      labelEnd = pos;
      break;
    } else if (ch === 0x0A /* \n */) {
      lines++;
    } else if (ch === 0x5C /* \ */) {
      pos++;
      if (pos < max && str.charCodeAt(pos) === 0x0A) {
        lines++;
      }
    }
  }

  if (labelEnd < 0 || str.charCodeAt(labelEnd + 1) !== 0x3A/* : */) { return false; }

  // [label]:   destination   'title'
  //         ^^^ skip optional whitespace here
  for (pos = labelEnd + 2; pos < max; pos++) {
    ch = str.charCodeAt(pos);
    if (ch === 0x0A) {
      lines++;
    } else if (isSpace$9(ch)) ; else {
      break;
    }
  }

  // [label]:   destination   'title'
  //            ^^^^^^^^^^^ parse this
  res = state.md.helpers.parseLinkDestination(str, pos, max);
  if (!res.ok) { return false; }

  href = state.md.normalizeLink(res.str);
  if (!state.md.validateLink(href)) { return false; }

  pos = res.pos;
  lines += res.lines;

  // save cursor state, we could require to rollback later
  destEndPos = pos;
  destEndLineNo = lines;

  // [label]:   destination   'title'
  //                       ^^^ skipping those spaces
  start = pos;
  for (; pos < max; pos++) {
    ch = str.charCodeAt(pos);
    if (ch === 0x0A) {
      lines++;
    } else if (isSpace$9(ch)) ; else {
      break;
    }
  }

  // [label]:   destination   'title'
  //                          ^^^^^^^ parse this
  res = state.md.helpers.parseLinkTitle(str, pos, max);
  if (pos < max && start !== pos && res.ok) {
    title = res.str;
    pos = res.pos;
    lines += res.lines;
  } else {
    title = '';
    pos = destEndPos;
    lines = destEndLineNo;
  }

  // skip trailing spaces until the rest of the line
  while (pos < max) {
    ch = str.charCodeAt(pos);
    if (!isSpace$9(ch)) { break; }
    pos++;
  }

  if (pos < max && str.charCodeAt(pos) !== 0x0A) {
    if (title) {
      // garbage at the end of the line after title,
      // but it could still be a valid reference if we roll back
      title = '';
      pos = destEndPos;
      lines = destEndLineNo;
      while (pos < max) {
        ch = str.charCodeAt(pos);
        if (!isSpace$9(ch)) { break; }
        pos++;
      }
    }
  }

  if (pos < max && str.charCodeAt(pos) !== 0x0A) {
    // garbage at the end of the line
    return false;
  }

  label = normalizeReference$2(str.slice(1, labelEnd));
  if (!label) {
    // CommonMark 0.20 disallows empty labels
    return false;
  }

  // Reference can not terminate anything. This check is for safety only.
  /*istanbul ignore if*/
  if (silent) { return true; }

  if (typeof state.env.references === 'undefined') {
    state.env.references = {};
  }
  if (typeof state.env.references[label] === 'undefined') {
    state.env.references[label] = { title: title, href: href };
  }

  state.parentType = oldParentType;

  state.line = startLine + lines + 1;
  return true;
};var html_blocks = [
  'address',
  'article',
  'aside',
  'base',
  'basefont',
  'blockquote',
  'body',
  'caption',
  'center',
  'col',
  'colgroup',
  'dd',
  'details',
  'dialog',
  'dir',
  'div',
  'dl',
  'dt',
  'fieldset',
  'figcaption',
  'figure',
  'footer',
  'form',
  'frame',
  'frameset',
  'h1',
  'h2',
  'h3',
  'h4',
  'h5',
  'h6',
  'head',
  'header',
  'hr',
  'html',
  'iframe',
  'legend',
  'li',
  'link',
  'main',
  'menu',
  'menuitem',
  'nav',
  'noframes',
  'ol',
  'optgroup',
  'option',
  'p',
  'param',
  'section',
  'source',
  'summary',
  'table',
  'tbody',
  'td',
  'tfoot',
  'th',
  'thead',
  'title',
  'tr',
  'track',
  'ul'
];var html_re = {};var attr_name     = '[a-zA-Z_:][a-zA-Z0-9:._-]*';

var unquoted      = '[^"\'=<>`\\x00-\\x20]+';
var single_quoted = "'[^']*'";
var double_quoted = '"[^"]*"';

var attr_value  = '(?:' + unquoted + '|' + single_quoted + '|' + double_quoted + ')';

var attribute   = '(?:\\s+' + attr_name + '(?:\\s*=\\s*' + attr_value + ')?)';

var open_tag    = '<[A-Za-z][A-Za-z0-9\\-]*' + attribute + '*\\s*\\/?>';

var close_tag   = '<\\/[A-Za-z][A-Za-z0-9\\-]*\\s*>';
var comment     = '<!---->|<!--(?:-?[^>-])(?:-?[^-])*-->';
var processing  = '<[?][\\s\\S]*?[?]>';
var declaration = '<![A-Z]+\\s+[^>]*>';
var cdata       = '<!\\[CDATA\\[[\\s\\S]*?\\]\\]>';

var HTML_TAG_RE$1 = new RegExp('^(?:' + open_tag + '|' + close_tag + '|' + comment +
                        '|' + processing + '|' + declaration + '|' + cdata + ')');
var HTML_OPEN_CLOSE_TAG_RE$1 = new RegExp('^(?:' + open_tag + '|' + close_tag + ')');

html_re.HTML_TAG_RE = HTML_TAG_RE$1;
html_re.HTML_OPEN_CLOSE_TAG_RE = HTML_OPEN_CLOSE_TAG_RE$1;var block_names = html_blocks;
var HTML_OPEN_CLOSE_TAG_RE = html_re.HTML_OPEN_CLOSE_TAG_RE;

// An array of opening and corresponding closing sequences for html tags,
// last argument defines whether it can terminate a paragraph or not
//
var HTML_SEQUENCES = [
  [ /^<(script|pre|style|textarea)(?=(\s|>|$))/i, /<\/(script|pre|style|textarea)>/i, true ],
  [ /^<!--/,        /-->/,   true ],
  [ /^<\?/,         /\?>/,   true ],
  [ /^<![A-Z]/,     />/,     true ],
  [ /^<!\[CDATA\[/, /\]\]>/, true ],
  [ new RegExp('^</?(' + block_names.join('|') + ')(?=(\\s|/?>|$))', 'i'), /^$/, true ],
  [ new RegExp(HTML_OPEN_CLOSE_TAG_RE.source + '\\s*$'),  /^$/, false ]
];


var html_block = function html_block(state, startLine, endLine, silent) {
  var i, nextLine, token, lineText,
      pos = state.bMarks[startLine] + state.tShift[startLine],
      max = state.eMarks[startLine];

  // if it's indented more than 3 spaces, it should be a code block
  if (state.sCount[startLine] - state.blkIndent >= 4) { return false; }

  if (!state.md.options.html) { return false; }

  if (state.src.charCodeAt(pos) !== 0x3C/* < */) { return false; }

  lineText = state.src.slice(pos, max);

  for (i = 0; i < HTML_SEQUENCES.length; i++) {
    if (HTML_SEQUENCES[i][0].test(lineText)) { break; }
  }

  if (i === HTML_SEQUENCES.length) { return false; }

  if (silent) {
    // true if this sequence can be a terminator, false otherwise
    return HTML_SEQUENCES[i][2];
  }

  nextLine = startLine + 1;

  // If we are here - we detected HTML block.
  // Let's roll down till block end.
  if (!HTML_SEQUENCES[i][1].test(lineText)) {
    for (; nextLine < endLine; nextLine++) {
      if (state.sCount[nextLine] < state.blkIndent) { break; }

      pos = state.bMarks[nextLine] + state.tShift[nextLine];
      max = state.eMarks[nextLine];
      lineText = state.src.slice(pos, max);

      if (HTML_SEQUENCES[i][1].test(lineText)) {
        if (lineText.length !== 0) { nextLine++; }
        break;
      }
    }
  }

  state.line = nextLine;

  token         = state.push('html_block', '', 0);
  token.map     = [ startLine, nextLine ];
  token.content = state.getLines(startLine, nextLine, state.blkIndent, true);

  return true;
};var isSpace$8 = utils$1.isSpace;


var heading$1 = function heading(state, startLine, endLine, silent) {
  var ch, level, tmp, token,
      pos = state.bMarks[startLine] + state.tShift[startLine],
      max = state.eMarks[startLine];

  // if it's indented more than 3 spaces, it should be a code block
  if (state.sCount[startLine] - state.blkIndent >= 4) { return false; }

  ch  = state.src.charCodeAt(pos);

  if (ch !== 0x23/* # */ || pos >= max) { return false; }

  // count heading level
  level = 1;
  ch = state.src.charCodeAt(++pos);
  while (ch === 0x23/* # */ && pos < max && level <= 6) {
    level++;
    ch = state.src.charCodeAt(++pos);
  }

  if (level > 6 || (pos < max && !isSpace$8(ch))) { return false; }

  if (silent) { return true; }

  // Let's cut tails like '    ###  ' from the end of string

  max = state.skipSpacesBack(max, pos);
  tmp = state.skipCharsBack(max, 0x23, pos); // #
  if (tmp > pos && isSpace$8(state.src.charCodeAt(tmp - 1))) {
    max = tmp;
  }

  state.line = startLine + 1;

  token        = state.push('heading_open', 'h' + String(level), 1);
  token.markup = '########'.slice(0, level);
  token.map    = [ startLine, state.line ];

  token          = state.push('inline', '', 0);
  token.content  = state.src.slice(pos, max).trim();
  token.map      = [ startLine, state.line ];
  token.children = [];

  token        = state.push('heading_close', 'h' + String(level), -1);
  token.markup = '########'.slice(0, level);

  return true;
};var lheading = function lheading(state, startLine, endLine/*, silent*/) {
  var content, terminate, i, l, token, pos, max, level, marker,
      nextLine = startLine + 1, oldParentType,
      terminatorRules = state.md.block.ruler.getRules('paragraph');

  // if it's indented more than 3 spaces, it should be a code block
  if (state.sCount[startLine] - state.blkIndent >= 4) { return false; }

  oldParentType = state.parentType;
  state.parentType = 'paragraph'; // use paragraph to match terminatorRules

  // jump line-by-line until empty one or EOF
  for (; nextLine < endLine && !state.isEmpty(nextLine); nextLine++) {
    // this would be a code block normally, but after paragraph
    // it's considered a lazy continuation regardless of what's there
    if (state.sCount[nextLine] - state.blkIndent > 3) { continue; }

    //
    // Check for underline in setext header
    //
    if (state.sCount[nextLine] >= state.blkIndent) {
      pos = state.bMarks[nextLine] + state.tShift[nextLine];
      max = state.eMarks[nextLine];

      if (pos < max) {
        marker = state.src.charCodeAt(pos);

        if (marker === 0x2D/* - */ || marker === 0x3D/* = */) {
          pos = state.skipChars(pos, marker);
          pos = state.skipSpaces(pos);

          if (pos >= max) {
            level = (marker === 0x3D/* = */ ? 1 : 2);
            break;
          }
        }
      }
    }

    // quirk for blockquotes, this line should already be checked by that rule
    if (state.sCount[nextLine] < 0) { continue; }

    // Some tags can terminate paragraph without empty line.
    terminate = false;
    for (i = 0, l = terminatorRules.length; i < l; i++) {
      if (terminatorRules[i](state, nextLine, endLine, true)) {
        terminate = true;
        break;
      }
    }
    if (terminate) { break; }
  }

  if (!level) {
    // Didn't find valid underline
    return false;
  }

  content = state.getLines(startLine, nextLine, state.blkIndent, false).trim();

  state.line = nextLine + 1;

  token          = state.push('heading_open', 'h' + String(level), 1);
  token.markup   = String.fromCharCode(marker);
  token.map      = [ startLine, state.line ];

  token          = state.push('inline', '', 0);
  token.content  = content;
  token.map      = [ startLine, state.line - 1 ];
  token.children = [];

  token          = state.push('heading_close', 'h' + String(level), -1);
  token.markup   = String.fromCharCode(marker);

  state.parentType = oldParentType;

  return true;
};var paragraph$1 = function paragraph(state, startLine, endLine) {
  var content, terminate, i, l, token, oldParentType,
      nextLine = startLine + 1,
      terminatorRules = state.md.block.ruler.getRules('paragraph');

  oldParentType = state.parentType;
  state.parentType = 'paragraph';

  // jump line-by-line until empty one or EOF
  for (; nextLine < endLine && !state.isEmpty(nextLine); nextLine++) {
    // this would be a code block normally, but after paragraph
    // it's considered a lazy continuation regardless of what's there
    if (state.sCount[nextLine] - state.blkIndent > 3) { continue; }

    // quirk for blockquotes, this line should already be checked by that rule
    if (state.sCount[nextLine] < 0) { continue; }

    // Some tags can terminate paragraph without empty line.
    terminate = false;
    for (i = 0, l = terminatorRules.length; i < l; i++) {
      if (terminatorRules[i](state, nextLine, endLine, true)) {
        terminate = true;
        break;
      }
    }
    if (terminate) { break; }
  }

  content = state.getLines(startLine, nextLine, state.blkIndent, false).trim();

  state.line = nextLine;

  token          = state.push('paragraph_open', 'p', 1);
  token.map      = [ startLine, state.line ];

  token          = state.push('inline', '', 0);
  token.content  = content;
  token.map      = [ startLine, state.line ];
  token.children = [];

  token          = state.push('paragraph_close', 'p', -1);

  state.parentType = oldParentType;

  return true;
};var Token$1 = token;
var isSpace$7 = utils$1.isSpace;


function StateBlock(src, md, env, tokens) {
  var ch, s, start, pos, len, indent, offset, indent_found;

  this.src = src;

  // link to parser instance
  this.md     = md;

  this.env = env;

  //
  // Internal state vartiables
  //

  this.tokens = tokens;

  this.bMarks = [];  // line begin offsets for fast jumps
  this.eMarks = [];  // line end offsets for fast jumps
  this.tShift = [];  // offsets of the first non-space characters (tabs not expanded)
  this.sCount = [];  // indents for each line (tabs expanded)

  // An amount of virtual spaces (tabs expanded) between beginning
  // of each line (bMarks) and real beginning of that line.
  //
  // It exists only as a hack because blockquotes override bMarks
  // losing information in the process.
  //
  // It's used only when expanding tabs, you can think about it as
  // an initial tab length, e.g. bsCount=21 applied to string `\t123`
  // means first tab should be expanded to 4-21%4 === 3 spaces.
  //
  this.bsCount = [];

  // block parser variables
  this.blkIndent  = 0; // required block content indent (for example, if we are
                       // inside a list, it would be positioned after list marker)
  this.line       = 0; // line index in src
  this.lineMax    = 0; // lines count
  this.tight      = false;  // loose/tight mode for lists
  this.ddIndent   = -1; // indent of the current dd block (-1 if there isn't any)
  this.listIndent = -1; // indent of the current list block (-1 if there isn't any)

  // can be 'blockquote', 'list', 'root', 'paragraph' or 'reference'
  // used in lists to determine if they interrupt a paragraph
  this.parentType = 'root';

  this.level = 0;

  // renderer
  this.result = '';

  // Create caches
  // Generate markers.
  s = this.src;
  indent_found = false;

  for (start = pos = indent = offset = 0, len = s.length; pos < len; pos++) {
    ch = s.charCodeAt(pos);

    if (!indent_found) {
      if (isSpace$7(ch)) {
        indent++;

        if (ch === 0x09) {
          offset += 4 - offset % 4;
        } else {
          offset++;
        }
        continue;
      } else {
        indent_found = true;
      }
    }

    if (ch === 0x0A || pos === len - 1) {
      if (ch !== 0x0A) { pos++; }
      this.bMarks.push(start);
      this.eMarks.push(pos);
      this.tShift.push(indent);
      this.sCount.push(offset);
      this.bsCount.push(0);

      indent_found = false;
      indent = 0;
      offset = 0;
      start = pos + 1;
    }
  }

  // Push fake entry to simplify cache bounds checks
  this.bMarks.push(s.length);
  this.eMarks.push(s.length);
  this.tShift.push(0);
  this.sCount.push(0);
  this.bsCount.push(0);

  this.lineMax = this.bMarks.length - 1; // don't count last fake line
}

// Push new token to "stream".
//
StateBlock.prototype.push = function (type, tag, nesting) {
  var token = new Token$1(type, tag, nesting);
  token.block = true;

  if (nesting < 0) { this.level--; } // closing tag
  token.level = this.level;
  if (nesting > 0) { this.level++; } // opening tag

  this.tokens.push(token);
  return token;
};

StateBlock.prototype.isEmpty = function isEmpty(line) {
  return this.bMarks[line] + this.tShift[line] >= this.eMarks[line];
};

StateBlock.prototype.skipEmptyLines = function skipEmptyLines(from) {
  for (var max = this.lineMax; from < max; from++) {
    if (this.bMarks[from] + this.tShift[from] < this.eMarks[from]) {
      break;
    }
  }
  return from;
};

// Skip spaces from given position.
StateBlock.prototype.skipSpaces = function skipSpaces(pos) {
  var ch;

  for (var max = this.src.length; pos < max; pos++) {
    ch = this.src.charCodeAt(pos);
    if (!isSpace$7(ch)) { break; }
  }
  return pos;
};

// Skip spaces from given position in reverse.
StateBlock.prototype.skipSpacesBack = function skipSpacesBack(pos, min) {
  if (pos <= min) { return pos; }

  while (pos > min) {
    if (!isSpace$7(this.src.charCodeAt(--pos))) { return pos + 1; }
  }
  return pos;
};

// Skip char codes from given position
StateBlock.prototype.skipChars = function skipChars(pos, code) {
  for (var max = this.src.length; pos < max; pos++) {
    if (this.src.charCodeAt(pos) !== code) { break; }
  }
  return pos;
};

// Skip char codes reverse from given position - 1
StateBlock.prototype.skipCharsBack = function skipCharsBack(pos, code, min) {
  if (pos <= min) { return pos; }

  while (pos > min) {
    if (code !== this.src.charCodeAt(--pos)) { return pos + 1; }
  }
  return pos;
};

// cut lines range from source.
StateBlock.prototype.getLines = function getLines(begin, end, indent, keepLastLF) {
  var i, lineIndent, ch, first, last, queue, lineStart,
      line = begin;

  if (begin >= end) {
    return '';
  }

  queue = new Array(end - begin);

  for (i = 0; line < end; line++, i++) {
    lineIndent = 0;
    lineStart = first = this.bMarks[line];

    if (line + 1 < end || keepLastLF) {
      // No need for bounds check because we have fake entry on tail.
      last = this.eMarks[line] + 1;
    } else {
      last = this.eMarks[line];
    }

    while (first < last && lineIndent < indent) {
      ch = this.src.charCodeAt(first);

      if (isSpace$7(ch)) {
        if (ch === 0x09) {
          lineIndent += 4 - (lineIndent + this.bsCount[line]) % 4;
        } else {
          lineIndent++;
        }
      } else if (first - lineStart < this.tShift[line]) {
        // patched tShift masked characters to look like spaces (blockquotes, list markers)
        lineIndent++;
      } else {
        break;
      }

      first++;
    }

    if (lineIndent > indent) {
      // partially expanding tabs in code blocks, e.g '\t\tfoobar'
      // with indent=2 becomes '  \tfoobar'
      queue[i] = new Array(lineIndent - indent + 1).join(' ') + this.src.slice(first, last);
    } else {
      queue[i] = this.src.slice(first, last);
    }
  }

  return queue.join('');
};

// re-export Token class to use in block rules
StateBlock.prototype.Token = Token$1;


var state_block = StateBlock;/** internal
 * class ParserBlock
 *
 * Block-level tokenizer.
 **/


var Ruler$1           = ruler;


var _rules$1 = [
  // First 2 params - rule name & source. Secondary array - list of rules,
  // which can be terminated by this one.
  [ 'table',      table$1,      [ 'paragraph', 'reference' ] ],
  [ 'code',       code ],
  [ 'fence',      fence,      [ 'paragraph', 'reference', 'blockquote', 'list' ] ],
  [ 'blockquote', blockquote, [ 'paragraph', 'reference', 'blockquote', 'list' ] ],
  [ 'hr',         hr,         [ 'paragraph', 'reference', 'blockquote', 'list' ] ],
  [ 'list',       list,       [ 'paragraph', 'reference', 'blockquote' ] ],
  [ 'reference',  reference ],
  [ 'html_block', html_block, [ 'paragraph', 'reference', 'blockquote' ] ],
  [ 'heading',    heading$1,    [ 'paragraph', 'reference', 'blockquote' ] ],
  [ 'lheading',   lheading ],
  [ 'paragraph',  paragraph$1 ]
];


/**
 * new ParserBlock()
 **/
function ParserBlock$1() {
  /**
   * ParserBlock#ruler -> Ruler
   *
   * [[Ruler]] instance. Keep configuration of block rules.
   **/
  this.ruler = new Ruler$1();

  for (var i = 0; i < _rules$1.length; i++) {
    this.ruler.push(_rules$1[i][0], _rules$1[i][1], { alt: (_rules$1[i][2] || []).slice() });
  }
}


// Generate tokens for input range
//
ParserBlock$1.prototype.tokenize = function (state, startLine, endLine) {
  var ok, i, prevLine,
      rules = this.ruler.getRules(''),
      len = rules.length,
      line = startLine,
      hasEmptyLines = false,
      maxNesting = state.md.options.maxNesting;

  while (line < endLine) {
    state.line = line = state.skipEmptyLines(line);
    if (line >= endLine) { break; }

    // Termination condition for nested calls.
    // Nested calls currently used for blockquotes & lists
    if (state.sCount[line] < state.blkIndent) { break; }

    // If nesting level exceeded - skip tail to the end. That's not ordinary
    // situation and we should not care about content.
    if (state.level >= maxNesting) {
      state.line = endLine;
      break;
    }

    // Try all possible rules.
    // On success, rule should:
    //
    // - update `state.line`
    // - update `state.tokens`
    // - return true
    prevLine = state.line;

    for (i = 0; i < len; i++) {
      ok = rules[i](state, line, endLine, false);
      if (ok) {
        if (prevLine >= state.line) {
          throw new Error("block rule didn't increment state.line");
        }
        break;
      }
    }

    // this can only happen if user disables paragraph rule
    if (!ok) { throw new Error('none of the block rules matched'); }

    // set state.tight if we had an empty line before current tag
    // i.e. latest empty line should not count
    state.tight = !hasEmptyLines;

    // paragraph might "eat" one newline after it in nested lists
    if (state.isEmpty(state.line - 1)) {
      hasEmptyLines = true;
    }

    line = state.line;

    if (line < endLine && state.isEmpty(line)) {
      hasEmptyLines = true;
      line++;
      state.line = line;
    }
  }
};


/**
 * ParserBlock.parse(str, md, env, outTokens)
 *
 * Process input string and push block tokens into `outTokens`
 **/
ParserBlock$1.prototype.parse = function (src, md, env, outTokens) {
  var state;

  if (!src) { return; }

  state = new this.State(src, md, env, outTokens);

  this.tokenize(state, state.line, state.lineMax);
};


ParserBlock$1.prototype.State = state_block;


var parser_block = ParserBlock$1;// Rule to skip pure text
// '{}$%@~+=:' reserved for extentions

// !, ", #, $, %, &, ', (, ), *, +, ,, -, ., /, :, ;, <, =, >, ?, @, [, \, ], ^, _, `, {, |, }, or ~

// !!!! Don't confuse with "Markdown ASCII Punctuation" chars
// http://spec.commonmark.org/0.15/#ascii-punctuation-character
function isTerminatorChar(ch) {
  switch (ch) {
    case 0x0A/* \n */:
    case 0x21/* ! */:
    case 0x23/* # */:
    case 0x24/* $ */:
    case 0x25/* % */:
    case 0x26/* & */:
    case 0x2A/* * */:
    case 0x2B/* + */:
    case 0x2D/* - */:
    case 0x3A/* : */:
    case 0x3C/* < */:
    case 0x3D/* = */:
    case 0x3E/* > */:
    case 0x40/* @ */:
    case 0x5B/* [ */:
    case 0x5C/* \ */:
    case 0x5D/* ] */:
    case 0x5E/* ^ */:
    case 0x5F/* _ */:
    case 0x60/* ` */:
    case 0x7B/* { */:
    case 0x7D/* } */:
    case 0x7E/* ~ */:
      return true;
    default:
      return false;
  }
}

var text$1 = function text(state, silent) {
  var pos = state.pos;

  while (pos < state.posMax && !isTerminatorChar(state.src.charCodeAt(pos))) {
    pos++;
  }

  if (pos === state.pos) { return false; }

  if (!silent) { state.pending += state.src.slice(state.pos, pos); }

  state.pos = pos;

  return true;
};// RFC3986: scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
var SCHEME_RE = /(?:^|[^a-z0-9.+-])([a-z][a-z0-9.+-]*)$/i;


var linkify$1 = function linkify(state, silent) {
  var pos, max, match, proto, link, url, fullUrl, token;

  if (!state.md.options.linkify) { return false; }
  if (state.linkLevel > 0) { return false; }

  pos = state.pos;
  max = state.posMax;

  if (pos + 3 > max) { return false; }
  if (state.src.charCodeAt(pos) !== 0x3A/* : */) { return false; }
  if (state.src.charCodeAt(pos + 1) !== 0x2F/* / */) { return false; }
  if (state.src.charCodeAt(pos + 2) !== 0x2F/* / */) { return false; }

  match = state.pending.match(SCHEME_RE);
  if (!match) { return false; }

  proto = match[1];

  link = state.md.linkify.matchAtStart(state.src.slice(pos - proto.length));
  if (!link) { return false; }

  url = link.url;

  // invalid link, but still detected by linkify somehow;
  // need to check to prevent infinite loop below
  if (url.length <= proto.length) { return false; }

  // disallow '*' at the end of the link (conflicts with emphasis)
  url = url.replace(/\*+$/, '');

  fullUrl = state.md.normalizeLink(url);
  if (!state.md.validateLink(fullUrl)) { return false; }

  if (!silent) {
    state.pending = state.pending.slice(0, -proto.length);

    token         = state.push('link_open', 'a', 1);
    token.attrs   = [ [ 'href', fullUrl ] ];
    token.markup  = 'linkify';
    token.info    = 'auto';

    token         = state.push('text', '', 0);
    token.content = state.md.normalizeLinkText(url);

    token         = state.push('link_close', 'a', -1);
    token.markup  = 'linkify';
    token.info    = 'auto';
  }

  state.pos += url.length - proto.length;
  return true;
};var isSpace$6 = utils$1.isSpace;


var newline = function newline(state, silent) {
  var pmax, max, ws, pos = state.pos;

  if (state.src.charCodeAt(pos) !== 0x0A/* \n */) { return false; }

  pmax = state.pending.length - 1;
  max = state.posMax;

  // '  \n' -> hardbreak
  // Lookup in pending chars is bad practice! Don't copy to other rules!
  // Pending string is stored in concat mode, indexed lookups will cause
  // convertion to flat mode.
  if (!silent) {
    if (pmax >= 0 && state.pending.charCodeAt(pmax) === 0x20) {
      if (pmax >= 1 && state.pending.charCodeAt(pmax - 1) === 0x20) {
        // Find whitespaces tail of pending chars.
        ws = pmax - 1;
        while (ws >= 1 && state.pending.charCodeAt(ws - 1) === 0x20) { ws--; }

        state.pending = state.pending.slice(0, ws);
        state.push('hardbreak', 'br', 0);
      } else {
        state.pending = state.pending.slice(0, -1);
        state.push('softbreak', 'br', 0);
      }

    } else {
      state.push('softbreak', 'br', 0);
    }
  }

  pos++;

  // skip heading spaces for next line
  while (pos < max && isSpace$6(state.src.charCodeAt(pos))) { pos++; }

  state.pos = pos;
  return true;
};var isSpace$5 = utils$1.isSpace;

var ESCAPED = [];

for (var i$1 = 0; i$1 < 256; i$1++) { ESCAPED.push(0); }

'\\!"#$%&\'()*+,./:;<=>?@[]^_`{|}~-'
  .split('').forEach(function (ch) { ESCAPED[ch.charCodeAt(0)] = 1; });


var _escape = function escape(state, silent) {
  var ch1, ch2, origStr, escapedStr, token, pos = state.pos, max = state.posMax;

  if (state.src.charCodeAt(pos) !== 0x5C/* \ */) { return false; }
  pos++;

  // '\' at the end of the inline block
  if (pos >= max) { return false; }

  ch1 = state.src.charCodeAt(pos);

  if (ch1 === 0x0A) {
    if (!silent) {
      state.push('hardbreak', 'br', 0);
    }

    pos++;
    // skip leading whitespaces from next line
    while (pos < max) {
      ch1 = state.src.charCodeAt(pos);
      if (!isSpace$5(ch1)) { break; }
      pos++;
    }

    state.pos = pos;
    return true;
  }

  escapedStr = state.src[pos];

  if (ch1 >= 0xD800 && ch1 <= 0xDBFF && pos + 1 < max) {
    ch2 = state.src.charCodeAt(pos + 1);

    if (ch2 >= 0xDC00 && ch2 <= 0xDFFF) {
      escapedStr += state.src[pos + 1];
      pos++;
    }
  }

  origStr = '\\' + escapedStr;

  if (!silent) {
    token = state.push('text_special', '', 0);

    if (ch1 < 256 && ESCAPED[ch1] !== 0) {
      token.content = escapedStr;
    } else {
      token.content = origStr;
    }

    token.markup = origStr;
    token.info   = 'escape';
  }

  state.pos = pos + 1;
  return true;
};var backticks = function backtick(state, silent) {
  var start, max, marker, token, matchStart, matchEnd, openerLength, closerLength,
      pos = state.pos,
      ch = state.src.charCodeAt(pos);

  if (ch !== 0x60/* ` */) { return false; }

  start = pos;
  pos++;
  max = state.posMax;

  // scan marker length
  while (pos < max && state.src.charCodeAt(pos) === 0x60/* ` */) { pos++; }

  marker = state.src.slice(start, pos);
  openerLength = marker.length;

  if (state.backticksScanned && (state.backticks[openerLength] || 0) <= start) {
    if (!silent) { state.pending += marker; }
    state.pos += openerLength;
    return true;
  }

  matchEnd = pos;

  // Nothing found in the cache, scan until the end of the line (or until marker is found)
  while ((matchStart = state.src.indexOf('`', matchEnd)) !== -1) {
    matchEnd = matchStart + 1;

    // scan marker length
    while (matchEnd < max && state.src.charCodeAt(matchEnd) === 0x60/* ` */) { matchEnd++; }

    closerLength = matchEnd - matchStart;

    if (closerLength === openerLength) {
      // Found matching closer length.
      if (!silent) {
        token     = state.push('code_inline', 'code', 0);
        token.markup  = marker;
        token.content = state.src.slice(pos, matchStart)
          .replace(/\n/g, ' ')
          .replace(/^ (.+) $/, '$1');
      }
      state.pos = matchEnd;
      return true;
    }

    // Some different length found, put it in cache as upper limit of where closer can be found
    state.backticks[closerLength] = matchStart;
  }

  // Scanned through the end, didn't find anything
  state.backticksScanned = true;

  if (!silent) { state.pending += marker; }
  state.pos += openerLength;
  return true;
};var strikethrough$1 = {};// Insert each marker as a separate text token, and add it to delimiter list
//
strikethrough$1.tokenize = function strikethrough(state, silent) {
  var i, scanned, token, len, ch,
      start = state.pos,
      marker = state.src.charCodeAt(start);

  if (silent) { return false; }

  if (marker !== 0x7E/* ~ */) { return false; }

  scanned = state.scanDelims(state.pos, true);
  len = scanned.length;
  ch = String.fromCharCode(marker);

  if (len < 2) { return false; }

  if (len % 2) {
    token         = state.push('text', '', 0);
    token.content = ch;
    len--;
  }

  for (i = 0; i < len; i += 2) {
    token         = state.push('text', '', 0);
    token.content = ch + ch;

    state.delimiters.push({
      marker: marker,
      length: 0,     // disable "rule of 3" length checks meant for emphasis
      token:  state.tokens.length - 1,
      end:    -1,
      open:   scanned.can_open,
      close:  scanned.can_close
    });
  }

  state.pos += scanned.length;

  return true;
};


function postProcess$1(state, delimiters) {
  var i, j,
      startDelim,
      endDelim,
      token,
      loneMarkers = [],
      max = delimiters.length;

  for (i = 0; i < max; i++) {
    startDelim = delimiters[i];

    if (startDelim.marker !== 0x7E/* ~ */) {
      continue;
    }

    if (startDelim.end === -1) {
      continue;
    }

    endDelim = delimiters[startDelim.end];

    token         = state.tokens[startDelim.token];
    token.type    = 's_open';
    token.tag     = 's';
    token.nesting = 1;
    token.markup  = '~~';
    token.content = '';

    token         = state.tokens[endDelim.token];
    token.type    = 's_close';
    token.tag     = 's';
    token.nesting = -1;
    token.markup  = '~~';
    token.content = '';

    if (state.tokens[endDelim.token - 1].type === 'text' &&
        state.tokens[endDelim.token - 1].content === '~') {

      loneMarkers.push(endDelim.token - 1);
    }
  }

  // If a marker sequence has an odd number of characters, it's splitted
  // like this: `~~~~~` -> `~` + `~~` + `~~`, leaving one marker at the
  // start of the sequence.
  //
  // So, we have to move all those markers after subsequent s_close tags.
  //
  while (loneMarkers.length) {
    i = loneMarkers.pop();
    j = i + 1;

    while (j < state.tokens.length && state.tokens[j].type === 's_close') {
      j++;
    }

    j--;

    if (i !== j) {
      token = state.tokens[j];
      state.tokens[j] = state.tokens[i];
      state.tokens[i] = token;
    }
  }
}


// Walk through delimiter list and replace text tokens with tags
//
strikethrough$1.postProcess = function strikethrough(state) {
  var curr,
      tokens_meta = state.tokens_meta,
      max = state.tokens_meta.length;

  postProcess$1(state, state.delimiters);

  for (curr = 0; curr < max; curr++) {
    if (tokens_meta[curr] && tokens_meta[curr].delimiters) {
      postProcess$1(state, tokens_meta[curr].delimiters);
    }
  }
};var emphasis = {};// Insert each marker as a separate text token, and add it to delimiter list
//
emphasis.tokenize = function emphasis(state, silent) {
  var i, scanned, token,
      start = state.pos,
      marker = state.src.charCodeAt(start);

  if (silent) { return false; }

  if (marker !== 0x5F /* _ */ && marker !== 0x2A /* * */) { return false; }

  scanned = state.scanDelims(state.pos, marker === 0x2A);

  for (i = 0; i < scanned.length; i++) {
    token         = state.push('text', '', 0);
    token.content = String.fromCharCode(marker);

    state.delimiters.push({
      // Char code of the starting marker (number).
      //
      marker: marker,

      // Total length of these series of delimiters.
      //
      length: scanned.length,

      // A position of the token this delimiter corresponds to.
      //
      token:  state.tokens.length - 1,

      // If this delimiter is matched as a valid opener, `end` will be
      // equal to its position, otherwise it's `-1`.
      //
      end:    -1,

      // Boolean flags that determine if this delimiter could open or close
      // an emphasis.
      //
      open:   scanned.can_open,
      close:  scanned.can_close
    });
  }

  state.pos += scanned.length;

  return true;
};


function postProcess(state, delimiters) {
  var i,
      startDelim,
      endDelim,
      token,
      ch,
      isStrong,
      max = delimiters.length;

  for (i = max - 1; i >= 0; i--) {
    startDelim = delimiters[i];

    if (startDelim.marker !== 0x5F/* _ */ && startDelim.marker !== 0x2A/* * */) {
      continue;
    }

    // Process only opening markers
    if (startDelim.end === -1) {
      continue;
    }

    endDelim = delimiters[startDelim.end];

    // If the previous delimiter has the same marker and is adjacent to this one,
    // merge those into one strong delimiter.
    //
    // `<em><em>whatever</em></em>` -> `<strong>whatever</strong>`
    //
    isStrong = i > 0 &&
               delimiters[i - 1].end === startDelim.end + 1 &&
               // check that first two markers match and adjacent
               delimiters[i - 1].marker === startDelim.marker &&
               delimiters[i - 1].token === startDelim.token - 1 &&
               // check that last two markers are adjacent (we can safely assume they match)
               delimiters[startDelim.end + 1].token === endDelim.token + 1;

    ch = String.fromCharCode(startDelim.marker);

    token         = state.tokens[startDelim.token];
    token.type    = isStrong ? 'strong_open' : 'em_open';
    token.tag     = isStrong ? 'strong' : 'em';
    token.nesting = 1;
    token.markup  = isStrong ? ch + ch : ch;
    token.content = '';

    token         = state.tokens[endDelim.token];
    token.type    = isStrong ? 'strong_close' : 'em_close';
    token.tag     = isStrong ? 'strong' : 'em';
    token.nesting = -1;
    token.markup  = isStrong ? ch + ch : ch;
    token.content = '';

    if (isStrong) {
      state.tokens[delimiters[i - 1].token].content = '';
      state.tokens[delimiters[startDelim.end + 1].token].content = '';
      i--;
    }
  }
}


// Walk through delimiter list and replace text tokens with tags
//
emphasis.postProcess = function emphasis(state) {
  var curr,
      tokens_meta = state.tokens_meta,
      max = state.tokens_meta.length;

  postProcess(state, state.delimiters);

  for (curr = 0; curr < max; curr++) {
    if (tokens_meta[curr] && tokens_meta[curr].delimiters) {
      postProcess(state, tokens_meta[curr].delimiters);
    }
  }
};var normalizeReference$1   = utils$1.normalizeReference;
var isSpace$4              = utils$1.isSpace;


var link$1 = function link(state, silent) {
  var attrs,
      code,
      label,
      labelEnd,
      labelStart,
      pos,
      res,
      ref,
      token,
      href = '',
      title = '',
      oldPos = state.pos,
      max = state.posMax,
      start = state.pos,
      parseReference = true;

  if (state.src.charCodeAt(state.pos) !== 0x5B/* [ */) { return false; }

  labelStart = state.pos + 1;
  labelEnd = state.md.helpers.parseLinkLabel(state, state.pos, true);

  // parser failed to find ']', so it's not a valid link
  if (labelEnd < 0) { return false; }

  pos = labelEnd + 1;
  if (pos < max && state.src.charCodeAt(pos) === 0x28/* ( */) {
    //
    // Inline link
    //

    // might have found a valid shortcut link, disable reference parsing
    parseReference = false;

    // [link](  <href>  "title"  )
    //        ^^ skipping these spaces
    pos++;
    for (; pos < max; pos++) {
      code = state.src.charCodeAt(pos);
      if (!isSpace$4(code) && code !== 0x0A) { break; }
    }
    if (pos >= max) { return false; }

    // [link](  <href>  "title"  )
    //          ^^^^^^ parsing link destination
    start = pos;
    res = state.md.helpers.parseLinkDestination(state.src, pos, state.posMax);
    if (res.ok) {
      href = state.md.normalizeLink(res.str);
      if (state.md.validateLink(href)) {
        pos = res.pos;
      } else {
        href = '';
      }

      // [link](  <href>  "title"  )
      //                ^^ skipping these spaces
      start = pos;
      for (; pos < max; pos++) {
        code = state.src.charCodeAt(pos);
        if (!isSpace$4(code) && code !== 0x0A) { break; }
      }

      // [link](  <href>  "title"  )
      //                  ^^^^^^^ parsing link title
      res = state.md.helpers.parseLinkTitle(state.src, pos, state.posMax);
      if (pos < max && start !== pos && res.ok) {
        title = res.str;
        pos = res.pos;

        // [link](  <href>  "title"  )
        //                         ^^ skipping these spaces
        for (; pos < max; pos++) {
          code = state.src.charCodeAt(pos);
          if (!isSpace$4(code) && code !== 0x0A) { break; }
        }
      }
    }

    if (pos >= max || state.src.charCodeAt(pos) !== 0x29/* ) */) {
      // parsing a valid shortcut link failed, fallback to reference
      parseReference = true;
    }
    pos++;
  }

  if (parseReference) {
    //
    // Link reference
    //
    if (typeof state.env.references === 'undefined') { return false; }

    if (pos < max && state.src.charCodeAt(pos) === 0x5B/* [ */) {
      start = pos + 1;
      pos = state.md.helpers.parseLinkLabel(state, pos);
      if (pos >= 0) {
        label = state.src.slice(start, pos++);
      } else {
        pos = labelEnd + 1;
      }
    } else {
      pos = labelEnd + 1;
    }

    // covers label === '' and label === undefined
    // (collapsed reference link and shortcut reference link respectively)
    if (!label) { label = state.src.slice(labelStart, labelEnd); }

    ref = state.env.references[normalizeReference$1(label)];
    if (!ref) {
      state.pos = oldPos;
      return false;
    }
    href = ref.href;
    title = ref.title;
  }

  //
  // We found the end of the link, and know for a fact it's a valid link;
  // so all that's left to do is to call tokenizer.
  //
  if (!silent) {
    state.pos = labelStart;
    state.posMax = labelEnd;

    token        = state.push('link_open', 'a', 1);
    token.attrs  = attrs = [ [ 'href', href ] ];
    if (title) {
      attrs.push([ 'title', title ]);
    }

    state.linkLevel++;
    state.md.inline.tokenize(state);
    state.linkLevel--;

    token        = state.push('link_close', 'a', -1);
  }

  state.pos = pos;
  state.posMax = max;
  return true;
};var normalizeReference   = utils$1.normalizeReference;
var isSpace$3              = utils$1.isSpace;


var image$1 = function image(state, silent) {
  var attrs,
      code,
      content,
      label,
      labelEnd,
      labelStart,
      pos,
      ref,
      res,
      title,
      token,
      tokens,
      start,
      href = '',
      oldPos = state.pos,
      max = state.posMax;

  if (state.src.charCodeAt(state.pos) !== 0x21/* ! */) { return false; }
  if (state.src.charCodeAt(state.pos + 1) !== 0x5B/* [ */) { return false; }

  labelStart = state.pos + 2;
  labelEnd = state.md.helpers.parseLinkLabel(state, state.pos + 1, false);

  // parser failed to find ']', so it's not a valid link
  if (labelEnd < 0) { return false; }

  pos = labelEnd + 1;
  if (pos < max && state.src.charCodeAt(pos) === 0x28/* ( */) {
    //
    // Inline link
    //

    // [link](  <href>  "title"  )
    //        ^^ skipping these spaces
    pos++;
    for (; pos < max; pos++) {
      code = state.src.charCodeAt(pos);
      if (!isSpace$3(code) && code !== 0x0A) { break; }
    }
    if (pos >= max) { return false; }

    // [link](  <href>  "title"  )
    //          ^^^^^^ parsing link destination
    start = pos;
    res = state.md.helpers.parseLinkDestination(state.src, pos, state.posMax);
    if (res.ok) {
      href = state.md.normalizeLink(res.str);
      if (state.md.validateLink(href)) {
        pos = res.pos;
      } else {
        href = '';
      }
    }

    // [link](  <href>  "title"  )
    //                ^^ skipping these spaces
    start = pos;
    for (; pos < max; pos++) {
      code = state.src.charCodeAt(pos);
      if (!isSpace$3(code) && code !== 0x0A) { break; }
    }

    // [link](  <href>  "title"  )
    //                  ^^^^^^^ parsing link title
    res = state.md.helpers.parseLinkTitle(state.src, pos, state.posMax);
    if (pos < max && start !== pos && res.ok) {
      title = res.str;
      pos = res.pos;

      // [link](  <href>  "title"  )
      //                         ^^ skipping these spaces
      for (; pos < max; pos++) {
        code = state.src.charCodeAt(pos);
        if (!isSpace$3(code) && code !== 0x0A) { break; }
      }
    } else {
      title = '';
    }

    if (pos >= max || state.src.charCodeAt(pos) !== 0x29/* ) */) {
      state.pos = oldPos;
      return false;
    }
    pos++;
  } else {
    //
    // Link reference
    //
    if (typeof state.env.references === 'undefined') { return false; }

    if (pos < max && state.src.charCodeAt(pos) === 0x5B/* [ */) {
      start = pos + 1;
      pos = state.md.helpers.parseLinkLabel(state, pos);
      if (pos >= 0) {
        label = state.src.slice(start, pos++);
      } else {
        pos = labelEnd + 1;
      }
    } else {
      pos = labelEnd + 1;
    }

    // covers label === '' and label === undefined
    // (collapsed reference link and shortcut reference link respectively)
    if (!label) { label = state.src.slice(labelStart, labelEnd); }

    ref = state.env.references[normalizeReference(label)];
    if (!ref) {
      state.pos = oldPos;
      return false;
    }
    href = ref.href;
    title = ref.title;
  }

  //
  // We found the end of the link, and know for a fact it's a valid link;
  // so all that's left to do is to call tokenizer.
  //
  if (!silent) {
    content = state.src.slice(labelStart, labelEnd);

    state.md.inline.parse(
      content,
      state.md,
      state.env,
      tokens = []
    );

    token          = state.push('image', 'img', 0);
    token.attrs    = attrs = [ [ 'src', href ], [ 'alt', '' ] ];
    token.children = tokens;
    token.content  = content;

    if (title) {
      attrs.push([ 'title', title ]);
    }
  }

  state.pos = pos;
  state.posMax = max;
  return true;
};/*eslint max-len:0*/
var EMAIL_RE    = /^([a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*)$/;
var AUTOLINK_RE = /^([a-zA-Z][a-zA-Z0-9+.\-]{1,31}):([^<>\x00-\x20]*)$/;


var autolink = function autolink(state, silent) {
  var url, fullUrl, token, ch, start, max,
      pos = state.pos;

  if (state.src.charCodeAt(pos) !== 0x3C/* < */) { return false; }

  start = state.pos;
  max = state.posMax;

  for (;;) {
    if (++pos >= max) { return false; }

    ch = state.src.charCodeAt(pos);

    if (ch === 0x3C /* < */) { return false; }
    if (ch === 0x3E /* > */) { break; }
  }

  url = state.src.slice(start + 1, pos);

  if (AUTOLINK_RE.test(url)) {
    fullUrl = state.md.normalizeLink(url);
    if (!state.md.validateLink(fullUrl)) { return false; }

    if (!silent) {
      token         = state.push('link_open', 'a', 1);
      token.attrs   = [ [ 'href', fullUrl ] ];
      token.markup  = 'autolink';
      token.info    = 'auto';

      token         = state.push('text', '', 0);
      token.content = state.md.normalizeLinkText(url);

      token         = state.push('link_close', 'a', -1);
      token.markup  = 'autolink';
      token.info    = 'auto';
    }

    state.pos += url.length + 2;
    return true;
  }

  if (EMAIL_RE.test(url)) {
    fullUrl = state.md.normalizeLink('mailto:' + url);
    if (!state.md.validateLink(fullUrl)) { return false; }

    if (!silent) {
      token         = state.push('link_open', 'a', 1);
      token.attrs   = [ [ 'href', fullUrl ] ];
      token.markup  = 'autolink';
      token.info    = 'auto';

      token         = state.push('text', '', 0);
      token.content = state.md.normalizeLinkText(url);

      token         = state.push('link_close', 'a', -1);
      token.markup  = 'autolink';
      token.info    = 'auto';
    }

    state.pos += url.length + 2;
    return true;
  }

  return false;
};var HTML_TAG_RE = html_re.HTML_TAG_RE;


function isLinkOpen(str) {
  return /^<a[>\s]/i.test(str);
}
function isLinkClose(str) {
  return /^<\/a\s*>/i.test(str);
}


function isLetter(ch) {
  /*eslint no-bitwise:0*/
  var lc = ch | 0x20; // to lower case
  return (lc >= 0x61/* a */) && (lc <= 0x7a/* z */);
}


var html_inline = function html_inline(state, silent) {
  var ch, match, max, token,
      pos = state.pos;

  if (!state.md.options.html) { return false; }

  // Check start
  max = state.posMax;
  if (state.src.charCodeAt(pos) !== 0x3C/* < */ ||
      pos + 2 >= max) {
    return false;
  }

  // Quick fail on second char
  ch = state.src.charCodeAt(pos + 1);
  if (ch !== 0x21/* ! */ &&
      ch !== 0x3F/* ? */ &&
      ch !== 0x2F/* / */ &&
      !isLetter(ch)) {
    return false;
  }

  match = state.src.slice(pos).match(HTML_TAG_RE);
  if (!match) { return false; }

  if (!silent) {
    token         = state.push('html_inline', '', 0);
    token.content = match[0];

    if (isLinkOpen(token.content))  { state.linkLevel++; }
    if (isLinkClose(token.content)) { state.linkLevel--; }
  }
  state.pos += match[0].length;
  return true;
};var entities          = entities$1;
var has               = utils$1.has;
var isValidEntityCode = utils$1.isValidEntityCode;
var fromCodePoint     = utils$1.fromCodePoint;


var DIGITAL_RE = /^&#((?:x[a-f0-9]{1,6}|[0-9]{1,7}));/i;
var NAMED_RE   = /^&([a-z][a-z0-9]{1,31});/i;


var entity = function entity(state, silent) {
  var ch, code, match, token, pos = state.pos, max = state.posMax;

  if (state.src.charCodeAt(pos) !== 0x26/* & */) { return false; }

  if (pos + 1 >= max) { return false; }

  ch = state.src.charCodeAt(pos + 1);

  if (ch === 0x23 /* # */) {
    match = state.src.slice(pos).match(DIGITAL_RE);
    if (match) {
      if (!silent) {
        code = match[1][0].toLowerCase() === 'x' ? parseInt(match[1].slice(1), 16) : parseInt(match[1], 10);

        token         = state.push('text_special', '', 0);
        token.content = isValidEntityCode(code) ? fromCodePoint(code) : fromCodePoint(0xFFFD);
        token.markup  = match[0];
        token.info    = 'entity';
      }
      state.pos += match[0].length;
      return true;
    }
  } else {
    match = state.src.slice(pos).match(NAMED_RE);
    if (match) {
      if (has(entities, match[1])) {
        if (!silent) {
          token         = state.push('text_special', '', 0);
          token.content = entities[match[1]];
          token.markup  = match[0];
          token.info    = 'entity';
        }
        state.pos += match[0].length;
        return true;
      }
    }
  }

  return false;
};function processDelimiters(delimiters) {
  var closerIdx, openerIdx, closer, opener, minOpenerIdx, newMinOpenerIdx,
      isOddMatch, lastJump,
      openersBottom = {},
      max = delimiters.length;

  if (!max) { return; }

  // headerIdx is the first delimiter of the current (where closer is) delimiter run
  var headerIdx = 0;
  var lastTokenIdx = -2; // needs any value lower than -1
  var jumps = [];

  for (closerIdx = 0; closerIdx < max; closerIdx++) {
    closer = delimiters[closerIdx];

    jumps.push(0);

    // markers belong to same delimiter run if:
    //  - they have adjacent tokens
    //  - AND markers are the same
    //
    if (delimiters[headerIdx].marker !== closer.marker || lastTokenIdx !== closer.token - 1) {
      headerIdx = closerIdx;
    }

    lastTokenIdx = closer.token;

    // Length is only used for emphasis-specific "rule of 3",
    // if it's not defined (in strikethrough or 3rd party plugins),
    // we can default it to 0 to disable those checks.
    //
    closer.length = closer.length || 0;

    if (!closer.close) { continue; }

    // Previously calculated lower bounds (previous fails)
    // for each marker, each delimiter length modulo 3,
    // and for whether this closer can be an opener;
    // https://github.com/commonmark/cmark/commit/34250e12ccebdc6372b8b49c44fab57c72443460
    if (!openersBottom.hasOwnProperty(closer.marker)) {
      openersBottom[closer.marker] = [ -1, -1, -1, -1, -1, -1 ];
    }

    minOpenerIdx = openersBottom[closer.marker][(closer.open ? 3 : 0) + (closer.length % 3)];

    openerIdx = headerIdx - jumps[headerIdx] - 1;

    newMinOpenerIdx = openerIdx;

    for (; openerIdx > minOpenerIdx; openerIdx -= jumps[openerIdx] + 1) {
      opener = delimiters[openerIdx];

      if (opener.marker !== closer.marker) { continue; }

      if (opener.open && opener.end < 0) {

        isOddMatch = false;

        // from spec:
        //
        // If one of the delimiters can both open and close emphasis, then the
        // sum of the lengths of the delimiter runs containing the opening and
        // closing delimiters must not be a multiple of 3 unless both lengths
        // are multiples of 3.
        //
        if (opener.close || closer.open) {
          if ((opener.length + closer.length) % 3 === 0) {
            if (opener.length % 3 !== 0 || closer.length % 3 !== 0) {
              isOddMatch = true;
            }
          }
        }

        if (!isOddMatch) {
          // If previous delimiter cannot be an opener, we can safely skip
          // the entire sequence in future checks. This is required to make
          // sure algorithm has linear complexity (see *_*_*_*_*_... case).
          //
          lastJump = openerIdx > 0 && !delimiters[openerIdx - 1].open ?
            jumps[openerIdx - 1] + 1 :
            0;

          jumps[closerIdx] = closerIdx - openerIdx + lastJump;
          jumps[openerIdx] = lastJump;

          closer.open  = false;
          opener.end   = closerIdx;
          opener.close = false;
          newMinOpenerIdx = -1;
          // treat next token as start of run,
          // it optimizes skips in **<...>**a**<...>** pathological case
          lastTokenIdx = -2;
          break;
        }
      }
    }

    if (newMinOpenerIdx !== -1) {
      // If match for this delimiter run failed, we want to set lower bound for
      // future lookups. This is required to make sure algorithm has linear
      // complexity.
      //
      // See details here:
      // https://github.com/commonmark/cmark/issues/178#issuecomment-270417442
      //
      openersBottom[closer.marker][(closer.open ? 3 : 0) + ((closer.length || 0) % 3)] = newMinOpenerIdx;
    }
  }
}


var balance_pairs = function link_pairs(state) {
  var curr,
      tokens_meta = state.tokens_meta,
      max = state.tokens_meta.length;

  processDelimiters(state.delimiters);

  for (curr = 0; curr < max; curr++) {
    if (tokens_meta[curr] && tokens_meta[curr].delimiters) {
      processDelimiters(tokens_meta[curr].delimiters);
    }
  }
};var fragments_join = function fragments_join(state) {
  var curr, last,
      level = 0,
      tokens = state.tokens,
      max = state.tokens.length;

  for (curr = last = 0; curr < max; curr++) {
    // re-calculate levels after emphasis/strikethrough turns some text nodes
    // into opening/closing tags
    if (tokens[curr].nesting < 0) { level--; } // closing tag
    tokens[curr].level = level;
    if (tokens[curr].nesting > 0) { level++; } // opening tag

    if (tokens[curr].type === 'text' &&
        curr + 1 < max &&
        tokens[curr + 1].type === 'text') {

      // collapse two adjacent text nodes
      tokens[curr + 1].content = tokens[curr].content + tokens[curr + 1].content;
    } else {
      if (curr !== last) { tokens[last] = tokens[curr]; }

      last++;
    }
  }

  if (curr !== last) {
    tokens.length = last;
  }
};var Token          = token;
var isWhiteSpace   = utils$1.isWhiteSpace;
var isPunctChar    = utils$1.isPunctChar;
var isMdAsciiPunct = utils$1.isMdAsciiPunct;


function StateInline(src, md, env, outTokens) {
  this.src = src;
  this.env = env;
  this.md = md;
  this.tokens = outTokens;
  this.tokens_meta = Array(outTokens.length);

  this.pos = 0;
  this.posMax = this.src.length;
  this.level = 0;
  this.pending = '';
  this.pendingLevel = 0;

  // Stores { start: end } pairs. Useful for backtrack
  // optimization of pairs parse (emphasis, strikes).
  this.cache = {};

  // List of emphasis-like delimiters for current tag
  this.delimiters = [];

  // Stack of delimiter lists for upper level tags
  this._prev_delimiters = [];

  // backtick length => last seen position
  this.backticks = {};
  this.backticksScanned = false;

  // Counter used to disable inline linkify-it execution
  // inside <a> and markdown links
  this.linkLevel = 0;
}


// Flush pending text
//
StateInline.prototype.pushPending = function () {
  var token = new Token('text', '', 0);
  token.content = this.pending;
  token.level = this.pendingLevel;
  this.tokens.push(token);
  this.pending = '';
  return token;
};


// Push new token to "stream".
// If pending text exists - flush it as text token
//
StateInline.prototype.push = function (type, tag, nesting) {
  if (this.pending) {
    this.pushPending();
  }

  var token = new Token(type, tag, nesting);
  var token_meta = null;

  if (nesting < 0) {
    // closing tag
    this.level--;
    this.delimiters = this._prev_delimiters.pop();
  }

  token.level = this.level;

  if (nesting > 0) {
    // opening tag
    this.level++;
    this._prev_delimiters.push(this.delimiters);
    this.delimiters = [];
    token_meta = { delimiters: this.delimiters };
  }

  this.pendingLevel = this.level;
  this.tokens.push(token);
  this.tokens_meta.push(token_meta);
  return token;
};


// Scan a sequence of emphasis-like markers, and determine whether
// it can start an emphasis sequence or end an emphasis sequence.
//
//  - start - position to scan from (it should point at a valid marker);
//  - canSplitWord - determine if these markers can be found inside a word
//
StateInline.prototype.scanDelims = function (start, canSplitWord) {
  var pos = start, lastChar, nextChar, count, can_open, can_close,
      isLastWhiteSpace, isLastPunctChar,
      isNextWhiteSpace, isNextPunctChar,
      left_flanking = true,
      right_flanking = true,
      max = this.posMax,
      marker = this.src.charCodeAt(start);

  // treat beginning of the line as a whitespace
  lastChar = start > 0 ? this.src.charCodeAt(start - 1) : 0x20;

  while (pos < max && this.src.charCodeAt(pos) === marker) { pos++; }

  count = pos - start;

  // treat end of the line as a whitespace
  nextChar = pos < max ? this.src.charCodeAt(pos) : 0x20;

  isLastPunctChar = isMdAsciiPunct(lastChar) || isPunctChar(String.fromCharCode(lastChar));
  isNextPunctChar = isMdAsciiPunct(nextChar) || isPunctChar(String.fromCharCode(nextChar));

  isLastWhiteSpace = isWhiteSpace(lastChar);
  isNextWhiteSpace = isWhiteSpace(nextChar);

  if (isNextWhiteSpace) {
    left_flanking = false;
  } else if (isNextPunctChar) {
    if (!(isLastWhiteSpace || isLastPunctChar)) {
      left_flanking = false;
    }
  }

  if (isLastWhiteSpace) {
    right_flanking = false;
  } else if (isLastPunctChar) {
    if (!(isNextWhiteSpace || isNextPunctChar)) {
      right_flanking = false;
    }
  }

  if (!canSplitWord) {
    can_open  = left_flanking  && (!right_flanking || isLastPunctChar);
    can_close = right_flanking && (!left_flanking  || isNextPunctChar);
  } else {
    can_open  = left_flanking;
    can_close = right_flanking;
  }

  return {
    can_open:  can_open,
    can_close: can_close,
    length:    count
  };
};


// re-export Token class to use in block rules
StateInline.prototype.Token = Token;


var state_inline = StateInline;/** internal
 * class ParserInline
 *
 * Tokenizes paragraph content.
 **/


var Ruler           = ruler;


////////////////////////////////////////////////////////////////////////////////
// Parser rules

var _rules = [
  [ 'text',            text$1 ],
  [ 'linkify',         linkify$1 ],
  [ 'newline',         newline ],
  [ 'escape',          _escape ],
  [ 'backticks',       backticks ],
  [ 'strikethrough',   strikethrough$1.tokenize ],
  [ 'emphasis',        emphasis.tokenize ],
  [ 'link',            link$1 ],
  [ 'image',           image$1 ],
  [ 'autolink',        autolink ],
  [ 'html_inline',     html_inline ],
  [ 'entity',          entity ]
];

// `rule2` ruleset was created specifically for emphasis/strikethrough
// post-processing and may be changed in the future.
//
// Don't use this for anything except pairs (plugins working with `balance_pairs`).
//
var _rules2 = [
  [ 'balance_pairs',   balance_pairs ],
  [ 'strikethrough',   strikethrough$1.postProcess ],
  [ 'emphasis',        emphasis.postProcess ],
  // rules for pairs separate '**' into its own text tokens, which may be left unused,
  // rule below merges unused segments back with the rest of the text
  [ 'fragments_join',  fragments_join ]
];


/**
 * new ParserInline()
 **/
function ParserInline$1() {
  var i;

  /**
   * ParserInline#ruler -> Ruler
   *
   * [[Ruler]] instance. Keep configuration of inline rules.
   **/
  this.ruler = new Ruler();

  for (i = 0; i < _rules.length; i++) {
    this.ruler.push(_rules[i][0], _rules[i][1]);
  }

  /**
   * ParserInline#ruler2 -> Ruler
   *
   * [[Ruler]] instance. Second ruler used for post-processing
   * (e.g. in emphasis-like rules).
   **/
  this.ruler2 = new Ruler();

  for (i = 0; i < _rules2.length; i++) {
    this.ruler2.push(_rules2[i][0], _rules2[i][1]);
  }
}


// Skip single token by running all rules in validation mode;
// returns `true` if any rule reported success
//
ParserInline$1.prototype.skipToken = function (state) {
  var ok, i, pos = state.pos,
      rules = this.ruler.getRules(''),
      len = rules.length,
      maxNesting = state.md.options.maxNesting,
      cache = state.cache;


  if (typeof cache[pos] !== 'undefined') {
    state.pos = cache[pos];
    return;
  }

  if (state.level < maxNesting) {
    for (i = 0; i < len; i++) {
      // Increment state.level and decrement it later to limit recursion.
      // It's harmless to do here, because no tokens are created. But ideally,
      // we'd need a separate private state variable for this purpose.
      //
      state.level++;
      ok = rules[i](state, true);
      state.level--;

      if (ok) {
        if (pos >= state.pos) { throw new Error("inline rule didn't increment state.pos"); }
        break;
      }
    }
  } else {
    // Too much nesting, just skip until the end of the paragraph.
    //
    // NOTE: this will cause links to behave incorrectly in the following case,
    //       when an amount of `[` is exactly equal to `maxNesting + 1`:
    //
    //       [[[[[[[[[[[[[[[[[[[[[foo]()
    //
    // TODO: remove this workaround when CM standard will allow nested links
    //       (we can replace it by preventing links from being parsed in
    //       validation mode)
    //
    state.pos = state.posMax;
  }

  if (!ok) { state.pos++; }
  cache[pos] = state.pos;
};


// Generate tokens for input range
//
ParserInline$1.prototype.tokenize = function (state) {
  var ok, i, prevPos,
      rules = this.ruler.getRules(''),
      len = rules.length,
      end = state.posMax,
      maxNesting = state.md.options.maxNesting;

  while (state.pos < end) {
    // Try all possible rules.
    // On success, rule should:
    //
    // - update `state.pos`
    // - update `state.tokens`
    // - return true
    prevPos = state.pos;

    if (state.level < maxNesting) {
      for (i = 0; i < len; i++) {
        ok = rules[i](state, false);
        if (ok) {
          if (prevPos >= state.pos) { throw new Error("inline rule didn't increment state.pos"); }
          break;
        }
      }
    }

    if (ok) {
      if (state.pos >= end) { break; }
      continue;
    }

    state.pending += state.src[state.pos++];
  }

  if (state.pending) {
    state.pushPending();
  }
};


/**
 * ParserInline.parse(str, md, env, outTokens)
 *
 * Process input string and push inline tokens into `outTokens`
 **/
ParserInline$1.prototype.parse = function (str, md, env, outTokens) {
  var i, rules, len;
  var state = new this.State(str, md, env, outTokens);

  this.tokenize(state);

  rules = this.ruler2.getRules('');
  len = rules.length;

  for (i = 0; i < len; i++) {
    rules[i](state);
  }
};


ParserInline$1.prototype.State = state_inline;


var parser_inline = ParserInline$1;var re;
var hasRequiredRe;

function requireRe () {
	if (hasRequiredRe) { return re; }
	hasRequiredRe = 1;


	re = function (opts) {
	  var re = {};
	  opts = opts || {};

	  // Use direct extract instead of `regenerate` to reduse browserified size
	  re.src_Any = requireRegex$3().source;
	  re.src_Cc  = requireRegex$2().source;
	  re.src_Z   = requireRegex().source;
	  re.src_P   = regex$4.source;

	  // \p{\Z\P\Cc\CF} (white spaces + control + format + punctuation)
	  re.src_ZPCc = [ re.src_Z, re.src_P, re.src_Cc ].join('|');

	  // \p{\Z\Cc} (white spaces + control)
	  re.src_ZCc = [ re.src_Z, re.src_Cc ].join('|');

	  // Experimental. List of chars, completely prohibited in links
	  // because can separate it from other part of text
	  var text_separators = '[><\uff5c]';

	  // All possible word characters (everything without punctuation, spaces & controls)
	  // Defined via punctuation & spaces to save space
	  // Should be something like \p{\L\N\S\M} (\w but without `_`)
	  re.src_pseudo_letter       = '(?:(?!' + text_separators + '|' + re.src_ZPCc + ')' + re.src_Any + ')';
	  // The same as abothe but without [0-9]
	  // var src_pseudo_letter_non_d = '(?:(?![0-9]|' + src_ZPCc + ')' + src_Any + ')';

	  ////////////////////////////////////////////////////////////////////////////////

	  re.src_ip4 =

	    '(?:(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)';

	  // Prohibit any of "@/[]()" in user/pass to avoid wrong domain fetch.
	  re.src_auth    = '(?:(?:(?!' + re.src_ZCc + '|[@/\\[\\]()]).)+@)?';

	  re.src_port =

	    '(?::(?:6(?:[0-4]\\d{3}|5(?:[0-4]\\d{2}|5(?:[0-2]\\d|3[0-5])))|[1-5]?\\d{1,4}))?';

	  re.src_host_terminator =

	    '(?=$|' + text_separators + '|' + re.src_ZPCc + ')' +
	    '(?!' + (opts['---'] ? '-(?!--)|' : '-|') + '_|:\\d|\\.-|\\.(?!$|' + re.src_ZPCc + '))';

	  re.src_path =

	    '(?:' +
	      '[/?#]' +
	        '(?:' +
	          '(?!' + re.src_ZCc + '|' + text_separators + '|[()[\\]{}.,"\'?!\\-;]).|' +
	          '\\[(?:(?!' + re.src_ZCc + '|\\]).)*\\]|' +
	          '\\((?:(?!' + re.src_ZCc + '|[)]).)*\\)|' +
	          '\\{(?:(?!' + re.src_ZCc + '|[}]).)*\\}|' +
	          '\\"(?:(?!' + re.src_ZCc + '|["]).)+\\"|' +
	          "\\'(?:(?!" + re.src_ZCc + "|[']).)+\\'|" +
	          "\\'(?=" + re.src_pseudo_letter + '|[-])|' +  // allow `I'm_king` if no pair found
	          '\\.{2,}[a-zA-Z0-9%/&]|' + // google has many dots in "google search" links (#66, #81).
	                                     // github has ... in commit range links,
	                                     // Restrict to
	                                     // - english
	                                     // - percent-encoded
	                                     // - parts of file path
	                                     // - params separator
	                                     // until more examples found.
	          '\\.(?!' + re.src_ZCc + '|[.]|$)|' +
	          (opts['---'] ?
	            '\\-(?!--(?:[^-]|$))(?:-*)|' // `---` => long dash, terminate
	            :
	            '\\-+|'
	          ) +
	          ',(?!' + re.src_ZCc + '|$)|' +       // allow `,,,` in paths
	          ';(?!' + re.src_ZCc + '|$)|' +       // allow `;` if not followed by space-like char
	          '\\!+(?!' + re.src_ZCc + '|[!]|$)|' +  // allow `!!!` in paths, but not at the end
	          '\\?(?!' + re.src_ZCc + '|[?]|$)' +
	        ')+' +
	      '|\\/' +
	    ')?';

	  // Allow anything in markdown spec, forbid quote (") at the first position
	  // because emails enclosed in quotes are far more common
	  re.src_email_name =

	    '[\\-;:&=\\+\\$,\\.a-zA-Z0-9_][\\-;:&=\\+\\$,\\"\\.a-zA-Z0-9_]*';

	  re.src_xn =

	    'xn--[a-z0-9\\-]{1,59}';

	  // More to read about domain names
	  // http://serverfault.com/questions/638260/

	  re.src_domain_root =

	    // Allow letters & digits (http://test1)
	    '(?:' +
	      re.src_xn +
	      '|' +
	      re.src_pseudo_letter + '{1,63}' +
	    ')';

	  re.src_domain =

	    '(?:' +
	      re.src_xn +
	      '|' +
	      '(?:' + re.src_pseudo_letter + ')' +
	      '|' +
	      '(?:' + re.src_pseudo_letter + '(?:-|' + re.src_pseudo_letter + '){0,61}' + re.src_pseudo_letter + ')' +
	    ')';

	  re.src_host =

	    '(?:' +
	    // Don't need IP check, because digits are already allowed in normal domain names
	    //   src_ip4 +
	    // '|' +
	      '(?:(?:(?:' + re.src_domain + ')\\.)*' + re.src_domain/*_root*/ + ')' +
	    ')';

	  re.tpl_host_fuzzy =

	    '(?:' +
	      re.src_ip4 +
	    '|' +
	      '(?:(?:(?:' + re.src_domain + ')\\.)+(?:%TLDS%))' +
	    ')';

	  re.tpl_host_no_ip_fuzzy =

	    '(?:(?:(?:' + re.src_domain + ')\\.)+(?:%TLDS%))';

	  re.src_host_strict =

	    re.src_host + re.src_host_terminator;

	  re.tpl_host_fuzzy_strict =

	    re.tpl_host_fuzzy + re.src_host_terminator;

	  re.src_host_port_strict =

	    re.src_host + re.src_port + re.src_host_terminator;

	  re.tpl_host_port_fuzzy_strict =

	    re.tpl_host_fuzzy + re.src_port + re.src_host_terminator;

	  re.tpl_host_port_no_ip_fuzzy_strict =

	    re.tpl_host_no_ip_fuzzy + re.src_port + re.src_host_terminator;


	  ////////////////////////////////////////////////////////////////////////////////
	  // Main rules

	  // Rude test fuzzy links by host, for quick deny
	  re.tpl_host_fuzzy_test =

	    'localhost|www\\.|\\.\\d{1,3}\\.|(?:\\.(?:%TLDS%)(?:' + re.src_ZPCc + '|>|$))';

	  re.tpl_email_fuzzy =

	      '(^|' + text_separators + '|"|\\(|' + re.src_ZCc + ')' +
	      '(' + re.src_email_name + '@' + re.tpl_host_fuzzy_strict + ')';

	  re.tpl_link_fuzzy =
	      // Fuzzy link can't be prepended with .:/\- and non punctuation.
	      // but can start with > (markdown blockquote)
	      '(^|(?![.:/\\-_@])(?:[$+<=>^`|\uff5c]|' + re.src_ZPCc + '))' +
	      '((?![$+<=>^`|\uff5c])' + re.tpl_host_port_fuzzy_strict + re.src_path + ')';

	  re.tpl_link_no_ip_fuzzy =
	      // Fuzzy link can't be prepended with .:/\- and non punctuation.
	      // but can start with > (markdown blockquote)
	      '(^|(?![.:/\\-_@])(?:[$+<=>^`|\uff5c]|' + re.src_ZPCc + '))' +
	      '((?![$+<=>^`|\uff5c])' + re.tpl_host_port_no_ip_fuzzy_strict + re.src_path + ')';

	  return re;
	};
	return re;
}////////////////////////////////////////////////////////////////////////////////
// Helpers

// Merge objects
//
function assign(obj /*from1, from2, from3, ...*/) {
  var sources = Array.prototype.slice.call(arguments, 1);

  sources.forEach(function (source) {
    if (!source) { return; }

    Object.keys(source).forEach(function (key) {
      obj[key] = source[key];
    });
  });

  return obj;
}

function _class(obj) { return Object.prototype.toString.call(obj); }
function isString(obj) { return _class(obj) === '[object String]'; }
function isObject(obj) { return _class(obj) === '[object Object]'; }
function isRegExp(obj) { return _class(obj) === '[object RegExp]'; }
function isFunction(obj) { return _class(obj) === '[object Function]'; }


function escapeRE(str) { return str.replace(/[.?*+^$[\]\\(){}|-]/g, '\\$&'); }

////////////////////////////////////////////////////////////////////////////////


var defaultOptions = {
  fuzzyLink: true,
  fuzzyEmail: true,
  fuzzyIP: false
};


function isOptionsObj(obj) {
  return Object.keys(obj || {}).reduce(function (acc, k) {
    return acc || defaultOptions.hasOwnProperty(k);
  }, false);
}


var defaultSchemas = {
  'http:': {
    validate: function (text, pos, self) {
      var tail = text.slice(pos);

      if (!self.re.http) {
        // compile lazily, because "host"-containing variables can change on tlds update.
        self.re.http =  new RegExp(
          '^\\/\\/' + self.re.src_auth + self.re.src_host_port_strict + self.re.src_path, 'i'
        );
      }
      if (self.re.http.test(tail)) {
        return tail.match(self.re.http)[0].length;
      }
      return 0;
    }
  },
  'https:':  'http:',
  'ftp:':    'http:',
  '//':      {
    validate: function (text, pos, self) {
      var tail = text.slice(pos);

      if (!self.re.no_http) {
      // compile lazily, because "host"-containing variables can change on tlds update.
        self.re.no_http =  new RegExp(
          '^' +
          self.re.src_auth +
          // Don't allow single-level domains, because of false positives like '//test'
          // with code comments
          '(?:localhost|(?:(?:' + self.re.src_domain + ')\\.)+' + self.re.src_domain_root + ')' +
          self.re.src_port +
          self.re.src_host_terminator +
          self.re.src_path,

          'i'
        );
      }

      if (self.re.no_http.test(tail)) {
        // should not be `://` & `///`, that protects from errors in protocol name
        if (pos >= 3 && text[pos - 3] === ':') { return 0; }
        if (pos >= 3 && text[pos - 3] === '/') { return 0; }
        return tail.match(self.re.no_http)[0].length;
      }
      return 0;
    }
  },
  'mailto:': {
    validate: function (text, pos, self) {
      var tail = text.slice(pos);

      if (!self.re.mailto) {
        self.re.mailto =  new RegExp(
          '^' + self.re.src_email_name + '@' + self.re.src_host_strict, 'i'
        );
      }
      if (self.re.mailto.test(tail)) {
        return tail.match(self.re.mailto)[0].length;
      }
      return 0;
    }
  }
};

/*eslint-disable max-len*/

// RE pattern for 2-character tlds (autogenerated by ./support/tlds_2char_gen.js)
var tlds_2ch_src_re = 'a[cdefgilmnoqrstuwxz]|b[abdefghijmnorstvwyz]|c[acdfghiklmnoruvwxyz]|d[ejkmoz]|e[cegrstu]|f[ijkmor]|g[abdefghilmnpqrstuwy]|h[kmnrtu]|i[delmnoqrst]|j[emop]|k[eghimnprwyz]|l[abcikrstuvy]|m[acdeghklmnopqrstuvwxyz]|n[acefgilopruz]|om|p[aefghklmnrstwy]|qa|r[eosuw]|s[abcdeghijklmnortuvxyz]|t[cdfghjklmnortvwz]|u[agksyz]|v[aceginu]|w[fs]|y[et]|z[amw]';

// DON'T try to make PRs with changes. Extend TLDs with LinkifyIt.tlds() instead
var tlds_default = 'biz|com|edu|gov|net|org|pro|web|xxx|aero|asia|coop|info|museum|name|shop|рф'.split('|');

/*eslint-enable max-len*/

////////////////////////////////////////////////////////////////////////////////

function resetScanCache(self) {
  self.__index__ = -1;
  self.__text_cache__   = '';
}

function createValidator(re) {
  return function (text, pos) {
    var tail = text.slice(pos);

    if (re.test(tail)) {
      return tail.match(re)[0].length;
    }
    return 0;
  };
}

function createNormalizer() {
  return function (match, self) {
    self.normalize(match);
  };
}

// Schemas compiler. Build regexps.
//
function compile(self) {

  // Load & clone RE patterns.
  var re = self.re = requireRe()(self.__opts__);

  // Define dynamic patterns
  var tlds = self.__tlds__.slice();

  self.onCompile();

  if (!self.__tlds_replaced__) {
    tlds.push(tlds_2ch_src_re);
  }
  tlds.push(re.src_xn);

  re.src_tlds = tlds.join('|');

  function untpl(tpl) { return tpl.replace('%TLDS%', re.src_tlds); }

  re.email_fuzzy      = RegExp(untpl(re.tpl_email_fuzzy), 'i');
  re.link_fuzzy       = RegExp(untpl(re.tpl_link_fuzzy), 'i');
  re.link_no_ip_fuzzy = RegExp(untpl(re.tpl_link_no_ip_fuzzy), 'i');
  re.host_fuzzy_test  = RegExp(untpl(re.tpl_host_fuzzy_test), 'i');

  //
  // Compile each schema
  //

  var aliases = [];

  self.__compiled__ = {}; // Reset compiled data

  function schemaError(name, val) {
    throw new Error('(LinkifyIt) Invalid schema "' + name + '": ' + val);
  }

  Object.keys(self.__schemas__).forEach(function (name) {
    var val = self.__schemas__[name];

    // skip disabled methods
    if (val === null) { return; }

    var compiled = { validate: null, link: null };

    self.__compiled__[name] = compiled;

    if (isObject(val)) {
      if (isRegExp(val.validate)) {
        compiled.validate = createValidator(val.validate);
      } else if (isFunction(val.validate)) {
        compiled.validate = val.validate;
      } else {
        schemaError(name, val);
      }

      if (isFunction(val.normalize)) {
        compiled.normalize = val.normalize;
      } else if (!val.normalize) {
        compiled.normalize = createNormalizer();
      } else {
        schemaError(name, val);
      }

      return;
    }

    if (isString(val)) {
      aliases.push(name);
      return;
    }

    schemaError(name, val);
  });

  //
  // Compile postponed aliases
  //

  aliases.forEach(function (alias) {
    if (!self.__compiled__[self.__schemas__[alias]]) {
      // Silently fail on missed schemas to avoid errons on disable.
      // schemaError(alias, self.__schemas__[alias]);
      return;
    }

    self.__compiled__[alias].validate =
      self.__compiled__[self.__schemas__[alias]].validate;
    self.__compiled__[alias].normalize =
      self.__compiled__[self.__schemas__[alias]].normalize;
  });

  //
  // Fake record for guessed links
  //
  self.__compiled__[''] = { validate: null, normalize: createNormalizer() };

  //
  // Build schema condition
  //
  var slist = Object.keys(self.__compiled__)
                      .filter(function (name) {
                        // Filter disabled & fake schemas
                        return name.length > 0 && self.__compiled__[name];
                      })
                      .map(escapeRE)
                      .join('|');
  // (?!_) cause 1.5x slowdown
  self.re.schema_test     = RegExp('(^|(?!_)(?:[><\uff5c]|' + re.src_ZPCc + '))(' + slist + ')', 'i');
  self.re.schema_search   = RegExp('(^|(?!_)(?:[><\uff5c]|' + re.src_ZPCc + '))(' + slist + ')', 'ig');
  self.re.schema_at_start = RegExp('^' + self.re.schema_search.source, 'i');

  self.re.pretest = RegExp(
    '(' + self.re.schema_test.source + ')|(' + self.re.host_fuzzy_test.source + ')|@',
    'i'
  );

  //
  // Cleanup
  //

  resetScanCache(self);
}

/**
 * class Match
 *
 * Match result. Single element of array, returned by [[LinkifyIt#match]]
 **/
function Match(self, shift) {
  var start = self.__index__,
      end   = self.__last_index__,
      text  = self.__text_cache__.slice(start, end);

  /**
   * Match#schema -> String
   *
   * Prefix (protocol) for matched string.
   **/
  this.schema    = self.__schema__.toLowerCase();
  /**
   * Match#index -> Number
   *
   * First position of matched string.
   **/
  this.index     = start + shift;
  /**
   * Match#lastIndex -> Number
   *
   * Next position after matched string.
   **/
  this.lastIndex = end + shift;
  /**
   * Match#raw -> String
   *
   * Matched string.
   **/
  this.raw       = text;
  /**
   * Match#text -> String
   *
   * Notmalized text of matched string.
   **/
  this.text      = text;
  /**
   * Match#url -> String
   *
   * Normalized url of matched string.
   **/
  this.url       = text;
}

function createMatch(self, shift) {
  var match = new Match(self, shift);

  self.__compiled__[match.schema].normalize(match, self);

  return match;
}


/**
 * class LinkifyIt
 **/

/**
 * new LinkifyIt(schemas, options)
 * - schemas (Object): Optional. Additional schemas to validate (prefix/validator)
 * - options (Object): { fuzzyLink|fuzzyEmail|fuzzyIP: true|false }
 *
 * Creates new linkifier instance with optional additional schemas.
 * Can be called without `new` keyword for convenience.
 *
 * By default understands:
 *
 * - `http(s)://...` , `ftp://...`, `mailto:...` & `//...` links
 * - "fuzzy" links and emails (example.com, foo@bar.com).
 *
 * `schemas` is an object, where each key/value describes protocol/rule:
 *
 * - __key__ - link prefix (usually, protocol name with `:` at the end, `skype:`
 *   for example). `linkify-it` makes shure that prefix is not preceeded with
 *   alphanumeric char and symbols. Only whitespaces and punctuation allowed.
 * - __value__ - rule to check tail after link prefix
 *   - _String_ - just alias to existing rule
 *   - _Object_
 *     - _validate_ - validator function (should return matched length on success),
 *       or `RegExp`.
 *     - _normalize_ - optional function to normalize text & url of matched result
 *       (for example, for @twitter mentions).
 *
 * `options`:
 *
 * - __fuzzyLink__ - recognige URL-s without `http(s):` prefix. Default `true`.
 * - __fuzzyIP__ - allow IPs in fuzzy links above. Can conflict with some texts
 *   like version numbers. Default `false`.
 * - __fuzzyEmail__ - recognize emails without `mailto:` prefix.
 *
 **/
function LinkifyIt$1(schemas, options) {
  if (!(this instanceof LinkifyIt$1)) {
    return new LinkifyIt$1(schemas, options);
  }

  if (!options) {
    if (isOptionsObj(schemas)) {
      options = schemas;
      schemas = {};
    }
  }

  this.__opts__           = assign({}, defaultOptions, options);

  // Cache last tested result. Used to skip repeating steps on next `match` call.
  this.__index__          = -1;
  this.__last_index__     = -1; // Next scan position
  this.__schema__         = '';
  this.__text_cache__     = '';

  this.__schemas__        = assign({}, defaultSchemas, schemas);
  this.__compiled__       = {};

  this.__tlds__           = tlds_default;
  this.__tlds_replaced__  = false;

  this.re = {};

  compile(this);
}


/** chainable
 * LinkifyIt#add(schema, definition)
 * - schema (String): rule name (fixed pattern prefix)
 * - definition (String|RegExp|Object): schema definition
 *
 * Add new rule definition. See constructor description for details.
 **/
LinkifyIt$1.prototype.add = function add(schema, definition) {
  this.__schemas__[schema] = definition;
  compile(this);
  return this;
};


/** chainable
 * LinkifyIt#set(options)
 * - options (Object): { fuzzyLink|fuzzyEmail|fuzzyIP: true|false }
 *
 * Set recognition options for links without schema.
 **/
LinkifyIt$1.prototype.set = function set(options) {
  this.__opts__ = assign(this.__opts__, options);
  return this;
};


/**
 * LinkifyIt#test(text) -> Boolean
 *
 * Searches linkifiable pattern and returns `true` on success or `false` on fail.
 **/
LinkifyIt$1.prototype.test = function test(text) {
  // Reset scan cache
  this.__text_cache__ = text;
  this.__index__      = -1;

  if (!text.length) { return false; }

  var m, ml, me, len, shift, next, re, tld_pos, at_pos;

  // try to scan for link with schema - that's the most simple rule
  if (this.re.schema_test.test(text)) {
    re = this.re.schema_search;
    re.lastIndex = 0;
    while ((m = re.exec(text)) !== null) {
      len = this.testSchemaAt(text, m[2], re.lastIndex);
      if (len) {
        this.__schema__     = m[2];
        this.__index__      = m.index + m[1].length;
        this.__last_index__ = m.index + m[0].length + len;
        break;
      }
    }
  }

  if (this.__opts__.fuzzyLink && this.__compiled__['http:']) {
    // guess schemaless links
    tld_pos = text.search(this.re.host_fuzzy_test);
    if (tld_pos >= 0) {
      // if tld is located after found link - no need to check fuzzy pattern
      if (this.__index__ < 0 || tld_pos < this.__index__) {
        if ((ml = text.match(this.__opts__.fuzzyIP ? this.re.link_fuzzy : this.re.link_no_ip_fuzzy)) !== null) {

          shift = ml.index + ml[1].length;

          if (this.__index__ < 0 || shift < this.__index__) {
            this.__schema__     = '';
            this.__index__      = shift;
            this.__last_index__ = ml.index + ml[0].length;
          }
        }
      }
    }
  }

  if (this.__opts__.fuzzyEmail && this.__compiled__['mailto:']) {
    // guess schemaless emails
    at_pos = text.indexOf('@');
    if (at_pos >= 0) {
      // We can't skip this check, because this cases are possible:
      // 192.168.1.1@gmail.com, my.in@example.com
      if ((me = text.match(this.re.email_fuzzy)) !== null) {

        shift = me.index + me[1].length;
        next  = me.index + me[0].length;

        if (this.__index__ < 0 || shift < this.__index__ ||
            (shift === this.__index__ && next > this.__last_index__)) {
          this.__schema__     = 'mailto:';
          this.__index__      = shift;
          this.__last_index__ = next;
        }
      }
    }
  }

  return this.__index__ >= 0;
};


/**
 * LinkifyIt#pretest(text) -> Boolean
 *
 * Very quick check, that can give false positives. Returns true if link MAY BE
 * can exists. Can be used for speed optimization, when you need to check that
 * link NOT exists.
 **/
LinkifyIt$1.prototype.pretest = function pretest(text) {
  return this.re.pretest.test(text);
};


/**
 * LinkifyIt#testSchemaAt(text, name, position) -> Number
 * - text (String): text to scan
 * - name (String): rule (schema) name
 * - position (Number): text offset to check from
 *
 * Similar to [[LinkifyIt#test]] but checks only specific protocol tail exactly
 * at given position. Returns length of found pattern (0 on fail).
 **/
LinkifyIt$1.prototype.testSchemaAt = function testSchemaAt(text, schema, pos) {
  // If not supported schema check requested - terminate
  if (!this.__compiled__[schema.toLowerCase()]) {
    return 0;
  }
  return this.__compiled__[schema.toLowerCase()].validate(text, pos, this);
};


/**
 * LinkifyIt#match(text) -> Array|null
 *
 * Returns array of found link descriptions or `null` on fail. We strongly
 * recommend to use [[LinkifyIt#test]] first, for best speed.
 *
 * ##### Result match description
 *
 * - __schema__ - link schema, can be empty for fuzzy links, or `//` for
 *   protocol-neutral  links.
 * - __index__ - offset of matched text
 * - __lastIndex__ - index of next char after mathch end
 * - __raw__ - matched text
 * - __text__ - normalized text
 * - __url__ - link, generated from matched text
 **/
LinkifyIt$1.prototype.match = function match(text) {
  var shift = 0, result = [];

  // Try to take previous element from cache, if .test() called before
  if (this.__index__ >= 0 && this.__text_cache__ === text) {
    result.push(createMatch(this, shift));
    shift = this.__last_index__;
  }

  // Cut head if cache was used
  var tail = shift ? text.slice(shift) : text;

  // Scan string until end reached
  while (this.test(tail)) {
    result.push(createMatch(this, shift));

    tail = tail.slice(this.__last_index__);
    shift += this.__last_index__;
  }

  if (result.length) {
    return result;
  }

  return null;
};


/**
 * LinkifyIt#matchAtStart(text) -> Match|null
 *
 * Returns fully-formed (not fuzzy) link if it starts at the beginning
 * of the string, and null otherwise.
 **/
LinkifyIt$1.prototype.matchAtStart = function matchAtStart(text) {
  // Reset scan cache
  this.__text_cache__ = text;
  this.__index__      = -1;

  if (!text.length) { return null; }

  var m = this.re.schema_at_start.exec(text);
  if (!m) { return null; }

  var len = this.testSchemaAt(text, m[2], m[0].length);
  if (!len) { return null; }

  this.__schema__     = m[2];
  this.__index__      = m.index + m[1].length;
  this.__last_index__ = m.index + m[0].length + len;

  return createMatch(this, 0);
};


/** chainable
 * LinkifyIt#tlds(list [, keepOld]) -> this
 * - list (Array): list of tlds
 * - keepOld (Boolean): merge with current list if `true` (`false` by default)
 *
 * Load (or merge) new tlds list. Those are user for fuzzy links (without prefix)
 * to avoid false positives. By default this algorythm used:
 *
 * - hostname with any 2-letter root zones are ok.
 * - biz|com|edu|gov|net|org|pro|web|xxx|aero|asia|coop|info|museum|name|shop|рф
 *   are ok.
 * - encoded (`xn--...`) root zones are ok.
 *
 * If list is replaced, then exact match for 2-chars root zones will be checked.
 **/
LinkifyIt$1.prototype.tlds = function tlds(list, keepOld) {
  list = Array.isArray(list) ? list : [ list ];

  if (!keepOld) {
    this.__tlds__ = list.slice();
    this.__tlds_replaced__ = true;
    compile(this);
    return this;
  }

  this.__tlds__ = this.__tlds__.concat(list)
                                  .sort()
                                  .filter(function (el, idx, arr) {
                                    return el !== arr[idx - 1];
                                  })
                                  .reverse();

  compile(this);
  return this;
};

/**
 * LinkifyIt#normalize(match)
 *
 * Default normalizer (if schema does not define it's own).
 **/
LinkifyIt$1.prototype.normalize = function normalize(match) {

  // Do minimal possible changes by default. Need to collect feedback prior
  // to move forward https://github.com/markdown-it/linkify-it/issues/1

  if (!match.schema) { match.url = 'http://' + match.url; }

  if (match.schema === 'mailto:' && !/^mailto:/i.test(match.url)) {
    match.url = 'mailto:' + match.url;
  }
};


/**
 * LinkifyIt#onCompile()
 *
 * Override to modify basic RegExp-s.
 **/
LinkifyIt$1.prototype.onCompile = function onCompile() {
};


var linkifyIt = LinkifyIt$1;/** Highest positive signed 32-bit float value */
var maxInt = 2147483647; // aka. 0x7FFFFFFF or 2^31-1

/** Bootstring parameters */
var base = 36;
var tMin = 1;
var tMax = 26;
var skew = 38;
var damp = 700;
var initialBias = 72;
var initialN = 128; // 0x80
var delimiter = '-'; // '\x2D'

/** Regular expressions */
var regexPunycode = /^xn--/;
var regexNonASCII = /[^\0-\x7F]/; // Note: U+007F DEL is excluded too.
var regexSeparators = /[\x2E\u3002\uFF0E\uFF61]/g; // RFC 3490 separators

/** Error messages */
var errors = {
	'overflow': 'Overflow: input needs wider integers to process',
	'not-basic': 'Illegal input >= 0x80 (not a basic code point)',
	'invalid-input': 'Invalid input'
};

/** Convenience shortcuts */
var baseMinusTMin = base - tMin;
var floor = Math.floor;
var stringFromCharCode = String.fromCharCode;

/*--------------------------------------------------------------------------*/

/**
 * A generic error utility function.
 * @private
 * @param {String} type The error type.
 * @returns {Error} Throws a `RangeError` with the applicable error message.
 */
function error(type) {
	throw new RangeError(errors[type]);
}

/**
 * A generic `Array#map` utility function.
 * @private
 * @param {Array} array The array to iterate over.
 * @param {Function} callback The function that gets called for every array
 * item.
 * @returns {Array} A new array of values returned by the callback function.
 */
function map(array, callback) {
	var result = [];
	var length = array.length;
	while (length--) {
		result[length] = callback(array[length]);
	}
	return result;
}

/**
 * A simple `Array#map`-like wrapper to work with domain name strings or email
 * addresses.
 * @private
 * @param {String} domain The domain name or email address.
 * @param {Function} callback The function that gets called for every
 * character.
 * @returns {String} A new string of characters returned by the callback
 * function.
 */
function mapDomain(domain, callback) {
	var parts = domain.split('@');
	var result = '';
	if (parts.length > 1) {
		// In email addresses, only the domain name should be punycoded. Leave
		// the local part (i.e. everything up to `@`) intact.
		result = parts[0] + '@';
		domain = parts[1];
	}
	// Avoid `split(regex)` for IE8 compatibility. See #17.
	domain = domain.replace(regexSeparators, '\x2E');
	var labels = domain.split('.');
	var encoded = map(labels, callback).join('.');
	return result + encoded;
}

/**
 * Creates an array containing the numeric code points of each Unicode
 * character in the string. While JavaScript uses UCS-2 internally,
 * this function will convert a pair of surrogate halves (each of which
 * UCS-2 exposes as separate characters) into a single code point,
 * matching UTF-16.
 * @see `punycode.ucs2.encode`
 * @see <https://mathiasbynens.be/notes/javascript-encoding>
 * @memberOf punycode.ucs2
 * @name decode
 * @param {String} string The Unicode input string (UCS-2).
 * @returns {Array} The new array of code points.
 */
function ucs2decode(string) {
	var output = [];
	var counter = 0;
	var length = string.length;
	while (counter < length) {
		var value = string.charCodeAt(counter++);
		if (value >= 0xD800 && value <= 0xDBFF && counter < length) {
			// It's a high surrogate, and there is a next character.
			var extra = string.charCodeAt(counter++);
			if ((extra & 0xFC00) == 0xDC00) { // Low surrogate.
				output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000);
			} else {
				// It's an unmatched surrogate; only append this code unit, in case the
				// next code unit is the high surrogate of a surrogate pair.
				output.push(value);
				counter--;
			}
		} else {
			output.push(value);
		}
	}
	return output;
}

/**
 * Creates a string based on an array of numeric code points.
 * @see `punycode.ucs2.decode`
 * @memberOf punycode.ucs2
 * @name encode
 * @param {Array} codePoints The array of numeric code points.
 * @returns {String} The new Unicode string (UCS-2).
 */
var ucs2encode = function (codePoints) { return String.fromCodePoint.apply(String, codePoints); };

/**
 * Converts a basic code point into a digit/integer.
 * @see `digitToBasic()`
 * @private
 * @param {Number} codePoint The basic numeric code point value.
 * @returns {Number} The numeric value of a basic code point (for use in
 * representing integers) in the range `0` to `base - 1`, or `base` if
 * the code point does not represent a value.
 */
var basicToDigit = function(codePoint) {
	if (codePoint >= 0x30 && codePoint < 0x3A) {
		return 26 + (codePoint - 0x30);
	}
	if (codePoint >= 0x41 && codePoint < 0x5B) {
		return codePoint - 0x41;
	}
	if (codePoint >= 0x61 && codePoint < 0x7B) {
		return codePoint - 0x61;
	}
	return base;
};

/**
 * Converts a digit/integer into a basic code point.
 * @see `basicToDigit()`
 * @private
 * @param {Number} digit The numeric value of a basic code point.
 * @returns {Number} The basic code point whose value (when used for
 * representing integers) is `digit`, which needs to be in the range
 * `0` to `base - 1`. If `flag` is non-zero, the uppercase form is
 * used; else, the lowercase form is used. The behavior is undefined
 * if `flag` is non-zero and `digit` has no uppercase form.
 */
var digitToBasic = function(digit, flag) {
	//  0..25 map to ASCII a..z or A..Z
	// 26..35 map to ASCII 0..9
	return digit + 22 + 75 * (digit < 26) - ((flag != 0) << 5);
};

/**
 * Bias adaptation function as per section 3.4 of RFC 3492.
 * https://tools.ietf.org/html/rfc3492#section-3.4
 * @private
 */
var adapt = function(delta, numPoints, firstTime) {
	var k = 0;
	delta = firstTime ? floor(delta / damp) : delta >> 1;
	delta += floor(delta / numPoints);
	for (/* no initialization */; delta > baseMinusTMin * tMax >> 1; k += base) {
		delta = floor(delta / baseMinusTMin);
	}
	return floor(k + (baseMinusTMin + 1) * delta / (delta + skew));
};

/**
 * Converts a Punycode string of ASCII-only symbols to a string of Unicode
 * symbols.
 * @memberOf punycode
 * @param {String} input The Punycode string of ASCII-only symbols.
 * @returns {String} The resulting string of Unicode symbols.
 */
var decode = function(input) {
	// Don't use UCS-2.
	var output = [];
	var inputLength = input.length;
	var i = 0;
	var n = initialN;
	var bias = initialBias;

	// Handle the basic code points: let `basic` be the number of input code
	// points before the last delimiter, or `0` if there is none, then copy
	// the first basic code points to the output.

	var basic = input.lastIndexOf(delimiter);
	if (basic < 0) {
		basic = 0;
	}

	for (var j = 0; j < basic; ++j) {
		// if it's not a basic code point
		if (input.charCodeAt(j) >= 0x80) {
			error('not-basic');
		}
		output.push(input.charCodeAt(j));
	}

	// Main decoding loop: start just after the last delimiter if any basic code
	// points were copied; start at the beginning otherwise.

	for (var index = basic > 0 ? basic + 1 : 0; index < inputLength; /* no final expression */) {

		// `index` is the index of the next character to be consumed.
		// Decode a generalized variable-length integer into `delta`,
		// which gets added to `i`. The overflow checking is easier
		// if we increase `i` as we go, then subtract off its starting
		// value at the end to obtain `delta`.
		var oldi = i;
		for (var w = 1, k = base; /* no condition */; k += base) {

			if (index >= inputLength) {
				error('invalid-input');
			}

			var digit = basicToDigit(input.charCodeAt(index++));

			if (digit >= base) {
				error('invalid-input');
			}
			if (digit > floor((maxInt - i) / w)) {
				error('overflow');
			}

			i += digit * w;
			var t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);

			if (digit < t) {
				break;
			}

			var baseMinusT = base - t;
			if (w > floor(maxInt / baseMinusT)) {
				error('overflow');
			}

			w *= baseMinusT;

		}

		var out = output.length + 1;
		bias = adapt(i - oldi, out, oldi == 0);

		// `i` was supposed to wrap around from `out` to `0`,
		// incrementing `n` each time, so we'll fix that now:
		if (floor(i / out) > maxInt - n) {
			error('overflow');
		}

		n += floor(i / out);
		i %= out;

		// Insert `n` at position `i` of the output.
		output.splice(i++, 0, n);

	}

	return String.fromCodePoint.apply(String, output);
};

/**
 * Converts a string of Unicode symbols (e.g. a domain name label) to a
 * Punycode string of ASCII-only symbols.
 * @memberOf punycode
 * @param {String} input The string of Unicode symbols.
 * @returns {String} The resulting Punycode string of ASCII-only symbols.
 */
var encode = function(input) {
	var output = [];

	// Convert the input in UCS-2 to an array of Unicode code points.
	input = ucs2decode(input);

	// Cache the length.
	var inputLength = input.length;

	// Initialize the state.
	var n = initialN;
	var delta = 0;
	var bias = initialBias;

	// Handle the basic code points.
	for (var currentValue of input) {
		if (currentValue < 0x80) {
			output.push(stringFromCharCode(currentValue));
		}
	}

	var basicLength = output.length;
	var handledCPCount = basicLength;

	// `handledCPCount` is the number of code points that have been handled;
	// `basicLength` is the number of basic code points.

	// Finish the basic string with a delimiter unless it's empty.
	if (basicLength) {
		output.push(delimiter);
	}

	// Main encoding loop:
	while (handledCPCount < inputLength) {

		// All non-basic code points < n have been handled already. Find the next
		// larger one:
		var m = maxInt;
		for (var currentValue$1 of input) {
			if (currentValue$1 >= n && currentValue$1 < m) {
				m = currentValue$1;
			}
		}

		// Increase `delta` enough to advance the decoder's <n,i> state to <m,0>,
		// but guard against overflow.
		var handledCPCountPlusOne = handledCPCount + 1;
		if (m - n > floor((maxInt - delta) / handledCPCountPlusOne)) {
			error('overflow');
		}

		delta += (m - n) * handledCPCountPlusOne;
		n = m;

		for (var currentValue$2 of input) {
			if (currentValue$2 < n && ++delta > maxInt) {
				error('overflow');
			}
			if (currentValue$2 === n) {
				// Represent delta as a generalized variable-length integer.
				var q = delta;
				for (var k = base; /* no condition */; k += base) {
					var t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);
					if (q < t) {
						break;
					}
					var qMinusT = q - t;
					var baseMinusT = base - t;
					output.push(
						stringFromCharCode(digitToBasic(t + qMinusT % baseMinusT, 0))
					);
					q = floor(qMinusT / baseMinusT);
				}

				output.push(stringFromCharCode(digitToBasic(q, 0)));
				bias = adapt(delta, handledCPCountPlusOne, handledCPCount === basicLength);
				delta = 0;
				++handledCPCount;
			}
		}

		++delta;
		++n;

	}
	return output.join('');
};

/**
 * Converts a Punycode string representing a domain name or an email address
 * to Unicode. Only the Punycoded parts of the input will be converted, i.e.
 * it doesn't matter if you call it on a string that has already been
 * converted to Unicode.
 * @memberOf punycode
 * @param {String} input The Punycoded domain name or email address to
 * convert to Unicode.
 * @returns {String} The Unicode representation of the given Punycode
 * string.
 */
var toUnicode = function(input) {
	return mapDomain(input, function(string) {
		return regexPunycode.test(string)
			? decode(string.slice(4).toLowerCase())
			: string;
	});
};

/**
 * Converts a Unicode string representing a domain name or an email address to
 * Punycode. Only the non-ASCII parts of the domain name will be converted,
 * i.e. it doesn't matter if you call it with a domain that's already in
 * ASCII.
 * @memberOf punycode
 * @param {String} input The domain name or email address to convert, as a
 * Unicode string.
 * @returns {String} The Punycode representation of the given domain name or
 * email address.
 */
var toASCII = function(input) {
	return mapDomain(input, function(string) {
		return regexNonASCII.test(string)
			? 'xn--' + encode(string)
			: string;
	});
};

/*--------------------------------------------------------------------------*/

/** Define the public API */
var punycode$1 = {
	/**
	 * A string representing the current Punycode.js version number.
	 * @memberOf punycode
	 * @type String
	 */
	'version': '2.3.1',
	/**
	 * An object of methods to convert from JavaScript's internal character
	 * representation (UCS-2) to Unicode code points, and back.
	 * @see <https://mathiasbynens.be/notes/javascript-encoding>
	 * @memberOf punycode
	 * @type Object
	 */
	'ucs2': {
		'decode': ucs2decode,
		'encode': ucs2encode
	},
	'decode': decode,
	'encode': encode,
	'toASCII': toASCII,
	'toUnicode': toUnicode
};var punycode_es6=/*#__PURE__*/Object.freeze({__proto__:null,decode:decode,default:punycode$1,encode:encode,toASCII:toASCII,toUnicode:toUnicode,ucs2decode:ucs2decode,ucs2encode:ucs2encode});var require$$8 = /*@__PURE__*/getAugmentedNamespace(punycode_es6);var _default = {
  options: {
    html:         false,        // Enable HTML tags in source
    xhtmlOut:     false,        // Use '/' to close single tags (<br />)
    breaks:       false,        // Convert '\n' in paragraphs into <br>
    langPrefix:   'language-',  // CSS language prefix for fenced blocks
    linkify:      false,        // autoconvert URL-like texts to links

    // Enable some language-neutral replacements + quotes beautification
    typographer:  false,

    // Double + single quotes replacement pairs, when typographer enabled,
    // and smartquotes on. Could be either a String or an Array.
    //
    // For example, you can use '«»„“' for Russian, '„“‚‘' for German,
    // and ['«\xA0', '\xA0»', '‹\xA0', '\xA0›'] for French (including nbsp).
    quotes: '\u201c\u201d\u2018\u2019', /* “”‘’ */

    // Highlighter function. Should return escaped HTML,
    // or '' if the source string is not changed and should be escaped externaly.
    // If result starts with <pre... internal wrapper is skipped.
    //
    // function (/*str, lang*/) { return ''; }
    //
    highlight: null,

    maxNesting:   100            // Internal protection, recursion limit
  },

  components: {

    core: {},
    block: {},
    inline: {}
  }
};var zero = {
  options: {
    html:         false,        // Enable HTML tags in source
    xhtmlOut:     false,        // Use '/' to close single tags (<br />)
    breaks:       false,        // Convert '\n' in paragraphs into <br>
    langPrefix:   'language-',  // CSS language prefix for fenced blocks
    linkify:      false,        // autoconvert URL-like texts to links

    // Enable some language-neutral replacements + quotes beautification
    typographer:  false,

    // Double + single quotes replacement pairs, when typographer enabled,
    // and smartquotes on. Could be either a String or an Array.
    //
    // For example, you can use '«»„“' for Russian, '„“‚‘' for German,
    // and ['«\xA0', '\xA0»', '‹\xA0', '\xA0›'] for French (including nbsp).
    quotes: '\u201c\u201d\u2018\u2019', /* “”‘’ */

    // Highlighter function. Should return escaped HTML,
    // or '' if the source string is not changed and should be escaped externaly.
    // If result starts with <pre... internal wrapper is skipped.
    //
    // function (/*str, lang*/) { return ''; }
    //
    highlight: null,

    maxNesting:   20            // Internal protection, recursion limit
  },

  components: {

    core: {
      rules: [
        'normalize',
        'block',
        'inline',
        'text_join'
      ]
    },

    block: {
      rules: [
        'paragraph'
      ]
    },

    inline: {
      rules: [
        'text'
      ],
      rules2: [
        'balance_pairs',
        'fragments_join'
      ]
    }
  }
};var commonmark = {
  options: {
    html:         true,         // Enable HTML tags in source
    xhtmlOut:     true,         // Use '/' to close single tags (<br />)
    breaks:       false,        // Convert '\n' in paragraphs into <br>
    langPrefix:   'language-',  // CSS language prefix for fenced blocks
    linkify:      false,        // autoconvert URL-like texts to links

    // Enable some language-neutral replacements + quotes beautification
    typographer:  false,

    // Double + single quotes replacement pairs, when typographer enabled,
    // and smartquotes on. Could be either a String or an Array.
    //
    // For example, you can use '«»„“' for Russian, '„“‚‘' for German,
    // and ['«\xA0', '\xA0»', '‹\xA0', '\xA0›'] for French (including nbsp).
    quotes: '\u201c\u201d\u2018\u2019', /* “”‘’ */

    // Highlighter function. Should return escaped HTML,
    // or '' if the source string is not changed and should be escaped externaly.
    // If result starts with <pre... internal wrapper is skipped.
    //
    // function (/*str, lang*/) { return ''; }
    //
    highlight: null,

    maxNesting:   20            // Internal protection, recursion limit
  },

  components: {

    core: {
      rules: [
        'normalize',
        'block',
        'inline',
        'text_join'
      ]
    },

    block: {
      rules: [
        'blockquote',
        'code',
        'fence',
        'heading',
        'hr',
        'html_block',
        'lheading',
        'list',
        'reference',
        'paragraph'
      ]
    },

    inline: {
      rules: [
        'autolink',
        'backticks',
        'emphasis',
        'entity',
        'escape',
        'html_inline',
        'image',
        'link',
        'newline',
        'text'
      ],
      rules2: [
        'balance_pairs',
        'emphasis',
        'fragments_join'
      ]
    }
  }
};var utils        = utils$1;
var helpers      = helpers$1;
var Renderer     = renderer;
var ParserCore   = parser_core;
var ParserBlock  = parser_block;
var ParserInline = parser_inline;
var LinkifyIt    = linkifyIt;
var mdurl        = mdurl$1;
var punycode     = require$$8;


var config = {
  default: _default,
  zero: zero,
  commonmark: commonmark
};

////////////////////////////////////////////////////////////////////////////////
//
// This validator can prohibit more than really needed to prevent XSS. It's a
// tradeoff to keep code simple and to be secure by default.
//
// If you need different setup - override validator method as you wish. Or
// replace it with dummy function and use external sanitizer.
//

var BAD_PROTO_RE = /^(vbscript|javascript|file|data):/;
var GOOD_DATA_RE = /^data:image\/(gif|png|jpeg|webp);/;

function validateLink(url) {
  // url should be normalized at this point, and existing entities are decoded
  var str = url.trim().toLowerCase();

  return BAD_PROTO_RE.test(str) ? (GOOD_DATA_RE.test(str) ? true : false) : true;
}

////////////////////////////////////////////////////////////////////////////////


var RECODE_HOSTNAME_FOR = [ 'http:', 'https:', 'mailto:' ];

function normalizeLink(url) {
  var parsed = mdurl.parse(url, true);

  if (parsed.hostname) {
    // Encode hostnames in urls like:
    // `http://host/`, `https://host/`, `mailto:user@host`, `//host/`
    //
    // We don't encode unknown schemas, because it's likely that we encode
    // something we shouldn't (e.g. `skype:name` treated as `skype:host`)
    //
    if (!parsed.protocol || RECODE_HOSTNAME_FOR.indexOf(parsed.protocol) >= 0) {
      try {
        parsed.hostname = punycode.toASCII(parsed.hostname);
      } catch (er) { /**/ }
    }
  }

  return mdurl.encode(mdurl.format(parsed));
}

function normalizeLinkText(url) {
  var parsed = mdurl.parse(url, true);

  if (parsed.hostname) {
    // Encode hostnames in urls like:
    // `http://host/`, `https://host/`, `mailto:user@host`, `//host/`
    //
    // We don't encode unknown schemas, because it's likely that we encode
    // something we shouldn't (e.g. `skype:name` treated as `skype:host`)
    //
    if (!parsed.protocol || RECODE_HOSTNAME_FOR.indexOf(parsed.protocol) >= 0) {
      try {
        parsed.hostname = punycode.toUnicode(parsed.hostname);
      } catch (er) { /**/ }
    }
  }

  // add '%' to exclude list because of https://github.com/markdown-it/markdown-it/issues/720
  return mdurl.decode(mdurl.format(parsed), mdurl.decode.defaultChars + '%');
}


/**
 * class MarkdownIt
 *
 * Main parser/renderer class.
 *
 * ##### Usage
 *
 * ```javascript
 * // node.js, "classic" way:
 * var MarkdownIt = require('markdown-it'),
 *     md = new MarkdownIt();
 * var result = md.render('# markdown-it rulezz!');
 *
 * // node.js, the same, but with sugar:
 * var md = require('markdown-it')();
 * var result = md.render('# markdown-it rulezz!');
 *
 * // browser without AMD, added to "window" on script load
 * // Note, there are no dash.
 * var md = window.markdownit();
 * var result = md.render('# markdown-it rulezz!');
 * ```
 *
 * Single line rendering, without paragraph wrap:
 *
 * ```javascript
 * var md = require('markdown-it')();
 * var result = md.renderInline('__markdown-it__ rulezz!');
 * ```
 **/

/**
 * new MarkdownIt([presetName, options])
 * - presetName (String): optional, `commonmark` / `zero`
 * - options (Object)
 *
 * Creates parser instanse with given config. Can be called without `new`.
 *
 * ##### presetName
 *
 * MarkdownIt provides named presets as a convenience to quickly
 * enable/disable active syntax rules and options for common use cases.
 *
 * - ["commonmark"](https://github.com/markdown-it/markdown-it/blob/master/lib/presets/commonmark.js) -
 *   configures parser to strict [CommonMark](http://commonmark.org/) mode.
 * - [default](https://github.com/markdown-it/markdown-it/blob/master/lib/presets/default.js) -
 *   similar to GFM, used when no preset name given. Enables all available rules,
 *   but still without html, typographer & autolinker.
 * - ["zero"](https://github.com/markdown-it/markdown-it/blob/master/lib/presets/zero.js) -
 *   all rules disabled. Useful to quickly setup your config via `.enable()`.
 *   For example, when you need only `bold` and `italic` markup and nothing else.
 *
 * ##### options:
 *
 * - __html__ - `false`. Set `true` to enable HTML tags in source. Be careful!
 *   That's not safe! You may need external sanitizer to protect output from XSS.
 *   It's better to extend features via plugins, instead of enabling HTML.
 * - __xhtmlOut__ - `false`. Set `true` to add '/' when closing single tags
 *   (`<br />`). This is needed only for full CommonMark compatibility. In real
 *   world you will need HTML output.
 * - __breaks__ - `false`. Set `true` to convert `\n` in paragraphs into `<br>`.
 * - __langPrefix__ - `language-`. CSS language class prefix for fenced blocks.
 *   Can be useful for external highlighters.
 * - __linkify__ - `false`. Set `true` to autoconvert URL-like text to links.
 * - __typographer__  - `false`. Set `true` to enable [some language-neutral
 *   replacement](https://github.com/markdown-it/markdown-it/blob/master/lib/rules_core/replacements.js) +
 *   quotes beautification (smartquotes).
 * - __quotes__ - `“”‘’`, String or Array. Double + single quotes replacement
 *   pairs, when typographer enabled and smartquotes on. For example, you can
 *   use `'«»„“'` for Russian, `'„“‚‘'` for German, and
 *   `['«\xA0', '\xA0»', '‹\xA0', '\xA0›']` for French (including nbsp).
 * - __highlight__ - `null`. Highlighter function for fenced code blocks.
 *   Highlighter `function (str, lang)` should return escaped HTML. It can also
 *   return empty string if the source was not changed and should be escaped
 *   externaly. If result starts with <pre... internal wrapper is skipped.
 *
 * ##### Example
 *
 * ```javascript
 * // commonmark mode
 * var md = require('markdown-it')('commonmark');
 *
 * // default mode
 * var md = require('markdown-it')();
 *
 * // enable everything
 * var md = require('markdown-it')({
 *   html: true,
 *   linkify: true,
 *   typographer: true
 * });
 * ```
 *
 * ##### Syntax highlighting
 *
 * ```js
 * var hljs = require('highlight.js') // https://highlightjs.org/
 *
 * var md = require('markdown-it')({
 *   highlight: function (str, lang) {
 *     if (lang && hljs.getLanguage(lang)) {
 *       try {
 *         return hljs.highlight(str, { language: lang, ignoreIllegals: true }).value;
 *       } catch (__) {}
 *     }
 *
 *     return ''; // use external default escaping
 *   }
 * });
 * ```
 *
 * Or with full wrapper override (if you need assign class to `<pre>`):
 *
 * ```javascript
 * var hljs = require('highlight.js') // https://highlightjs.org/
 *
 * // Actual default values
 * var md = require('markdown-it')({
 *   highlight: function (str, lang) {
 *     if (lang && hljs.getLanguage(lang)) {
 *       try {
 *         return '<pre class="hljs"><code>' +
 *                hljs.highlight(str, { language: lang, ignoreIllegals: true }).value +
 *                '</code></pre>';
 *       } catch (__) {}
 *     }
 *
 *     return '<pre class="hljs"><code>' + md.utils.escapeHtml(str) + '</code></pre>';
 *   }
 * });
 * ```
 *
 **/
function MarkdownIt(presetName, options) {
  if (!(this instanceof MarkdownIt)) {
    return new MarkdownIt(presetName, options);
  }

  if (!options) {
    if (!utils.isString(presetName)) {
      options = presetName || {};
      presetName = 'default';
    }
  }

  /**
   * MarkdownIt#inline -> ParserInline
   *
   * Instance of [[ParserInline]]. You may need it to add new rules when
   * writing plugins. For simple rules control use [[MarkdownIt.disable]] and
   * [[MarkdownIt.enable]].
   **/
  this.inline = new ParserInline();

  /**
   * MarkdownIt#block -> ParserBlock
   *
   * Instance of [[ParserBlock]]. You may need it to add new rules when
   * writing plugins. For simple rules control use [[MarkdownIt.disable]] and
   * [[MarkdownIt.enable]].
   **/
  this.block = new ParserBlock();

  /**
   * MarkdownIt#core -> Core
   *
   * Instance of [[Core]] chain executor. You may need it to add new rules when
   * writing plugins. For simple rules control use [[MarkdownIt.disable]] and
   * [[MarkdownIt.enable]].
   **/
  this.core = new ParserCore();

  /**
   * MarkdownIt#renderer -> Renderer
   *
   * Instance of [[Renderer]]. Use it to modify output look. Or to add rendering
   * rules for new token types, generated by plugins.
   *
   * ##### Example
   *
   * ```javascript
   * var md = require('markdown-it')();
   *
   * function myToken(tokens, idx, options, env, self) {
   *   //...
   *   return result;
   * };
   *
   * md.renderer.rules['my_token'] = myToken
   * ```
   *
   * See [[Renderer]] docs and [source code](https://github.com/markdown-it/markdown-it/blob/master/lib/renderer.js).
   **/
  this.renderer = new Renderer();

  /**
   * MarkdownIt#linkify -> LinkifyIt
   *
   * [linkify-it](https://github.com/markdown-it/linkify-it) instance.
   * Used by [linkify](https://github.com/markdown-it/markdown-it/blob/master/lib/rules_core/linkify.js)
   * rule.
   **/
  this.linkify = new LinkifyIt();

  /**
   * MarkdownIt#validateLink(url) -> Boolean
   *
   * Link validation function. CommonMark allows too much in links. By default
   * we disable `javascript:`, `vbscript:`, `file:` schemas, and almost all `data:...` schemas
   * except some embedded image types.
   *
   * You can change this behaviour:
   *
   * ```javascript
   * var md = require('markdown-it')();
   * // enable everything
   * md.validateLink = function () { return true; }
   * ```
   **/
  this.validateLink = validateLink;

  /**
   * MarkdownIt#normalizeLink(url) -> String
   *
   * Function used to encode link url to a machine-readable format,
   * which includes url-encoding, punycode, etc.
   **/
  this.normalizeLink = normalizeLink;

  /**
   * MarkdownIt#normalizeLinkText(url) -> String
   *
   * Function used to decode link url to a human-readable format`
   **/
  this.normalizeLinkText = normalizeLinkText;


  // Expose utils & helpers for easy acces from plugins

  /**
   * MarkdownIt#utils -> utils
   *
   * Assorted utility functions, useful to write plugins. See details
   * [here](https://github.com/markdown-it/markdown-it/blob/master/lib/common/utils.js).
   **/
  this.utils = utils;

  /**
   * MarkdownIt#helpers -> helpers
   *
   * Link components parser functions, useful to write plugins. See details
   * [here](https://github.com/markdown-it/markdown-it/blob/master/lib/helpers).
   **/
  this.helpers = utils.assign({}, helpers);


  this.options = {};
  this.configure(presetName);

  if (options) { this.set(options); }
}


/** chainable
 * MarkdownIt.set(options)
 *
 * Set parser options (in the same format as in constructor). Probably, you
 * will never need it, but you can change options after constructor call.
 *
 * ##### Example
 *
 * ```javascript
 * var md = require('markdown-it')()
 *             .set({ html: true, breaks: true })
 *             .set({ typographer, true });
 * ```
 *
 * __Note:__ To achieve the best possible performance, don't modify a
 * `markdown-it` instance options on the fly. If you need multiple configurations
 * it's best to create multiple instances and initialize each with separate
 * config.
 **/
MarkdownIt.prototype.set = function (options) {
  utils.assign(this.options, options);
  return this;
};


/** chainable, internal
 * MarkdownIt.configure(presets)
 *
 * Batch load of all options and compenent settings. This is internal method,
 * and you probably will not need it. But if you will - see available presets
 * and data structure [here](https://github.com/markdown-it/markdown-it/tree/master/lib/presets)
 *
 * We strongly recommend to use presets instead of direct config loads. That
 * will give better compatibility with next versions.
 **/
MarkdownIt.prototype.configure = function (presets) {
  var self = this, presetName;

  if (utils.isString(presets)) {
    presetName = presets;
    presets = config[presetName];
    if (!presets) { throw new Error('Wrong `markdown-it` preset "' + presetName + '", check name'); }
  }

  if (!presets) { throw new Error('Wrong `markdown-it` preset, can\'t be empty'); }

  if (presets.options) { self.set(presets.options); }

  if (presets.components) {
    Object.keys(presets.components).forEach(function (name) {
      if (presets.components[name].rules) {
        self[name].ruler.enableOnly(presets.components[name].rules);
      }
      if (presets.components[name].rules2) {
        self[name].ruler2.enableOnly(presets.components[name].rules2);
      }
    });
  }
  return this;
};


/** chainable
 * MarkdownIt.enable(list, ignoreInvalid)
 * - list (String|Array): rule name or list of rule names to enable
 * - ignoreInvalid (Boolean): set `true` to ignore errors when rule not found.
 *
 * Enable list or rules. It will automatically find appropriate components,
 * containing rules with given names. If rule not found, and `ignoreInvalid`
 * not set - throws exception.
 *
 * ##### Example
 *
 * ```javascript
 * var md = require('markdown-it')()
 *             .enable(['sub', 'sup'])
 *             .disable('smartquotes');
 * ```
 **/
MarkdownIt.prototype.enable = function (list, ignoreInvalid) {
  var result = [];

  if (!Array.isArray(list)) { list = [ list ]; }

  [ 'core', 'block', 'inline' ].forEach(function (chain) {
    result = result.concat(this[chain].ruler.enable(list, true));
  }, this);

  result = result.concat(this.inline.ruler2.enable(list, true));

  var missed = list.filter(function (name) { return result.indexOf(name) < 0; });

  if (missed.length && !ignoreInvalid) {
    throw new Error('MarkdownIt. Failed to enable unknown rule(s): ' + missed);
  }

  return this;
};


/** chainable
 * MarkdownIt.disable(list, ignoreInvalid)
 * - list (String|Array): rule name or list of rule names to disable.
 * - ignoreInvalid (Boolean): set `true` to ignore errors when rule not found.
 *
 * The same as [[MarkdownIt.enable]], but turn specified rules off.
 **/
MarkdownIt.prototype.disable = function (list, ignoreInvalid) {
  var result = [];

  if (!Array.isArray(list)) { list = [ list ]; }

  [ 'core', 'block', 'inline' ].forEach(function (chain) {
    result = result.concat(this[chain].ruler.disable(list, true));
  }, this);

  result = result.concat(this.inline.ruler2.disable(list, true));

  var missed = list.filter(function (name) { return result.indexOf(name) < 0; });

  if (missed.length && !ignoreInvalid) {
    throw new Error('MarkdownIt. Failed to disable unknown rule(s): ' + missed);
  }
  return this;
};


/** chainable
 * MarkdownIt.use(plugin, params)
 *
 * Load specified plugin with given params into current parser instance.
 * It's just a sugar to call `plugin(md, params)` with curring.
 *
 * ##### Example
 *
 * ```javascript
 * var iterator = require('markdown-it-for-inline');
 * var md = require('markdown-it')()
 *             .use(iterator, 'foo_replace', 'text', function (tokens, idx) {
 *               tokens[idx].content = tokens[idx].content.replace(/foo/g, 'bar');
 *             });
 * ```
 **/
MarkdownIt.prototype.use = function (plugin /*, params, ... */) {
  var args = [ this ].concat(Array.prototype.slice.call(arguments, 1));
  plugin.apply(plugin, args);
  return this;
};


/** internal
 * MarkdownIt.parse(src, env) -> Array
 * - src (String): source string
 * - env (Object): environment sandbox
 *
 * Parse input string and return list of block tokens (special token type
 * "inline" will contain list of inline tokens). You should not call this
 * method directly, until you write custom renderer (for example, to produce
 * AST).
 *
 * `env` is used to pass data between "distributed" rules and return additional
 * metadata like reference info, needed for the renderer. It also can be used to
 * inject data in specific cases. Usually, you will be ok to pass `{}`,
 * and then pass updated object to renderer.
 **/
MarkdownIt.prototype.parse = function (src, env) {
  if (typeof src !== 'string') {
    throw new Error('Input data should be a String');
  }

  var state = new this.core.State(src, this, env);

  this.core.process(state);

  return state.tokens;
};


/**
 * MarkdownIt.render(src [, env]) -> String
 * - src (String): source string
 * - env (Object): environment sandbox
 *
 * Render markdown string into html. It does all magic for you :).
 *
 * `env` can be used to inject additional metadata (`{}` by default).
 * But you will not need it with high probability. See also comment
 * in [[MarkdownIt.parse]].
 **/
MarkdownIt.prototype.render = function (src, env) {
  env = env || {};

  return this.renderer.render(this.parse(src, env), this.options, env);
};


/** internal
 * MarkdownIt.parseInline(src, env) -> Array
 * - src (String): source string
 * - env (Object): environment sandbox
 *
 * The same as [[MarkdownIt.parse]] but skip all block rules. It returns the
 * block tokens list with the single `inline` element, containing parsed inline
 * tokens in `children` property. Also updates `env` object.
 **/
MarkdownIt.prototype.parseInline = function (src, env) {
  var state = new this.core.State(src, this, env);

  state.inlineMode = true;
  this.core.process(state);

  return state.tokens;
};


/**
 * MarkdownIt.renderInline(src [, env]) -> String
 * - src (String): source string
 * - env (Object): environment sandbox
 *
 * Similar to [[MarkdownIt.render]] but for single paragraph content. Result
 * will NOT be wrapped into `<p>` tags.
 **/
MarkdownIt.prototype.renderInline = function (src, env) {
  env = env || {};

  return this.renderer.render(this.parseInline(src, env), this.options, env);
};


var lib = MarkdownIt;var markdownIt = lib;

var markdownit = /*@__PURE__*/getDefaultExportFromCjs(markdownIt);var inst$1 = new markdownit();
var isSpace$2 = inst$1.utils.isSpace;

function htmlBreak(state, silent) {
    var max = state.posMax;
    var start  = state.pos;
    var pos = state.pos;

    if (silent) { return false; } // don't run any pairs in validation mode
    //if (state.src.charCodeAt(start) !== 0x3c/* < */) { return false; }
    if (state.src.substr(start, 4) !== '<br>') { return false; }

    state.push('hardbreak', 'br', 0);

    pos = pos + 4;

    // skip heading spaces for next line
    while (pos < max && isSpace$2(state.src.charCodeAt(pos))) {
        pos++;
    }

    state.pos = pos;
    return true;
}/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 *
 */

var hard_break = {
    id: 'hard_break',
    schema: schema$g,
    registerMarkdownIt: function (markdownIt) {
        markdownIt.inline.ruler.before('newline','htmlbreak', htmlBreak);
    }
};var schema$f = {
    nodes: {
        heading: {
            attrs: {level: {default: 1}},
            content: "inline*",
            group: "block",
            defining: true,
            parseDOM: [
                {tag: "h1", attrs: {level: 1}},
                {tag: "h2", attrs: {level: 2}},
                {tag: "h3", attrs: {level: 3}},
                {tag: "h4", attrs: {level: 4}},
                {tag: "h5", attrs: {level: 5}},
                {tag: "h6", attrs: {level: 6}}
            ],
            toDOM: function (node) {
                return ["h" + node.attrs.level, 0];
            },
            parseMarkdown: {
                block: "heading",
                getAttrs: function (tok) {
                    return ({level: +tok.tag.slice(1)});
                }
            },
            toMarkdown: function (state, node) {
                state.write(state.repeat("#", node.attrs.level) + " ");
                state.renderInline(node);
                state.closeBlock(node);
            }
        }
    }
};/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 */


// : (NodeType) → InputRule
// Given a blockquote node type, returns an input rule that turns `"> "`
// at the start of a textblock into a blockquote.
var headingRule = function (schema) {
    var maxLevel = 6;
    return textblockTypeInputRule(
        new RegExp("^(#{1," + maxLevel + "})\\s$"),
        schema.nodes.heading,
        function (match) { return ({level: match[1].length}); }
    );
};/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 */


function makeHeading(context, i) {
    return blockTypeItem(context.schema.nodes.heading, {
        id: 'makeHeading' + i,
        attrs: {level: i},
        label: ((context.translate('Heading')) + " " + i),
        title: ((context.translate("Change to heading")) + " " + i + " (" + (Array(i + 1).join("#")) + ")"),
    });
}

function menu$d(context) {
    var headers = [];

    for (var i = 1; i <= 4; i++) {
        headers.push({
            node: 'heading',
            group: 'types',
            sortOrder: 100 + i,
            item: makeHeading(context, i)
        });
    }

    return headers;
}/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 */

var heading = {
    id: 'heading',
    schema: schema$f,
    menu: function (context) { return menu$d(context); },
    inputRules: function (schema) {return [headingRule(schema)]}
};/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2018 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 *
 */


function menu$c(context) {
    return [
        {
            id: 'undo',
            group: 'helper',
            item: undoItem()
        },
        {
            id: 'redo',
            group: 'helper',
            item: redoItem()
        } ]
}/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2018 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 *
 */

var historyPlugin = {
    id: 'history',
    menu: function (context) { return menu$c(); },
    plugins: function (context) {
        return [
            history()
        ]
    }
};/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 */

var schema$e = {
    nodes: {
        horizontal_rule: {
            sortOrder: 300,
            group: "block",
            parseDOM: [{tag: "hr"}],
            toDOM: function () {
                return ["div", ["hr"]]
            },
            parseMarkdown: {hr: {node: "horizontal_rule"}},
            toMarkdown: function (state, node) {
                state.write(node.attrs.markup || "---");
                state.closeBlock(node);
            }
        }
    }
};/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 *
 */

var horizontal_rule = {
    id: 'horizontal_rule',
    schema: schema$e,
    // menu: (context) => menu(context)
};var FLOAT_NONE = 0;
var FLOAT_LEFT = 1;
var FLOAT_CENTER = 2;
var FLOAT_RIGHT = 3;

var FLOAT_ALT_EXT_NONE = '';
var FLOAT_ALT_EXT_LEFT = '<';
var FLOAT_ALT_EXT_CENTER = '><';
var FLOAT_ALT_EXT_RIGHT = '>';

var FLOAT_MAP = [
    FLOAT_ALT_EXT_NONE,
    FLOAT_ALT_EXT_LEFT,
    FLOAT_ALT_EXT_CENTER,
    FLOAT_ALT_EXT_RIGHT
];

function getAltExtensionByFloat(float) {
    return FLOAT_MAP[parseInt(float)] || FLOAT_ALT_EXT_NONE;
}

function parseFloatFromAlt(alt) {
    var float = FLOAT_NONE;
    var ext = FLOAT_ALT_EXT_NONE;

    if (!alt) {
        return {
            alt: alt,
            float: float,
            ext: ext
        };
    }

    if (endsWith$3(alt, FLOAT_ALT_EXT_CENTER)) {
        alt = alt.substring(0, alt.length - 2);
        ext = FLOAT_ALT_EXT_CENTER;
        float = FLOAT_CENTER;
    } else if (endsWith$3(alt, FLOAT_ALT_EXT_LEFT)) {
        alt = alt.substring(0, alt.length - 1);
        ext = FLOAT_ALT_EXT_LEFT;
        float = FLOAT_LEFT;
    } else if (endsWith$3(alt, FLOAT_ALT_EXT_RIGHT)) {
        alt = alt.substring(0, alt.length - 1);
        ext = FLOAT_ALT_EXT_RIGHT;
        float = FLOAT_RIGHT;
    }

    return {
        alt: alt,
        ext: ext,
        float: float
    };
}

function getClassForFloat(float) {
    float = parseInt(float);
    switch (float) {
        case FLOAT_LEFT:
            return 'float-start';
        case FLOAT_CENTER:
            return 'd-block mx-auto';
        case FLOAT_RIGHT:
            return 'float-end';
        default:
            return '';
    }
}

var endsWith$3 = function (string, suffix) {
    return string.indexOf(suffix, string.length - suffix.length) !== -1;
};var imageFloat$1=/*#__PURE__*/Object.freeze({__proto__:null,FLOAT_ALT_EXT_CENTER:FLOAT_ALT_EXT_CENTER,FLOAT_ALT_EXT_LEFT:FLOAT_ALT_EXT_LEFT,FLOAT_ALT_EXT_NONE:FLOAT_ALT_EXT_NONE,FLOAT_ALT_EXT_RIGHT:FLOAT_ALT_EXT_RIGHT,FLOAT_CENTER:FLOAT_CENTER,FLOAT_LEFT:FLOAT_LEFT,FLOAT_MAP:FLOAT_MAP,FLOAT_NONE:FLOAT_NONE,FLOAT_RIGHT:FLOAT_RIGHT,getAltExtensionByFloat:getAltExtensionByFloat,getClassForFloat:getClassForFloat,parseFloatFromAlt:parseFloatFromAlt});var DEFAULT_LINK_REL = 'noopener noreferrer nofollow';

function validateHref(href, cfg) {
    cfg = cfg || {};

    return /^https?:\/\//i.test(href) //http:/https:
        || /^mailto:/i.test(href) //mailto:
        || /^ftps?:\/\//i.test(href) //ftp:/ftps:
        || (cfg.anchor && validateAnchor(href)) //anchor
        || (cfg.relative && validateRelative(href)); //relative
}

function validateRelative(href) {
    // eslint-disable-next-line
    return /^\/[^\/].*$/i.test(href);
}

function validateAnchor(href) {
    return /^#((?:[!$&()*+,;=._~:@?-]|%[0-9a-fA-F]{2}|[a-zA-Z0-9])+)$/i.test(href);
}

function buildLink(href, attrs, text, validate) {
    attrs = attrs || {};

    if(validate !== false) {
        href = validateHref(href, validate) ? href : '#';
    }

    text = text || href;

    var defaultAttrs = {href: href};

    if(href !== '#') {
        defaultAttrs.target = '_blank';
        defaultAttrs.rel = DEFAULT_LINK_REL;
    }

    return $('<div>').append($('<a>').attr($.extend(defaultAttrs, attrs)).text(text)).html();
}/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 */


var schema$d = {
    nodes: {
        image: {
            sortOrder: 1000,
            group: "inline",
            inline: true,
            draggable: true,
            attrs: {
                src: {},
                alt: {default: null},
                title: {default: null},
                width: {default: null},
                height: {default: null},
                float: {default: FLOAT_NONE},
                fileGuid: {default: null},
            },
            parseDOM: [{
                tag: "img[src]",
                getAttrs: function (dom) {
                    return {
                        src: dom.getAttribute("src"),
                        title: dom.getAttribute("title"),
                        alt: dom.getAttribute("alt"),
                        width: dom.getAttribute("width"),
                        height: dom.getAttribute("height"),
                        fileGuid: dom.getAttribute("data-file-guid")
                    }
                }
            }],
            toDOM: function (node) {
                return ['img', node.attrs];
            },
            parseMarkdown: {
                node: "image",
                getAttrs: function (tok) {
                    var ref = filterFileUrl(tok.attrGet("src"));
                    var url = ref.url;
                    var guid = ref.guid;

                    if (!validateHref(url, {relative: true})) {
                        url = '#';
                    }
                    return ({
                        src: url,
                        title: tok.attrGet("title") || null,
                        width: tok.attrGet("width") || null,
                        height: tok.attrGet("height") || null,
                        alt: tok.attrGet("alt") || null,
                        float: tok.attrGet("float") || FLOAT_NONE,
                        fileGuid: guid
                    });
                }
            },
            toMarkdown: function (state, node) {
                var resizeAddition = "";

                if (node.attrs.width || node.attrs.height) {
                    resizeAddition += " =";
                    resizeAddition += (node.attrs.width) ? node.attrs.width : '';
                    resizeAddition += 'x';
                    resizeAddition += (node.attrs.height) ? node.attrs.height : '';
                }

                var src = (node.attrs.fileGuid) ? 'file-guid:' + node.attrs.fileGuid : node.attrs.src;
                var float = getAltExtensionByFloat(node.attrs.float);

                state.write("![" + state.esc(node.attrs.alt || "") + float + "](" + state.esc(src) +
                    (node.attrs.title ? " " + state.quote(node.attrs.title) : "") + resizeAddition + ")");
            }
        }
    }
};var require$$0 = /*@__PURE__*/getAugmentedNamespace(imageFloat$1);function parseNextNumber(str, pos, max) {
    var code,
        start = pos,
        result = {
            ok: false,
            pos: pos,
            value: ''
        };

    code = str.charCodeAt(pos);

    while (pos < max && (code >= 0x30 /* 0 */ && code <= 0x39 /* 9 */) || code === 0x25 /* % */) {
        code = str.charCodeAt(++pos);
    }

    result.ok = true;
    result.pos = pos;
    result.value = str.slice(start, pos);

    return result;
}

var parse_image_size = function parseImageSize(str, pos, max) {
    var code,
        result = {
            ok: false,
            pos: 0,
            width: '',
            height: ''
        };

    if (pos >= max) {
        return result;
    }

    code = str.charCodeAt(pos);

    if (code !== 0x3d /* = */) {
        return result;
    }

    pos++;

    // size must follow = without any white spaces as follows
    // (1) =300x200
    // (2) =300x
    // (3) =x200
    code = str.charCodeAt(pos);
    if (code !== 0x78 /* x */ && (code < 0x30 || code > 0x39) /* [0-9] */) {
        return result;
    }

    // parse width
    var resultW = parseNextNumber(str, pos, max);
    pos = resultW.pos;

    // next charactor must be 'x'
    code = str.charCodeAt(pos);
    if (code !== 0x78 /* x */) {
        return result;
    }

    pos++;

    // parse height
    var resultH = parseNextNumber(str, pos, max);
    pos = resultH.pos;

    result.width = resultW.value;
    result.height = resultH.value;
    result.pos = pos;
    result.ok = true;
    return result;
};/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 */

// Process ![test]( x =100x200)
//                    ^^^^^^^^ this size specification

var imageFloat = require$$0;
var parseImageSize = parse_image_size;

var MEDIA_TOKEN_MAP = {
    video: 'video',
    audio: 'audio'
};

function parseMediaOptions(src, pos, max) {
    var result = {
        ok: false,
        pos: pos,
        options: ''
    };

    if (pos >= max || src.charCodeAt(pos) !== 0x7b /* { */) {
        return result;
    }

    var endPos = src.indexOf('}', pos + 1);
    if (endPos < 0 || endPos > max) {
        return result;
    }

    var raw = src.slice(pos + 1, endPos).trim();
    if (!raw.length) {
        return result;
    }

    result.ok = true;
    result.pos = endPos + 1;
    result.options = raw;
    return result;
}

function parseOptionFlags(rawOptions) {
    return rawOptions.trim().split(/\s+/).filter(Boolean);
}

function parseMediaOptionsWithoutBraces(src, pos, max) {
    var result = {
        ok: false,
        pos: pos,
        options: ''
    };

    var pointer = pos;
    var flags = [];

    while (pointer < max) {
        var code = src.charCodeAt(pointer);

        if (code === 0x20 || code === 0x0A) {
            pointer++;
            continue;
        }

        if (code === 0x29 /* ) */ || code === 0x3d /* = */) {
            break;
        }

        var start = pointer;
        while (pointer < max) {
            code = src.charCodeAt(pointer);
            if (code === 0x20 || code === 0x0A || code === 0x29 || code === 0x3d) {
                break;
            }
            pointer++;
        }

        var flag = src.slice(start, pointer).trim();
        if (!flag.length) {
            break;
        }

        flags.push(flag);
    }

    if (!flags.length) {
        return result;
    }

    result.options = flags.join(' ');
    if (!resolveMediaTokenType(result.options)) {
        return result;
    }

    result.ok = true;
    result.pos = pointer;
    return result;
}

function resolveMediaTokenType(rawOptions) {
    var flags = parseOptionFlags(rawOptions);
    for (var i = 0; i < flags.length; i++) {
        if (MEDIA_TOKEN_MAP[flags[i]]) {
            return MEDIA_TOKEN_MAP[flags[i]];
        }
    }

    return null;
}

function pushUniqueAttr(attrs, key, value) {
    for (var i = 0; i < attrs.length; i++) {
        if (attrs[i][0] === key) {
            return;
        }
    }
    attrs.push([key, value]);
}

function image_with_size(md, options) {
    return function (state, silent) {
        var attrs,
            code,
            label,
            labelEnd,
            labelStart,
            pos,
            ref,
            res,
            title,
            width = '',
            height = '',
            mediaOptions = '',
            token,
            tokens,
            start,
            href = '',
            oldPos = state.pos,
            max = state.posMax;

        if (state.src.charCodeAt(state.pos) !== 0x21/* ! */) {
            return false;
        }
        if (state.src.charCodeAt(state.pos + 1) !== 0x5B/* [ */) {
            return false;
        }

        labelStart = state.pos + 2;
        labelEnd = md.helpers.parseLinkLabel(state, state.pos + 1, false);

        // parser failed to find ']', so it's not a valid link
        if (labelEnd < 0) {
            return false;
        }

        pos = labelEnd + 1;
        if (pos < max && state.src.charCodeAt(pos) === 0x28) {
            // Inline link

            // [link](  <href>  "title"  )
            //        ^^ skipping these spaces
            pos++;
            for (; pos < max; pos++) {
                code = state.src.charCodeAt(pos);
                if (code !== 0x20 && code !== 0x0A) {
                    break;
                }
            }
            if (pos >= max) {
                return false;
            }

            // [link](  <href>  "title"  )
            //          ^^^^^^ parsing link destination
            start = pos;
            res = md.helpers.parseLinkDestination(state.src, pos, state.posMax);
            if (res.ok) {
                href = state.md.normalizeLink(res.str);
                if (state.md.validateLink(href)) {
                    pos = res.pos;
                } else {
                    href = '';
                }
            }

            // [link](  <href>  "title"  )
            //                ^^ skipping these spaces
            start = pos;
            for (; pos < max; pos++) {
                code = state.src.charCodeAt(pos);
                if (code !== 0x20 && code !== 0x0A) {
                    break;
                }
            }

            // [link](  <href>  "title"  )
            //                  ^^^^^^^ parsing link title
            res = md.helpers.parseLinkTitle(state.src, pos, state.posMax);
            if (pos < max && start !== pos && res.ok) {
                title = res.str;
                pos = res.pos;

                // [link](  <href>  "title"  )
                //                         ^^ skipping these spaces
                for (; pos < max; pos++) {
                    code = state.src.charCodeAt(pos);
                    if (code !== 0x20 && code !== 0x0A) {
                        break;
                    }
                }
            } else {
                title = '';
            }

            // [link](  <href>  "title" {video ...} =WxH  )
            //                         ^^^^^^^^^^^ ^^^^ parse optional media options and image size
            while (pos - 1 >= 0) {
                var hasChange = false;
                code = state.src.charCodeAt(pos - 1);

                // there must be at least one white spaces between previous field and the optional extension.
                if (code !== 0x20) {
                    break;
                }

                res = parseMediaOptions(state.src, pos, state.posMax);
                if (res.ok) {
                    mediaOptions = res.options;
                    pos = res.pos;
                    hasChange = true;

                    for (; pos < max; pos++) {
                        code = state.src.charCodeAt(pos);
                        if (code !== 0x20 && code !== 0x0A) {
                            break;
                        }
                    }
                }

                if (!mediaOptions) {
                    res = parseMediaOptionsWithoutBraces(state.src, pos, state.posMax);
                    if (res.ok) {
                        mediaOptions = res.options;
                        pos = res.pos;
                        hasChange = true;

                        for (; pos < max; pos++) {
                            code = state.src.charCodeAt(pos);
                            if (code !== 0x20 && code !== 0x0A) {
                                break;
                            }
                        }
                    }
                }

                res = parseImageSize(state.src, pos, state.posMax);
                if (res.ok) {
                    width = res.width;
                    height = res.height;
                    pos = res.pos;
                    hasChange = true;

                    for (; pos < max; pos++) {
                        code = state.src.charCodeAt(pos);
                        if (code !== 0x20 && code !== 0x0A) {
                            break;
                        }
                    }
                }

                if (!hasChange) {
                    break;
                }
            }

            if (pos >= max || state.src.charCodeAt(pos) !== 0x29/* ) */) {
                state.pos = oldPos;
                return false;
            }
            pos++;

        } else {
            // Link reference
            if (typeof state.env.references === 'undefined') {
                return false;
            }

            // [foo]  [bar]
            //      ^^ optional whitespace (can include newlines)
            for (; pos < max; pos++) {
                code = state.src.charCodeAt(pos);
                if (code !== 0x20 && code !== 0x0A) {
                    break;
                }
            }

            if (pos < max && state.src.charCodeAt(pos) === 0x5B/* [ */) {
                start = pos + 1;
                pos = md.helpers.parseLinkLabel(state, pos);
                if (pos >= 0) {
                    label = state.src.slice(start, pos++);
                } else {
                    pos = labelEnd + 1;
                }
            } else {
                pos = labelEnd + 1;
            }

            // covers label === '' and label === undefined
            // (collapsed reference link and shortcut reference link respectively)
            if (!label) {
                label = state.src.slice(labelStart, labelEnd);
            }

            ref = state.env.references[md.utils.normalizeReference(label)];
            if (!ref) {
                state.pos = oldPos;
                return false;
            }
            href = ref.href;
            title = ref.title;
        }

        // We found the end of the link, and know for a fact it's a valid link;
        // so all that's left to do is to call tokenizer.
        if (!silent) {
            state.pos = labelStart;
            state.posMax = labelEnd;

            var newState = new state.md.inline.State(
                state.src.slice(labelStart, labelEnd),
                state.md,
                state.env,
                tokens = []
            );
            newState.md.inline.tokenize(newState);

            // if 'autofill' option is specified
            // and width/height are both blank,
            // they are filled automatically
            if (options) {
                if (options.autofill && width === '' && height === '') {
                    try {
                        var dimensions = sizeOf(href);
                        width = dimensions.width;
                        height = dimensions.height;
                    } catch (e) {
                        /* empty */
                    }
                }
            }

            var mediaTokenType = mediaOptions ? resolveMediaTokenType(mediaOptions) : null;
            var tokenType = mediaTokenType || 'image';
            var tokenTag = mediaTokenType || 'img';

            token = state.push(tokenType, tokenTag, 0);
            token.attrs = attrs = [['src', href]];
            token.children = tokens;

            // Parse image float extension
            var altTextToken = tokens.length ? tokens[tokens.length - 1] : null;

            if (altTextToken) {
                var ref$1 = imageFloat.parseFloatFromAlt(altTextToken['content']);
                var float = ref$1.float;
                var alt = ref$1.alt;
                altTextToken['content'] = alt;
                token.attrs.push(['float', float]);
                token.attrs.push(['alt', alt]);
            } else {
                token.attrs.push(['float', imageFloat.FLOAT_NONE]);
                token.attrs.push(['alt', '']);
            }

            if (title) {
                attrs.push(['title', title]);
            }

            if (mediaOptions) {
                attrs.push(['media-options', mediaOptions]);
                if (mediaTokenType) {
                    parseOptionFlags(mediaOptions).forEach(function (flag) {
                        pushUniqueAttr(attrs, flag, flag);
                    });
                }
            }

            if (width !== '') {
                attrs.push(['width', width]);
            }

            if (height !== '') {
                attrs.push(['height', height]);
            }
        }

        state.pos = pos;
        state.posMax = max;
        return true;
    };
}

var markdownit_imsize = function imsize_plugin(md, options) {
    md.inline.ruler.before('emphasis', 'image', image_with_size(md, options));
};

var imsize_plugin = /*@__PURE__*/getDefaultExportFromCjs(markdownit_imsize);/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 */


function editNode$3(node, context, view) {
    promt$1(context.translate("Edit image"), context, node.attrs, view, node);
}

var isDefined$1 = function (obj) {
    if (arguments.length > 1) {
        var result = true;
        this.each(arguments, function (index, value) {
            if (!isDefined$1(value)) {
                return false;
            }
        });

        return result;
    }
    return typeof obj !== 'undefined';
};

var endsWith$2 = function (val, suffix) {
    if (!isDefined$1(val) || !isDefined$1(suffix)) {
        return false;
    }
    return val.indexOf(suffix, val.length - suffix.length) !== -1;
};

function promt$1(title, context, attrs, view, node) {
    var state = view.state;
    var ref = state.selection;
    var from = ref.from;
    var to = ref.to;

    var cleanDimension = function (val) {
        val = val.trim();
        if (endsWith$2(val, 'px')) {
            val = val.substring(0, val.length - 2);
        }
        return val;
    };

    var validateDimension = function (val) {
        val = cleanDimension(val);

        if (val.length && !/^[0-9]+%?$/.test(val)) {
            return context.translate('Invalid dimension format used.');
        }
    };

    var validateSource = function (val) {
        if (!validateHref(val)) {
            return context.translate('Invalid image source.');
        }
    };

    openPrompt({
        title: title,
        fields: {
            src: new TextField({
                label: context.translate("Location"),
                required: true,
                value: attrs && attrs.src,
                validate: validateSource
            }),
            title: new TextField({label: context.translate("Title"), value: attrs && attrs.title}),
            alt: new TextField({
                label: context.translate("Description"),
                value: attrs ? attrs.alt : state.doc.textBetween(from, to, " ")
            }),
            width: new TextField({
                label: context.translate("Width"),
                value: attrs && attrs.width,
                clean: cleanDimension,
                validate: validateDimension
            }),
            height: new TextField({
                label: context.translate("Height"),
                value: attrs && attrs.height,
                clean: cleanDimension,
                validate: validateDimension
            }),
            float: new SelectField({
                label: context.translate("Position"),
                value: attrs && attrs.float,
                options: [
                    {label: context.translate("Normal"), value: 0},
                    {label: context.translate("Left"), value: 1},
                    {label: context.translate("Center"), value: 2},
                    {label: context.translate("Right"), value: 3}
                ]
            })
        },
        callback: function callback(attrs) {
            if (node && node.attrs.src === attrs.src) {
                attrs.fileGuid = node.attrs.fileGuid;
            }

            attrs.float = parseInt(attrs.float);

            view.dispatch(view.state.tr.replaceSelectionWith(context.schema.nodes.image.createAndFill(attrs)));
            view.focus();
        }
    });
}/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2018 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 */


var imagePlugin = function (context) {
    context.editor.$.on('mouseleave', function (e) {
        var target = e.toElement || e.relatedTarget;
        if (!$(target).closest('.humhub-richtext-inline-menu').length) {
            $('.humhub-richtext-inline-menu').remove();
        }
    });

    return new Plugin({
        props: {
            nodeViews: {
                image: function image(node) {
                    return new ImageView(node, context);
                }
            },
        },
        filterTransaction: function (tr, state) {
            if (!(tr.curSelection instanceof NodeSelection)) {
                $('.humhub-richtext-image-edit').remove();
            }

            return true;
        }
    });
};

var ImageView = function ImageView(node, context) {
    var this$1$1 = this;

    // The editor will use this as the node's DOM representation
    this.createDom(node);

    context.event.on('clear, serialize', function () {
        $('.humhub-richtext-inline-menu').remove();
    });

    this.dom.addEventListener("mouseenter", function (e) {
        var $img = $(this$1$1.dom);
        var offset = $img.offset();
        var editorOffset = context.editor.$.offset();

        if (offset.top < editorOffset.top) {
            return;
        }

        var $edit = $('<div>').addClass('humhub-richtext-inline-menu').addClass('humhub-richtext-image-edit')
            .html('<button class="btn btn-primary btn-sm btn-icon-only"><i class="fa fa-pencil"></i></button>')
            .css({
                position: 'absolute',
                left: offset.left + $img.width() - (25),
                top: offset.top + 5,
                'z-index': 9999
            }).on('mousedown', function (evt) {
                var view = context.editor.view;
                var doc = view.state.doc;
                view.dispatch(view.state.tr.setSelection(NodeSelection.create(doc, view.posAtDOM(this$1$1.dom))).scrollIntoView());
                editNode$3(node, context, view);
            });

        $('html').append($edit);
    });

    this.dom.addEventListener("mouseleave", function (e) {
        var target = e.toElement || e.relatedTarget;
        if (!$(target).closest('.humhub-richtext-inline-menu').length) {
            $('.humhub-richtext-inline-menu').remove();
        }
    });
};

ImageView.prototype.createDom = function createDom (node) {
    var src = validateHref(node.attrs.src) ? node.attrs.src : '#';

    this.dom = $('<img>').attr({
        src: src,
        title: node.attrs.title || null,
        width: node.attrs.width || null,
        height: node.attrs.height || null,
        alt: node.attrs.alt || null,
        class: getClassForFloat(node.attrs.float),
        'data-file-guid': node.attrs.fileGuid
    })[0];
};/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 */


var image = {
    id: 'image',
    schema: schema$d,
    // menu: (context) => menu(context),
    plugins: function (context) {
        return [
            imagePlugin(context)
        ];
    },
    registerMarkdownIt: function (markdownIt) {
        markdownIt.use(imsize_plugin);

        var defaultRender = markdownIt.renderer.rules.image || function (tokens, idx, options, env, self) {
            return self.renderToken(tokens, idx, options);
        };

        markdownIt.renderer.rules.image = function (tokens, idx, options, env, self) {
            var imageToken = tokens[idx];
            var srcIndex = imageToken.attrIndex('src');

            var srcFilter = filterFileUrl(imageToken.attrs[srcIndex][1]);
            imageToken.attrs[srcIndex][1] = validateHref(srcFilter.url) ? srcFilter.url : '#';

            if (srcFilter.guid) {
                imageToken.attrPush(['data-file-guid', srcFilter.guid]); // add new attribute
            }

            if (env && env.context && env.context.uuid) {
                imageToken.attrPush(['data-ui-gallery', env.context.uuid]);
            }

            var float = imageToken.attrs[imageToken.attrIndex('float')][1];

            if (float) {
                imageToken.attrPush(['class', getClassForFloat(float)]);
                imageToken.attrs.splice(imageToken.attrIndex('float'), 1);
            }

            ['media-options', 'video', 'audio', 'controls', 'autoplay', 'muted', 'loop'].forEach(function (attr) {
                var attrIndex = imageToken.attrIndex(attr);
                if (attrIndex >= 0) {
                    imageToken.attrs.splice(attrIndex, 1);
                }
            });

            // pass token to default renderer.
            return defaultRender(tokens, idx, options, env, self);
        };
    }
};/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2026 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 */


var MEDIA_OPTION_BLOCK_REGEXP = /^\{([^{}]+)\}$/;

var parseMediaOptionFlags = function (rawValue) {
    if (!rawValue || typeof rawValue !== 'string') {
        return [];
    }

    var flags = rawValue.trim().split(/\s+/).filter(Boolean);
    return [].concat( new Set(flags) );
};

var parseMediaOptionBlock = function (value) {
    if (!value || typeof value !== 'string') {
        return null;
    }

    var match = value.trim().match(MEDIA_OPTION_BLOCK_REGEXP);
    if (!match) {
        return null;
    }

    return parseMediaOptionFlags(match[1]);
};

var getMediaFlagsFromToken = function (token) {
    if (!token || typeof token.attrGet !== 'function') {
        return [];
    }

    var optionsAttr = token.attrGet('media-options') || token.attrGet('data-media-options');
    if (optionsAttr) {
        return parseMediaOptionFlags(optionsAttr);
    }

    var title = token.attrGet('title');
    var titleFlags = parseMediaOptionBlock(title);
    return titleFlags || [];
};

var getBooleanAttrsFromTokenFlags = function (token, booleanAttrs) {
    if ( booleanAttrs === void 0 ) booleanAttrs = [];

    var flags = getMediaFlagsFromToken(token);
    var result = {};

    booleanAttrs.forEach(function (attr) {
        result[attr] = !!(token && token.attrGet && token.attrGet(attr)) || flags.includes(attr);
    });

    return result;
};/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2026 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 */


var BOOLEAN_VIDEO_ATTRS = ['controls', 'autoplay', 'muted', 'loop'];
var FILE_GUID_PREFIX$3 = 'file-guid:';

var normalizeFileUrl$3 = function (raw, source) {
    if (raw && typeof raw === 'object') {
        return raw;
    }

    if (typeof source === 'string' && source.indexOf(FILE_GUID_PREFIX$3) === 0) {
        return {
            url: source,
            guid: source.substring(FILE_GUID_PREFIX$3.length)
        };
    }

    return {
        url: source,
        guid: null
    };
};

var buildVideoDomAttrs = function (attrs) {
    var domAttrs = {
        src: attrs.src,
        title: attrs.title || null,
        width: attrs.width || null,
        height: attrs.height || null,
        class: getClassForFloat(attrs.float),
        'data-file-guid': attrs.fileGuid || null
    };

    BOOLEAN_VIDEO_ATTRS.forEach(function (attr) {
        if (attrs[attr]) {
            domAttrs[attr] = attr;
        }
    });

    return domAttrs;
};

var schema$c = {
    nodes: {
        video: {
            sortOrder: 1010,
            group: "inline",
            inline: true,
            draggable: true,
            attrs: {
                src: {},
                title: {default: null},
                controls: {default: false},
                autoplay: {default: false},
                muted: {default: false},
                loop: {default: false},
                width: {default: null},
                height: {default: null},
                float: {default: FLOAT_NONE},
                fileGuid: {default: null}
            },
            parseDOM: [{
                tag: "video[src]",
                getAttrs: function (dom) {
                    return {
                        src: dom.getAttribute("src"),
                        title: dom.getAttribute("title"),
                        controls: dom.hasAttribute("controls"),
                        autoplay: dom.hasAttribute("autoplay"),
                        muted: dom.hasAttribute("muted"),
                        loop: dom.hasAttribute("loop"),
                        width: dom.getAttribute("width"),
                        height: dom.getAttribute("height"),
                        fileGuid: dom.getAttribute("data-file-guid")
                    };
                }
            }],
            toDOM: function (node) {
                return ['video', buildVideoDomAttrs(node.attrs)];
            },
            parseMarkdown: {
                video: {
                    node: "video",
                    getAttrs: function (tok) {
                        var src = tok.attrGet("src");
                        var ref = normalizeFileUrl$3(filterFileUrl(src), src);
                        var url = ref.url;
                        var guid = ref.guid;

                        if (!validateHref(url, {relative: true})) {
                            if (!guid) {
                                url = '#';
                            }
                        }

                        return Object.assign({
                            src: url,
                            title: tok.attrGet("alt") || tok.attrGet("title") || null,
                            width: tok.attrGet("width") || null,
                            height: tok.attrGet("height") || null,
                            float: tok.attrGet("float") || FLOAT_NONE,
                            fileGuid: guid
                        }, getBooleanAttrsFromTokenFlags(tok, BOOLEAN_VIDEO_ATTRS));
                    }
                }
            },
            toMarkdown: function (state, node) {
                var src = node.attrs.fileGuid ? 'file-guid:' + node.attrs.fileGuid : node.attrs.src;
                var options = ['video'];
                BOOLEAN_VIDEO_ATTRS.forEach(function (attr) {
                    if (node.attrs[attr]) {
                        options.push(attr);
                    }
                });
                var title = (node.attrs.title || "") + getAltExtensionByFloat(node.attrs.float);

                var resizeAddition = "";
                if (node.attrs.width || node.attrs.height) {
                    resizeAddition += " =";
                    resizeAddition += (node.attrs.width) ? node.attrs.width : '';
                    resizeAddition += 'x';
                    resizeAddition += (node.attrs.height) ? node.attrs.height : '';
                }

                state.write("![" + state.esc(title) + "](" + state.esc(src) + " " + options.join(' ') + resizeAddition + ")");
            }
        }
    }
};/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2026 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 */


var BOOLEAN_FIELDS$1 = ['controls', 'autoplay', 'muted', 'loop'];
var isDefined = function (obj) {
    if (arguments.length > 1) {
        var result = true;
        this.each(arguments, function (index, value) {
            if (!isDefined(value)) {
                return false;
            }
        });

        return result;
    }
    return typeof obj !== 'undefined';
};

var endsWith$1 = function (val, suffix) {
    if (!isDefined(val) || !isDefined(suffix)) {
        return false;
    }
    return val.indexOf(suffix, val.length - suffix.length) !== -1;
};

var editNode$2 = function (node, context, view) {
    var cleanDimension = function (val) {
        val = val.trim();
        if (endsWith$1(val, 'px')) {
            val = val.substring(0, val.length - 2);
        }
        return val;
    };

    var validateDimension = function (val) {
        val = cleanDimension(val);

        if (val.length && !/^[0-9]+%?$/.test(val)) {
            return context.translate('Invalid dimension format used.');
        }
    };

    var validateSource = function (val) {
        if (!validateHref(val)) {
            return context.translate('Invalid video source.');
        }
    };

    openPrompt({
        title: context.translate("Edit video"),
        fields: {
            src: new TextField({
                label: context.translate("Location"),
                required: true,
                value: node.attrs.src,
                validate: validateSource
            }),
            title: new TextField({
                label: context.translate("Title"),
                value: node.attrs.title
            }),
            width: new TextField({
                label: context.translate("Width"),
                value: node.attrs.width,
                clean: cleanDimension,
                validate: validateDimension
            }),
            height: new TextField({
                label: context.translate("Height"),
                value: node.attrs.height,
                clean: cleanDimension,
                validate: validateDimension
            }),
            float: new SelectField({
                label: context.translate("Position"),
                value: node.attrs.float,
                options: [
                    {label: context.translate("Normal"), value: 0},
                    {label: context.translate("Left"), value: 1},
                    {label: context.translate("Center"), value: 2},
                    {label: context.translate("Right"), value: 3}
                ]
            }),
            controls: new CheckboxField({
                label: context.translate("Show controls"),
                value: node.attrs.controls
            }),
            autoplay: new CheckboxField({
                label: context.translate("Autoplay"),
                value: node.attrs.autoplay
            }),
            muted: new CheckboxField({
                label: context.translate("Muted"),
                value: node.attrs.muted
            }),
            loop: new CheckboxField({
                label: context.translate("Loop"),
                value: node.attrs.loop
            }),
        },
        callback: function callback(attrs) {
            var nextAttrs = Object.assign({}, node.attrs);
            nextAttrs.src = attrs.src;
            nextAttrs.title = attrs.title;
            nextAttrs.width = attrs.width;
            nextAttrs.height = attrs.height;
            nextAttrs.float = parseInt(attrs.float);
            BOOLEAN_FIELDS$1.forEach(function (field) {
                nextAttrs[field] = !!attrs[field];
            });

            view.dispatch(view.state.tr.replaceSelectionWith(context.schema.nodes.video.create(nextAttrs)));
            view.focus();
        }
    });
};/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2026 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 */


var videoPlugin = function (context) {
    context.editor.$.on('mouseleave', function (e) {
        var target = e.toElement || e.relatedTarget;
        if (!$(target).closest('.humhub-richtext-inline-menu').length) {
            $('.humhub-richtext-inline-menu').remove();
        }
    });

    return new Plugin({
        props: {
            nodeViews: {
                video: function video(node) {
                    return new VideoView(node, context);
                }
            }
        },
        filterTransaction: function (tr) {
            if (!(tr.curSelection instanceof NodeSelection)) {
                $('.humhub-richtext-video-edit').remove();
            }

            return true;
        }
    });
};

var VideoView = function VideoView(node, context) {
    var this$1$1 = this;

    this.createDom(node);

    context.event.on('clear, serialize', function () {
        $('.humhub-richtext-inline-menu').remove();
    });

    this.dom.addEventListener("mouseenter", function () {
        var $video = $(this$1$1.dom);
        var offset = $video.offset();
        var editorOffset = context.editor.$.offset();

        if (offset.top < editorOffset.top) {
            return;
        }

        var $edit = $('<div>').addClass('humhub-richtext-inline-menu').addClass('humhub-richtext-video-edit')
            .html('<button class="btn btn-primary btn-sm btn-icon-only"><i class="fa fa-pencil"></i></button>')
            .css({
                position: 'absolute',
                left: offset.left + $video.width() - 25,
                top: offset.top + 5,
                'z-index': 9999
            }).on('mousedown', function () {
                var view = context.editor.view;
                var doc = view.state.doc;
                view.dispatch(view.state.tr.setSelection(NodeSelection.create(doc, view.posAtDOM(this$1$1.dom))).scrollIntoView());
                editNode$2(node, context, view);
            });

        $('html').append($edit);
    });

    this.dom.addEventListener("mouseleave", function (e) {
        var target = e.toElement || e.relatedTarget;
        if (!$(target).closest('.humhub-richtext-inline-menu').length) {
            $('.humhub-richtext-inline-menu').remove();
        }
    });
};

VideoView.prototype.createDom = function createDom (node) {
        var this$1$1 = this;

    var src = validateHref(node.attrs.src) ? node.attrs.src : '#';
    this.dom = $('<video>').attr({
        src: src,
        title: node.attrs.title || null,
        width: node.attrs.width || null,
        height: node.attrs.height || null,
        class: getClassForFloat(node.attrs.float),
        'data-file-guid': node.attrs.fileGuid || null
    })[0];

    ['controls', 'autoplay', 'muted', 'loop'].forEach(function (attr) {
        if (node.attrs[attr]) {
            this$1$1.dom.setAttribute(attr, attr);
        }
    });
};/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2026 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 */


var FILE_GUID_PREFIX$2 = 'file-guid:';

var normalizeFileUrl$2 = function (raw, source) {
    if (raw && typeof raw === 'object') {
        return raw;
    }

    if (typeof source === 'string' && source.indexOf(FILE_GUID_PREFIX$2) === 0) {
        return {
            url: source,
            guid: source.substring(FILE_GUID_PREFIX$2.length)
        };
    }

    return {
        url: source,
        guid: null
    };
};

var hasFlag$1 = function (token, attr) {
    if (token.attrGet(attr)) {
        return true;
    }

    var options = token.attrGet('media-options');
    if (!options) {
        return false;
    }

    return parseMediaOptionFlags(options).includes(attr);
};

var setBooleanAttr$1 = function (token, attr) {
    if (hasFlag$1(token, attr)) {
        token.attrSet(attr, attr);
    }
};

var removeAttr$1 = function (token, attr) {
    var attrIndex = token.attrIndex(attr);
    if (attrIndex >= 0) {
        token.attrs.splice(attrIndex, 1);
    }
};

var video = {
    id: 'video',
    schema: schema$c,
    plugins: function (context) {
        return [
            videoPlugin(context)
        ];
    },
    registerMarkdownIt: function (markdownIt) {
        markdownIt.renderer.rules.video = function (tokens, idx, options, env, self) {
            var token = tokens[idx];
            var srcIndex = token.attrIndex('src');
            var title = token.attrGet('title') || token.attrGet('alt');

            if (srcIndex >= 0) {
                var source = token.attrs[srcIndex][1];
                var srcFilter = normalizeFileUrl$2(filterFileUrl(source), source);
                token.attrs[srcIndex][1] = validateHref(srcFilter.url) ? srcFilter.url : '#';

                if (srcFilter.guid) {
                    token.attrSet('data-file-guid', srcFilter.guid);
                }
            }

            if (title) {
                token.attrSet('title', title);
            }

            setBooleanAttr$1(token, 'controls');
            setBooleanAttr$1(token, 'autoplay');
            setBooleanAttr$1(token, 'muted');
            setBooleanAttr$1(token, 'loop');
            if (token.attrGet('float')) {
                token.attrSet('class', getClassForFloat(token.attrGet('float')));
            }
            ['media-options', 'video', 'alt', 'float'].forEach(function (attr) { return removeAttr$1(token, attr); });

            token.attrSet('playsinline', 'playsinline');
            return '<video' + self.renderAttrs(token) + '></video>';
        };
    }
};/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2026 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 */


var BOOLEAN_AUDIO_ATTRS = ['controls', 'autoplay', 'muted', 'loop'];
var FILE_GUID_PREFIX$1 = 'file-guid:';

var normalizeFileUrl$1 = function (raw, source) {
    if (raw && typeof raw === 'object') {
        return raw;
    }

    if (typeof source === 'string' && source.indexOf(FILE_GUID_PREFIX$1) === 0) {
        return {
            url: source,
            guid: source.substring(FILE_GUID_PREFIX$1.length)
        };
    }

    return {
        url: source,
        guid: null
    };
};

var buildAudioDomAttrs = function (attrs) {
    var domAttrs = {
        src: attrs.src,
        title: attrs.title || null,
        class: getClassForFloat(attrs.float),
        'data-file-guid': attrs.fileGuid || null
    };

    BOOLEAN_AUDIO_ATTRS.forEach(function (attr) {
        if (attrs[attr]) {
            domAttrs[attr] = attr;
        }
    });

    return domAttrs;
};

var schema$b = {
    nodes: {
        audio: {
            sortOrder: 1015,
            group: "inline",
            inline: true,
            draggable: true,
            attrs: {
                src: {},
                title: {default: null},
                controls: {default: false},
                autoplay: {default: false},
                muted: {default: false},
                loop: {default: false},
                float: {default: FLOAT_NONE},
                fileGuid: {default: null}
            },
            parseDOM: [{
                tag: "audio[src]",
                getAttrs: function (dom) {
                    return {
                        src: dom.getAttribute("src"),
                        title: dom.getAttribute("title"),
                        controls: dom.hasAttribute("controls"),
                        autoplay: dom.hasAttribute("autoplay"),
                        muted: dom.hasAttribute("muted"),
                        loop: dom.hasAttribute("loop"),
                        fileGuid: dom.getAttribute("data-file-guid")
                    };
                }
            }],
            toDOM: function (node) {
                return ['audio', buildAudioDomAttrs(node.attrs)];
            },
            parseMarkdown: {
                audio: {
                    node: "audio",
                    getAttrs: function (tok) {
                        var src = tok.attrGet("src");
                        var ref = normalizeFileUrl$1(filterFileUrl(src), src);
                        var url = ref.url;
                        var guid = ref.guid;

                        if (!validateHref(url, {relative: true})) {
                            if (!guid) {
                                url = '#';
                            }
                        }

                        return Object.assign({
                            src: url,
                            title: tok.attrGet("alt") || tok.attrGet("title") || null,
                            float: tok.attrGet("float") || FLOAT_NONE,
                            fileGuid: guid
                        }, getBooleanAttrsFromTokenFlags(tok, BOOLEAN_AUDIO_ATTRS));
                    }
                }
            },
            toMarkdown: function (state, node) {
                var src = node.attrs.fileGuid ? 'file-guid:' + node.attrs.fileGuid : node.attrs.src;
                var options = ['audio'];
                BOOLEAN_AUDIO_ATTRS.forEach(function (attr) {
                    if (node.attrs[attr]) {
                        options.push(attr);
                    }
                });
                var title = (node.attrs.title || "") + getAltExtensionByFloat(node.attrs.float);
                state.write("![" + state.esc(title) + "](" + state.esc(src) + " " + options.join(' ') + ")");
            }
        }
    }
};/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2026 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 */


var BOOLEAN_FIELDS = ['controls', 'autoplay', 'muted', 'loop'];

var editNode$1 = function (node, context, view) {
    var validateSource = function (val) {
        if (!validateHref(val)) {
            return context.translate('Invalid audio source.');
        }
    };

    openPrompt({
        title: context.translate("Edit audio"),
        fields: {
            src: new TextField({
                label: context.translate("Location"),
                required: true,
                value: node.attrs.src,
                validate: validateSource
            }),
            title: new TextField({
                label: context.translate("Title"),
                value: node.attrs.title
            }),
            float: new SelectField({
                label: context.translate("Position"),
                value: node.attrs.float,
                options: [
                    {label: context.translate("Normal"), value: 0},
                    {label: context.translate("Left"), value: 1},
                    {label: context.translate("Center"), value: 2},
                    {label: context.translate("Right"), value: 3}
                ]
            }),
            controls: new CheckboxField({
                label: context.translate("Show controls"),
                value: node.attrs.controls
            }),
            autoplay: new CheckboxField({
                label: context.translate("Autoplay"),
                value: node.attrs.autoplay
            }),
            muted: new CheckboxField({
                label: context.translate("Muted"),
                value: node.attrs.muted
            }),
            loop: new CheckboxField({
                label: context.translate("Loop"),
                value: node.attrs.loop
            }),
        },
        callback: function callback(attrs) {
            var nextAttrs = Object.assign({}, node.attrs);
            nextAttrs.src = attrs.src;
            nextAttrs.title = attrs.title;
            nextAttrs.float = parseInt(attrs.float);
            BOOLEAN_FIELDS.forEach(function (field) {
                nextAttrs[field] = !!attrs[field];
            });

            view.dispatch(view.state.tr.replaceSelectionWith(context.schema.nodes.audio.create(nextAttrs)));
            view.focus();
        }
    });
};/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2026 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 */


var audioPlugin = function (context) {
    context.editor.$.on('mouseleave', function (e) {
        var target = e.toElement || e.relatedTarget;
        if (!$(target).closest('.humhub-richtext-inline-menu').length) {
            $('.humhub-richtext-inline-menu').remove();
        }
    });

    return new Plugin({
        props: {
            nodeViews: {
                audio: function audio(node) {
                    return new AudioView(node, context);
                }
            }
        },
        filterTransaction: function (tr) {
            if (!(tr.curSelection instanceof NodeSelection)) {
                $('.humhub-richtext-audio-edit').remove();
            }

            return true;
        }
    });
};

var AudioView = function AudioView(node, context) {
    var this$1$1 = this;

    this.createDom(node);

    context.event.on('clear, serialize', function () {
        $('.humhub-richtext-inline-menu').remove();
    });

    this.dom.addEventListener("mouseenter", function () {
        var $audio = $(this$1$1.dom);
        var offset = $audio.offset();
        var editorOffset = context.editor.$.offset();

        if (offset.top < editorOffset.top) {
            return;
        }

        var $edit = $('<div>').addClass('humhub-richtext-inline-menu').addClass('humhub-richtext-audio-edit')
            .html('<button class="btn btn-primary btn-sm btn-icon-only"><i class="fa fa-pencil"></i></button>')
            .css({
                position: 'absolute',
                left: offset.left + $audio.width() - 25,
                top: offset.top + 5,
                'z-index': 9999
            }).on('mousedown', function () {
                var view = context.editor.view;
                var doc = view.state.doc;
                view.dispatch(view.state.tr.setSelection(NodeSelection.create(doc, view.posAtDOM(this$1$1.dom))).scrollIntoView());
                editNode$1(node, context, view);
            });

        $('html').append($edit);
    });

    this.dom.addEventListener("mouseleave", function (e) {
        var target = e.toElement || e.relatedTarget;
        if (!$(target).closest('.humhub-richtext-inline-menu').length) {
            $('.humhub-richtext-inline-menu').remove();
        }
    });
};

AudioView.prototype.createDom = function createDom (node) {
        var this$1$1 = this;

    var src = validateHref(node.attrs.src) ? node.attrs.src : '#';
    this.dom = $('<audio>').attr({
        src: src,
        title: node.attrs.title || null,
        class: getClassForFloat(node.attrs.float),
        'data-file-guid': node.attrs.fileGuid || null
    })[0];

    ['controls', 'autoplay', 'muted', 'loop'].forEach(function (attr) {
        if (node.attrs[attr]) {
            this$1$1.dom.setAttribute(attr, attr);
        }
    });
};/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2026 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 */


var FILE_GUID_PREFIX = 'file-guid:';

var normalizeFileUrl = function (raw, source) {
    if (raw && typeof raw === 'object') {
        return raw;
    }

    if (typeof source === 'string' && source.indexOf(FILE_GUID_PREFIX) === 0) {
        return {
            url: source,
            guid: source.substring(FILE_GUID_PREFIX.length)
        };
    }

    return {
        url: source,
        guid: null
    };
};

var hasFlag = function (token, attr) {
    if (token.attrGet(attr)) {
        return true;
    }

    var options = token.attrGet('media-options');
    if (!options) {
        return false;
    }

    return parseMediaOptionFlags(options).includes(attr);
};

var setBooleanAttr = function (token, attr) {
    if (hasFlag(token, attr)) {
        token.attrSet(attr, attr);
    }
};

var removeAttr = function (token, attr) {
    var attrIndex = token.attrIndex(attr);
    if (attrIndex >= 0) {
        token.attrs.splice(attrIndex, 1);
    }
};

var audio = {
    id: 'audio',
    schema: schema$b,
    plugins: function (context) {
        return [
            audioPlugin(context)
        ];
    },
    registerMarkdownIt: function (markdownIt) {
        markdownIt.renderer.rules.audio = function (tokens, idx, options, env, self) {
            var token = tokens[idx];
            var srcIndex = token.attrIndex('src');
            var title = token.attrGet('title') || token.attrGet('alt');

            if (srcIndex >= 0) {
                var source = token.attrs[srcIndex][1];
                var srcFilter = normalizeFileUrl(filterFileUrl(source), source);
                token.attrs[srcIndex][1] = validateHref(srcFilter.url) ? srcFilter.url : '#';

                if (srcFilter.guid) {
                    token.attrSet('data-file-guid', srcFilter.guid);
                }
            }

            if (title) {
                token.attrSet('title', title);
            }

            setBooleanAttr(token, 'controls');
            setBooleanAttr(token, 'autoplay');
            setBooleanAttr(token, 'muted');
            setBooleanAttr(token, 'loop');
            if (token.attrGet('float')) {
                token.attrSet('class', getClassForFloat(token.attrGet('float')));
            }
            ['media-options', 'audio', 'alt', 'float'].forEach(function (attr) { return removeAttr(token, attr); });

            return '<audio' + self.renderAttrs(token) + '></audio>';
        };
    }
};/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 */


var schema$a = {
    marks: {
        sortOrder: 300,
        link: {
            attrs: {
                href: {},
                title: {default: null},
                target: {default: '_blank'},
                fileGuid: { default: null},
                rel: {default: DEFAULT_LINK_REL}
            },
            inclusive: false,
            parseDOM:
                [{
                    tag: "a[href]", getAttrs: function getAttrs(dom) {
                        var href = dom.getAttribute("href");
                        if (!validateHref(href))  {
                            href = '#';
                        }

                        return {
                            href: href,
                            title: dom.getAttribute("title"),
                            target: dom.getAttribute("target"),
                            fileGuid: dom.getAttribute("data-file-guid")
                        }
                    }
                }],
            toDOM: function toDOM(node) { var ref = node.attrs;
            var href = ref.href;
            var title = ref.title; return ["a", {href: href, title: title}, 0] },
            parseMarkdown: {
                mark: "link", getAttrs: function (tok) {
                    var ref = filterFileUrl(tok.attrGet("href"), 'view');
                    var url = ref.url;
                    var guid = ref.guid;

                    if (!validateHref(url))  {
                        url = '#';
                    }

                    return ({
                        href: url,
                        title: tok.attrGet("title") || null,
                        fileGuid: guid
                    });
                }
            },
            toMarkdown: {
                open: "[",
                close: function close(state, mark) {
                    var href = (mark.attrs.fileGuid) ? 'file-guid:'+mark.attrs.fileGuid  : mark.attrs.href;
                    return "](" + state.esc(href) + (mark.attrs.title ? " " + state.quote(mark.attrs.title) : "") + ")"
                }
            }
        }
    }
};/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 */


function linkItem(context) {
    var mark = context.schema.marks.link;
    return new MenuItem({
        title: context.translate("Add or remove link"),
        sortOrder: 500,
        icon: icons.link,
        active: function active(state) {
            return markActive(state, mark)
        },
        enable: function enable(state) {
            if (state.selection.empty) {
                return false;
            }

            return canInsertLink(state);
        },
        run: function run(state, dispatch, view) {
            if (markActive(state, mark)) {
                toggleMark(mark)(state, dispatch);
                return true;
            }

            var ref = state.selection;
            var $from = ref.$from;
            var $to = ref.$to;
            var node = $from.node($from.depth);
            var nodeText = node.textBetween($from.parentOffset, $to.parentOffset, "\n");
            var attrs = {text: nodeText, title: nodeText, href: validateHref(nodeText, {anchor: '#'}) ? nodeText : ''};

            promt(context.translate("Create a link"), context, $.extend({}, mark.attrs, attrs));
        }
    })
}

function editNode(dom, context) {
    var doc = context.editor.view.state.doc;
    var view = context.editor.view;

    var nodePos = view.posAtDOM(dom);
    var node = doc.nodeAt(nodePos);

    if (node.type !== context.schema.nodes.text) {
        return;
    }

    var $pos = doc.resolve(nodePos);
    var $end = $pos.node(0).resolve($pos.pos + node.nodeSize);
    view.dispatch(view.state.tr.setSelection(new TextSelection($pos, $end)).scrollIntoView());

    var mark = getLinkMark(node, context);

    promt(context.translate("Edit link"), context, $.extend({}, mark.attrs, {text: node.text}), node, mark);
}

function promt(title, context, attrs, node, mark) {
    var view = context.editor.view;

    var fields = {
        text: new TextField({label: "Text", value: attrs && attrs.text}),
        href: new TextField({
            label: context.translate("Link target"),
            value: attrs && attrs.href,
            required: true,
            clean: function (val) {
                if (!validateHref(val, {anchor: '#'}) && !validateRelative(val))  {
                    return 'https://' + val;
                }

                return val;
            }
        }),
        title: new TextField({label: "Title", value: attrs && attrs.title})
    };

    if (!node) {
        delete fields['text'];
    }

    openPrompt({
        title: title,
        fields: fields,
        callback: function callback(attrs) {
            if (node) {
                if (mark.attrs.href === attrs.href) {
                    attrs.fileGuid = mark.attrs.fileGuid;
                }
                var newLinkMark = context.schema.marks.link.create(attrs);
                var newLinkNode = context.schema.text(attrs.text).mark([newLinkMark]);

                view.dispatch(view.state.tr.replaceSelectionWith(newLinkNode, false));
            } else {
                toggleMark(context.schema.marks.link, attrs)(view.state, view.dispatch);
            }
            view.focus();
        }
    });
}

function getLinkMark(node, context) {
    var result = null;
    node.marks.forEach(function (mark) {
        if (mark.type === context.schema.marks.link) {
            result = mark;
        }
    });

    return result;
}

function menu$b(context) {
    return [{
        id: 'linkItem',
        mark: 'link',
        group: 'marks',
        item: linkItem(context)
    }];
}var linkPlugin = function (context) {
    return new Plugin({
        props: {
            nodeViews: {
                link: function link(node) { return new LinkView(node, context) }
            },
            transformPasted: function (slice) {
                return new Slice(linkify(slice.content, context), slice.openStart, slice.openEnd);
            }
        }
    });
};

var LinkView = function LinkView(mark, context) {
    var this$1$1 = this;

    // The editor will use this as the node's DOM representation
    this.createDom(mark);
    this.dom.addEventListener("click", function (e) { return editNode(this$1$1.dom, context); });
};

LinkView.prototype.createDom = function createDom (mark) {
    this.dom = $(buildLink(mark.attrs.href, {
        'data-file-guid': mark.attrs.fileGuid,
        target: mark.attrs.target || '_blank'
    }))[0];
};

LinkView.prototype.stopEvent = function stopEvent () { return true };

// eslint-disable-next-line
var HTTP_LINK_REGEX = /((https?:\/\/(?:www\.|(?!www))[^\s\.]+\.[^\s]{2,})|[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,6})/ig;

var linkify = function(fragment, context) {
    var linkified = [];
    var urls = [];
    fragment.forEach(function (child) {
        if (child.isText) {
            var text = child.text;
            var pos = 0, match;

            while (match = HTTP_LINK_REGEX.exec(text)) {
                var start = match.index;
                var end = start + match[0].length;
                var link = child.type.schema.marks['link'];

                // simply copy across the text from before the match
                if (start > 0) {
                    linkified.push(child.cut(pos, start));
                }

                var urlText = text.slice(start, end);

                if (urlText.indexOf('http') !== 0) {
                    urlText = 'mailto:'+urlText;
                }

                urls.push(urlText);
                linkified.push(
                    child.cut(start, end).mark(link.create({href: urlText}).addToSet(child.marks))
                );
                pos = end;
            }

            // copy over whatever is left
            if (pos < text.length) {
                linkified.push(child.cut(pos));
            }
        } else {
            linkified.push(child.copy(linkify(child.content, context)));
        }
    });

    if (urls.length) {
        context.event.trigger('linkified', [urls, linkified]);
    }
    return Fragment.fromArray(linkified);
};/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 */


var link = {
    id: 'link',
    schema: schema$a,
    menu: function (context) { return menu$b(context); },
    registerMarkdownIt: function (md) {
        var defaultRender = md.renderer.rules.link_open || function(tokens, idx, options, env, self) {
            return self.renderToken(tokens, idx, options);
        };

        md.renderer.rules.link_open = function (tokens, idx, options, env, self) {
            var hrefIndex = tokens[idx].attrIndex('href');

            var ref = filterFileUrl(tokens[idx].attrs[hrefIndex][1], 'view');
            var url = ref.url;
            var guid = ref.guid;

            tokens[idx].attrs[hrefIndex][1] = url;

            if (guid) {
                tokens[idx].attrPush(['data-file-guid', guid]); // add new attribute
                tokens[idx].attrPush(['data-file-download', '']); // add new attribute
                tokens[idx].attrPush(['data-file-url', url]); // add new attribute
                tokens[idx].attrPush(['data-bs-target', '#globalModal']);
            }

            // If you are sure other plugins can't add `target` - drop check below
            var aIndex = tokens[idx].attrIndex('target');

            if (aIndex < 0) {
                // Check if the link is external
                var href = tokens[idx].attrs[hrefIndex][1];

                if (href[0] !== '#') {
                    var hrefUrl = new URL(href);
                    if (hrefUrl.hostname !== window.location.hostname || guid) {
                        tokens[idx].attrPush(['target', '_blank']); // add new attribute
                    }
                } else {
                    tokens[idx].attrPush(['target', '_self']);
                }
            } else if (!tokens[idx].attrs[aIndex][1]) {
                tokens[idx].attrs[aIndex][1] = '_blank'; // replace value of existing attr
            }

            tokens[idx].attrPush(['rel', DEFAULT_LINK_REL]);

            // pass token to default renderer.
            return defaultRender(tokens, idx, options, env, self);
        };
    },
    plugins: function (context) {
        return [linkPlugin(context)];
    }
};/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 */

var schema$9 = {
    nodes: {
        list_item: {
            sortOrder: 800,
            content: "paragraph block*",
            defining: true,
            parseDOM: [{tag: "li"}],
            toDOM: function () {
                return ["li", 0]
            },
            parseMarkdown: {block: "list_item"},
            toMarkdown: function (state, node) {
                state.renderContent(node);
            }
        }
    }
};/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 */


function outdentListItem(context) {
    return cmdItem(liftListItem(context.schema.nodes.list_item), {
        title: context.translate("Decrease indent"),
        feature: true,
        icon: icons.outdent,
        sortOrder: 120
    });
}

function indentListItem(context) {
    return cmdItem(sinkListItem(context.schema.nodes.list_item), {
        title: context.translate("Increase indent"),
        icon: icons.indent,
        sortOrder: 130
    });
}

function menu$a(context) {
    return [
        {
            id: 'outdentListItem',
            node: 'list_item',
            group: 'format',
            item: outdentListItem(context)
        },
        {
            id: 'indentListItem',
            node: 'list_item',
            group: 'format',
            item: indentListItem(context)
        }
    ];
}/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 *
 */

var list_item = {
    id: 'list_item',
    schema: schema$9,
    menu: function (context) {
        return menu$a(context);
    },
};var schema$8 = {
    nodes: {
        mention: {
            inline: true,
            group: 'inline',
            selectable: true,
            draggable: true,
            attrs: {
                name: {default: ''},
                guid: {default: ''},
                href: {default: '#'},
            },
            parseDOM: [{
                tag: 'span[data-mention]',
                getAttrs: function (dom) {
                    return {
                        guid: dom.getAttribute('data-mention'),
                        name: dom.textContent,
                    };
                },
            }],
            toDOM: function toDOM(node) {
                var attrs = {
                    'data-mention': node.attrs.guid,
                    contentEditable: 'false',
                    style: 'display:inline-block'
                };

                return [
                    'span',
                    attrs,
                    ['span', {style: 'display:block'}, (node.attrs.name.charAt(0) === '@' ? '' : '@') + node.attrs.name]
                ];
            },
            parseMarkdown: {
                node: "mention",
                getAttrs: function (tok) {
                    return ({
                        name: tok.attrGet("name"),
                        guid: tok.attrGet("guid"),
                        href: tok.attrGet("href")
                    })
                }
            },
            toMarkdown: function (state, node) {
                var linkMark = $node(node).getMark('link');
                if (linkMark) {
                    state.write(schema$a.marks.link.toMarkdown.close(state, linkMark));
                }

                var ref = node.attrs;
                var guid = ref.guid;
                var name = ref.name;
                var href = ref.href;
                state.write("[" + state.esc(name) + "](mention:" + state.esc(guid) + " " + state.quote(href) + ")");

                if (linkMark) {
                    state.write(schema$a.marks.link.toMarkdown.open);
                }
            },
        }
    },
    marks: {
        mentionQuery: {
            excludes: "_",
            inclusive: true,
            parseDOM: [
                {tag: 'span[data-mention-query]'}
            ],
            toDOM: function toDOM(node) {
                return ['span', {
                    'data-mention-query': true,
                    style: "color: #0078D7"
                }];
            }
        }
    }
};// https://github.com/ProseMirror/prosemirror/issues/262
var objectReplacementCharacter = '\ufffc';

var mentionRule = function (schema) {
    // eslint-disable-next-line
    return new InputRule(new RegExp('(^|[\\s\(' + objectReplacementCharacter + '])@$'), function (state, match, start, end) {
        var mark = schema.mark('mentionQuery');
        var mentionText = schema.text('@', [mark]);

        // Prevents an error log when using IME
        if (hasMark(state.selection.$anchor.nodeBefore, mark)) {
            return;
        }

        start = start + (match[0].length - 1);

        return state.tr
            .removeMark(0, state.doc.nodeSize - 2, mark)
            .setSelection(TextSelection.create(state.doc, start, end))
            .replaceSelectionWith(mentionText, false);
    });
};/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 *
 */


var MentionState = function MentionState(state, options) {
    this.state = state;
    this.provider = options.provider;
    this.reset();
};

MentionState.prototype.findQueryNode = function findQueryNode () {
    return $(this.view.dom).find('[data-mention-query]');
};

MentionState.prototype.update = function update (state, view) {
    this.view = view;
    this.state = state;
    var ref = state.schema.marks;
        var mentionQuery = ref.mentionQuery;
    var doc = state.doc;
        var selection = state.selection;
    var $from = selection.$from;
        var from = selection.from;
        var to = selection.to;

    this.active = doc.rangeHasMark(from - 1, to, mentionQuery);

    if (!this.active) {
        return this.reset();
    }

    var $query = this.findQueryNode();
    if(endsWith($query.text(), '  ')) {
        view.dispatch(this.state.tr.removeMark(0, this.state.doc.nodeSize -2, mentionQuery));
        return this.reset();
    }

    var $pos = doc.resolve(from - 1);

    this.queryMark = {
        start: $pos.path[$pos.path.length - 1],
        end: to
    };

    if(!$from.nodeBefore || !$from.nodeBefore.text) {
        return;
    }

    var query = $from.nodeBefore.text.substr(1);

    if(query != this.query) {
        this.query = query;
        this.provider.query(this, $query[0]);
    }
};

MentionState.prototype.reset = function reset () {
    var ref = this.state.schema.marks;
        var mentionQuery = ref.mentionQuery;

    if(this.state.storedMarks && this.state.storedMarks.length) {
        this.state.storedMarks = mentionQuery.removeFromSet(this.state.storedMarks);
    }
    //this.state.storedMarks = [];
    this.active = false;
    this.query = null;
    this.provider.reset();
};

MentionState.prototype.addMention = function addMention (item) {
    if(!item || !item.name || !item.guid) {
        this.view.dispatch(this.state.tr.removeMark(0, this.state.doc.nodeSize -2, mentionQuery));
        this.reset();
        return;
    }
    var ref = this.state.schema.nodes;
        var mention = ref.mention;
    var ref$1 = this.state.schema.marks;
        var mentionQuery = ref$1.mentionQuery;

    var nodes = [mention.create({
        name: item.name,
        guid: item.guid,
        href: item.link
    }, null), this.state.schema.text(' ')];


    var tr = this.state.tr
        .removeMark(0, this.state.doc.nodeSize -2, mentionQuery)
        .replaceWith(this.queryMark.start, this.queryMark.end, nodes);

    if(isChromeWithSelectionBug) {
        document.getSelection().empty();
    }

    this.view.dispatch(tr);
    this.view.focus();
};

var endsWith = function(string, suffix) {
    return string.indexOf(suffix, string.length - suffix.length) !== -1;
};var pluginKey$1 = new PluginKey('mention');

var mentionPlugin = function (context) {
    return new Plugin({
        state: {
            init: function init(config, state) {
                return new MentionState(state, context.options.mention);
            },
            apply: function apply(tr, prevPluginState, oldState, newState) {
                return prevPluginState;
            }
        },
        key: pluginKey$1,
        view: function (view) {
            var mentionState = pluginKey$1.getState(view.state);

            return {
                update: function update(view, prevState) {
                    mentionState.update(view.state, view);
                },
                destroy: function destroy() {}
            };
        },
        appendTransaction: function (transactions, oldState, newState) {
            return $node(newState.doc).find('mention').mark('link').removeMark('link', newState);
        }
    });
};var keymap$1 = function () {
    return {
        'ArrowUp': function (state, dispatch) {
            var mentionState = pluginKey$1.getState(state);

            if (mentionState && mentionState.active) {
                mentionState.provider.prev();
                return true;
            }

            return false;
        },
        'ArrowDown': function (state, dispatch) {
            var mentionState = pluginKey$1.getState(state);

            if (mentionState && mentionState.active) {
                mentionState.provider.next();
                return true;
            }

            return false;
        },
        'Enter': function (state, dispatch) {
            var mentionState = pluginKey$1.getState(state);

            if (mentionState && mentionState.active) {
                mentionState.provider.select();
                return true;
            }

            return false;
        },
        'Escape': function (state, dispatch) {
            var mentionState = pluginKey$1.getState(state);

            if (mentionState && mentionState.active) {
                mentionState.provider.reset();
                return true;
            }

            return false;
        }
    };
};/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 */


var inst = new markdownit();
var isSpace$1 = inst.utils.isSpace;

function createLinkExtension(id, options) {
    options = options || {};

    options.node = options.node || 'a';
    options.hrefAttr = options.hrefAttr || 'href';
    options.titleAttr = options.titleAttr || 'title';
    options.labelAttr = options.labelAttr || 'label';

    return function (state, silent) {
        var attrs,
            code,
            labelEnd,
            labelStart,
            label,
            pos,
            res,
            title,
            token,
            href = '',
            prefix = id + ':';
            state.pos;
            var max = state.posMax,
            start = state.pos;

        if (state.src.charCodeAt(state.pos) !== 0x5B/* [ */) {
            return false;
        }

        labelStart = state.pos + 1;
        labelEnd = state.md.helpers.parseLinkLabel(state, state.pos, true);

        // parser failed to find ']', so it's not a valid link
        if (labelEnd < 0) {
            return false;
        }

        pos = labelEnd + 1;
        if (pos < max && state.src.charCodeAt(pos) === 0x28/* ( */) {
            // Inline link

            // [link](  <id>:<href>  "title"  )
            //        ^^ skipping these spaces
            pos++;
            for (; pos < max; pos++) {
                code = state.src.charCodeAt(pos);
                if (!isSpace$1(code) && code !== 0x0A) {
                    break;
                }
            }
            if (pos >= max) {
                return false;
            }

            // [link](  <id>:<href>  "title"  )
            //          ^^^^ parsing prefix
            for (var i = 0; i < prefix.length; i++) {
                if (state.src.charAt(pos++) !== prefix.charAt(i)) {
                    return false;
                }
            }

            // [link](  <id>:<href>  "title"  )
            //               ^^^^ parsing href
            res = state.md.helpers.parseLinkDestination(state.src, pos, state.posMax);

            if (res.ok) {
                href = state.md.normalizeLink(res.str);
                if (state.md.validateLink(href)) {
                    pos = res.pos;
                } else {
                    href = '';
                }
            }

            // [link](  <id>:<href>  "title"  )
            //                     ^^ skipping these spaces
            start = pos;
            for (; pos < max; pos++) {
                code = state.src.charCodeAt(pos);
                if (!isSpace$1(code) && code !== 0x0A) {
                    break;
                }
            }

            // [link](  <id>:<href>  "title"  )
            //                       ^^^^^^^ parsing link title
            res = state.md.helpers.parseLinkTitle(state.src, pos, state.posMax);
            if (pos < max && start !== pos && res.ok) {
                title = res.str;
                pos = res.pos;

                // [link](  <id>:<href>  "title"  )
                //                              ^^ skipping these spaces
                for (; pos < max; pos++) {
                    code = state.src.charCodeAt(pos);
                    if (!isSpace$1(code) && code !== 0x0A) {
                        break;
                    }
                }
            } else {
                title = '';
            }

            if (pos >= max || state.src.charCodeAt(pos) !== 0x29/* ) */) {
                // parsing a valid shortcut link failed
                return false;
            }
            pos++;
        } else {
            return false;
        }

        // We found the end of the link, and know for a fact it's a valid link;
        // so all that's left to do is to call tokenizer.
        if (!silent) {
            state.pos = labelStart;
            state.posMax = labelEnd;

            label = state.src.substring(labelStart, labelEnd);

            token = state.push(id, options.node, 0);
            token.attrs = attrs = [[options.hrefAttr, href]];

            if (label) {
                attrs.push([options.labelAttr, label]);
            }

            if (title) {
                attrs.push([options.titleAttr, title]);
            }

            while (state.src.charCodeAt(state.pos) !== 0x29/* ) */) {
                state.pos++;
            }

            // NOTE linkExtensions currently do not support inline formatting:
            // TODO: make _open, _close behavior optional in order to support inline label format state.md.inline.tokenize(state);
        }

        state.pos = pos;
        state.posMax = max;
        return true;
    };
}/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 */


var mention$1 = {
    id: 'mention',
    schema: schema$8,
    plugins: function (context) {
        if (!context.options.mention || !context.options.mention.provider) {
            return [];
        }
        return [
            mentionPlugin(context)
        ];
    },
    inputRules: function (schema) {
        return [mentionRule(schema)];
    },
    keymap: function (context) { return keymap$1(); },
    registerMarkdownIt: function (markdownIt) {
        // [name](mention:guid "href")
        markdownIt.inline.ruler.before('link', 'mention', createLinkExtension('mention', {
            labelAttr: 'name',
            hrefAttr: 'guid',
            titleAttr: 'href'
        }));

        markdownIt.renderer.rules.mention = function (token, idx) {
            var mentioning = token[idx];
            var href = mentioning.attrGet('href');
            var guid = mentioning.attrGet('guid');
            var label = '@' + mentioning.attrGet('name');

            if (!validateHref(href, {relative: true})) {
                return buildLink('#', {'class': 'not-found'}, label);
            }

            return buildLink(href, {'data-contentcontainer-guid': guid}, label, false);
        };
    }
};var oembed$1 = {
    attrs: {
        href: {},
    },
    marks: "",
    atom: true,
    draggable: true,
    inline: true,
    group: "inline",
    parseDOM: [{
        tag: "[data-oembed]", getAttrs: function getAttrs(dom) {

            return {
                href: dom.getAttribute("data-oembed")
            };
        }
    }],
    toDOM: function (node) {
        var href = node.attrs.href;
        var $oembed = getOembed(href);

        if ($oembed && $oembed.length) {
            return $oembed.show()[0];
        }

        if(!validateHref(href)) {
            href = '#';
        }

        return $(buildLink(href, {'class': 'not-found'}))[0];
    },
    parseMarkdown: {
        node: "oembed", getAttrs: function(tok) {
            return ({
                href: tok.attrGet("href")
            });
        }
    },
    toMarkdown: function (state, node) {
        state.write('['+node.attrs.href+'](oembed:'+node.attrs.href+')');
    }
};

var schema$7 = {
    nodes: {
        oembed: oembed$1
    }
};/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 *
 */


var oembed_plugin = createLinkExtension('oembed', {node : 'div'});/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 */


var oembed = {
    id: 'oembed',
    schema: schema$7,
    init: function (context, isEdit) {
        if (!isEdit) {
            return;
        }

        context.event.on('linkified', function (evt, urls) {
            var doc = context.editor.view.state.doc;
            if ($node(doc).find('oembed').size() >= context.getPluginOption('oembed', 'max', 5)) {
                return;
            }

            loadOembeds(urls).then(function (result) {
                $.each(result, function (url, oembed) {
                    var $links = $node(context.editor.view.state.doc).find().mark('link').where(function (node) {
                        return $node(node).getMark('link').attrs.href === url;
                    });

                    $links.replaceWith(context.schema.nodes.oembed.create({href: url}), context.editor.view);

                    // We only allow a single oembed per copy/paste
                    return false;
                });
            });
        });
    },
    registerMarkdownIt: function (markdownIt) {
        markdownIt.inline.ruler.before('link', 'oembed', oembed_plugin);

        markdownIt.renderer.rules.oembed = function (token, idx) {
            var oembed = token[idx];
            var href = oembed.attrGet('href');
            var $oembed = humhub
                .require('oembed')
                .get(href);

            if (!$oembed || !$oembed.length) {
                return buildLink(href);
            }

            return $('<div>').append($oembed).html();
        };
    }
};/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 */


var focusKey = new PluginKey('focus');

var focusPlugin = function (context) {
    return new Plugin({
        key: focusKey,
        state: {
            init: function init() {
                return false;
            },
            apply: function apply(transaction, prevFocused) {
                var focused = transaction.getMeta(focusKey);
                if (typeof focused === 'boolean') {
                    return focused;
                }
                return prevFocused;
            }
        },
        props: {
            handleDOMEvents: {
                blur: function (view) {
                    view.dispatch(view.state.tr.setMeta(focusKey, false));
                    return false;
                },
                focus: function (view, event) {
                    view.dispatch(view.state.tr.setMeta(focusKey, true));
                    return false;
                }
            }
        }
    });
};/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 *
 */

var focus = {
    id: 'focus',
    plugins: function (context) {
        return [
            focusPlugin()
        ];
    },
};/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 */

var schema$6 = {
    nodes: {
        ordered_list: {
            sortOrder: 600,
            content: "list_item+",
            group: "block",
            attrs: {level: {default: 1}, order: {default: 1}, tight: {default: true}},
            parseDOM: [{
                tag: "ol", getAttrs: function getAttrs(dom) {
                    return {
                        level: 1,
                        order: dom.hasAttribute("start") ? +dom.getAttribute("start") : 1,
                        tight: dom.hasAttribute("data-tight")
                    }
                }
            }],
            toDOM: function (node) {
                return ["ol", {
                    start: node.attrs.order == 1 ? null : node.attrs.order,
                    "data-tight": node.attrs.tight ? "true" : null
                }, 0]
            },
            parseMarkdown: {
                block: "ordered_list", getAttrs: function (tok) {
                    return ({order: +tok.attrGet("start") || 1});
                }
            },
            toMarkdown: function (state, node) {
                if (state.table) {
                    state.text(node.textContent);
                    return;
                }

                var start = node.attrs.order || 1;
                var maxW = String(start + node.childCount - 1).length;
                var space = state.repeat(" ", maxW + 2);
                state.renderList(node, space, function (i) {
                    var nStr = String(start + i);
                    return state.repeat(" ", maxW - nStr.length) + nStr + ". "
                });
            }
        }
    }
};/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 *
 */


// : (NodeType) → InputRule
// Given a list node type, returns an input rule that turns a number
// followed by a dot at the start of a textblock into an ordered list.
var orderedListRule = function(schema) {
    return wrappingInputRule(/^(\d+)\.\s$/, schema.nodes.ordered_list, function (match) { return ({order: +match[1]}); },
        function (match, node) { return node.childCount + node.attrs.order == +match[1]; })
};/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 *
 */


function wrapOrderedList(context) {
    return cmdItem(wrapInList(context.schema.nodes.ordered_list), {
        title: context.translate("Wrap in ordered list"),
        icon: icons.orderedList,
        hideOnCollapse: true,
        sortOrder: 110
    });
}

function menu$9(context) {
    return [
        {
            id: 'wrapOrderedList',
            node: 'ordered_list',
            group: 'format',
            item: wrapOrderedList(context)
        }
    ]
}/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 *
 */

var ordered_list = {
    id: 'ordered_list',
    menu: function (context) { return menu$9(context); },
    schema: schema$6,
    inputRules: function (schema) {return [orderedListRule(schema)]}
};var schema$5 = {
    nodes: {
        paragraph:  {
            content: "inline*",
            group: "block",
            parseDOM: [{tag: "p"}],
            toDOM: function () {
                return ["p", 0]
            },
            parseMarkdown: {block: "paragraph"},
            toMarkdown: function (state, node, parent) {
                state.renderInline(node);

                if (!state.table) {
                    state.closeBlock(node);
                } else if (node.content && node.content.size && parent.lastChild !== node) {
                    state.write('<br><br>');
                }
            }
        }
    }
};/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 */


function makeParagraph(context) {
    return blockTypeItem(context.schema.nodes.paragraph, {
        title: context.translate("Change to paragraph"),
        label: context.translate("Paragraph")
    });
}

function menu$8(context) {
    return [{
        id: 'makeParagraph',
        node: 'paragraph',
        group: 'types',
        sortOrder: 100,
        item: makeParagraph(context)
    }];
}/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 *
 */
var paragraph = {
    id: 'paragraph',
    schema: schema$5,
    menu: function (context) { return menu$8(context); }
};/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 *
 */

var schema$4 = {
    marks: {
        strikethrough: {
            parseDOM: [{tag: "s"}],
            toDOM: function () {
                return ["s"]
            },
            parseMarkdown: {s: {mark: "strikethrough"}},
            toMarkdown: {open: "~~", close: "~~", mixable: true, expelEnclosingWhitespace: true}
        }
    }
};/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 *
 */



function markStrikethrough(context) {
    return markItem(context.schema.marks.strikethrough, {
        title: context.translate("Toggle strikethrough"),
        icon: icons.strikethrough,
        sortOrder: 300
    }, context);
}

function menu$7(context) {
    return [
        {
            id: 'markStrikethrough',
            mark: 'strikethrough',
            group: 'marks',
            item: markStrikethrough(context)
        }
    ]
}/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 *
 */

var strikethrough = {
    id: 'strikethrough',
    schema: schema$4,
    menu: function (context) { return menu$7(context); }
};/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 *
 */

var schema$3 = {
    marks: {
        strong: {
            sortOrder: 200,
            parseDOM: [{tag: "b"}, {tag: "strong"},
                {
                    style: "font-weight", getAttrs: function (value) {
                    return /^(bold(er)?|[5-9]\d{2,})$/.test(value) && null;
                }
                }],
            toDOM: function () {
                return ["strong"]
            },
            parseMarkdown: {mark: "strong"},
            toMarkdown: {open: "**", close: "**", mixable: true, expelEnclosingWhitespace: true}
        }
    }
};/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 *
 */



function markStrong(context) {
    return markItem(context.schema.marks.strong, {
        title: context.translate("Toggle strong style"),
        icon: icons.strong,
        sortOrder: 100
    }, context);
}

function menu$6(context) {
    return [
        {
            id: 'markStrong',
            mark: 'strong',
            group: 'marks',
            item: markStrong(context)
        }
    ]
}// : (NodeType) → InputRule
// Given a blockquote node type, returns an input rule that turns `"> "`
// at the start of a textblock into a blockquote.
var strongRule = function (schema) {
    // eslint-disable-next-line
    return markInputRule(/(?:\*\*|__)([^\*_]+)(?:\*\*|__)$/, schema.marks.strong);
};

function hasCodeMark(node)
{
    if (!node) {
        return false;
    }

    var result = false;
    node.marks.forEach(function (mark) {
        if (mark.type.spec.isCode) {
            result = true;
        }
    });

    return result;
}

function markInputRule(regexp, markType, getAttrs) {
    return new InputRule(regexp, function (state, match, start, end) {
        var attrs = getAttrs instanceof Function ? getAttrs(match) : getAttrs;
        var nodeBeforeEnd = state.selection.$to.nodeBefore;

        if (!nodeBeforeEnd || !nodeBeforeEnd.isText
            || nodeBeforeEnd.text.length < match[0].length - 1 // check that the match does not span multiple nodes
            || hasCodeMark(nodeBeforeEnd)
            || markType.isInSet(nodeBeforeEnd.marks)) {
            return null;
        }

        if (match[1]) {
            var tr = state.tr;
            var textStart = start + match[0].indexOf(match[1]);
            var textEnd = textStart + match[1].length;
            if (textEnd < end) { tr.delete(textEnd, end); }
            if (textStart > start) { tr.delete(start, textStart); }
            end = start + match[1].length;
            tr.addMark(start, end, markType.create(attrs));
            tr.removeStoredMark(markType); // Do not continue with mark.
            return tr;
        }

        return null;
    });
}/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 *
 */

var strong = {
    id: 'strong',
    schema: schema$3,
    menu: function (context) { return menu$6(context); },
    inputRules: function (schema) { return [strongRule(schema)]; },
};var nodes = tableNodes({
    tableGroup: "block",
    cellContent: "paragraph+",
    cellAttributes: {
        style: {
            default: null,
            getFromDOM: function getFromDOM(dom) {
                return dom.style;
            },
            setDOMAttr: function setDOMAttr(value, attrs) {
                if (value) {
                    attrs.style = value;
                }
            }
        }
    }
});

nodes.table_row.parseMarkdown = {tr: {block: "table_row"}};
nodes.table_header.parseMarkdown = {th: {block: "table_header"}};
nodes.table_cell.parseMarkdown = {td: {block: "table_cell"}};

nodes = Object.assign(nodes, {
    table: {
        content: "(table_row+ | table_head | table_body | table_foot)",
        tableRole: "table",
        isolating: false,
        group: "block",
        parseDOM: [{tag: "table"}],
        toDOM: function () {
            return ["table", ["tbody", 0]]
        },
        toMarkdown: function (state, node) {
            renderTable(state,node);
        },
        parseMarkdown: {block: "table"}
    },
    table_head: {
        content: "table_row*",
        tableRole: "head",
        parseDOM: [{tag: "thead"}],
        toDOM: function () {
            return ["thead", 0]
        },
        parseMarkdown: {thead: {block: "table_head"}}
    },
    table_body: {
        content: "table_row*",
        tableRole: "body",
        parseDOM: [{tag: "tbody"}],
        toDOM: function () {
            return ["tbody", 0]
        },
        parseMarkdown: {tbody: {block: "table_body"}}
    },
    table_foot: {
        content: "table_row*",
        tableRole: "foot",
        parseDOM: [{tag: "tfoot"}],
        toDOM: function () {
            return ["tfoot", 0]
        },
        parseMarkdown: {tfoot: {block: "table_foot"}}
    }
});

var renderTable = function(state, node, withHead) {
    state.table = true;

    if(typeof withHead === 'undefined') {
        withHead = true;
    }

    node.forEach(function (child, _, i) {
        if(child.type.name === 'table_body' || child.type.name === 'table_head') {
            renderTable(state, child, i === 0);
        } else if(withHead && i === 0) {
            renderHeadRow(state,child);
        } else {
            renderRow(state, child);
        }

        if(i !== (node.childCount -1)) {
            state.write("\n");
        }
    });

    state.table = false;
    state.closeBlock(node);
};

var renderHeadRow = function(state, node) {
    renderRow(state,node);
    state.write("\n");
    renderRow(state,node, true);
};

var renderRow = function(state, node, headMarker) {
    state.write('|');
    node.forEach(function (child, _, i) {
        renderCell(state, child, headMarker);
    });
};

var renderCell = function(state, node, headMarker) {
    state.write(' ');
    if(headMarker) {
        (node.textContent.length) ? state.write(state.repeat('-', node.textContent.length)) : state.write('---');
       /* if(node.attrs.style && node.attrs.style.indexOf("text-align:right") >= 0) {
            state.write(':');
        } else {
            state.write(' ');
        }*/
        state.write(' ');
    } else {
        state.renderContent(node);

        state.write(' ');
    }
    state.write('|');
};


var schema$2 = {
    nodes: nodes
};/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 */


function wrapTableItem(context) {
    var schema = context.schema;
    var command = wrapIn(schema.nodes.table_header);
    var itemOptions = {
        title: context.translate("Create table"),
        icon: icons.table,
        sortOrder: 300,
        hideOnCollapse: true,
        run: function run(state, dispatch, view) {
            openPrompt({
                title: context.translate("Insert table"),
                fields: {
                    rowCount: new TextField({label: context.translate("Rows"), required: true, value: 1}),
                    columnCount: new TextField({label: context.translate("Columns"), value: 1})
                },
                callback: function callback(attrs) {
                    wrapIn(schema.nodes.table_header)(view.state, dispatch);

                    for (var i = 1; i < attrs.columnCount; i++) {
                        addColumnAfter(view.state, dispatch);
                    }

                    toggleHeaderRow(view.state, dispatch);
                    toggleHeaderRow(view.state, dispatch);

                    for (var i$1 = 1; i$1 < attrs.rowCount; i$1++) {
                        addRowAfter(view.state, dispatch);
                        //toggleHeaderRow();
                    }

                    view.focus();
                }
            });
        },
        enable: function enable(state) {
            return command(state);
        },
        select: function select(state) {
            return command(state);
        }
    };

    return new MenuItem(itemOptions);
}

function menu$5(context) {
    return [
        {
            id: 'insertTable',
            node: 'table',
            item: wrapTableItem(context)
        },
        {
            id: 'tableOptions',
            node: 'table',
            item: new Dropdown(buildTableMenu(context), {
                icon: icons.table,
                sortOrder: 301
            })
        }
    ];
}

var buildTableMenu = function (context) {
    function item(label, cmd, sortOrder) {
        return new MenuItem({label: label, select: cmd, run: cmd, sortOrder: sortOrder, title: ''});
    }

    return [
        item(context.translate("Insert column before"), addColumnBefore, 0),
        item(context.translate("Insert column after"), addColumnAfter, 1),
        item(context.translate("Delete column"), deleteColumn, 2),
        item(context.translate("Insert row before"), addRowBefore, 3),
        item(context.translate("Insert row after"), addRowAfter, 4),
        item(context.translate("Delete row"), deleteRow, 5),
        item(context.translate("Delete table"), deleteTable, 6)
    ];
};/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 *
 */

// GFM table, non-standard
function isSpace(code) {
    switch (code) {
        case 0x09:
        case 0x20:
            return true;
    }
    return false;
}

function getLine(state, line) {
    var pos = state.bMarks[line] + state.blkIndent,
        max = state.eMarks[line];

    return state.src.substr(pos, max - pos);
}

function escapedSplit(str) {
    var result = [],
        pos = 0,
        max = str.length,
        ch,
        escapes = 0,
        lastPos = 0,
        backTicked = false,
        lastBackTick = 0;

    ch = str.charCodeAt(pos);

    while (pos < max) {
        if (ch === 0x60/* ` */) {
            if (backTicked) {
                // make \` close code sequence, but not open it;
                // the reason is: `\` is correct code block
                backTicked = false;
                lastBackTick = pos;
            } else if (escapes % 2 === 0) {
                backTicked = true;
                lastBackTick = pos;
            }
        } else if (ch === 0x7c/* | */ && (escapes % 2 === 0) && !backTicked) {
            result.push(str.substring(lastPos, pos));
            lastPos = pos + 1;
        }

        if (ch === 0x5c/* \ */) {
            escapes++;
        } else {
            escapes = 0;
        }

        pos++;

        // If there was an un-closed backtick, go back to just after
        // the last backtick, but as if it was a normal character
        if (pos === max && backTicked) {
            backTicked = false;
            pos = lastBackTick + 1;
        }

        ch = str.charCodeAt(pos);
    }

    result.push(str.substring(lastPos));

    return result;
}

var markdownit_table = function table_plugin(state, startLine, endLine, silent) {
    var ch, lineText, pos, i, nextLine, columns, columnCount, token,
        aligns, t, tableLines, tbodyLines;

    // should have at least two lines
    if (startLine + 2 > endLine) {
        return false;
    }

    nextLine = startLine + 1;

    if (state.sCount[nextLine] < state.blkIndent) {
        return false;
    }

    // if it's indented more than 3 spaces, it should be a code block
    if (state.sCount[nextLine] - state.blkIndent >= 4) {
        return false;
    }

    // first character of the second line should be '|', '-', ':',
    // and no other characters are allowed but spaces;
    // basically, this is the equivalent of /^[-:|][-:|\s]*$/ regexp

    pos = state.bMarks[nextLine] + state.tShift[nextLine];
    if (pos >= state.eMarks[nextLine]) {
        return false;
    }

    ch = state.src.charCodeAt(pos++);
    if (ch !== 0x7C/* | */ && ch !== 0x2D/* - */ && ch !== 0x3A/* : */) {
        return false;
    }

    while (pos < state.eMarks[nextLine]) {
        ch = state.src.charCodeAt(pos);

        if (ch !== 0x7C/* | */ && ch !== 0x2D/* - */ && ch !== 0x3A/* : */ && !isSpace(ch)) {
            return false;
        }

        pos++;
    }

    lineText = getLine(state, startLine + 1);

    columns = lineText.split('|');
    aligns = [];
    for (i = 0; i < columns.length; i++) {
        t = columns[i].trim();
        if (!t) {
            // allow empty columns before and after table, but not in between columns;
            // e.g. allow ` |---| `, disallow ` ---||--- `
            if (i === 0 || i === columns.length - 1) {
                continue;
            } else {
                return false;
            }
        }

        if (!/^:?-+:?$/.test(t)) {
            return false;
        }
        if (t.charCodeAt(t.length - 1) === 0x3A/* : */) {
            aligns.push(t.charCodeAt(0) === 0x3A/* : */ ? 'center' : 'right');
        } else if (t.charCodeAt(0) === 0x3A/* : */) {
            aligns.push('left');
        } else {
            aligns.push('');
        }
    }

    lineText = getLine(state, startLine).trim();
    if (lineText.indexOf('|') === -1) {
        return false;
    }
    if (state.sCount[startLine] - state.blkIndent >= 4) {
        return false;
    }
    columns = escapedSplit(lineText.replace(/^\||\|$/g, ''));

    // header row will define an amount of columns in the entire table,
    // and align row shouldn't be smaller than that (the rest of the rows can)
    columnCount = columns.length;
    if (columnCount > aligns.length) {
        return false;
    }

    if (silent) {
        return true;
    }


    token = state.push('table_open', 'table', 1);
    token.map = tableLines = [startLine, 0];

    // token = state.push('thead_open', 'thead', 1);
    // token.map = [ startLine, startLine + 1 ];

    token = state.push('tr_open', 'tr', 1);
    token.map = [startLine, startLine + 1];

    for (i = 0; i < columns.length; i++) {
        token = state.push('th_open', 'th', 1);
        token.map = [startLine, startLine + 1];
        if (aligns[i]) {
            token.attrs = [['style', 'text-align:' + aligns[i]]];
        }

        token = state.push('paragraph_open', 'p', 1);
        token.map = [startLine, state.line];

        token = state.push('inline', '', 0);
        token.content = columns[i].trim();
        token.map = [startLine, startLine + 1];
        token.children = [];

        token = state.push('paragraph_close', 'p', -1);
        token = state.push('th_close', 'th', -1);
    }

    token = state.push('tr_close', 'tr', -1);
    // token = state.push('thead_close', 'thead', -1);

    // token = state.push('tbody_open', 'tbody', 1);
    token.map = tbodyLines = [startLine + 2, 0];

    for (nextLine = startLine + 2; nextLine < endLine; nextLine++) {
        if (state.sCount[nextLine] < state.blkIndent) {
            break;
        }

        lineText = getLine(state, nextLine).trim();
        if (lineText.indexOf('|') === -1) {
            break;
        }
        if (state.sCount[nextLine] - state.blkIndent >= 4) {
            break;
        }
        columns = escapedSplit(lineText.replace(/^\||\|$/g, ''));

        token = state.push('tr_open', 'tr', 1);

        for (i = 0; i < columnCount; i++) {
            token = state.push('td_open', 'td', 1);

            if (aligns[i]) {
                token.attrs = [['style', 'text-align:' + aligns[i]]];
            }

            token = state.push('paragraph_open', 'p', 1);
            token.map = [startLine, state.line];

            token = state.push('inline', '', 0);
            token.content = columns[i] ? columns[i].trim() : '';
            token.children = [];

            token = state.push('paragraph_close', 'p', -1);

            token = state.push('td_close', 'td', -1);
        }
        token = state.push('tr_close', 'tr', -1);
    }
    // token = state.push('tbody_close', 'tbody', -1);
    token = state.push('table_close', 'table', -1);

    tableLines[1] = tbodyLines[1] = nextLine;
    state.line = nextLine;
    return true;
};

var table_plugin = /*@__PURE__*/getDefaultExportFromCjs(markdownit_table);/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 */


var table = {
    id: 'table',
    schema: schema$2,
    menu: function (context) { return menu$5(context); },
    registerMarkdownIt: function (markdownIt) {
        markdownIt.block.ruler.at('table', table_plugin);
    }
};/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 */

var schema$1 = {
    nodes: {
        text: {
            sortOrder: 900,
            group: "inline",
            toDOM: function (node) {
                return node.text
            },
            toMarkdown: function (state, node) {
                var isCodeMark = false;
                node.marks.forEach(function(mark) {
                    if(mark.type.spec.isCode) {
                        isCodeMark = true;
                    }
                });

                var text = node.text;

                if(isCodeMark) {
                    text = text.replace('`', '');
                }

                state.text(text, !isCodeMark);
            }
        }
    }
};/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 *
 */

var text = {
    id: 'text',
    schema: schema$1
};/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 *
 */


var attributesPlugin = function (context) {
    return new Plugin({
        props: {
            attributes: context.options.attributes
        }
    });
};/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 *
 */

var attributes = {
    id: 'attributes',
    plugins: function (context) {
        return [
            attributesPlugin(context)
        ]
    },
};/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 *
 */


var placeholderPlugin = function (context) {
    return new Plugin({
        state: {
            init: function init(config, state) {
                if(!isEmpty(state.doc, context)) {
                    return DecorationSet.empty;
                } else {
                    return DecorationSet.create(state.doc, [createDecoration(state.doc, context)]);
                }
            },
            apply: function apply(tr, set, state, newState) {
                // TODO: Currently if we leave the node with an empty e.g heading there is no placeholder
                // We should check when focusout, if the node is empty and change the first child to a paragraph

                if(focusKey.getState(newState)) {
                    return DecorationSet.empty;
                }

                if (!isEmpty(tr.doc, context)) {
                    return DecorationSet.empty;
                }

                return set.add(tr.doc, [createDecoration(tr.doc, context)]);
            }
        },
        props: {
            decorations: function decorations(state) {
                return this.getState(state);
            }
        }
    });
};

var isEmpty = function (doc, context) {
    return doc.childCount === 1
        && doc.firstChild.type.name === 'paragraph'
        && doc.firstChild.content.size === 0 &&
        !context.hasContentDecorations()
};

var createDecoration = function(doc, context) {
    var node = document.createElement('div');
    node.textContent = context.options.placeholder.text;
    node.className = context.options.placeholder['class'] || 'placeholder';
    return Decoration$1.widget(1, node);
};/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 *
 */

var placeholder = {
    id: 'placeholder',
    plugins: function (context) {
        if(!context.options.placeholder || !context.options.placeholder.text) {
            return [];
        }

        return [
            placeholderPlugin(context)
        ];
    },
};/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 *
 */


var loader = {
    id: 'loader',
    plugins: function (context) {
        return [loaderPlugin(context)]
    },
};/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 *
 */


var isVideoFile = function (file) {
    return !!((file.mimeIcon && file.mimeIcon.indexOf('mime-video') === 0) ||
        (file.mimeType && file.mimeType.indexOf('video/') === 0) ||
        (file.type && file.type.indexOf('video/') === 0));
};

var isAudioFile = function (file) {
    return !!((file.mimeIcon && file.mimeIcon.indexOf('mime-audio') === 0) ||
        (file.mimeType && file.mimeType.indexOf('audio/') === 0) ||
        (file.type && file.type.indexOf('audio/') === 0));
};

var createNodeFromFile = function (context, file) {
    if (file.error) {
        return null;
    }

    var schema = context.schema;

    if (file.mimeIcon === 'mime-image') {
        return schema.nodes.image.create({src: file.url, title: file.name, alt: file.name, fileGuid: file.guid});
    }

    if (schema.nodes.video && isVideoFile(file)) {
        return schema.nodes.video.create({
            src: file.url,
            title: file.name,
            controls: true,
            fileGuid: file.guid
        });
    }

    if (schema.nodes.audio && isAudioFile(file)) {
        return schema.nodes.audio.create({
            src: file.url,
            title: file.name,
            controls: true,
            fileGuid: file.guid
        });
    }

    var linkMark = schema.marks.link.create({href: file.url, fileGuid: file.guid});
    return schema.text(file.name, [linkMark]);
};

var triggerUpload = function(state, view, context, files) {
    // A fresh object to act as the ID for this upload
    var id = {};

    var uploadWidget = humhub.require('ui.widget.Widget').instance($('#'+context.id+'-file-upload'));

    if (uploadWidget) {
        uploadWidget.off('uploadStart.richtext').on('uploadStart.richtext', function (evt, response) {
            // Replace the selection with a placeholder
            loaderStart(context, id, true);
        }).off('uploadEnd.richtext').on('uploadEnd.richtext', function (evt, response) {
            replaceLoader(context, id, createNodesFromResponse(context, response), true);
            console.log('UPLOADER uploadEnd.richtext');
        }).off('uploadFinish.richtext').on('uploadFinish.richtext', function () {
            // Make sure our loader is removed after upload
            removeLoader(context, id, true);
        });

        if (files) {
            uploadWidget.$.fileupload('add', {files: files});
        } else {
            uploadWidget.run();
        }
    }
};

var createNodesFromResponse = function(context, response) {
    var nodes = [];

    // Otherwise, insert it at the placeholder's position, and remove the placeholder
    response.result.files.forEach(function (file) {
        var node = createNodeFromFile(context, file);

        if (node) {
            nodes.push(node);
        }
    });

    return nodes;
};/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 *
 */


var uploadFile = function (context) {
    return new MenuItem({
        title: context.translate("Upload and include a File"),
        label: '<i class="fa fa-upload"></i>' + context.translate("Upload File"),
        sortOrder: 0,
        enable: function enable(state) {
            return canInsertLink(state);
        },
        run: function run(state, dispatch, view) {
            if (view.state.selection.$from.parent.inlineContent) {
                triggerUpload(state, view, context);
            }
        }
    });
};

function menu$4(context) {
    return [
        {
            id: 'uploadFile',
            mark: 'link',
            group: 'insert',
            item: uploadFile(context)
        }
    ]
}/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 *
 */


var upload = {
    id: 'upload',
    menu:  function (context) { return menu$4(context); }
};/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 */


var clipboardPlugin = function (context) {
    var parser = getParser(context);

    return new Plugin({
        props: {
            clipboardTextParser: $.proxy(parser.parse, parser),
            transformPasted: function (slice) {
                if (slice && slice instanceof Node$1 && slice.type === context.schema.nodes.doc) {
                    return new Slice(slice.content, 0, 0)
                } else {
                    try {
                        var selectionMarks = getSelectionMarks(context);

                        if (selectionMarks && selectionMarks.length) {
                            applyMarksToRawText(slice, selectionMarks);
                        }
                    } catch (e) {
                        console.warn(e);
                    }
                }

                return slice;
            },
            handleDOMEvents: {
                paste: function (view, e) {
                    if (e.clipboardData.files && e.clipboardData.files.length) {
                        triggerUpload(view.state, view, context, e.clipboardData.files);
                        e.preventDefault();
                    }
                }
            }
        },
    });
};

function getSelectionMarks(context) {
    if (context.editor.view.state.storedMarks && context.editor.view.state.storedMarks.length) {
        return context.editor.view.state.storedMarks
    }

    var selection = context.editor.view.state.selection;
    var nodeBefore = selection.$from.nodeBefore;
    return nodeBefore ? nodeBefore.marks : null;
}

function applyMarksToRawText(slice, marks) {
    var fragment = slice.content;
    var firstChild = fragment.firstChild;

    if (!firstChild) {
        return;
    }

    var texts = $node(firstChild).find('text');
    if (texts.flat.length) {
        var firstText = texts.flat[0];
        if (firstText.isPlain()) {
            firstText.addMarks(marks);
        }
    }
}/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2018 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 *
 */


var clipboard = {
    id: 'clipboard',
    plugins: function (context) {
        return [
            clipboardPlugin(context)
        ]
    },
};var e=!1,n={false:"push",true:"unshift",after:"push",before:"unshift"},t={isPermalinkSymbol:!0};function r(r,a,i,l){var o;if(!e){var c="Using deprecated markdown-it-anchor permalink option, see https://github.com/valeriangalliat/markdown-it-anchor#permalinks";"object"==typeof process&&process&&process.emitWarning?process.emitWarning(c):console.warn(c),e=!0;}var s=[Object.assign(new i.Token("link_open","a",1),{attrs:[].concat(a.permalinkClass?[["class",a.permalinkClass]]:[],[["href",a.permalinkHref(r,i)]],Object.entries(a.permalinkAttrs(r,i)))}),Object.assign(new i.Token("html_block","",0),{content:a.permalinkSymbol,meta:t}),new i.Token("link_close","a",-1)];a.permalinkSpace&&i.tokens[l+1].children[n[a.permalinkBefore]](Object.assign(new i.Token("text","",0),{content:" "})),(o=i.tokens[l+1].children)[n[a.permalinkBefore]].apply(o,s);}function a(e){return "#"+e}function i(e){return {}}var l={class:"header-anchor",symbol:"#",renderHref:a,renderAttrs:i};function o(e){function n(t){return t=Object.assign({},n.defaults,t),function(n,r,a,i){return e(n,t,r,a,i)}}return n.defaults=Object.assign({},l),n.renderPermalinkImpl=e,n}var c=o(function(e,r,a,i,l){var o,c=[Object.assign(new i.Token("link_open","a",1),{attrs:[].concat(r.class?[["class",r.class]]:[],[["href",r.renderHref(e,i)]],r.ariaHidden?[["aria-hidden","true"]]:[],Object.entries(r.renderAttrs(e,i)))}),Object.assign(new i.Token("html_inline","",0),{content:r.symbol,meta:t}),new i.Token("link_close","a",-1)];if(r.space){var s="string"==typeof r.space?r.space:" ";i.tokens[l+1].children[n[r.placement]](Object.assign(new i.Token("string"==typeof r.space?"html_inline":"text","",0),{content:s}));}(o=i.tokens[l+1].children)[n[r.placement]].apply(o,c);});Object.assign(c.defaults,{space:!0,placement:"after",ariaHidden:!1});var s=o(c.renderPermalinkImpl);s.defaults=Object.assign({},c.defaults,{ariaHidden:!0});var u=o(function(e,n,t,r,a){var i=[Object.assign(new r.Token("link_open","a",1),{attrs:[].concat(n.class?[["class",n.class]]:[],[["href",n.renderHref(e,r)]],Object.entries(n.renderAttrs(e,r)))})].concat(n.safariReaderFix?[new r.Token("span_open","span",1)]:[],r.tokens[a+1].children,n.safariReaderFix?[new r.Token("span_close","span",-1)]:[],[new r.Token("link_close","a",-1)]);r.tokens[a+1]=Object.assign(new r.Token("inline","",0),{children:i});});Object.assign(u.defaults,{safariReaderFix:!1});var d=o(function(e,r,a,i,l){var o;if(!["visually-hidden","aria-label","aria-describedby","aria-labelledby"].includes(r.style)){ throw new Error("`permalink.linkAfterHeader` called with unknown style option `"+r.style+"`"); }if(!["aria-describedby","aria-labelledby"].includes(r.style)&&!r.assistiveText){ throw new Error("`permalink.linkAfterHeader` called without the `assistiveText` option in `"+r.style+"` style"); }if("visually-hidden"===r.style&&!r.visuallyHiddenClass){ throw new Error("`permalink.linkAfterHeader` called without the `visuallyHiddenClass` option in `visually-hidden` style"); }var c=i.tokens[l+1].children.filter(function(e){return "text"===e.type||"code_inline"===e.type}).reduce(function(e,n){return e+n.content},""),s=[],u=[];if(r.class&&u.push(["class",r.class]),u.push(["href",r.renderHref(e,i)]),u.push.apply(u,Object.entries(r.renderAttrs(e,i))),"visually-hidden"===r.style){if(s.push(Object.assign(new i.Token("span_open","span",1),{attrs:[["class",r.visuallyHiddenClass]]}),Object.assign(new i.Token("text","",0),{content:r.assistiveText(c)}),new i.Token("span_close","span",-1)),r.space){var d="string"==typeof r.space?r.space:" ";s[n[r.placement]](Object.assign(new i.Token("string"==typeof r.space?"html_inline":"text","",0),{content:d}));}s[n[r.placement]](Object.assign(new i.Token("span_open","span",1),{attrs:[["aria-hidden","true"]]}),Object.assign(new i.Token("html_inline","",0),{content:r.symbol,meta:t}),new i.Token("span_close","span",-1));}else { s.push(Object.assign(new i.Token("html_inline","",0),{content:r.symbol,meta:t})); }"aria-label"===r.style?u.push(["aria-label",r.assistiveText(c)]):["aria-describedby","aria-labelledby"].includes(r.style)&&u.push([r.style,e]);var f=[Object.assign(new i.Token("link_open","a",1),{attrs:u})].concat(s,[new i.Token("link_close","a",-1)]);(o=i.tokens).splice.apply(o,[l+3,0].concat(f)),r.wrapper&&(i.tokens.splice(l,0,Object.assign(new i.Token("html_block","",0),{content:r.wrapper[0]+"\n"})),i.tokens.splice(l+3+f.length+1,0,Object.assign(new i.Token("html_block","",0),{content:r.wrapper[1]+"\n"})));});function f(e,n,t,r){var a=e,i=r;if(t&&Object.prototype.hasOwnProperty.call(n,a)){ throw new Error("User defined `id` attribute `"+e+"` is not unique. Please fix it in your Markdown to continue."); }for(;Object.prototype.hasOwnProperty.call(n,a);){ a=e+"-"+i,i+=1; }return n[a]=!0,a}function p(e,n){n=Object.assign({},p.defaults,n),e.core.ruler.push("anchor",function(e){for(var t,a={},i=e.tokens,l=Array.isArray(n.level)?(t=n.level,function(e){return t.includes(e)}):function(e){return function(n){return n>=e}}(n.level),o=0;o<i.length;o++){var c=i[o];if("heading_open"===c.type&&l(Number(c.tag.substr(1)))){var s=n.getTokensText(i[o+1].children),u=c.attrGet("id");u=null==u?f(n.slugify(s),a,!1,n.uniqueSlugStartIndex):f(u,a,!0,n.uniqueSlugStartIndex),c.attrSet("id",u),!1!==n.tabIndex&&c.attrSet("tabindex",""+n.tabIndex),"function"==typeof n.permalink?n.permalink(u,n,e,o):(n.permalink||n.renderPermalink&&n.renderPermalink!==r)&&n.renderPermalink(u,n,e,o),o=i.indexOf(c),n.callback&&n.callback(c,{slug:u,title:s});}}});}Object.assign(d.defaults,{style:"visually-hidden",space:!0,placement:"after",wrapper:null}),p.permalink={__proto__:null,legacy:r,renderHref:a,renderAttrs:i,makePermalink:o,linkInsideHeader:c,ariaHidden:s,headerLink:u,linkAfterHeader:d},p.defaults={level:1,slugify:function(e){return encodeURIComponent(String(e).trim().toLowerCase().replace(/\s+/g,"-"))},uniqueSlugStartIndex:1,tabIndex:"-1",getTokensText:function(e){return e.filter(function(e){return ["text","code_inline"].includes(e.type)}).map(function(e){return e.content}).join("")},permalink:!1,renderPermalink:r,permalinkClass:s.defaults.class,permalinkSpace:s.defaults.space,permalinkSymbol:"¶",permalinkBefore:"before"===s.defaults.placement,permalinkHref:s.defaults.renderHref,permalinkAttrs:s.defaults.renderAttrs},p.default=p;
/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2018 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 */


var copyHrefToClipboard = function (target, context) {
    var href = target.href || target.parentElement.href;
    if (href) {
        var successMsg = context.translate('Link has been copied to clipboard');
        navigator.clipboard.writeText(href).then(function (r) { return showSuccessNotify(successMsg); });
    }
};

var anchors = {
    id: 'anchor',
    renderOnly: true,
    init: function (context, isEdit) {
        if (!isEdit) {
            context.editor.$.on('mouseenter', ':header', function () {
                $(this).find('.header-anchor').show().on('click', function (e) { return copyHrefToClipboard(e.target, context); });
            }).on('mouseleave', ':header', function () {
                $(this).find('.header-anchor').hide().off('click');
            });
        }
    },
    registerMarkdownIt: function (markdownIt) {
        var anchorOptions = {
            permalink: p.permalink.linkInsideHeader({
                symbol: '<i class="fa fa-chain"></i>',
                placement: 'after',
                ariaHidden: true,
                renderAttrs: function (slug, state) {
                    return {'style': 'display:none'};
                }
            })
        };

        markdownIt.use(p, anchorOptions);
    }
};/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2018 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 */


function fullScreen(context) {
    return new MenuItem({
        id: 'fullscreen',
        title: "Fullscreen",
        icon: icons.enlarge,
        sortOrder: 300,
        hideOnCollapse: true,
        run: function () {
            var $editor = context.editor.$;
            var $textarea = $editor.find('.ProseMirror-editor-source');

            if ($editor.is('.fullscreen')) {
                minimize(context);

                if ($textarea.length) {
                    var elem = $textarea.get(0);
                    var paddingTop = window.getComputedStyle(elem, null).getPropertyValue('padding-top');
                    var paddingTopValue = parseFloat(paddingTop.replace('px', ''));

                    $textarea.css({height: elem.scrollHeight + paddingTopValue});
                }
            } else {
                maximize(context);

                $editor.find('.ProseMirror-menubar-wrapper').css({height: $textarea.length ? 'auto' : '100%'});
                if ($textarea.length) {
                    $textarea.css({
                        height: 'calc(100% - ' + $editor.find('.ProseMirror-menubar').outerHeight() + 'px)',
                    });
                }
            }
        }
    });
}

function minimize(context, menuItem) {
    var $editor = context.editor.$;

    if ($editor.is('.fullscreen')) {
        $('body').removeClass('modal-open');
        $editor.removeClass('fullscreen');
        $editor.find('.Prosemirror').blur();

        context.fullScreenMenuItem.switchIcon(icons.enlarge);
    }
}

function maximize(context, menuItem) {
    var $editor = context.editor.$;

    if (!$editor.is('.fullscreen')) {
        // Fixes a bug in ios safari when displaying a position:fixed element with input focus...
        document.activeElement.blur();
        setTimeout(function () {
            context.editor.view.focus();
        }, 200);

        $('body').addClass('modal-open');
        $editor.addClass('fullscreen');

        context.fullScreenMenuItem.switchIcon(icons.shrink);
    }
}

function menu$3(context) {
    return [
        {
            id: 'fullScreen',
            group: 'resize',
            item: fullScreen(context)
        } ];
}/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2018 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 */


var fullscreen = {
    id: 'fullscreen',
    init: function init(context) {
        if (context.getPluginOption('fullscreen', 'autoFullScreen') === true) {
            context.editor.$.on('click', '.ProseMirror', function (e) {
                if (isSmallView && !context.editor.$.is('.fullscreen')) {
                    maximize(context);
                }
            });
        }

        context.editor.$.on('clear', function () {
            minimize(context);
        });
    },
    menu: function (context) {
        var fullScreenMenu = menu$3(context);
        context.fullScreenMenuItem = fullScreenMenu[0].item;
        return fullScreenMenu;
    }
};var toggleNavPluginKey = new PluginKey('toggleNav');

function isCollapsed(state) {
    return toggleNavPluginKey.getState(state);
}

function toggleNavPlugin(context) {
    return new Plugin({
        key: toggleNavPluginKey,
        state: {
            init: function init(config, state) {
                return localStorage.getItem("isExpandedToolbar") !== 'true';
            },
            apply: function apply(tr, prevPluginState, oldState, newState) {
                var meta = tr.getMeta(toggleNavPluginKey);
                if (typeof meta !== 'undefined') {
                    localStorage.setItem("isExpandedToolbar", !meta);
                }

                return typeof meta !== 'undefined' ? meta : prevPluginState;
            }
        },
    })
}/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2018 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 */


function resizeNav$1(context) {
    return new MenuItem({
        id: 'resizeNav',
        title: "More",
        sortOrder: 400,
        run: function run(state, dispatch) {
            var wasCollapsed = isCollapsed(state);
            dispatch(state.tr.setMeta(toggleNavPluginKey, !wasCollapsed));

            if (wasCollapsed) {
                this.switchIcon(icons.angleDoubleLeft);
            } else {
                this.switchIcon(icons.angleDoubleRight);
            }
        },
        icon: localStorage.getItem("isExpandedToolbar") !== 'true' ? icons.angleDoubleRight : icons.angleDoubleLeft
    });
}

function menu$2(context) {
    return [{
        id: 'resizeNav',
        group: 'resize',
        item: resizeNav$1()
    }];
}

function menuWrapper$1(context) {
    return {
        select: function (menuItem, state, active) {
            var collapsed = toggleNavPluginKey.getState(state);

            if (collapsed && menuItem.options.hideOnCollapse) {
                return false;
            }

            return active;
        }
    }
}/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2018 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 *
 */


var resizeNav = {
    id: 'resizeNav',
    menu: function (context) { return menu$2(); },
    menuWrapper: function (context) { return menuWrapper$1(); },
    plugins: function (context) {
        return [
            toggleNavPlugin()
        ]
    }
};/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2018 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 *
 */


var MaxHeightState = function MaxHeightState(state, options) {
    this.state = state;
    this.context = options.context;
    this.oldStageHeight = 0;
    this.scrollActive = false;
    this.niceScrollInit = false;
    this.initialized = false;
};

MaxHeightState.prototype.update = function update () {
    var stageHeight = this.context.editor.getStage()[0].offsetHeight;

    if(stageHeight === this.oldStageHeight) {
        return;
    }

    this.oldStageHeight = stageHeight;

    if(!this.scrollActive && this.context.editor.getStage()[0].scrollHeight > stageHeight) {
        if(!this.niceScrollInit && !isSmallView() && this.context.editor.getStage().niceScroll) {
            this.context.editor.getStage().niceScroll({
                cursorwidth: "7",
                cursorborder: "",
                cursorcolor: "#606572",
                cursoropacitymax: "0.3",
                nativeparentscrolling: false,
                autohidemode: false,
                railpadding: {top: 2, right: 3, left: 0, bottom: 2}
            });
        }

        this.niceScrollInit = true;
        this.scrollActive = true;
        this.context.editor.trigger('scrollActive');
    } else if(!this.initialized || this.scrollActive) {
        this.scrollActive = false;
        this.context.editor.trigger('scrollInactive');
    }

    this.initialized = true;
};/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2018 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 *
 */


var pluginKey = new PluginKey('max_height');

var maxHeight = {
    id: 'max-height',
    init: function (context, isEdit) {
        if(!isEdit) {
            return;
        }

        context.editor.on('init', function () {
            if(context.options.maxHeight) {
                context.editor.getStage().css({'max-height': context.options.maxHeight, 'overflow': 'auto'});
            }

            if(!context.editor.isEmpty()) {
                var maxHeightState = pluginKey.getState(context.editor.view.state);
                maxHeightState.update();
            }
        });
    },
    plugins: function (context) {
        return [new Plugin({
            state: {
                init: function init(config, state) {
                    return new MaxHeightState(state, {context: context});
                },
                apply: function apply(tr, prevPluginState, newState) {
                    return prevPluginState;
                }
            },
            key: pluginKey,
            view: function (view) {
                return {
                    update: function (view, prevState) {
                        var maxHeightState = pluginKey.getState(view.state);
                        maxHeightState.update();
                    },
                    destroy: function () {}
                }
            }
        })];
    }
};var savePlugin = function (context) {
    return new Plugin({
        props: {
            handleKeyDown: function handleKeyDown(view, event) {
                if(context.options.keySubmit === false) {
                    return;
                }

                if(event.ctrlKey && event.key === 's') {
                    event.preventDefault();
                    var $form = context.editor.$.closest('form');

                    if(!$form.length) {
                        return;
                    }

                    var $submit = $form.find('[type="submit"]');
                    if($submit.length) {
                        context.editor.$.trigger('focusout');
                        $submit.trigger('click');
                    }
                }
            },
        },
    });
};/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 */


var mention = {
    id: 'save',
    plugins: function (context) {
        if (!context.options.mention || !context.options.mention.provider) {
            return [];
        }
        return [
            savePlugin(context)
        ];
    },
};var sourcePluginKey = new PluginKey('source');

var EDIT_MODE_SOURCE = 'source';
var EDIT_MODE_RICHTEXT = 'richtext';

function isSourceMode(state) {
    return sourcePluginKey.getState(state) === EDIT_MODE_SOURCE;
}

function sourcePlugin(context) {
    return new Plugin({
        key: sourcePluginKey,
        state: {
            init: function init(config, state) {
                return EDIT_MODE_RICHTEXT;
            },
            apply: function apply(tr, prevPluginState, oldState, newState) {
                return tr.getMeta(sourcePluginKey) || prevPluginState;
            }
        },
    })
}

var textareaHandler = function (event, context) {
    var isFullscreen = context.editor.$.is('.fullscreen');

    if (!isFullscreen) {
        setTimeout(function () {
            var elem = event.target;
            var paddingTop = window.getComputedStyle(elem, null).getPropertyValue('padding-top');
            var paddingTopValue = parseFloat(paddingTop.replace('px', ''));

            elem.style.cssText = 'height: auto';
            elem.style.cssText = 'height:' + (elem.scrollHeight + paddingTopValue) + 'px';
        }, 0);
    }
};

function switchToSourceMode(context, focus) {
    if ( focus === void 0 ) focus = true;

    var $editor = context.editor.$;
    var $wrapper = $editor.find('.ProseMirror-menubar-wrapper');
    var $menubar = $editor.find('.ProseMirror-menubar');
    var $stage = $editor.find('.ProseMirror');
    var $textarea = $editor.find('textarea');

    if ($editor.is('.fullscreen')) {
        $wrapper.css({ height: 'auto' });
    }

    if (!$textarea.length) {
        $textarea = $('<textarea class="ProseMirror-editor-source"></textarea>');
        $editor.append($textarea);
        context.$source = $textarea;
    }

    $textarea.on('keydown', function (event) { return textareaHandler(event, context); });

    $textarea.css({
        height: $editor.is('.fullscreen') ? 'calc(100% - ' + $menubar.outerHeight() + 'px)' : $stage.outerHeight(),
        width: '100%',
    });

    $stage.addClass('d-none');
    $textarea.val(context.editor.serialize());

    if (focus) {
        context.editor.focus();
    }

    return EDIT_MODE_SOURCE;
}

function switchToRichtextMode(context) {
    var $editor = context.editor.$;
    var $wrapper = $editor.find('.ProseMirror-menubar-wrapper');
    var $stage = $editor.find('.ProseMirror');
    var $textarea = $editor.find('textarea');

    if ($editor.is('.fullscreen')) {
        $wrapper.css({ height: '100%' });
    }

    context.editor.init($textarea.val());
    $textarea.off('keydown', function (event) { return textareaHandler(event, context); });
    $textarea.remove();

    $stage.removeClass('d-none');
    context.menu.update();
    context.editor.focus();

    return EDIT_MODE_RICHTEXT;
}/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 */


var switchMode = function (context) {
    return new MenuItem({
        id: 'source',
        title: context.translate("Switch editor mode"),
        icon: icons.markdown,
        hideOnCollapse: true,
        run: function (state, dispatch) {
            if (isSourceMode(state)) {
                switchToRichtextMode(context);
                // We do not need to dispatch a transaction, since the editor will be reinitialized anyways
            } else {
                switchToSourceMode(context);
                dispatch(state.tr.setMeta(sourcePluginKey, EDIT_MODE_SOURCE));
            }
        },
        select: function (state) { return true; },
        active: function active(state) {
            return isSourceMode(state);
        }
    });
};

function menu$1(context) {
    return [{
        type: 'group',
        id: 'source-group',
        sortOrder: 550,
        items: [switchMode(context)]
    }];
}

function menuWrapper(context) {
    return {
        run: function(menuItem, state) {
            if (menuItem.options.id === 'source' || !isSourceMode(state)) {
                return false;
            }

            if (menuItem.runSource) {
                menuItem.runSource();
                return true;
            }

            return false;
        },
        enable: function(menuItem, state, enabled) {
            var sourceMode = isSourceMode(state);
            var enabledButtons = [
                'main-menu-group',
                'marks',
                'marks-group',
                'source',
                'source-group',
                'resize-group',
                'resizeNav',
                'fullScreen'
            ];

            if (enabledButtons.includes(menuItem.options.id) || (sourceMode && menuItem.runSource)) {
                return enabled;
            }

            return sourceMode ? false : enabled;
        },
        active: function(menuItem, state, active) {
            if (['main-menu-group', 'source', 'source-group'].includes(menuItem.options.id)) {
                return active;
            }

            return (isSourceMode(state)) ? false : active;
        }
    }
}/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 */

var source = {
    id: 'source',
    menu: function (context) { return menu$1(context); },
    menuWrapper: function (context) { return menuWrapper(); },
    plugins: function (context) {
        return [
            sourcePlugin()
        ];
    },
};/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2018 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 */


var keymap = function () {
    var getNextSelectionCell = function ($from) {
        var depth = $from.depth;
        var parent;

        do {
            parent = $from.node(depth);
            if (parent) {
                if (parent.type.name === "table_header" || parent.type.name === "table_cell") {
                    var table = $from.node(depth - 2); // Get the table node
                    var row = $from.node(depth - 1);
                    // Check if the current cell is the last cell in the table
                    var isLastCell = $from.index(depth - 2) === (table.childCount - 1)
                        && $from.index(depth - 1) === (row.childCount - 1);

                    return !isLastCell;
                }
                depth--;
            }
        } while (depth > 0 && parent);

        return null;
    };

    return {
        'Tab': function (state, dispatch, view) {
            if (dispatch) {
                var ref = state.selection;
                var $from = ref.$from;
                var parent = $from.node($from.depth - 1);
                var nodeType = parent ? parent.type : null;

                if (state.selection.empty && $from.depth > 1 && nodeType.name === "list_item") {
                    sinkListItem(nodeType)(state, dispatch);
                } else {
                    var nextSelection = getNextSelectionCell($from);
                    if (nextSelection !== null) {
                        if (nextSelection) {
                            goToNextCell(1)(state, dispatch);
                        } else {
                            addRowAfter(state, dispatch);
                            view.dispatchEvent(new KeyboardEvent('keydown', {key: 'Tab', code: 9}));
                        }
                    } else {
                        return false;
                    }
                }
            }
            return true;
        },
        "Shift-Tab": function (state, dispatch) {
            if (dispatch) {
                var ref = state.selection;
                var $from = ref.$from;
                var parent = $from.node($from.depth - 1);
                var nodeType = parent ? parent.type : null;

                if (state.selection.empty && $from.depth > 1 && nodeType.name === "list_item") {
                    liftListItem(nodeType)(state, dispatch);
                } else {
                    var nextSelection = getNextSelectionCell($from);
                    if (nextSelection !== null) {
                        goToNextCell(-1)(state, dispatch);
                    } else {
                        return false;
                    }
                }
            }
            return true;
        }
    };
};/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 */


var tabBehavior = {
    id: 'tab_behavior',
    keymap: function (context) { return keymap(); },
};var PluginRegistry = function PluginRegistry() {
    this.plugins = [];
    this.pluginMap = {};
    this.presets = new PresetRegistry(this);
    this.editorPresets = new PresetRegistry(this);
};

PluginRegistry.prototype.getPresetRegistry = function getPresetRegistry (context) {
    return context.editor.isEdit() ? this.editorPresets : this.presets;
};

PluginRegistry.prototype.register = function register (plugin, options) {
    options = options || {};

    this.plugins.push(plugin);
    this.pluginMap[plugin.id] = plugin;

    options = (typeof options === 'string') ? {preset: options} : options;

    if (options.preset) {
        this.addToPreset(plugin, options.preset, options);
    }
};

PluginRegistry.prototype.registerPreset = function registerPreset (id, plugins) {
    this.presets.register(id, plugins);
    this.editorPresets.register(id, plugins);

    if (plugins.callback) {
        plugins.callback($.proxy(this.addToPreset, this));
    }
};

PluginRegistry.prototype.addToPreset = function addToPreset (plugin, presetId, options) {
    options = options || {};

    if (typeof plugin === 'string') {
        plugin = this.pluginMap[plugin];
    }

    if (!plugin) {
        console.warn('Could not add plugin to preset ' + presetId);
        return;
    }

    if (!plugin.renderOnly) {
        this.editorPresets.add(presetId, plugin, options);
    }

    if (!plugin.editorOnly) {
        this.presets.add(presetId, plugin, options);
    }
};

var PresetRegistry = function PresetRegistry(pluginRegistry) {
    this.pluginRegistry = pluginRegistry;
    this.map = {};
};

PresetRegistry.prototype.get = function get (presetId) {
    return this.map[presetId];
};

PresetRegistry.prototype.register = function register (id, plugins) {
        var this$1$1 = this;

    var result = [];

    if (Array.isArray(plugins)) {
        plugins.forEach(function (pluginId) {
            var plugin = this$1$1.pluginRegistry.pluginMap[pluginId];
            if (plugin) {
                result.push(plugin);
            }
        });
    } else if (plugins.extend) {
        var toExtend = this.map[plugins.extend];

        if (!toExtend) {
            console.error('Could not extend richtext preset ' + plugins.extend + ' preset not registered!');
            return;
        }

        if (plugins.exclude && Array.isArray(plugins.exclude)) {
            toExtend.forEach(function (plugin) {
                if (plugin && !plugins.exclude.includes(plugin.id)) {
                    result.push(plugin);
                }
            });
        } else {
            result = toExtend.slice(0);
        }

        if (plugins.include && Array.isArray(plugins.include)) {
            plugins.include.forEach(function (plugin) {
                if (!this$1$1.pluginRegistry.pluginMap[plugin]) {
                    console.error('Could not include plugin ' + plugin + ' to preset ' + id + ' plugin not found!');
                } else {
                    result.push(this$1$1.pluginRegistry.pluginMap[plugin]);
                }
            });
        }
    }

    this.map[id] = result;
};

PresetRegistry.prototype.add = function add (presetId, plugin, options) {
    options = options || {};
    var preset = this.map[presetId] ? this.map[presetId].slice() : [];

    if (options['before'] && this.pluginRegistry.pluginMap[options['before']]) {
        var index = preset.indexOf(this.pluginRegistry.pluginMap[options['before']]);
        if (index >= 0) {
            preset.splice(index, 0, plugin);
        } else {
            console.warn('Tried appending plugin before non existing preset plugin: ' + presetId + ' before:' + options['before']);
            preset.push(plugin);
        }
    } else if (options['after'] && this.pluginRegistry.pluginMap[options['after']]) {
        var index$1 = preset.indexOf(this.pluginRegistry.pluginMap[options['after']]);
        if (index$1 >= 0) {
            preset.splice(index$1 + 1, 0, plugin);
        } else {
            console.warn('Tried appending plugin after non existing preset plugin: ' + presetId + ' after:' + options['after']);
            preset.push(plugin);
        }
    } else {
        preset.push(plugin);
    }

    this.map[presetId] = preset;
};/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2023 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 *
 */


var isActiveFileHandler = function () {
    return isHumhub() &&
        typeof humhub.prosemirrorFileHandler !== 'undefined' &&
        humhub.prosemirrorFileHandler === true;
};

var getFileHandlerItem = function(context, link, index) {
    link.on('click', function () {
        if (isHumhub()) {
            humhub.prosemirrorFileHandler = false;
        }
    });

    return new MenuItem({
        label: link.html(),
        title: link.text(),
        sortOrder: 300 + index,
        enable: function enable(state) {
            return canInsertLink(state)
        },
        run: function run() {
            link.click();
            if (isHumhub()) {
                humhub.prosemirrorFileHandler = true;
            }
        }
    })
};

var initFileHandler = function(context) {
    if (!isHumhub()) {
        return
    }

    humhub.event.on('humhub:file:created', function (evt, file) {
        if (isActiveFileHandler() && typeof context.editor.view !== 'undefined') {
            var view = context.editor.view;
            var node = createFileHandlerNode(context, file);
            if (node) {
                view.dispatch(view.state.tr.replaceSelectionWith(node, false));
            }
        }
    });

    var uploadWidget = humhub.require('ui.widget').Widget.instance(getFileHandlerContainer(context).find('[data-ui-widget="file.Upload"]').last());
    if (uploadWidget) {
        var id = context.id + '-file-handler';
        uploadWidget.off('uploadStart.richtext').on('uploadStart.richtext', function () {
            if (isActiveFileHandler()) {
                loaderStart(context, id, true);
            }
        }).off('uploadEnd.richtext').on('uploadEnd.richtext', function (evt, response) {
            if (isActiveFileHandler()) {
                replaceLoader(context, id, createNodesFromResponse(context, response), true);
            }
        }).off('uploadFinish.richtext').on('uploadFinish.richtext', function () {
            if (isActiveFileHandler()) {
                removeLoader(context, id, true);
            }
        });
    }
};

var createFileHandlerNode = function(context, file) {
    return createNodeFromFile(context, file)
};

var getFileHandlerContainer = function (context) {
    var form = context.editor.$.closest('form');
    var uploadButton = form.find('#' + context.id + '-file-upload').closest('.btn-group');
    return uploadButton.length ? uploadButton : form
};/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2023 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 *
 */

function menu(context) {
    var links = getFileHandlerContainer(context).find('a[data-action-process=file-handler]');

    if (links.length === 0) {
        return []
    }

    var isModalWindow = getFileHandlerContainer(context).closest('[data-ui-widget="ui.modal.Modal"]').length !== 0;

    var menus = [];
    for (var l = 0; l < links.length; l++) {
        var link = links.eq(l);

        if (isModalWindow && link.data('action-click') === 'ui.modal.load') {
            // Skip File Handler if it works through modal window and current editor is initialized from modal window as well,
            // because original modal window is replaced with the File Handler's modal window so impossible proper work there.
            continue
        }

        menus.push({
            id: 'insertFileHandler',
            node: 'file_handler',
            group: 'insert',
            item: getFileHandlerItem(context, link, l)
        });
    }

    return menus
}/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2023 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 */


var schema = {
    nodes: {
        file_handler: {}
    },
    marks: {
        sortOrder: 100,
        link: {
            attrs: {
                href: {},
                fileGuid: {default: null}
            },
            inclusive: false,
            parseDOM: [{
                tag: "a[href]", getAttrs: function getAttrs(dom) {
                    var href = dom.getAttribute("href");
                    if (!validateHref(href))  {
                        href = '#';
                    }

                    return {
                        href: href,
                        fileGuid: dom.getAttribute("data-file-guid")
                    }
                }
            }],
            toDOM: function toDOM(node) { var ref = node.attrs;
            var href = ref.href; return ["a", {href: href}, 0] },
            parseMarkdown: {
                mark: "link",
                getAttrs: function (tok) {
                    var ref = filterFileUrl(tok.attrGet("href"), 'view');
                    var url = ref.url;
                    var guid = ref.guid;

                    if (!validateHref(url))  {
                        url = '#';
                    }

                    return ({
                        href: url,
                        fileGuid: guid
                    });
                }
            },
            toMarkdown: {
                open: "[",
                close: function close(state, mark) {
                    var href = (mark.attrs.fileGuid) ? 'file-guid:' + mark.attrs.fileGuid  : mark.attrs.href;
                    return "](" + state.esc(href) + ")"
                }
            }
        }
    }
};/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2023 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 *
 */

var file_handler = {
    id: 'file_handler',
    schema: schema,
    menu: function (context) { return menu(context); },
    init: function (context) { return initFileHandler(context); }
};/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 */


var registry = new PluginRegistry();

var registerPlugin = function (plugin, options) {
    registry.register(plugin, options);
};

var registerPreset = function (id, plugins) {
    registry.registerPreset(id, plugins);
};

registerPlugin(doc$1, 'markdown');
registerPlugin(historyPlugin, 'markdown');
registerPlugin(focus, 'markdown');
registerPlugin(clipboard, 'markdown');
registerPlugin(loader, 'markdown');
registerPlugin(paragraph, 'markdown');
registerPlugin(heading, 'markdown');
registerPlugin(blockquote$1, 'markdown');
registerPlugin(strikethrough, 'markdown');
registerPlugin(em, 'markdown');
registerPlugin(strong, 'markdown');
registerPlugin(code$1, 'markdown');
registerPlugin(link, 'markdown');
registerPlugin(code_block, 'markdown');
registerPlugin(hard_break, 'markdown');
registerPlugin(horizontal_rule, 'markdown');
registerPlugin(file_handler, 'markdown');
registerPlugin(image, 'markdown');
registerPlugin(video, 'markdown');
registerPlugin(audio, 'markdown');
registerPlugin(list_item, 'markdown');
registerPlugin(bullet_list, 'markdown');
registerPlugin(ordered_list, 'markdown');
registerPlugin(table, 'markdown');
registerPlugin(text, 'markdown');
registerPlugin(attributes, 'markdown');
registerPlugin(upload, 'markdown');
registerPlugin(placeholder, 'markdown');
registerPlugin(fullscreen, 'markdown');
registerPlugin(resizeNav, 'markdown');
registerPlugin(maxHeight, 'markdown');
registerPlugin(mention, 'markdown');
registerPlugin(source, 'markdown');
registerPlugin(tabBehavior, 'markdown');
registerPlugin(emoji);
registerPlugin(mention$1);
registerPlugin(oembed);
registerPlugin(anchors);

registerPreset('normal', {
    extend: 'markdown',
    callback: function (addToPreset) {
        addToPreset('emoji', 'normal', {
            'before': 'hard_break'
        });

        addToPreset('mention', 'normal', {
            'before': 'ordered_list'
        });

        addToPreset('oembed', 'normal', {
            'before': 'ordered_list'
        });
    }
});

registerPreset('full', {
    extend: 'normal'
});

registerPreset('document', {
    extend: 'full',
    callback: function (addToPreset) {
        addToPreset('anchor', 'document', {
            'before': 'save'
        });
    }
});

var PresetManager = function PresetManager(options) {
    this.map = {};
    this.options = options;
};

PresetManager.prototype.add = function add (options, value) {
    this.map[options.preset] = value;
};

PresetManager.prototype.create = function create (context) {
    return this.options.create.apply(null, [context]);
};

PresetManager.isCustomPluginSet = function isCustomPluginSet (options) {
    return !!options.exclude || !!options.include || !!options.only;
};

PresetManager.prototype.check = function check (context) {
    var options = context.options;

    if (this.options.name && context[this.options.name]) {
        return context[this.options.name];
    }

    var result = [];

    if (!PresetManager.isCustomPluginSet(options) && this.map[options.preset]) {
        result = this.map[options.preset];
    }

    if (!result || (Array.isArray(result) && !result.length)) {
        result = this.create(context);

        if (!PresetManager.isCustomPluginSet(options)) {
            this.add(options, result);
        }
    }

    if (this.options.name) {
        context[this.options.name] = result;
    }

    return result;
};

var getPlugins = function (context) {
    var options = context.options;

    if (context.plugins) {
        return context.plugins;
    }

    var presetMap = registry.getPresetRegistry(context);
    var toExtend = presetMap.get(options.preset) ? presetMap.get(options.preset) : registry.plugins;

    if (!PresetManager.isCustomPluginSet(options)) {
        return context.plugins = toExtend.slice();
    }

    var result = [];

    if (options.only) {
        options.only.forEach(function (pluginId) {
            if (registry.pluginMap[pluginId]) {
                result.push(registry.pluginMap[pluginId]);
            } else {
                console.error('Could not include plugin ' + pluginId + ' plugin not registered!');
            }
        });

        return context.plugins = result;
    }

    if (options.exclude) {
        toExtend.forEach(function (plugin) {
            if (plugin && !options.exclude.includes(plugin.id)) {
                result.push(plugin);
            }
        });
    } else {
        result = toExtend.slice();
    }

    if (options.include) {
        options.include.forEach(function (pluginId) {
            if (registry.pluginMap[pluginId] && result.findIndex(function (plugin) { return plugin.id === pluginId; }) === -1) {
                result.push(registry.pluginMap[pluginId]);
            } else {
                console.error('Could not include plugin ' + pluginId + ' plugin not registered!');
            }
        });
    }

    return context.plugins = result;
};

var buildInputRules = function (context) {
    var plugins = context.plugins;
    var schema = context.schema;

    var rules = smartQuotes.concat([ellipsis, emDash]);
    plugins.forEach(function (plugin) {
        if (plugin.inputRules) {
            rules = rules.concat(plugin.inputRules(schema));
        }
    });

    return inputRules({rules: rules})
};

var buildPlugins = function (context) {
    var plugins = context.plugins;

    var result = [];
    plugins.forEach(function (plugin) {
        var isEdit = context.editor.isEdit();
        if (plugin.init) {
            plugin.init(context, isEdit);
        }

        if (isEdit && plugin.plugins) {
            var pl = plugin.plugins(context);
            if (pl && pl.length) {
                result = result.concat(pl);
                context.prosemirrorPlugins[plugin.id] = pl;
            }
        }
    });

    return result;
};

var buildPluginKeymap = function (context) {
    var plugins = context.plugins;

    var result = [];
    plugins.forEach(function (plugin) {
        if (plugin.keymap) {
            result.push(keymap$5(plugin.keymap(context)));
        }
    });

    return result;
};


// https://github.com/ProseMirror/prosemirror/issues/710
var isChromeWithSelectionBug = !!navigator.userAgent.match(/Chrome\/(5[89]|6[012])/);/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 */


var presets$3 = new PresetManager({
    name: 'renderer',
    create: function (context) {
        return createRenderer(context);
    }
});

var getRenderer = function (context) {
    return presets$3.check(context);
};

var createRenderer = function (context) {
    var markdownItOptions = context && context.options.markdownIt || {html: false, breaks: true, linkify: true};
    var renderer = markdownit(markdownItOptions);

    var plugins = getPlugins(context);
    plugins.forEach(function (plugin) {
        if (plugin.registerMarkdownIt) {
            plugin.registerMarkdownIt(renderer);
        }
    });

    return renderer;
};/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 *
 */


var mergeSchema = function(schema, plugin, context) {
    if(Array.isArray(plugin)) {
        plugin.forEach(function (newPlugin) {
            schema = mergeSchema(schema, newPlugin, context);
        });
    } else {
        if($.isFunction(schema)) {
            schema = schema(context);
        }
        schema.nodes = Object.assign(schema.nodes || {}, plugin.schema && plugin.schema.nodes || {});
        schema.marks = Object.assign(schema.marks || {}, plugin.schema && plugin.schema.marks || {});
    }

    return schema;
};

var presets$2 = new PresetManager({
    name: 'schema',
    create: function (context) {
        return new Schema(mergeSchema({}, context.plugins, context));
    }
});

var getSchema = function(context) {
    return presets$2.check(context);
};/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 */


var presets$1 = new PresetManager({
    name: 'parser',
    create: function (context) {
        return createParser(context);
    }
});

var getParser = function (context) {
    return presets$1.check(context);
};

var createParser = function (context) {
    var plugins = getPlugins(context);

    var tokens = {};
    plugins.forEach(function (plugin) {
        if (!plugin.schema) {
            return;
        }

        var schemaSpecs = Object.assign({}, plugin.schema.nodes || {}, plugin.schema.marks || {});

        for (var key in schemaSpecs) {
            var spec = schemaSpecs[key];
            if (spec.parseMarkdown) {
                if (spec.parseMarkdown.block || spec.parseMarkdown.node || spec.parseMarkdown.mark || spec.parseMarkdown.ignore) {
                    tokens[key] = spec.parseMarkdown;
                } else {
                    var tokenKey = Object.keys(spec.parseMarkdown)[0];
                    tokens[tokenKey] = spec.parseMarkdown[tokenKey];
                }
            }
        }
    });

    return new MarkdownParser(context.schema || getSchema(context), getRenderer(context), tokens);
};/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 */


var presets = new PresetManager({
    name: 'serializer',
    create: function (context) {
        return createSerializer(context);
    }
});

var getSerializer = function (context) {
    return presets.check(context);
};

var createSerializer = function (context) {
    var plugins = getPlugins(context);
    var nodeSpec = {};
    var markSpec = {};
    plugins.forEach(function (plugin) {
        if (!plugin.schema) {
            return;
        }

        var nodes = plugin.schema.nodes || {};

        for (var key in nodes) {
            var node = nodes[key];
            if (node.toMarkdown) {
                nodeSpec[key] = node.toMarkdown;
            }
        }

        var marks = plugin.schema.marks || {};

        for (var key$1 in marks) {
            var mark = marks[key$1];
            if (mark.toMarkdown) {
                markSpec[key$1] = mark.toMarkdown;
            } else {
                markSpec[key$1] = {open: '', close: ''};
            }
        }
    });

    return new HumHubMarkdownSerializer(nodeSpec, markSpec);
};

var HumHubMarkdownSerializer = /*@__PURE__*/(function (MarkdownSerializer) {
    function HumHubMarkdownSerializer () {
        MarkdownSerializer.apply(this, arguments);
    }

    if ( MarkdownSerializer ) HumHubMarkdownSerializer.__proto__ = MarkdownSerializer;
    HumHubMarkdownSerializer.prototype = Object.create( MarkdownSerializer && MarkdownSerializer.prototype );
    HumHubMarkdownSerializer.prototype.constructor = HumHubMarkdownSerializer;

    HumHubMarkdownSerializer.prototype.serialize = function serialize (content, options) {
        var state = new HumHubMarkdownSerializerState(
          this.nodes,
          this.marks,
          Object.assign(options || {}, {tightLists: false})
        );
        state.renderContent(content);
        return state.out;
    };

    return HumHubMarkdownSerializer;
}(MarkdownSerializer));

var HumHubMarkdownSerializerState = /*@__PURE__*/(function (MarkdownSerializerState) {
    function HumHubMarkdownSerializerState () {
        MarkdownSerializerState.apply(this, arguments);
    }

    if ( MarkdownSerializerState ) HumHubMarkdownSerializerState.__proto__ = MarkdownSerializerState;
    HumHubMarkdownSerializerState.prototype = Object.create( MarkdownSerializerState && MarkdownSerializerState.prototype );
    HumHubMarkdownSerializerState.prototype.constructor = HumHubMarkdownSerializerState;

    HumHubMarkdownSerializerState.prototype.esc = function esc (str, startOfLine) {
        // eslint-disable-next-line
        str = str.replace(/[|`*\\~\[\]]/g, "\\$&");
        if (startOfLine)
            { str = str.replace(/^[:#\-*+]/, "\\$&").replace(/^(\d+)\./, "$1\\."); }
        return str;
    };

    return HumHubMarkdownSerializerState;
}(MarkdownSerializerState));/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 */var markdown=/*#__PURE__*/Object.freeze({__proto__:null,MarkdownParser:MarkdownParser,MarkdownSerializer:MarkdownSerializer,MarkdownSerializerState:MarkdownSerializerState,createLinkExtension:createLinkExtension,defaultMarkdownParser:defaultMarkdownParser,defaultMarkdownSerializer:defaultMarkdownSerializer,getParser:getParser,getRenderer:getRenderer,getSerializer:getSerializer,schema:schema$o});/**
Create a plugin that, when added to a ProseMirror instance,
causes a decoration to show up at the drop position when something
is dragged over the editor.

Nodes may add a `disableDropCursor` property to their spec to
control the showing of a drop cursor inside them. This may be a
boolean or a function, which will be called with a view and a
position, and should return a boolean.
*/
function dropCursor(options) {
    if ( options === void 0 ) options = {};

    return new Plugin({
        view: function view(editorView) { return new DropCursorView(editorView, options); }
    });
}
var DropCursorView = function DropCursorView(editorView, options) {
    var this$1$1 = this;

    var _a;
    this.editorView = editorView;
    this.cursorPos = null;
    this.element = null;
    this.timeout = -1;
    this.width = (_a = options.width) !== null && _a !== void 0 ? _a : 1;
    this.color = options.color === false ? undefined : (options.color || "black");
    this.class = options.class;
    this.handlers = ["dragover", "dragend", "drop", "dragleave"].map(function (name) {
        var handler = function (e) { this$1$1[name](e); };
        editorView.dom.addEventListener(name, handler);
        return { name: name, handler: handler };
    });
};
DropCursorView.prototype.destroy = function destroy () {
        var this$1$1 = this;

    this.handlers.forEach(function (ref) {
            var name = ref.name;
            var handler = ref.handler;

            return this$1$1.editorView.dom.removeEventListener(name, handler);
        });
};
DropCursorView.prototype.update = function update (editorView, prevState) {
    if (this.cursorPos != null && prevState.doc != editorView.state.doc) {
        if (this.cursorPos > editorView.state.doc.content.size)
            { this.setCursor(null); }
        else
            { this.updateOverlay(); }
    }
};
DropCursorView.prototype.setCursor = function setCursor (pos) {
    if (pos == this.cursorPos)
        { return; }
    this.cursorPos = pos;
    if (pos == null) {
        this.element.parentNode.removeChild(this.element);
        this.element = null;
    }
    else {
        this.updateOverlay();
    }
};
DropCursorView.prototype.updateOverlay = function updateOverlay () {
    var $pos = this.editorView.state.doc.resolve(this.cursorPos);
    var isBlock = !$pos.parent.inlineContent, rect;
    if (isBlock) {
        var before = $pos.nodeBefore, after = $pos.nodeAfter;
        if (before || after) {
            var node = this.editorView.nodeDOM(this.cursorPos - (before ? before.nodeSize : 0));
            if (node) {
                var nodeRect = node.getBoundingClientRect();
                var top = before ? nodeRect.bottom : nodeRect.top;
                if (before && after)
                    { top = (top + this.editorView.nodeDOM(this.cursorPos).getBoundingClientRect().top) / 2; }
                rect = { left: nodeRect.left, right: nodeRect.right, top: top - this.width / 2, bottom: top + this.width / 2 };
            }
        }
    }
    if (!rect) {
        var coords = this.editorView.coordsAtPos(this.cursorPos);
        rect = { left: coords.left - this.width / 2, right: coords.left + this.width / 2, top: coords.top, bottom: coords.bottom };
    }
    var parent = this.editorView.dom.offsetParent;
    if (!this.element) {
        this.element = parent.appendChild(document.createElement("div"));
        if (this.class)
            { this.element.className = this.class; }
        this.element.style.cssText = "position: absolute; z-index: 50; pointer-events: none;";
        if (this.color) {
            this.element.style.backgroundColor = this.color;
        }
    }
    this.element.classList.toggle("prosemirror-dropcursor-block", isBlock);
    this.element.classList.toggle("prosemirror-dropcursor-inline", !isBlock);
    var parentLeft, parentTop;
    if (!parent || parent == document.body && getComputedStyle(parent).position == "static") {
        parentLeft = -pageXOffset;
        parentTop = -pageYOffset;
    }
    else {
        var rect$1 = parent.getBoundingClientRect();
        parentLeft = rect$1.left - parent.scrollLeft;
        parentTop = rect$1.top - parent.scrollTop;
    }
    this.element.style.left = (rect.left - parentLeft) + "px";
    this.element.style.top = (rect.top - parentTop) + "px";
    this.element.style.width = (rect.right - rect.left) + "px";
    this.element.style.height = (rect.bottom - rect.top) + "px";
};
DropCursorView.prototype.scheduleRemoval = function scheduleRemoval (timeout) {
        var this$1$1 = this;

    clearTimeout(this.timeout);
    this.timeout = setTimeout(function () { return this$1$1.setCursor(null); }, timeout);
};
DropCursorView.prototype.dragover = function dragover (event) {
    if (!this.editorView.editable)
        { return; }
    var pos = this.editorView.posAtCoords({ left: event.clientX, top: event.clientY });
    var node = pos && pos.inside >= 0 && this.editorView.state.doc.nodeAt(pos.inside);
    var disableDropCursor = node && node.type.spec.disableDropCursor;
    var disabled = typeof disableDropCursor == "function" ? disableDropCursor(this.editorView, pos, event) : disableDropCursor;
    if (pos && !disabled) {
        var target = pos.pos;
        if (this.editorView.dragging && this.editorView.dragging.slice) {
            var point = dropPoint(this.editorView.state.doc, target, this.editorView.dragging.slice);
            if (point != null)
                { target = point; }
        }
        this.setCursor(target);
        this.scheduleRemoval(5000);
    }
};
DropCursorView.prototype.dragend = function dragend () {
    this.scheduleRemoval(20);
};
DropCursorView.prototype.drop = function drop () {
    this.scheduleRemoval(20);
};
DropCursorView.prototype.dragleave = function dragleave (event) {
    if (event.target == this.editorView.dom || !this.editorView.dom.contains(event.relatedTarget))
        { this.setCursor(null); }
};/**
Gap cursor selections are represented using this class. Its
`$anchor` and `$head` properties both point at the cursor position.
*/
var GapCursor = /*@__PURE__*/(function (Selection) {
    function GapCursor($pos) {
        Selection.call(this, $pos, $pos);
    }

    if ( Selection ) GapCursor.__proto__ = Selection;
    GapCursor.prototype = Object.create( Selection && Selection.prototype );
    GapCursor.prototype.constructor = GapCursor;
    GapCursor.prototype.map = function map (doc, mapping) {
        var $pos = doc.resolve(mapping.map(this.head));
        return GapCursor.valid($pos) ? new GapCursor($pos) : Selection.near($pos);
    };
    GapCursor.prototype.content = function content () { return Slice.empty; };
    GapCursor.prototype.eq = function eq (other) {
        return other instanceof GapCursor && other.head == this.head;
    };
    GapCursor.prototype.toJSON = function toJSON () {
        return { type: "gapcursor", pos: this.head };
    };
    /**
    @internal
    */
    GapCursor.fromJSON = function fromJSON (doc, json) {
        if (typeof json.pos != "number")
            { throw new RangeError("Invalid input for GapCursor.fromJSON"); }
        return new GapCursor(doc.resolve(json.pos));
    };
    /**
    @internal
    */
    GapCursor.prototype.getBookmark = function getBookmark () { return new GapBookmark(this.anchor); };
    /**
    @internal
    */
    GapCursor.valid = function valid ($pos) {
        var parent = $pos.parent;
        if (parent.isTextblock || !closedBefore($pos) || !closedAfter($pos))
            { return false; }
        var override = parent.type.spec.allowGapCursor;
        if (override != null)
            { return override; }
        var deflt = parent.contentMatchAt($pos.index()).defaultType;
        return deflt && deflt.isTextblock;
    };
    /**
    @internal
    */
    GapCursor.findGapCursorFrom = function findGapCursorFrom ($pos, dir, mustMove) {
        if ( mustMove === void 0 ) mustMove = false;

        search: for (;;) {
            if (!mustMove && GapCursor.valid($pos))
                { return $pos; }
            var pos = $pos.pos, next = null;
            // Scan up from this position
            for (var d = $pos.depth;; d--) {
                var parent = $pos.node(d);
                if (dir > 0 ? $pos.indexAfter(d) < parent.childCount : $pos.index(d) > 0) {
                    next = parent.child(dir > 0 ? $pos.indexAfter(d) : $pos.index(d) - 1);
                    break;
                }
                else if (d == 0) {
                    return null;
                }
                pos += dir;
                var $cur = $pos.doc.resolve(pos);
                if (GapCursor.valid($cur))
                    { return $cur; }
            }
            // And then down into the next node
            for (;;) {
                var inside = dir > 0 ? next.firstChild : next.lastChild;
                if (!inside) {
                    if (next.isAtom && !next.isText && !NodeSelection.isSelectable(next)) {
                        $pos = $pos.doc.resolve(pos + next.nodeSize * dir);
                        mustMove = false;
                        continue search;
                    }
                    break;
                }
                next = inside;
                pos += dir;
                var $cur$1 = $pos.doc.resolve(pos);
                if (GapCursor.valid($cur$1))
                    { return $cur$1; }
            }
            return null;
        }
    };

    return GapCursor;
}(Selection));
GapCursor.prototype.visible = false;
GapCursor.findFrom = GapCursor.findGapCursorFrom;
Selection.jsonID("gapcursor", GapCursor);
var GapBookmark = function GapBookmark(pos) {
    this.pos = pos;
};
GapBookmark.prototype.map = function map (mapping) {
    return new GapBookmark(mapping.map(this.pos));
};
GapBookmark.prototype.resolve = function resolve (doc) {
    var $pos = doc.resolve(this.pos);
    return GapCursor.valid($pos) ? new GapCursor($pos) : Selection.near($pos);
};
function closedBefore($pos) {
    for (var d = $pos.depth; d >= 0; d--) {
        var index = $pos.index(d), parent = $pos.node(d);
        // At the start of this parent, look at next one
        if (index == 0) {
            if (parent.type.spec.isolating)
                { return true; }
            continue;
        }
        // See if the node before (or its first ancestor) is closed
        for (var before = parent.child(index - 1);; before = before.lastChild) {
            if ((before.childCount == 0 && !before.inlineContent) || before.isAtom || before.type.spec.isolating)
                { return true; }
            if (before.inlineContent)
                { return false; }
        }
    }
    // Hit start of document
    return true;
}
function closedAfter($pos) {
    for (var d = $pos.depth; d >= 0; d--) {
        var index = $pos.indexAfter(d), parent = $pos.node(d);
        if (index == parent.childCount) {
            if (parent.type.spec.isolating)
                { return true; }
            continue;
        }
        for (var after = parent.child(index);; after = after.firstChild) {
            if ((after.childCount == 0 && !after.inlineContent) || after.isAtom || after.type.spec.isolating)
                { return true; }
            if (after.inlineContent)
                { return false; }
        }
    }
    return true;
}

/**
Create a gap cursor plugin. When enabled, this will capture clicks
near and arrow-key-motion past places that don't have a normally
selectable position nearby, and create a gap cursor selection for
them. The cursor is drawn as an element with class
`ProseMirror-gapcursor`. You can either include
`style/gapcursor.css` from the package's directory or add your own
styles to make it visible.
*/
function gapCursor() {
    return new Plugin({
        props: {
            decorations: drawGapCursor,
            createSelectionBetween: function createSelectionBetween(_view, $anchor, $head) {
                return $anchor.pos == $head.pos && GapCursor.valid($head) ? new GapCursor($head) : null;
            },
            handleClick: handleClick,
            handleKeyDown: handleKeyDown,
            handleDOMEvents: { beforeinput: beforeinput }
        }
    });
}
var handleKeyDown = keydownHandler({
    "ArrowLeft": arrow("horiz", -1),
    "ArrowRight": arrow("horiz", 1),
    "ArrowUp": arrow("vert", -1),
    "ArrowDown": arrow("vert", 1)
});
function arrow(axis, dir) {
    var dirStr = axis == "vert" ? (dir > 0 ? "down" : "up") : (dir > 0 ? "right" : "left");
    return function (state, dispatch, view) {
        var sel = state.selection;
        var $start = dir > 0 ? sel.$to : sel.$from, mustMove = sel.empty;
        if (sel instanceof TextSelection) {
            if (!view.endOfTextblock(dirStr) || $start.depth == 0)
                { return false; }
            mustMove = false;
            $start = state.doc.resolve(dir > 0 ? $start.after() : $start.before());
        }
        var $found = GapCursor.findGapCursorFrom($start, dir, mustMove);
        if (!$found)
            { return false; }
        if (dispatch)
            { dispatch(state.tr.setSelection(new GapCursor($found))); }
        return true;
    };
}
function handleClick(view, pos, event) {
    if (!view || !view.editable)
        { return false; }
    var $pos = view.state.doc.resolve(pos);
    if (!GapCursor.valid($pos))
        { return false; }
    var clickPos = view.posAtCoords({ left: event.clientX, top: event.clientY });
    if (clickPos && clickPos.inside > -1 && NodeSelection.isSelectable(view.state.doc.nodeAt(clickPos.inside)))
        { return false; }
    view.dispatch(view.state.tr.setSelection(new GapCursor($pos)));
    return true;
}
// This is a hack that, when a composition starts while a gap cursor
// is active, quickly creates an inline context for the composition to
// happen in, to avoid it being aborted by the DOM selection being
// moved into a valid position.
function beforeinput(view, event) {
    if (event.inputType != "insertCompositionText" || !(view.state.selection instanceof GapCursor))
        { return false; }
    var ref = view.state.selection;
    var $from = ref.$from;
    var insert = $from.parent.contentMatchAt($from.index()).findWrapping(view.state.schema.nodes.text);
    if (!insert)
        { return false; }
    var frag = Fragment.empty;
    for (var i = insert.length - 1; i >= 0; i--)
        { frag = Fragment.from(insert[i].createAndFill(null, frag)); }
    var tr = view.state.tr.replace($from.pos, $from.pos, new Slice(frag, 0, 0));
    tr.setSelection(TextSelection.near(tr.doc.resolve($from.pos + 1)));
    view.dispatch(tr);
    return false;
}
function drawGapCursor(state) {
    if (!(state.selection instanceof GapCursor))
        { return null; }
    var node = document.createElement("div");
    node.className = "ProseMirror-gapcursor";
    return DecorationSet.create(state.doc, [Decoration$1.widget(state.selection.head, node, { key: "gapcursor" })]);
}var mac = typeof navigator != "undefined" ? /Mac/.test(navigator.platform) : false;

function exitCodeAtLast(state, dispatch) {
    var ref = state.selection;
    var $head = ref.$head;
    var $anchor = ref.$anchor;
    var parent = $head.parent;

    var isBlockQuote = false;
    $anchor.path.forEach(function (item, index) {
        if (!(index % 3) && item.type && item.type.name === 'blockquote') {
            isBlockQuote = true;
        }
    });

    if (!(parent.type.spec.code || isBlockQuote)
        || $anchor.parentOffset != $head.parentOffset
        || !$head.sameParent($anchor)
        || $head.parent.content.size != $head.parentOffset) {
        return false;
    }

    var nodeAfter = state.doc.resolve($head.pos - $head.parentOffset + parent.nodeSize - 1).nodeAfter;
    if (nodeAfter) {
        return false;
    }

    var above = $head.node(-1);
    var after = $head.indexAfter(-1);
    var type = above.contentMatchAt(after).defaultType;

    if (!above.canReplaceWith(after, after, type)) {
        return false;
    }

    if (dispatch) {
        var pos = (!parent.type.spec.code && isBlockQuote) ? $head.after() + 1 : $head.after();
        var tr = state.tr.replaceWith(pos, pos, type.createAndFill());
        tr.setSelection(Selection.near(tr.doc.resolve(pos), 1));
        dispatch(tr.scrollIntoView());
    }

    return true;
}

function exitMarkAtLast(state, dispatch) {
    var selection = state.selection;
    if (selection instanceof TextSelection
        && !selection.$head.nodeAfter
        && selection.$head.nodeBefore
        && selection.$head.nodeBefore.isText
        && selection.$head.nodeBefore.marks.length) {
        if (dispatch) {
            selection.$head.nodeBefore.marks.forEach(function (mark) {
                removeMark(mark.type, state, dispatch);
            });
        }
    }

    return false;
}

function removeMark(markType, state, dispatch) {
    var ref = state.selection;
    var empty = ref.empty;
    var $cursor = ref.$cursor;
    var ranges = ref.ranges;
    if ((empty && !$cursor) || !markApplies(state.doc, ranges, markType)) { return false; }
    if (dispatch) {
        if ($cursor) {
            if (markType.isInSet(state.storedMarks || $cursor.marks()))
                { dispatch(state.tr.removeStoredMark(markType)); }
        } else {
            var has = false, tr = state.tr;
            for (var i = 0; !has && i < ranges.length; i++) {
                var ref$1 = ranges[i];
                var $from = ref$1.$from;
                var $to = ref$1.$to;
                has = state.doc.rangeHasMark($from.pos, $to.pos, markType);
            }
            for (var i$1 = 0; i$1 < ranges.length; i$1++) {
                var ref$2 = ranges[i$1];
                var $from$1 = ref$2.$from;
                var $to$1 = ref$2.$to;
                if (has) { tr.removeMark($from$1.pos, $to$1.pos, markType); }
            }
            dispatch(tr.scrollIntoView());
        }
    }
    return true;
}

function markApplies(doc, ranges, type) {
    var loop = function ( i ) {
        var ref = ranges[i];
        var $from = ref.$from;
        var $to = ref.$to;
        var can = $from.depth == 0 ? doc.type.allowsMarkType(type) : false;
        doc.nodesBetween($from.pos, $to.pos, function (node) {
            if (can) { return false; }
            can = node.inlineContent && node.type.allowsMarkType(type);
        });
        if (can) { return { v: true }; }
    };

    for (var i = 0; i < ranges.length; i++) {
        var returned = loop( i );

        if ( returned ) return returned.v;
    }
    return false;
}

// :: (Schema, ?Object) → Object
// Inspect the given schema looking for marks and nodes from the
// basic schema, and if found, add key bindings related to them.
// This will add:
//
// * **Mod-b** for toggling [strong](#schema-basic.StrongMark)
// * **Mod-i** for toggling [emphasis](#schema-basic.EmMark)
// * **Mod-`** for toggling [code font](#schema-basic.CodeMark)
// * **Ctrl-Shift-0** for making the current textblock a paragraph
// * **Ctrl-Shift-1** to **Ctrl-Shift-Digit6** for making the current
//   textblock a heading of the corresponding level
// * **Ctrl-Shift-Backslash** to make the current textblock a code block
// * **Ctrl-Shift-8** to wrap the selection in an ordered list
// * **Ctrl-Shift-9** to wrap the selection in a bullet list
// * **Ctrl->** to wrap the selection in a block quote
// * **Enter** to split a non-empty textblock in a list item while at
//   the same time splitting the list item
// * **Mod-Enter** to insert a hard break
// * **Mod-_** to insert a horizontal rule
// * **Backspace** to undo an input rule
// * **Alt-ArrowUp** to `joinUp`
// * **Alt-ArrowDown** to `joinDown`
// * **Mod-BracketLeft** to `lift`
// * **Escape** to `selectParentNode`
//
// You can suppress or map these bindings by passing a `mapKeys`
// argument, which maps key names (say `"Mod-B"` to either `false`, to
// remove the binding, or a new key name string.
function buildKeymap(context) {
    var keys = {}, type;

    var schema = context.schema;
    var mapKeys = context.options.mapKeys;

    function bind(key, cmd) {
        if (mapKeys) {
            var mapped = mapKeys[key];
            if (mapped === false) { return; }
            if (mapped) { key = mapped; }
        }
        keys[key] = cmd;
    }

    bind("Escape", selectParentNode);
    bind('ArrowDown', exitCodeAtLast);
    bind('ArrowRight', exitMarkAtLast);

    bind("Alt-ArrowUp", joinUp);
    bind("Alt-ArrowDown", joinDown);
    bind("Mod-BracketLeft", lift$1);

    bind("Mod-z", undo);
    bind("Shift-Mod-z", redo);

    if (!mac) { bind("Mod-y", redo); }

    if (type = schema.marks.strong)
        { bind("Mod-b", toggleMark(type)); }
    if (type = schema.marks.em)
        { bind("Mod-i", toggleMark(type)); }
    if (type = schema.marks.code)
        { bind("Mod-`", toggleMark(type)); }

    if (type = schema.nodes.bullet_list)
        { bind("Shift-Ctrl-8", wrapInList(type)); }
    if (type = schema.nodes.ordered_list)
        { bind("Shift-Ctrl-9", wrapInList(type)); }
    if (type = schema.nodes.blockquote)
        { bind("Ctrl->", wrapIn(type)); }
    if (type = schema.nodes.hard_break) {
        var br = type, cmd = chainCommands(exitCode, function (state, dispatch) {
            if (state.selection
                && state.selection.$anchor.parent
                && state.selection.$anchor.parent.type === schema.nodes.heading) {
                splitBlock(state, dispatch);
                return true;
            }
            dispatch(state.tr.replaceSelectionWith(br.create()).scrollIntoView());
            return true;
        });
        bind("Mod-Enter", cmd);
        bind("Shift-Enter", cmd);
        if (mac) { bind("Ctrl-Enter", cmd); }
    }

    var splitList;

    if (type = schema.nodes.list_item) {
        splitList = splitListItem(type);
        bind("Mod-[", liftListItem(type));
        bind("Mod-]", sinkListItem(type));
    }
    if (type = schema.nodes.paragraph)
        { bind("Shift-Ctrl-0", setBlockType(type)); }
    if (type = schema.nodes.code_block)
        { bind("Shift-Ctrl-\\", setBlockType(type)); }
    if (type = schema.nodes.heading)
        { for (var i = 1; i <= 6; i++)
            { bind("Shift-Ctrl-" + i, setBlockType(type, {level: i})); } }
    if (type = schema.nodes.horizontal_rule) {
        var hr = type;
        bind("Mod-_", function (state, dispatch) {
            dispatch(state.tr.replaceSelectionWith(hr.create()).scrollIntoView());
            return true;
        });
    }

    baseKeymap['Backspace'] = chainCommands(undoInputRule, deleteSelection, joinBackward, selectNodeBackward);

    if (splitList) {
        baseKeymap['Enter'] = chainCommands(splitList, newlineInCode, createParagraphNear, liftEmptyBlock, splitBlock);
    } else {
        baseKeymap['Enter'] = chainCommands(newlineInCode, createParagraphNear, liftEmptyBlock, splitBlock);
    }

    for (var key in baseKeymap) {
        bind(key, baseKeymap[key]);
    }

    return keys;
}// !! This module exports helper functions for deriving a set of basic
// menu items, input rules, or key bindings from a schema. These
// values need to know about the schema for two reasons—they need
// access to specific instances of node and mark types, and they need
// to know which of the node and mark types that they know about are
// actually present in the schema.
//
// The `exampleSetup` plugin ties these together into a plugin that
// will automatically enable this basic functionality in an editor.

// :: (Object) → [Plugin]
// A convenience plugin that bundles together a simple menu with basic
// key bindings, input rules, and styling for the example schema.
// Probably only useful for quickly setting up a passable
// editor—you'll need more control over your settings in most
// real-world situations.
//
//   options::- The following options are recognized:
//
//     schema:: Schema
//     The schema to generate key bindings and menu items for.
//
//     mapKeys:: ?Object
//     Can be used to [adjust](#example-setup.buildKeymap) the key bindings created.
//
//     menuBar:: ?bool
//     Set to false to disable the menu bar.
//
//     history:: ?bool
//     Set to false to disable the history plugin.
//
//     floatingMenu:: ?bool
//     Set to false to make the menu bar non-floating.
//
//     menuContent:: [[MenuItem]]
//     Can be used to override the menu content.
function setupPlugins(context) {
    var result = buildPluginKeymap(context);

    result = result.concat([
        buildInputRules(context),
        keymap$5(buildKeymap(context)),
        keymap$5(baseKeymap),
        dropCursor(),
        gapCursor(),
        tableEditing(),
        buildMenuBar(context)
    ]);

    return result.concat(buildPlugins(context));
}/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 */


var MentionProvider = function (options) {
    this.event = $({});
    this.options = options;
    if (typeof this.options.minInput === 'undefined') {
        this.options.minInput = 2;
    }
    this.options.minInputText = this.options.minInputText || 'Please type at least ' + this.options.minInput + ' characters';
};

MentionProvider.prototype.query = function (state, node) {
    var this$1$1 = this;

    this.state = state;
    this.$node = $(node);

    if (this.options.minInput > 0 && this.state.query.length < this.options.minInput) {
        this.result = {text: this.options.minInputText};
        this.update();
        return;
    }

    this.loading();
    var queryResult = this.find(this.state.query, node);

    if (queryResult.then) {
        queryResult.then(function (result) {
            this$1$1.updateResult(result);
        });
    } else {
        this.updateResult(queryResult);
    }
};

MentionProvider.prototype.loading = function () {
    this.result = {loader: true};
    this.update();
};

MentionProvider.prototype.updateResult = function (result) {
    this.result = result;
    this.update();
};

MentionProvider.prototype.find = function (query, node) {
    // Abstract method has to be implemented by subclasses
};

MentionProvider.prototype.reset = function (query, node) {
    if (this.$container) {
        this.$container.remove();
        this.$container = null;
        this.event.trigger('closed');
    }
};

MentionProvider.prototype.prev = function () {
    var $cur = this.$container.find('.cur');
    var $prev = $cur.prev();
    if ($prev.length) {
        $prev.addClass('cur');
        $cur.removeClass('cur');
    }
};

MentionProvider.prototype.next = function () {
    var $cur = this.$container.find('.cur');
    var $next = $cur.next();
    if ($next.length) {
        $next.addClass('cur');
        $cur.removeClass('cur');
    }
};

MentionProvider.prototype.select = function () {
    var $cur = this.$container.find('.cur');
    this.state.addMention($cur.data('item'));
    this.reset();
};

MentionProvider.prototype.update = function (loading) {
    if (!this.$container) {
        this.$container = $('<div class="atwho-view humhub-richtext-provider">').css({'margin-top': '5px'});
    } else {
        this.$container.empty();
    }

    var position = this.$node.offset();
    this.$container.css({
        top: position.top + this.$node.outerHeight() + 2,
        left: position.left,
    });


    var that = this;
    if (this.result && this.result.length) {
        var $list = $('<ul style="list-style-type: none;padding:0px;margin:0px;">');
        this.result.forEach(function (item) {
            var name = encode$4(item.name);
            var $li = (item.image) ? $('<li>' + item.image + ' ' + name + '</li>') : $('<li>' + name + '</li>');

            $li.data('item', item).on('click', function () {
                that.$container.find('.cur').removeClass('cur');
                $li.addClass('cur');
                that.select();
            });

            $list.append($li);
        });

        $list.find('li').first().addClass('cur');

        this.$container.append($list);
    } else if (this.result.text) {
        var name = encode$4(this.result.text);
        this.$container.append($('<span>' + name + '</span>'));
    } else if (this.result.loader) {
        var $loader = getLoaderWidget();

        this.$container.append($('<div style="text-align:center;">').append($loader));
    } else {
        this.$container.append($('<span>No Result</span>'));
    }

    $('body').append(this.$container.show());
};/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2018 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 */


function uuidv4() {
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
        var r = Math.random() * 16 | 0,
            v = c === 'x' ? r : (r & 0x3 | 0x8);
        return v.toString(16);
    });
}


var Context = function Context(editor, options) {
    this.event = $({});
    this.uuid = uuidv4();
    this.editor = editor;
    this.editor.context = this;
    this.id = this.editor.$.attr('id');
    this.init(options);

    // This is used to indicate active decorations relevant for some content related assumptions (e.g placeholder plugin)
    this.contentDecorations = [];

    // Map of related prosemirror plugin array by plugin id
    this.prosemirrorPlugins = {};
};

Context.prototype.init = function init (options) {
    if (options.pluginOptions) {
        $.extend(options, options.pluginOptions);
    }

    this.options = options;
    this.options.preset = options.preset || 'full';

    if (Array.isArray(this.options.exclude) && !this.options.exclude.length) {
        this.options.exclude = undefined;
    }

    if (typeof this.options.exclude === 'string') {
        this.options.exclude = [this.options.exclude];
    }

    if (Array.isArray(this.options.include) && !this.options.include.length) {
        this.options.include = undefined;
    }

    if (typeof this.options.include === 'string') {
        this.options.include = [this.options.include];
    }

    if (!Array.isArray(this.options.only) || !this.options.only.length) {
        this.options.only = undefined;
    }

    getPlugins(this);
    getSchema(this);
};

Context.prototype.clear = function clear () {
    this.event.trigger('clear');
};

Context.prototype.getGlobalOption = function getGlobalOption (id, option, defaultValue) {
    var globalOptions = this.getGlobalOptions();

    if (option && typeof globalOptions[id] === 'undefined') {
        return defaultValue;
    }

    if (!option) {
        return globalOptions[id];
    }

    if (typeof globalOptions[id][option] === 'undefined') {
        return defaultValue;
    }

    return globalOptions[id][option];
};

Context.prototype.getPresetOption = function getPresetOption (id, option, defaultValue) {
    var globalOptions = this.getGlobalOptions();

    if (!globalOptions.presets) {
        return defaultValue;
    }

    if (!globalOptions.presets[this.options.preset]
        || !globalOptions.presets[this.options.preset][id]) {
        return defaultValue;
    }

    if (!option) {
        return globalOptions.presets[this.options.preset][id];
    }

    if (typeof globalOptions.presets[this.options.preset][id][option] === 'undefined') {
        return defaultValue;
    }

    return globalOptions.presets[this.options.preset][id][option];
};

Context.prototype.getOption = function getOption (id, option, defaultValue) {
    // First try fetching option from context
    var result = this.getPluginOption(id, option);

    // Then check for global option for current preset
    if (!result) {
        result = this.getPresetOption(id, option);
    }

    // Then check for global option
    if (!result) {
        result = this.getGlobalOption(id, option);
    }

    return typeof result !== 'undefined' ? result : defaultValue;
};


Context.prototype.getPluginOption = function getPluginOption (id, option, defaultValue) {
    var pluginOptions = this.options[id];

    if (!option) {
        return pluginOptions;
    } else if (pluginOptions) {
        return !(typeof pluginOptions[option] === 'undefined') ? pluginOptions[option] : defaultValue;
    }

    return defaultValue;
};

Context.prototype.translate = function translate (key) {
    var translateOption = this.options.translate || this.getGlobalOptions().translate;

    if (!translateOption) {
        return key;
    }

    if (typeof translateOption === 'function') {
        return translateOption(key) || key;
    }

    if (typeof translateOption === 'object') {
        return translateOption[key] || key;
    }

    return key;
};

Context.prototype.getGlobalOptions = function getGlobalOptions () {
    if (!window.humhub.richtext.globalOptions) {
        window.humhub.richtext.globalOptions = {};
    }

    return window.humhub.richtext.globalOptions;
};

Context.prototype.getProsemirrorPlugins = function getProsemirrorPlugins (id, prosemirror) {
    return this.prosemirrorPlugins[id];
};

Context.prototype.getPlugin = function getPlugin (id) {
    for (var i = 0; i < this.plugins.length; i++) {
        var plugin = this.plugins[i];
        if (plugin.id === id) {
            return plugin;
        }
    }
};

Context.prototype.addContentDecoration = function addContentDecoration (id) {
    if(this.contentDecorations.indexOf(id) < 0) {
        this.contentDecorations.push(id);
    }
};

Context.prototype.removeContentDecoration = function removeContentDecoration (id) {
    var index = this.contentDecorations.indexOf();
    if (index >= 0) {
        this.contentDecorations.splice(index, 1);
    }
};

Context.prototype.hasContentDecorations = function hasContentDecorations () {
    return !!this.contentDecorations.length;
};/*
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 */


$(document).on('mousedown.richtextProvider', function (evt) {
    if (!$(evt.target).closest('.humhub-richtext-provider:visible').length) {
        $('.humhub-richtext-provider:visible').each(function () {
            var $provider = $(this);

            var provider = $provider.data('provider');
            if (provider && provider.reset) {
                provider.reset();
            } else {
                $provider.hide().trigger('hidden');
            }
        });
    }
});

var BaseView = function BaseView(selector, options) {
    if ( options === void 0 ) options = {};

    this.$ = $(selector);

    var existingInstance = this.$.data('richtextInstance');
    if (existingInstance && existingInstance.view) {
        existingInstance.destroy();
        this.$.data('richtextInstance', this);
    }

    this.context = new Context(this, options);

    if (!this.isEdit()) {
        buildPlugins(this.context);
    }

    this.$.data('richtextInstance', this);
};

BaseView.prototype.isEdit = function isEdit () {
    return this.context.options.edit;
};

BaseView.prototype.trigger = function trigger (trigger$1, args) {
    this.context.event.trigger(trigger$1, args);
    this.$.trigger(trigger$1, args);

    var callBack = 'on' + trigger$1.charAt(0).toUpperCase() + trigger$1.slice(1);

    if (typeof this.context.options[callBack] === 'function') {
        this.context.options[callBack].apply(this, args);
    }
};

BaseView.prototype.on = function on (event, handler) {
    this.$.on(event, handler);
};

BaseView.prototype.getParser = function getParser$1 () {
    if (!this.parser) {
        this.parser = getParser(this.context);
    }

    return this.parser;
};

BaseView.prototype.getRenderer = function getRenderer$1 () {
    if (!this.renderer) {
        this.renderer = getRenderer(this.context);
    }

    return this.renderer;
};

BaseView.prototype.render = function render (md) {
    md = md || this.$.text();
    return this.getRenderer().render(md, this);
};

var MarkdownEditor = /*@__PURE__*/(function (BaseView) {
    function MarkdownEditor(selector, options) {
        if ( options === void 0 ) options = {};

        if (typeof options.edit === 'undefined') {
            options.edit = true;
        }

        BaseView.call(this, selector, options);
    }

    if ( BaseView ) MarkdownEditor.__proto__ = BaseView;
    MarkdownEditor.prototype = Object.create( BaseView && BaseView.prototype );
    MarkdownEditor.prototype.constructor = MarkdownEditor;

    MarkdownEditor.prototype.getSerializer = function getSerializer$1 () {
        if (!this.serializer) {
            this.serializer = getSerializer(this.context);
        }

        return this.serializer;
    };

    MarkdownEditor.prototype.init = function init (md) {
        if ( md === void 0 ) md = "";

        if (this.view) {
            this.destroy();
        }

        this.trigger('beforeInit');

        var editorState = EditorState$1.create({
            doc: this.getParser().parse(md),
            plugins: setupPlugins(this.context)
        });

        var fix = fixTables(editorState);
        editorState = (fix) ? editorState.apply(fix.setMeta("addToHistory", false)) : editorState;

        this.view = new EditorView$1(this.$[0], {
            state: editorState
        });

        this.$editor = $(this.view.dom);

        // Dirty workaround, force inline menus to be removed, this is required e.g. if the editor is removed from dom
        $('.humhub-richtext-inline-menu').remove();

        this.trigger('init');
    };

    MarkdownEditor.prototype.destroy = function destroy () {
        // TODO: rather trigger event and handle in module
        if (this.context.$source) {
            this.context.$source.remove();
            this.context.$source = null;
        }

        this.trigger('beforeDestroy');
        this.view.destroy();
        this.trigger('afterDestroy');
    };

    MarkdownEditor.prototype.isEdit = function isEdit () {
        return this.context.options.edit;
    };

    MarkdownEditor.prototype.clear = function clear () {
        this.trigger('beforeClear');
        this.destroy();
        this.context.clear();
        this.$stage = null;
        this.init();
        this.trigger('afterClear');
    };

    MarkdownEditor.prototype.getStage = function getStage () {
        if (!this.$stage) {
            this.$stage = this.$.find('.ProseMirror');
        }
        return this.$stage;
    };

    MarkdownEditor.prototype.isEmpty = function isEmpty () {
        var doc = this.view.state.doc;
        return doc.childCount === 1 &&
            doc.firstChild.type.name === 'paragraph' &&
            doc.firstChild.content.size === 0 &&
            !this.context.hasContentDecorations()
    };

    MarkdownEditor.prototype.focus = function focus (atEnd) {
        this.trigger('beforeFocus');

        // The extra condition is required when switching to source mode, but the state is not available yet
        if (isSourceMode(this.view.state) || (this.context.$source && this.context.$source.is(':visible'))) {
            if (atEnd) {
                var end = this.context.$source.val().length;
                this.context.$source[0].setSelectionRange(end, end);
            }
            return this.context.$source.focus();
        } else {
            if (atEnd) {
                var selection = Selection.atEnd(this.view.docView.node);
                var tr = this.view.state.tr.setSelection(selection);
                var state = this.view.state.apply(tr);
                this.view.updateState(state);
            }
            this.view.focus();
        }
        this.trigger('afterFocus');
    };

    MarkdownEditor.prototype.hasFocus = function hasFocus () {
        return isSourceMode(this.view.state)
            ? this.context.$source.is(':focus')
            : $(this.view.dom).is(':focus');
    };

    MarkdownEditor.prototype.serialize = function serialize () {
        this.trigger('beforeSerialize');

        var result = isSourceMode(this.view.state)
            ? this.context.$source.val()
            : this.getSerializer().serialize(this.view.state.doc);

        this.trigger('afterSerialize', result);

        return result;
    };

    MarkdownEditor.prototype.showSourceView = function showSourceView () {
        switchToSourceMode(this.context, false);
        this.view.dispatch(this.view.state.tr.setMeta(sourcePluginKey, EDIT_MODE_SOURCE));
    };

    MarkdownEditor.prototype.transformToView = function transformToView () {
        this.destroy();
        var serialized = this.serialize();
        var view = new MarkdownView(this.$, this.context.options);
        view.init(serialized);
        return view;
    };

    return MarkdownEditor;
}(BaseView));

var MarkdownView = /*@__PURE__*/(function (BaseView) {
    function MarkdownView(selector, options) {
        if ( options === void 0 ) options = {};

        options.edit = false;

        BaseView.call(this, selector, options);

        this.renderer = getRenderer(this.context);
    }

    if ( BaseView ) MarkdownView.__proto__ = BaseView;
    MarkdownView.prototype = Object.create( BaseView && BaseView.prototype );
    MarkdownView.prototype.constructor = MarkdownView;

    MarkdownView.prototype.init = function init (md) {
        this.context.source = md;
        this.$.html(this.render(md));
    };

    MarkdownView.prototype.destroy = function destroy () {
        this.$.html('');
    };

    MarkdownView.prototype.clear = function clear () {
        this.destroy();
        this.context.clear();
        this.init();
    };

    MarkdownView.prototype.isEdit = function isEdit () {
        return false;
    };

    MarkdownView.prototype.transformToEditor = function transformToEditor (focus) {
        this.destroy();
        var editor = new MarkdownEditor(this.$, this.context.options);
        editor.init(this.context.source);

        if (focus !== false) {
            editor.focus();
        }

        return editor;
    };

    return MarkdownView;
}(BaseView));

window.humhub = window.humhub || {};

window.prosemirror = window.humhub.richtext = {
    MarkdownEditor: MarkdownEditor,
    MarkdownView: MarkdownView,
    globalOptions: {},
    state: state,
    view: view,
    transform: transform,
    inputRules: inputRules$1,
    model: model,
    commands: commands,
    history: history$1,
    keymap: keymap$6,
    menu: menu$k,
    loader: loader$1,
    pmmenu: pmmenu,
    prompt: prompt,
    getRenderer: getRenderer,
    plugin: {
        registerPreset: registerPreset,
        registerPlugin: registerPlugin,
        markdown: markdown
    },
    $node: $node,
    MentionProvider: MentionProvider
};

if (window.humhub && window.humhub.module) {
    window.humhub.module('ui.richtext', function (module) {
        module.export(window.humhub.richtext);
    });
}})();