text: "use strict";
  
  const CookieJar = require("tough-cookie").CookieJar;
  
  const NodeImpl = require("./Node-impl").implementation;
  
  const NODE_TYPE = require("../node-type");
  const memoizeQuery = require("../../utils").memoizeQuery;
  const firstChildWithHTMLLocalName = require("../helpers/traversal").firstChildWithHTMLLocalName;
  const firstChildWithHTMLLocalNames = require("../helpers/traversal").firstChildWithHTMLLocalNames;
  const firstDescendantWithHTMLLocalName = require("../helpers/traversal").firstDescendantWithHTMLLocalName;
  const whatwgURL = require("whatwg-url");
  const domSymbolTree = require("../helpers/internal-constants").domSymbolTree;
  const eventAccessors = require("../helpers/create-event-accessor");
  const stripAndCollapseASCIIWhitespace = require("../helpers/strings").stripAndCollapseASCIIWhitespace;
  const DOMException = require("../../web-idl/DOMException");
  const HTMLToDOM = require("../../browser/htmltodom");
  const History = require("../generated/History");
  const Location = require("../generated/Location");
  const HTMLCollection = require("../generated/HTMLCollection");
  const idlUtils = require("../generated/utils");
  const validateName = require("../helpers/validate-names").name;
  const validateAndExtract = require("../helpers/validate-names").validateAndExtract;
  const resourceLoader = require("../../browser/resource-loader");
  
  const GlobalEventHandlersImpl = require("./GlobalEventHandlers-impl").implementation;
  
  const clone = require("../node").clone;
  const generatedAttr = require("../generated/Attr");
  const listOfElementsWithQualifiedName = require("../node").listOfElementsWithQualifiedName;
  const listOfElementsWithNamespaceAndLocalName = require("../node").listOfElementsWithNamespaceAndLocalName;
  const listOfElementsWithClassNames = require("../node").listOfElementsWithClassNames;
  const Comment = require("../generated/Comment");
  const ProcessingInstruction = require("../generated/ProcessingInstruction");
  const CDATASection = require("../generated/CDATASection");
  const Text = require("../generated/Text");
  const DocumentFragment = require("../generated/DocumentFragment");
  const DOMImplementation = require("../generated/DOMImplementation");
  const ParentNodeImpl = require("./ParentNode-impl").implementation;
  const HTMLElement = require("../generated/HTMLElement");
  const HTMLUnknownElement = require("../generated/HTMLUnknownElement");
  const TreeWalker = require("../generated/TreeWalker");
  const NodeIterator = require("../generated/NodeIterator");
  
  const CustomEvent = require("../generated/CustomEvent");
  const ErrorEvent = require("../generated/ErrorEvent");
  const Event = require("../generated/Event");
  const FocusEvent = require("../generated/FocusEvent");
  const HashChangeEvent = require("../generated/HashChangeEvent");
  const KeyboardEvent = require("../generated/KeyboardEvent");
  const MessageEvent = require("../generated/MessageEvent");
  const MouseEvent = require("../generated/MouseEvent");
  const PopStateEvent = require("../generated/PopStateEvent");
  const ProgressEvent = require("../generated/ProgressEvent");
  const TouchEvent = require("../generated/TouchEvent");
  const UIEvent = require("../generated/UIEvent");
  
  function clearChildNodes(node) {
    for (let child = domSymbolTree.firstChild(node); child; child = domSymbolTree.firstChild(node)) {
      node.removeChild(child);
    }
  }
  
  function setInnerHTML(document, node, html) {
    // Clear the children first:
    if (node._templateContents) {
      clearChildNodes(node._templateContents);
    } else {
      clearChildNodes(node);
    }
  
    if (html !== "") {
      if (node.nodeName === "#document") {
        document._htmlToDom.appendToDocument(html, node);
      } else {
        document._htmlToDom.appendToElement(html, node);
      }
    }
  }
  
  class ResourceQueue {
    constructor(paused) {
      this.paused = Boolean(paused);
    }
  
    push(callback) {
      const q = this;
      const item = {
        prev: q.tail,
        check() {
          if (!q.paused && !this.prev && this.fired) {
            callback(this.err, this.data, this.response);
            if (this.next) {
              this.next.prev = null;
              this.next.check();
            } else { // q.tail===this
              q.tail = null;
            }
          }
        }
      };
      if (q.tail) {
        q.tail.next = item;
      }
      q.tail = item;
      return (err, data, response) => {
        item.fired = 1;
        item.err = err;
        item.data = data;
        item.response = response;
        item.check();
      };
    }
  
    resume() {
      if (!this.paused) {
        return;
      }
      this.paused = false;
  
      let head = this.tail;
      while (head && head.prev) {
        head = head.prev;
      }
      if (head) {
        head.check();
      }
    }
  }
  
  class RequestManager {
    constructor() {
      this.openedRequests = [];
    }
  
    add(req) {
      this.openedRequests.push(req);
    }
  
    remove(req) {
      const idx = this.openedRequests.indexOf(req);
      if (idx !== -1) {
        this.openedRequests.splice(idx, 1);
      }
    }
  
    close() {
      for (const openedRequest of this.openedRequests) {
        openedRequest.abort();
      }
      this.openedRequests = [];
    }
  
    size() {
      return this.openedRequests.length;
    }
  }
  
  function pad(number) {
    if (number < 10) {
      return "0" + number;
    }
    return number;
  }
  
  function toLastModifiedString(date) {
    return pad(date.getMonth() + 1) +
      "/" + pad(date.getDate()) +
      "/" + date.getFullYear() +
      " " + pad(date.getHours()) +
      ":" + pad(date.getMinutes()) +
      ":" + pad(date.getSeconds());
  }
  
  const nonInheritedTags = new Set([
    "article", "section", "nav", "aside", "hgroup", "header", "footer", "address", "dt",
    "dd", "figure", "figcaption", "main", "em", "strong", "small", "s", "cite", "dfn", "abbr",
    "ruby", "rt", "rp", "code", "var", "samp", "kbd", "i", "b", "u", "mark", "bdi", "bdo", "wbr"
  ]);
  
  const eventInterfaceTable = {
    customevent: CustomEvent,
    errorevent: ErrorEvent,
    event: Event,
    events: Event,
    focusevent: FocusEvent,
    hashchangeevent: HashChangeEvent,
    htmlevents: Event,
    keyboardevent: KeyboardEvent,
    messageevent: MessageEvent,
    mouseevent: MouseEvent,
    mouseevents: MouseEvent,
    popstateevent: PopStateEvent,
    progressevent: ProgressEvent,
    svgevents: Event,
    touchevent: TouchEvent,
    uievent: UIEvent,
    uievents: UIEvent
  };
  
  class DocumentImpl extends NodeImpl {
    constructor(args, privateData) {
      super(args, privateData);
  
      this._initGlobalEvents();
  
      this._ownerDocument = this;
      this.nodeType = NODE_TYPE.DOCUMENT_NODE;
      if (!privateData.options) {
        privateData.options = {};
      }
      if (!privateData.options.parsingMode) {
        privateData.options.parsingMode = "xml";
      }
  
      this._parsingMode = privateData.options.parsingMode;
      this._htmlToDom = new HTMLToDOM(privateData.core, privateData.options.parsingMode);
  
      this._implementation = DOMImplementation.createImpl([], {
        core: this._core,
        ownerDocument: this
      });
  
      this._defaultView = privateData.options.defaultView || null;
      this._global = privateData.options.global;
      this._documentElement = null;
      this._ids = Object.create(null);
      this._attached = true;
      this._currentScript = null;
      this._cookieJar = privateData.options.cookieJar;
      this._parseOptions = privateData.options.parseOptions;
      if (this._cookieJar === undefined) {
        this._cookieJar = new CookieJar(null, { looseMode: true });
      }
  
      this._contentType = privateData.options.contentType;
      this._encoding = privateData.options.encoding;
  
      const urlOption = privateData.options.url === undefined ? "about:blank" : privateData.options.url;
      const parsed = whatwgURL.parseURL(urlOption);
      if (parsed === null) {
        throw new TypeError(`Could not parse "${urlOption}" as a URL`);
      }
  
      this._URL = parsed;
      this._origin = whatwgURL.serializeURLOrigin(parsed);
  
      this._location = Location.createImpl([], { relevantDocument: this });
      this._history = History.createImpl([], {
        window: this._defaultView,
        document: this,
        actAsIfLocationReloadCalled: () => this._location.reload()
      });
  
      if (privateData.options.cookie) {
        const cookies = Array.isArray(privateData.options.cookie) ?
          privateData.options.cookie : [privateData.options.cookie];
        const document = this;
  
        cookies.forEach(cookieStr => {
          document._cookieJar.setCookieSync(cookieStr, document.URL, { ignoreError: true });
        });
      }
  
      this._workingNodeIterators = [];
      this._workingNodeIteratorsMax = privateData.options.concurrentNodeIterators === undefined ?
                                      10 :
                                      Number(privateData.options.concurrentNodeIterators);
  
      if (isNaN(this._workingNodeIteratorsMax)) {
        throw new TypeError("The 'concurrentNodeIterators' option must be a Number");
      }
  
      if (this._workingNodeIteratorsMax < 0) {
        throw new RangeError("The 'concurrentNodeIterators' option must be a non negative Number");
      }
  
      this._referrer = privateData.options.referrer || "";
      this._lastModified = toLastModifiedString(privateData.options.lastModified || new Date());
      this._queue = new ResourceQueue(privateData.options.deferClose);
      this._customResourceLoader = privateData.options.resourceLoader;
      this._pool = privateData.options.pool;
      this._agentOptions = privateData.options.agentOptions;
      this._strictSSL = privateData.options.strictSSL;
      this._proxy = privateData.options.proxy;
      this._requestManager = new RequestManager();
      this.readyState = "loading";
  
      this._lastFocusedElement = null;
  
      // Each Document in a browsing context can also have a latest entry. This is the entry for that Document
      // to which the browsing context's session history was most recently traversed. When a Document is created,
      // it initially has no latest entry.
      this._latestEntry = null;
    }
  
    _defaultElementBuilder(document, tagName) {
      if (nonInheritedTags.has(tagName.toLowerCase())) {
        return HTMLElement.create([], {
          core: this._core,
          ownerDocument: this,
          localName: tagName
        });
      }
      return HTMLUnknownElement.create([], {
        core: this._core,
        ownerDocument: this,
        localName: tagName
      });
    }
  
    get contentType() {
      return this._contentType || (this._parsingMode === "xml" ? "application/xml" : "text/html");
    }
    get compatMode() {
      return this._parsingMode === "xml" || this.doctype ? "CSS1Compat" : "BackCompat";
    }
    get charset() {
      return this._encoding;
    }
    get characterSet() {
      return this._encoding;
    }
    get inputEncoding() {
      return this._encoding;
    }
    get doctype() {
      for (const childNode of domSymbolTree.childrenIterator(this)) {
        if (childNode.nodeType === NODE_TYPE.DOCUMENT_TYPE_NODE) {
          return childNode;
        }
      }
      return null;
    }
    get URL() {
      return whatwgURL.serializeURL(this._URL);
    }
    get documentURI() {
      return whatwgURL.serializeURL(this._URL);
    }
    get origin() {
      return this._origin;
    }
    get location() {
      return this._defaultView ? this._location : null;
    }
    get documentElement() {
      if (this._documentElement) {
        return this._documentElement;
      }
  
      for (const childNode of domSymbolTree.childrenIterator(this)) {
        if (childNode.nodeType === NODE_TYPE.ELEMENT_NODE) {
          this._documentElement = childNode;
          return childNode;
        }
      }
  
      return null;
    }
  
    get implementation() {
      return this._implementation;
    }
    set implementation(implementation) {
      this._implementation = implementation;
    }
  
    get defaultView() {
      return this._defaultView;
    }
  
    get currentScript() {
      return this._currentScript;
    }
  
    get activeElement() {
      if (this._lastFocusedElement) {
        return this._lastFocusedElement;
      }
  
      return this.body;
    }
  
    hasFocus() {
      return Boolean(this._lastFocusedElement);
    }
  
    _createElementWithCorrectElementInterface(name, namespace) {
      // https://dom.spec.whatwg.org/#concept-element-interface
      // TODO: eventually we should re-write the element-builder system to be namespace aware, but for now it is not.
      const builder = this._elementBuilders[name.toLowerCase()] || this._defaultElementBuilder.bind(this);
      const elem = builder(this, name, namespace);
      return idlUtils.implForWrapper(elem);
    }
  
    appendChild(/* Node */ arg) {
      if (this.documentElement && arg.nodeType === NODE_TYPE.ELEMENT_NODE) {
        throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR);
      }
      return super.appendChild(arg);
    }
  
    removeChild(/* Node */ arg) {
      const ret = super.removeChild(arg);
      if (arg === this._documentElement) {
        this._documentElement = null;// force a recalculation
      }
      return ret;
    }
  
    _descendantRemoved(parent, child) {
      if (child.tagName === "STYLE") {
        const index = this.styleSheets.indexOf(child.sheet);
        if (index > -1) {
          this.styleSheets.splice(index, 1);
        }
      }
    }
  
    write() {
      let text = "";
      for (let i = 0; i < arguments.length; ++i) {
        text += String(arguments[i]);
      }
  
      if (this._parsingMode === "xml") {
        throw new DOMException(DOMException.INVALID_STATE_ERR, "Cannot use document.write on XML documents");
      }
  
      if (this._writeAfterElement) {
        // If called from an script element directly (during the first tick),
        // the new elements are inserted right after that element.
        const tempDiv = this.createElement("div");
        setInnerHTML(this, tempDiv, text);
  
        let child = tempDiv.firstChild;
        let previous = this._writeAfterElement;
        const parent = this._writeAfterElement.parentNode;
  
        while (child) {
          const node = child;
          child = child.nextSibling;
          parent.insertBefore(node, previous.nextSibling);
          previous = node;
        }
      } else if (this.readyState === "loading") {
        // During page loading, document.write appends to the current element
        // Find the last child that has been added to the document.
        let node = this;
        while (node.lastChild && node.lastChild.nodeType === NODE_TYPE.ELEMENT_NODE) {
          node = node.lastChild;
        }
        setInnerHTML(this, node, text);
      } else if (text) {
        setInnerHTML(this, this, text);
      }
    }
  
    writeln() {
      this.write(...arguments, "\n");
    }
  
    getElementById(id) {
      // return the first element
      return this._ids[id] && this._ids[id].length > 0 ? this._ids[id][0] : null;
    }
  
    get referrer() {
      return this._referrer || "";
    }
    get lastModified() {
      return this._lastModified;
    }
    get images() {
      return this.getElementsByTagName("IMG");
    }
    get embeds() {
      return this.getElementsByTagName("EMBED");
    }
    get plugins() {
      return this.embeds;
    }
    get links() {
      return HTMLCollection.createImpl([], {
        element: this,
        query: () => domSymbolTree.treeToArray(this, {
          filter: node => (node._localName === "a" || node._localName === "area") &&
                          node.hasAttribute("href") &&
                          node._namespaceURI === "http://www.w3.org/1999/xhtml"
        })
      });
    }
    get forms() {
      return this.getElementsByTagName("FORM");
    }
    get scripts() {
      return this.getElementsByTagName("SCRIPT");
    }
    get anchors() {
      return HTMLCollection.createImpl([], {
        element: this,
        query: () => domSymbolTree.treeToArray(this, {
          filter: node => node._localName === "a" &&
                          node.hasAttribute("name") &&
                          node._namespaceURI === "http://www.w3.org/1999/xhtml"
        })
      });
    }
    get applets() {
      return this.getElementsByTagName("APPLET");
    }
    open() {
      let child = domSymbolTree.firstChild(this);
      while (child) {
        this.removeChild(child);
        child = domSymbolTree.firstChild(this);
      }
      this._documentElement = null;
      this._modified();
      return this;
    }
    close() {
      this._queue.resume();
  
      // Set the readyState to 'complete' once all resources are loaded.
      // As a side-effect the document's load-event will be dispatched.
      resourceLoader.enqueue(this, null, function () {
        this.readyState = "complete";
        const ev = this.createEvent("HTMLEvents");
        ev.initEvent("DOMContentLoaded", false, false);
        this.dispatchEvent(ev);
      })(null, true);
    }
  
    getElementsByName(elementName) {
      // TODO: should be NodeList, should be memoized
      return HTMLCollection.createImpl([], {
        element: this,
        query: () => domSymbolTree.treeToArray(this, {
          filter: node => node.getAttribute && node.getAttribute("name") === elementName
        })
      });
    }
  
    get title() {
      // TODO SVG
  
      const titleElement = firstDescendantWithHTMLLocalName(this, "title");
      let value = titleElement !== null ? titleElement.textContent : "";
      value = stripAndCollapseASCIIWhitespace(value);
      return value;
    }
  
    set title(val) {
      // TODO SVG
  
      const titleElement = firstDescendantWithHTMLLocalName(this, "title");
      const headElement = this.head;
  
      if (titleElement === null && headElement === null) {
        return;
      }
  
      let element;
      if (titleElement !== null) {
        element = titleElement;
      } else {
        element = this.createElement("title");
        headElement.appendChild(element);
      }
  
      element.textContent = val;
    }
  
    get dir() {
      return this.documentElement ? this.documentElement.dir : "";
    }
    set dir(value) {
      if (this.documentElement) {
        this.documentElement.dir = value;
      }
    }
  
    get head() {
      return this.documentElement ? firstChildWithHTMLLocalName(this.documentElement, "head") : null;
    }
  
    get body() {
      const documentElement = this.documentElement;
      if (!documentElement || documentElement._localName !== "html" ||
          documentElement._namespaceURI !== "http://www.w3.org/1999/xhtml") {
        return null;
      }
  
      return firstChildWithHTMLLocalNames(this.documentElement, new Set(["body", "frameset"]));
    }
  
    set body(value) {
      if (value === null ||
          value._namespaceURI !== "http://www.w3.org/1999/xhtml" ||
          (value._localName !== "body" && value._localName !== "frameset")) {
        throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR,
          "Cannot set the body to null or a non-body/frameset element");
      }
  
      const bodyElement = this.body;
      if (value === bodyElement) {
        return;
      }
  
      if (bodyElement !== null) {
        bodyElement.parentNode.replaceChild(value, bodyElement);
        return;
      }
  
      const documentElement = this.documentElement;
      if (documentElement === null) {
        throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR,
          "Cannot set the body when there is no document element");
      }
  
      documentElement.appendChild(value);
    }
  
    _runPreRemovingSteps(oldNode) {
      for (const activeNodeIterator of this._workingNodeIterators) {
        activeNodeIterator._preRemovingSteps(oldNode);
      }
    }
  
    createEvent(type) {
      const typeLower = type.toLowerCase();
      const eventWrapper = eventInterfaceTable[typeLower] || null;
  
      if (!eventWrapper) {
        throw new DOMException(DOMException.NOT_SUPPORTED_ERR,
          "The provided event type (\"" + type + "\") is invalid");
      }
  
      const impl = eventWrapper.createImpl([""]);
      impl._initializedFlag = false;
      return impl;
    }
  
    createProcessingInstruction(target, data) {
      validateName(target);
  
      if (data.includes("?>")) {
        throw new DOMException(DOMException.INVALID_CHARACTER_ERR,
          "Processing instruction data cannot contain the string \"?>\"");
      }
  
      return ProcessingInstruction.createImpl([], {
        core: this._core,
        ownerDocument: this,
        target,
        data
      });
    }
  
    // https://dom.spec.whatwg.org/#dom-document-createcdatasection
    createCDATASection(data) {
      if (this._parsingMode === "html") {
        throw new DOMException(DOMException.NOT_SUPPORTED_ERR,
          "Cannot create CDATA sections in HTML documents");
      }
  
      if (data.includes("]]>")) {
        throw new DOMException(DOMException.INVALID_CHARACTER_ERR,
          "CDATA section data cannot contain the string \"]]>\"");
      }
  
      return CDATASection.createImpl([], {
        core: this._core,
        ownerDocument: this,
        data
      });
    }
  
    createTextNode(data) {
      return Text.createImpl([], {
        core: this._core,
        ownerDocument: this,
        data
      });
    }
  
    createComment(data) {
      return Comment.createImpl([], {
        core: this._core,
        ownerDocument: this,
        data
      });
    }
  
    createElement(localName) {
      validateName(localName);
      if (this._parsingMode === "html") {
        localName = localName.toLowerCase();
      }
  
      const element = this._createElementWithCorrectElementInterface(localName, "http://www.w3.org/1999/xhtml");
      element._namespaceURI = "http://www.w3.org/1999/xhtml";
      element._localName = localName;
  
      return element;
    }
  
    createElementNS(namespace, qualifiedName) {
      namespace = namespace !== null ? String(namespace) : namespace;
  
      const extracted = validateAndExtract(namespace, qualifiedName);
  
      const element = this._createElementWithCorrectElementInterface(extracted.localName, extracted.namespace);
      element._namespaceURI = extracted.namespace;
      element._prefix = extracted.prefix;
      element._localName = extracted.localName;
  
      return element;
    }
  
    createDocumentFragment() {
      return DocumentFragment.createImpl([], { ownerDocument: this });
    }
  
    createAttribute(localName) {
      validateName(localName);
  
      if (this._parsingMode === "html") {
        localName = localName.toLowerCase();
      }
  
      return generatedAttr.createImpl([], { localName });
    }
  
    createAttributeNS(namespace, name) {
      if (namespace === undefined) {
        namespace = null;
      }
      namespace = namespace !== null ? String(namespace) : namespace;
  
      const extracted = validateAndExtract(namespace, name);
      return generatedAttr.createImpl([], {
        namespace: extracted.namespace,
        namespacePrefix: extracted.prefix,
        localName: extracted.localName
      });
    }
  
    // TODO: Add callback interface support to `webidl2js`
    createTreeWalker(root, whatToShow, filter) {
      return TreeWalker.createImpl([], { root, whatToShow, filter });
    }
  
    createNodeIterator(root, whatToShow, filter) {
      const nodeIterator = NodeIterator.createImpl([], { root, whatToShow, filter });
  
      this._workingNodeIterators.push(nodeIterator);
      while (this._workingNodeIterators.length > this._workingNodeIteratorsMax) {
        const toInactivate = this._workingNodeIterators.shift();
        toInactivate._working = false;
      }
  
      return nodeIterator;
    }
  
    importNode(node, deep) {
      if (node.nodeType === NODE_TYPE.DOCUMENT_NODE) {
        throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Cannot import a document node");
      }
  
      return clone(this._core, node, this, deep);
    }
  
    adoptNode(node) {
      if (node.nodeType === NODE_TYPE.DOCUMENT_NODE) {
        throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Cannot adopt a document node");
      }
      // TODO: Determine correct way to detect a shadow root
      // See also https://github.com/w3c/webcomponents/issues/182
  
      if (node.parentNode) {
        node.parentNode.removeChild(node);
      }
      node._ownerDocument = this;
      for (const descendant of domSymbolTree.treeIterator(node)) {
        descendant._ownerDocument = this;
      }
  
      return node;
    }
  
    get cookie() {
      return this._cookieJar.getCookieStringSync(this.URL, { http: false });
    }
    set cookie(cookieStr) {
      cookieStr = String(cookieStr);
      this._cookieJar.setCookieSync(cookieStr, this.URL, {
        http: false,
        ignoreError: true
      });
    }
  
    // The clear(), captureEvents(), and releaseEvents() methods must do nothing
    clear() {}
  
    captureEvents() {}
  
    releaseEvents() {}
  
    get styleSheets() {
      if (!this._styleSheets) {
        this._styleSheets = new this._core.StyleSheetList();
      }
  
      // TODO: each style and link element should register its sheet on creation
      // and remove it on removal.
      return this._styleSheets;
    }
  
    get hidden() {
      return true;
    }
  
    get visibilityState() {
      return "prerender";
    }
  }
  
  eventAccessors.createEventAccessor(DocumentImpl.prototype, "readystatechange");
  idlUtils.mixin(DocumentImpl.prototype, GlobalEventHandlersImpl.prototype);
  idlUtils.mixin(DocumentImpl.prototype, ParentNodeImpl.prototype);
  
  DocumentImpl.prototype._elementBuilders = Object.create(null);
  
  DocumentImpl.prototype.getElementsByTagName = memoizeQuery(function (qualifiedName) {
    return listOfElementsWithQualifiedName(qualifiedName, this);
  });
  
  DocumentImpl.prototype.getElementsByTagNameNS = memoizeQuery(function (namespace, localName) {
    return listOfElementsWithNamespaceAndLocalName(namespace, localName, this);
  });
  
  DocumentImpl.prototype.getElementsByClassName = memoizeQuery(function getElementsByClassName(classNames) {
    return listOfElementsWithClassNames(classNames, this);
  });
  
  module.exports = {
    implementation: DocumentImpl
  };
  