!C99Shell v. 2.5 [PHP 8 Update] [24.05.2025]!

Software: Apache/2.4.41 (Ubuntu). PHP/8.0.30 

uname -a: Linux apirnd 5.4.0-204-generic #224-Ubuntu SMP Thu Dec 5 13:38:28 UTC 2024 x86_64 

uid=33(www-data) gid=33(www-data) groups=33(www-data) 

Safe-mode: OFF (not secure)

/var/www/html/space/node_modules/playwright-core/lib/generated/   drwxr-xr-x
Free 13.29 GB of 57.97 GB (22.92%)
Home    Back    Forward    UPDIR    Refresh    Search    Buffer    Encoder    Tools    Proc.    FTP brute    Sec.    SQL    PHP-code    Update    Self remove    Logout    


Viewing file:     injectedScriptSource.js (236.4 KB)      -rw-r--r--
Select action/file-type:
(+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.source = void 0;
const source = exports.source = "\nvar __commonJS = obj => {\n  let required = false;\n  let result;\n  return function __require() {\n    if (!required) {\n      required = true;\n      let fn;\n      for (const name in obj) { fn = obj[name]; break; }\n      const module = { exports: {} };\n      fn(module.exports, module);\n      result = module.exports;\n    }\n    return result;\n  }\n};\nvar __export = (target, all) => {for (var name in all) target[name] = all[name];};\nvar __toESM = mod => ({ ...mod, 'default': mod });\nvar __toCommonJS = mod => ({ ...mod, __esModule: true });\n\n\n// packages/playwright-core/src/server/injected/injectedScript.ts\nvar injectedScript_exports = {};\n__export(injectedScript_exports, {\n  InjectedScript: () => InjectedScript\n});\nmodule.exports = __toCommonJS(injectedScript_exports);\n\n// packages/playwright-core/src/server/injected/xpathSelectorEngine.ts\nvar XPathEngine = {\n  queryAll(root, selector) {\n    if (selector.startsWith(\"/\") && root.nodeType !== Node.DOCUMENT_NODE)\n      selector = \".\" + selector;\n    const result = [];\n    const document = root.ownerDocument || root;\n    if (!document)\n      return result;\n    const it = document.evaluate(selector, root, null, XPathResult.ORDERED_NODE_ITERATOR_TYPE);\n    for (let node = it.iterateNext(); node; node = it.iterateNext()) {\n      if (node.nodeType === Node.ELEMENT_NODE)\n        result.push(node);\n    }\n    return result;\n  }\n};\n\n// packages/playwright-core/src/server/injected/domUtils.ts\nvar browserNameForWorkarounds = \"\";\nfunction setBrowserName(name) {\n  browserNameForWorkarounds = name;\n}\nfunction isInsideScope(scope, element) {\n  while (element) {\n    if (scope.contains(element))\n      return true;\n    element = enclosingShadowHost(element);\n  }\n  return false;\n}\nfunction parentElementOrShadowHost(element) {\n  if (element.parentElement)\n    return element.parentElement;\n  if (!element.parentNode)\n    return;\n  if (element.parentNode.nodeType === 11 && element.parentNode.host)\n    return element.parentNode.host;\n}\nfunction enclosingShadowRootOrDocument(element) {\n  let node = element;\n  while (node.parentNode)\n    node = node.parentNode;\n  if (node.nodeType === 11 || node.nodeType === 9)\n    return node;\n}\nfunction enclosingShadowHost(element) {\n  while (element.parentElement)\n    element = element.parentElement;\n  return parentElementOrShadowHost(element);\n}\nfunction closestCrossShadow(element, css, scope) {\n  while (element) {\n    const closest = element.closest(css);\n    if (scope && closest !== scope && (closest == null ? void 0 : closest.contains(scope)))\n      return;\n    if (closest)\n      return closest;\n    element = enclosingShadowHost(element);\n  }\n}\nfunction getElementComputedStyle(element, pseudo) {\n  return element.ownerDocument && element.ownerDocument.defaultView ? element.ownerDocument.defaultView.getComputedStyle(element, pseudo) : void 0;\n}\nfunction isElementStyleVisibilityVisible(element, style) {\n  style = style != null ? style : getElementComputedStyle(element);\n  if (!style)\n    return true;\n  if (Element.prototype.checkVisibility && browserNameForWorkarounds !== \"webkit\") {\n    if (!element.checkVisibility({ checkOpacity: false, checkVisibilityCSS: false }))\n      return false;\n  } else {\n    const detailsOrSummary = element.closest(\"details,summary\");\n    if (detailsOrSummary !== element && (detailsOrSummary == null ? void 0 : detailsOrSummary.nodeName) === \"DETAILS\" && !detailsOrSummary.open)\n      return false;\n  }\n  if (style.visibility !== \"visible\")\n    return false;\n  return true;\n}\nfunction isElementVisible(element) {\n  const style = getElementComputedStyle(element);\n  if (!style)\n    return true;\n  if (style.display === \"contents\") {\n    for (let child = element.firstChild; child; child = child.nextSibling) {\n      if (child.nodeType === 1 && isElementVisible(child))\n        return true;\n      if (child.nodeType === 3 && isVisibleTextNode(child))\n        return true;\n    }\n    return false;\n  }\n  if (!isElementStyleVisibilityVisible(element, style))\n    return false;\n  const rect = element.getBoundingClientRect();\n  return rect.width > 0 && rect.height > 0;\n}\nfunction isVisibleTextNode(node) {\n  const range = node.ownerDocument.createRange();\n  range.selectNode(node);\n  const rect = range.getBoundingClientRect();\n  return rect.width > 0 && rect.height > 0;\n}\nfunction elementSafeTagName(element) {\n  if (element instanceof HTMLFormElement)\n    return \"FORM\";\n  return element.tagName.toUpperCase();\n}\n\n// packages/playwright-core/src/utils/isomorphic/stringUtils.ts\nfunction escapeWithQuotes(text, char = \"'\") {\n  const stringified = JSON.stringify(text);\n  const escapedText = stringified.substring(1, stringified.length - 1).replace(/\\\\\"/g, '\"');\n  if (char === \"'\")\n    return char + escapedText.replace(/[']/g, \"\\\\'\") + char;\n  if (char === '\"')\n    return char + escapedText.replace(/[\"]/g, '\\\\\"') + char;\n  if (char === \"`\")\n    return char + escapedText.replace(/[`]/g, \"`\") + char;\n  throw new Error(\"Invalid escape char\");\n}\nfunction toTitleCase(name) {\n  return name.charAt(0).toUpperCase() + name.substring(1);\n}\nfunction toSnakeCase(name) {\n  return name.replace(/([a-z0-9])([A-Z])/g, \"$1_$2\").replace(/([A-Z])([A-Z][a-z])/g, \"$1_$2\").toLowerCase();\n}\nfunction cssEscape(s) {\n  let result = \"\";\n  for (let i = 0; i < s.length; i++)\n    result += cssEscapeOne(s, i);\n  return result;\n}\nfunction quoteCSSAttributeValue(text) {\n  return `\"${cssEscape(text).replace(/\\\\ /g, \" \")}\"`;\n}\nfunction cssEscapeOne(s, i) {\n  const c = s.charCodeAt(i);\n  if (c === 0)\n    return \"\\uFFFD\";\n  if (c >= 1 && c <= 31 || c >= 48 && c <= 57 && (i === 0 || i === 1 && s.charCodeAt(0) === 45))\n    return \"\\\\\" + c.toString(16) + \" \";\n  if (i === 0 && c === 45 && s.length === 1)\n    return \"\\\\\" + s.charAt(i);\n  if (c >= 128 || c === 45 || c === 95 || c >= 48 && c <= 57 || c >= 65 && c <= 90 || c >= 97 && c <= 122)\n    return s.charAt(i);\n  return \"\\\\\" + s.charAt(i);\n}\nfunction normalizeWhiteSpace(text) {\n  return text.replace(/\\u200b/g, \"\").trim().replace(/\\s+/g, \" \");\n}\nfunction normalizeEscapedRegexQuotes(source) {\n  return source.replace(/(^|[^\\\\])(\\\\\\\\)*\\\\(['\"`])/g, \"$1$2$3\");\n}\nfunction escapeRegexForSelector(re) {\n  if (re.unicode || re.unicodeSets)\n    return String(re);\n  return String(re).replace(/(^|[^\\\\])(\\\\\\\\)*([\"'`])/g, \"$1$2\\\\$3\").replace(/>>/g, \"\\\\>\\\\>\");\n}\nfunction escapeForTextSelector(text, exact) {\n  if (typeof text !== \"string\")\n    return escapeRegexForSelector(text);\n  return `${JSON.stringify(text)}${exact ? \"s\" : \"i\"}`;\n}\nfunction escapeForAttributeSelector(value, exact) {\n  if (typeof value !== \"string\")\n    return escapeRegexForSelector(value);\n  return `\"${value.replace(/\\\\/g, \"\\\\\\\\\").replace(/[\"]/g, '\\\\\"')}\"${exact ? \"s\" : \"i\"}`;\n}\nfunction trimString(input, cap, suffix = \"\") {\n  if (input.length <= cap)\n    return input;\n  const chars = [...input];\n  if (chars.length > cap)\n    return chars.slice(0, cap - suffix.length).join(\"\") + suffix;\n  return chars.join(\"\");\n}\nfunction trimStringWithEllipsis(input, cap) {\n  return trimString(input, cap, \"\\u2026\");\n}\nfunction escapeRegExp(s) {\n  return s.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\n// packages/playwright-core/src/server/injected/roleUtils.ts\nfunction hasExplicitAccessibleName(e) {\n  return e.hasAttribute(\"aria-label\") || e.hasAttribute(\"aria-labelledby\");\n}\nvar kAncestorPreventingLandmark = \"article:not([role]), aside:not([role]), main:not([role]), nav:not([role]), section:not([role]), [role=article], [role=complementary], [role=main], [role=navigation], [role=region]\";\nvar kGlobalAriaAttributes = /* @__PURE__ */ new Map([\n  [\"aria-atomic\", void 0],\n  [\"aria-busy\", void 0],\n  [\"aria-controls\", void 0],\n  [\"aria-current\", void 0],\n  [\"aria-describedby\", void 0],\n  [\"aria-details\", void 0],\n  // Global use deprecated in ARIA 1.2\n  // ['aria-disabled', undefined],\n  [\"aria-dropeffect\", void 0],\n  // Global use deprecated in ARIA 1.2\n  // ['aria-errormessage', undefined],\n  [\"aria-flowto\", void 0],\n  [\"aria-grabbed\", void 0],\n  // Global use deprecated in ARIA 1.2\n  // ['aria-haspopup', undefined],\n  [\"aria-hidden\", void 0],\n  // Global use deprecated in ARIA 1.2\n  // ['aria-invalid', undefined],\n  [\"aria-keyshortcuts\", void 0],\n  [\"aria-label\", /* @__PURE__ */ new Set([\"caption\", \"code\", \"deletion\", \"emphasis\", \"generic\", \"insertion\", \"paragraph\", \"presentation\", \"strong\", \"subscript\", \"superscript\"])],\n  [\"aria-labelledby\", /* @__PURE__ */ new Set([\"caption\", \"code\", \"deletion\", \"emphasis\", \"generic\", \"insertion\", \"paragraph\", \"presentation\", \"strong\", \"subscript\", \"superscript\"])],\n  [\"aria-live\", void 0],\n  [\"aria-owns\", void 0],\n  [\"aria-relevant\", void 0],\n  [\"aria-roledescription\", /* @__PURE__ */ new Set([\"generic\"])]\n]);\nfunction hasGlobalAriaAttribute(element, forRole) {\n  return [...kGlobalAriaAttributes].some(([attr, prohibited]) => {\n    return !(prohibited == null ? void 0 : prohibited.has(forRole || \"\")) && element.hasAttribute(attr);\n  });\n}\nfunction hasTabIndex(element) {\n  return !Number.isNaN(Number(String(element.getAttribute(\"tabindex\"))));\n}\nfunction isFocusable(element) {\n  return !isNativelyDisabled(element) && (isNativelyFocusable(element) || hasTabIndex(element));\n}\nfunction isNativelyFocusable(element) {\n  const tagName = elementSafeTagName(element);\n  if ([\"BUTTON\", \"DETAILS\", \"SELECT\", \"TEXTAREA\"].includes(tagName))\n    return true;\n  if (tagName === \"A\" || tagName === \"AREA\")\n    return element.hasAttribute(\"href\");\n  if (tagName === \"INPUT\")\n    return !element.hidden;\n  return false;\n}\nvar kImplicitRoleByTagName = {\n  \"A\": (e) => {\n    return e.hasAttribute(\"href\") ? \"link\" : null;\n  },\n  \"AREA\": (e) => {\n    return e.hasAttribute(\"href\") ? \"link\" : null;\n  },\n  \"ARTICLE\": () => \"article\",\n  \"ASIDE\": () => \"complementary\",\n  \"BLOCKQUOTE\": () => \"blockquote\",\n  \"BUTTON\": () => \"button\",\n  \"CAPTION\": () => \"caption\",\n  \"CODE\": () => \"code\",\n  \"DATALIST\": () => \"listbox\",\n  \"DD\": () => \"definition\",\n  \"DEL\": () => \"deletion\",\n  \"DETAILS\": () => \"group\",\n  \"DFN\": () => \"term\",\n  \"DIALOG\": () => \"dialog\",\n  \"DT\": () => \"term\",\n  \"EM\": () => \"emphasis\",\n  \"FIELDSET\": () => \"group\",\n  \"FIGURE\": () => \"figure\",\n  \"FOOTER\": (e) => closestCrossShadow(e, kAncestorPreventingLandmark) ? null : \"contentinfo\",\n  \"FORM\": (e) => hasExplicitAccessibleName(e) ? \"form\" : null,\n  \"H1\": () => \"heading\",\n  \"H2\": () => \"heading\",\n  \"H3\": () => \"heading\",\n  \"H4\": () => \"heading\",\n  \"H5\": () => \"heading\",\n  \"H6\": () => \"heading\",\n  \"HEADER\": (e) => closestCrossShadow(e, kAncestorPreventingLandmark) ? null : \"banner\",\n  \"HR\": () => \"separator\",\n  \"HTML\": () => \"document\",\n  \"IMG\": (e) => e.getAttribute(\"alt\") === \"\" && !e.getAttribute(\"title\") && !hasGlobalAriaAttribute(e) && !hasTabIndex(e) ? \"presentation\" : \"img\",\n  \"INPUT\": (e) => {\n    const type = e.type.toLowerCase();\n    if (type === \"search\")\n      return e.hasAttribute(\"list\") ? \"combobox\" : \"searchbox\";\n    if ([\"email\", \"tel\", \"text\", \"url\", \"\"].includes(type)) {\n      const list = getIdRefs(e, e.getAttribute(\"list\"))[0];\n      return list && elementSafeTagName(list) === \"DATALIST\" ? \"combobox\" : \"textbox\";\n    }\n    if (type === \"hidden\")\n      return \"\";\n    return {\n      \"button\": \"button\",\n      \"checkbox\": \"checkbox\",\n      \"image\": \"button\",\n      \"number\": \"spinbutton\",\n      \"radio\": \"radio\",\n      \"range\": \"slider\",\n      \"reset\": \"button\",\n      \"submit\": \"button\"\n    }[type] || \"textbox\";\n  },\n  \"INS\": () => \"insertion\",\n  \"LI\": () => \"listitem\",\n  \"MAIN\": () => \"main\",\n  \"MARK\": () => \"mark\",\n  \"MATH\": () => \"math\",\n  \"MENU\": () => \"list\",\n  \"METER\": () => \"meter\",\n  \"NAV\": () => \"navigation\",\n  \"OL\": () => \"list\",\n  \"OPTGROUP\": () => \"group\",\n  \"OPTION\": () => \"option\",\n  \"OUTPUT\": () => \"status\",\n  \"P\": () => \"paragraph\",\n  \"PROGRESS\": () => \"progressbar\",\n  \"SECTION\": (e) => hasExplicitAccessibleName(e) ? \"region\" : null,\n  \"SELECT\": (e) => e.hasAttribute(\"multiple\") || e.size > 1 ? \"listbox\" : \"combobox\",\n  \"STRONG\": () => \"strong\",\n  \"SUB\": () => \"subscript\",\n  \"SUP\": () => \"superscript\",\n  // For <svg> we default to Chrome behavior:\n  // - Chrome reports 'img'.\n  // - Firefox reports 'diagram' that is not in official ARIA spec yet.\n  // - Safari reports 'no role', but still computes accessible name.\n  \"SVG\": () => \"img\",\n  \"TABLE\": () => \"table\",\n  \"TBODY\": () => \"rowgroup\",\n  \"TD\": (e) => {\n    const table = closestCrossShadow(e, \"table\");\n    const role = table ? getExplicitAriaRole(table) : \"\";\n    return role === \"grid\" || role === \"treegrid\" ? \"gridcell\" : \"cell\";\n  },\n  \"TEXTAREA\": () => \"textbox\",\n  \"TFOOT\": () => \"rowgroup\",\n  \"TH\": (e) => {\n    if (e.getAttribute(\"scope\") === \"col\")\n      return \"columnheader\";\n    if (e.getAttribute(\"scope\") === \"row\")\n      return \"rowheader\";\n    const table = closestCrossShadow(e, \"table\");\n    const role = table ? getExplicitAriaRole(table) : \"\";\n    return role === \"grid\" || role === \"treegrid\" ? \"gridcell\" : \"cell\";\n  },\n  \"THEAD\": () => \"rowgroup\",\n  \"TIME\": () => \"time\",\n  \"TR\": () => \"row\",\n  \"UL\": () => \"list\"\n};\nvar kPresentationInheritanceParents = {\n  \"DD\": [\"DL\", \"DIV\"],\n  \"DIV\": [\"DL\"],\n  \"DT\": [\"DL\", \"DIV\"],\n  \"LI\": [\"OL\", \"UL\"],\n  \"TBODY\": [\"TABLE\"],\n  \"TD\": [\"TR\"],\n  \"TFOOT\": [\"TABLE\"],\n  \"TH\": [\"TR\"],\n  \"THEAD\": [\"TABLE\"],\n  \"TR\": [\"THEAD\", \"TBODY\", \"TFOOT\", \"TABLE\"]\n};\nfunction getImplicitAriaRole(element) {\n  var _a;\n  const implicitRole = ((_a = kImplicitRoleByTagName[elementSafeTagName(element)]) == null ? void 0 : _a.call(kImplicitRoleByTagName, element)) || \"\";\n  if (!implicitRole)\n    return null;\n  let ancestor = element;\n  while (ancestor) {\n    const parent = parentElementOrShadowHost(ancestor);\n    const parents = kPresentationInheritanceParents[elementSafeTagName(ancestor)];\n    if (!parents || !parent || !parents.includes(elementSafeTagName(parent)))\n      break;\n    const parentExplicitRole = getExplicitAriaRole(parent);\n    if ((parentExplicitRole === \"none\" || parentExplicitRole === \"presentation\") && !hasPresentationConflictResolution(parent, parentExplicitRole))\n      return parentExplicitRole;\n    ancestor = parent;\n  }\n  return implicitRole;\n}\nvar allRoles = [\n  \"alert\",\n  \"alertdialog\",\n  \"application\",\n  \"article\",\n  \"banner\",\n  \"blockquote\",\n  \"button\",\n  \"caption\",\n  \"cell\",\n  \"checkbox\",\n  \"code\",\n  \"columnheader\",\n  \"combobox\",\n  \"command\",\n  \"complementary\",\n  \"composite\",\n  \"contentinfo\",\n  \"definition\",\n  \"deletion\",\n  \"dialog\",\n  \"directory\",\n  \"document\",\n  \"emphasis\",\n  \"feed\",\n  \"figure\",\n  \"form\",\n  \"generic\",\n  \"grid\",\n  \"gridcell\",\n  \"group\",\n  \"heading\",\n  \"img\",\n  \"input\",\n  \"insertion\",\n  \"landmark\",\n  \"link\",\n  \"list\",\n  \"listbox\",\n  \"listitem\",\n  \"log\",\n  \"main\",\n  \"marquee\",\n  \"math\",\n  \"meter\",\n  \"menu\",\n  \"menubar\",\n  \"menuitem\",\n  \"menuitemcheckbox\",\n  \"menuitemradio\",\n  \"navigation\",\n  \"none\",\n  \"note\",\n  \"option\",\n  \"paragraph\",\n  \"presentation\",\n  \"progressbar\",\n  \"radio\",\n  \"radiogroup\",\n  \"range\",\n  \"region\",\n  \"roletype\",\n  \"row\",\n  \"rowgroup\",\n  \"rowheader\",\n  \"scrollbar\",\n  \"search\",\n  \"searchbox\",\n  \"section\",\n  \"sectionhead\",\n  \"select\",\n  \"separator\",\n  \"slider\",\n  \"spinbutton\",\n  \"status\",\n  \"strong\",\n  \"structure\",\n  \"subscript\",\n  \"superscript\",\n  \"switch\",\n  \"tab\",\n  \"table\",\n  \"tablist\",\n  \"tabpanel\",\n  \"term\",\n  \"textbox\",\n  \"time\",\n  \"timer\",\n  \"toolbar\",\n  \"tooltip\",\n  \"tree\",\n  \"treegrid\",\n  \"treeitem\",\n  \"widget\",\n  \"window\"\n];\nvar abstractRoles = [\"command\", \"composite\", \"input\", \"landmark\", \"range\", \"roletype\", \"section\", \"sectionhead\", \"select\", \"structure\", \"widget\", \"window\"];\nvar validRoles = allRoles.filter((role) => !abstractRoles.includes(role));\nfunction getExplicitAriaRole(element) {\n  const roles = (element.getAttribute(\"role\") || \"\").split(\" \").map((role) => role.trim());\n  return roles.find((role) => validRoles.includes(role)) || null;\n}\nfunction hasPresentationConflictResolution(element, role) {\n  return hasGlobalAriaAttribute(element, role) || isFocusable(element);\n}\nfunction getAriaRole(element) {\n  const explicitRole = getExplicitAriaRole(element);\n  if (!explicitRole)\n    return getImplicitAriaRole(element);\n  if (explicitRole === \"none\" || explicitRole === \"presentation\") {\n    const implicitRole = getImplicitAriaRole(element);\n    if (hasPresentationConflictResolution(element, implicitRole))\n      return implicitRole;\n  }\n  return explicitRole;\n}\nfunction getAriaBoolean(attr) {\n  return attr === null ? void 0 : attr.toLowerCase() === \"true\";\n}\nfunction isElementHiddenForAria(element) {\n  if ([\"STYLE\", \"SCRIPT\", \"NOSCRIPT\", \"TEMPLATE\"].includes(elementSafeTagName(element)))\n    return true;\n  const style = getElementComputedStyle(element);\n  const isSlot = element.nodeName === \"SLOT\";\n  if ((style == null ? void 0 : style.display) === \"contents\" && !isSlot) {\n    for (let child = element.firstChild; child; child = child.nextSibling) {\n      if (child.nodeType === 1 && !isElementHiddenForAria(child))\n        return false;\n      if (child.nodeType === 3 && isVisibleTextNode(child))\n        return false;\n    }\n    return true;\n  }\n  const isOptionInsideSelect = element.nodeName === \"OPTION\" && !!element.closest(\"select\");\n  if (!isOptionInsideSelect && !isSlot && !isElementStyleVisibilityVisible(element, style))\n    return true;\n  return belongsToDisplayNoneOrAriaHiddenOrNonSlotted(element);\n}\nfunction belongsToDisplayNoneOrAriaHiddenOrNonSlotted(element) {\n  let hidden = cacheIsHidden == null ? void 0 : cacheIsHidden.get(element);\n  if (hidden === void 0) {\n    hidden = false;\n    if (element.parentElement && element.parentElement.shadowRoot && !element.assignedSlot)\n      hidden = true;\n    if (!hidden) {\n      const style = getElementComputedStyle(element);\n      hidden = !style || style.display === \"none\" || getAriaBoolean(element.getAttribute(\"aria-hidden\")) === true;\n    }\n    if (!hidden) {\n      const parent = parentElementOrShadowHost(element);\n      if (parent)\n        hidden = belongsToDisplayNoneOrAriaHiddenOrNonSlotted(parent);\n    }\n    cacheIsHidden == null ? void 0 : cacheIsHidden.set(element, hidden);\n  }\n  return hidden;\n}\nfunction getIdRefs(element, ref) {\n  if (!ref)\n    return [];\n  const root = enclosingShadowRootOrDocument(element);\n  if (!root)\n    return [];\n  try {\n    const ids = ref.split(\" \").filter((id) => !!id);\n    const set = /* @__PURE__ */ new Set();\n    for (const id of ids) {\n      const firstElement = root.querySelector(\"#\" + CSS.escape(id));\n      if (firstElement)\n        set.add(firstElement);\n    }\n    return [...set];\n  } catch (e) {\n    return [];\n  }\n}\nfunction trimFlatString(s) {\n  return s.trim();\n}\nfunction asFlatString(s) {\n  return s.split(\"\\xA0\").map((chunk) => chunk.replace(/\\r\\n/g, \"\\n\").replace(/\\s\\s*/g, \" \")).join(\"\\xA0\").trim();\n}\nfunction queryInAriaOwned(element, selector) {\n  const result = [...element.querySelectorAll(selector)];\n  for (const owned of getIdRefs(element, element.getAttribute(\"aria-owns\"))) {\n    if (owned.matches(selector))\n      result.push(owned);\n    result.push(...owned.querySelectorAll(selector));\n  }\n  return result;\n}\nfunction getPseudoContent(element, pseudo) {\n  const cache = pseudo === \"::before\" ? cachePseudoContentBefore : cachePseudoContentAfter;\n  if (cache == null ? void 0 : cache.has(element))\n    return (cache == null ? void 0 : cache.get(element)) || \"\";\n  const pseudoStyle = getElementComputedStyle(element, pseudo);\n  const content = getPseudoContentImpl(pseudoStyle);\n  if (cache)\n    cache.set(element, content);\n  return content;\n}\nfunction getPseudoContentImpl(pseudoStyle) {\n  if (!pseudoStyle)\n    return \"\";\n  const content = pseudoStyle.content;\n  if (content[0] === \"'\" && content[content.length - 1] === \"'\" || content[0] === '\"' && content[content.length - 1] === '\"') {\n    const unquoted = content.substring(1, content.length - 1);\n    const display = pseudoStyle.display || \"inline\";\n    if (display !== \"inline\")\n      return \" \" + unquoted + \" \";\n    return unquoted;\n  }\n  return \"\";\n}\nfunction getAriaLabelledByElements(element) {\n  const ref = element.getAttribute(\"aria-labelledby\");\n  if (ref === null)\n    return null;\n  return getIdRefs(element, ref);\n}\nfunction allowsNameFromContent(role, targetDescendant) {\n  const alwaysAllowsNameFromContent = [\"button\", \"cell\", \"checkbox\", \"columnheader\", \"gridcell\", \"heading\", \"link\", \"menuitem\", \"menuitemcheckbox\", \"menuitemradio\", \"option\", \"radio\", \"row\", \"rowheader\", \"switch\", \"tab\", \"tooltip\", \"treeitem\"].includes(role);\n  const descendantAllowsNameFromContent = targetDescendant && [\"\", \"caption\", \"code\", \"contentinfo\", \"definition\", \"deletion\", \"emphasis\", \"insertion\", \"list\", \"listitem\", \"mark\", \"none\", \"paragraph\", \"presentation\", \"region\", \"row\", \"rowgroup\", \"section\", \"strong\", \"subscript\", \"superscript\", \"table\", \"term\", \"time\"].includes(role);\n  return alwaysAllowsNameFromContent || descendantAllowsNameFromContent;\n}\nfunction getElementAccessibleName(element, includeHidden) {\n  const cache = includeHidden ? cacheAccessibleNameHidden : cacheAccessibleName;\n  let accessibleName = cache == null ? void 0 : cache.get(element);\n  if (accessibleName === void 0) {\n    accessibleName = \"\";\n    const elementProhibitsNaming = [\"caption\", \"code\", \"definition\", \"deletion\", \"emphasis\", \"generic\", \"insertion\", \"mark\", \"paragraph\", \"presentation\", \"strong\", \"subscript\", \"suggestion\", \"superscript\", \"term\", \"time\"].includes(getAriaRole(element) || \"\");\n    if (!elementProhibitsNaming) {\n      accessibleName = asFlatString(getTextAlternativeInternal(element, {\n        includeHidden,\n        visitedElements: /* @__PURE__ */ new Set(),\n        embeddedInDescribedBy: void 0,\n        embeddedInLabelledBy: void 0,\n        embeddedInLabel: void 0,\n        embeddedInNativeTextAlternative: void 0,\n        embeddedInTargetElement: \"self\"\n      }));\n    }\n    cache == null ? void 0 : cache.set(element, accessibleName);\n  }\n  return accessibleName;\n}\nfunction getElementAccessibleDescription(element, includeHidden) {\n  const cache = includeHidden ? cacheAccessibleDescriptionHidden : cacheAccessibleDescription;\n  let accessibleDescription = cache == null ? void 0 : cache.get(element);\n  if (accessibleDescription === void 0) {\n    accessibleDescription = \"\";\n    if (element.hasAttribute(\"aria-describedby\")) {\n      const describedBy = getIdRefs(element, element.getAttribute(\"aria-describedby\"));\n      accessibleDescription = asFlatString(describedBy.map((ref) => getTextAlternativeInternal(ref, {\n        includeHidden,\n        visitedElements: /* @__PURE__ */ new Set(),\n        embeddedInLabelledBy: void 0,\n        embeddedInLabel: void 0,\n        embeddedInNativeTextAlternative: void 0,\n        embeddedInTargetElement: \"none\",\n        embeddedInDescribedBy: { element: ref, hidden: isElementHiddenForAria(ref) }\n      })).join(\" \"));\n    } else if (element.hasAttribute(\"aria-description\")) {\n      accessibleDescription = asFlatString(element.getAttribute(\"aria-description\") || \"\");\n    } else {\n      accessibleDescription = asFlatString(element.getAttribute(\"title\") || \"\");\n    }\n    cache == null ? void 0 : cache.set(element, accessibleDescription);\n  }\n  return accessibleDescription;\n}\nfunction getTextAlternativeInternal(element, options) {\n  var _a, _b, _c, _d;\n  if (options.visitedElements.has(element))\n    return \"\";\n  const childOptions = {\n    ...options,\n    embeddedInTargetElement: options.embeddedInTargetElement === \"self\" ? \"descendant\" : options.embeddedInTargetElement\n  };\n  if (!options.includeHidden && !((_a = options.embeddedInLabelledBy) == null ? void 0 : _a.hidden) && !((_b = options.embeddedInDescribedBy) == null ? void 0 : _b.hidden) && !((_c = options == null ? void 0 : options.embeddedInNativeTextAlternative) == null ? void 0 : _c.hidden) && !((_d = options == null ? void 0 : options.embeddedInLabel) == null ? void 0 : _d.hidden) && isElementHiddenForAria(element)) {\n    options.visitedElements.add(element);\n    return \"\";\n  }\n  const labelledBy = getAriaLabelledByElements(element);\n  if (!options.embeddedInLabelledBy) {\n    const accessibleName = (labelledBy || []).map((ref) => getTextAlternativeInternal(ref, {\n      ...options,\n      embeddedInLabelledBy: { element: ref, hidden: isElementHiddenForAria(ref) },\n      embeddedInDescribedBy: void 0,\n      embeddedInTargetElement: \"none\",\n      embeddedInLabel: void 0,\n      embeddedInNativeTextAlternative: void 0\n    })).join(\" \");\n    if (accessibleName)\n      return accessibleName;\n  }\n  const role = getAriaRole(element) || \"\";\n  const tagName = elementSafeTagName(element);\n  if (!!options.embeddedInLabel || !!options.embeddedInLabelledBy || options.embeddedInTargetElement === \"descendant\") {\n    const isOwnLabel = [...element.labels || []].includes(element);\n    const isOwnLabelledBy = (labelledBy || []).includes(element);\n    if (!isOwnLabel && !isOwnLabelledBy) {\n      if (role === \"textbox\") {\n        options.visitedElements.add(element);\n        if (tagName === \"INPUT\" || tagName === \"TEXTAREA\")\n          return element.value;\n        return element.textContent || \"\";\n      }\n      if ([\"combobox\", \"listbox\"].includes(role)) {\n        options.visitedElements.add(element);\n        let selectedOptions;\n        if (tagName === \"SELECT\") {\n          selectedOptions = [...element.selectedOptions];\n          if (!selectedOptions.length && element.options.length)\n            selectedOptions.push(element.options[0]);\n        } else {\n          const listbox = role === \"combobox\" ? queryInAriaOwned(element, \"*\").find((e) => getAriaRole(e) === \"listbox\") : element;\n          selectedOptions = listbox ? queryInAriaOwned(listbox, '[aria-selected=\"true\"]').filter((e) => getAriaRole(e) === \"option\") : [];\n        }\n        if (!selectedOptions.length && tagName === \"INPUT\") {\n          return element.value;\n        }\n        return selectedOptions.map((option) => getTextAlternativeInternal(option, childOptions)).join(\" \");\n      }\n      if ([\"progressbar\", \"scrollbar\", \"slider\", \"spinbutton\", \"meter\"].includes(role)) {\n        options.visitedElements.add(element);\n        if (element.hasAttribute(\"aria-valuetext\"))\n          return element.getAttribute(\"aria-valuetext\") || \"\";\n        if (element.hasAttribute(\"aria-valuenow\"))\n          return element.getAttribute(\"aria-valuenow\") || \"\";\n        return element.getAttribute(\"value\") || \"\";\n      }\n      if ([\"menu\"].includes(role)) {\n        options.visitedElements.add(element);\n        return \"\";\n      }\n    }\n  }\n  const ariaLabel = element.getAttribute(\"aria-label\") || \"\";\n  if (trimFlatString(ariaLabel)) {\n    options.visitedElements.add(element);\n    return ariaLabel;\n  }\n  if (![\"presentation\", \"none\"].includes(role)) {\n    if (tagName === \"INPUT\" && [\"button\", \"submit\", \"reset\"].includes(element.type)) {\n      options.visitedElements.add(element);\n      const value = element.value || \"\";\n      if (trimFlatString(value))\n        return value;\n      if (element.type === \"submit\")\n        return \"Submit\";\n      if (element.type === \"reset\")\n        return \"Reset\";\n      const title = element.getAttribute(\"title\") || \"\";\n      return title;\n    }\n    if (tagName === \"INPUT\" && element.type === \"image\") {\n      options.visitedElements.add(element);\n      const labels = element.labels || [];\n      if (labels.length && !options.embeddedInLabelledBy)\n        return getAccessibleNameFromAssociatedLabels(labels, options);\n      const alt = element.getAttribute(\"alt\") || \"\";\n      if (trimFlatString(alt))\n        return alt;\n      const title = element.getAttribute(\"title\") || \"\";\n      if (trimFlatString(title))\n        return title;\n      return \"Submit\";\n    }\n    if (!labelledBy && tagName === \"BUTTON\") {\n      options.visitedElements.add(element);\n      const labels = element.labels || [];\n      if (labels.length)\n        return getAccessibleNameFromAssociatedLabels(labels, options);\n    }\n    if (!labelledBy && tagName === \"OUTPUT\") {\n      options.visitedElements.add(element);\n      const labels = element.labels || [];\n      if (labels.length)\n        return getAccessibleNameFromAssociatedLabels(labels, options);\n      return element.getAttribute(\"title\") || \"\";\n    }\n    if (!labelledBy && (tagName === \"TEXTAREA\" || tagName === \"SELECT\" || tagName === \"INPUT\")) {\n      options.visitedElements.add(element);\n      const labels = element.labels || [];\n      if (labels.length)\n        return getAccessibleNameFromAssociatedLabels(labels, options);\n      const usePlaceholder = tagName === \"INPUT\" && [\"text\", \"password\", \"search\", \"tel\", \"email\", \"url\"].includes(element.type) || tagName === \"TEXTAREA\";\n      const placeholder = element.getAttribute(\"placeholder\") || \"\";\n      const title = element.getAttribute(\"title\") || \"\";\n      if (!usePlaceholder || title)\n        return title;\n      return placeholder;\n    }\n    if (!labelledBy && tagName === \"FIELDSET\") {\n      options.visitedElements.add(element);\n      for (let child = element.firstElementChild; child; child = child.nextElementSibling) {\n        if (elementSafeTagName(child) === \"LEGEND\") {\n          return getTextAlternativeInternal(child, {\n            ...childOptions,\n            embeddedInNativeTextAlternative: { element: child, hidden: isElementHiddenForAria(child) }\n          });\n        }\n      }\n      const title = element.getAttribute(\"title\") || \"\";\n      return title;\n    }\n    if (!labelledBy && tagName === \"FIGURE\") {\n      options.visitedElements.add(element);\n      for (let child = element.firstElementChild; child; child = child.nextElementSibling) {\n        if (elementSafeTagName(child) === \"FIGCAPTION\") {\n          return getTextAlternativeInternal(child, {\n            ...childOptions,\n            embeddedInNativeTextAlternative: { element: child, hidden: isElementHiddenForAria(child) }\n          });\n        }\n      }\n      const title = element.getAttribute(\"title\") || \"\";\n      return title;\n    }\n    if (tagName === \"IMG\") {\n      options.visitedElements.add(element);\n      const alt = element.getAttribute(\"alt\") || \"\";\n      if (trimFlatString(alt))\n        return alt;\n      const title = element.getAttribute(\"title\") || \"\";\n      return title;\n    }\n    if (tagName === \"TABLE\") {\n      options.visitedElements.add(element);\n      for (let child = element.firstElementChild; child; child = child.nextElementSibling) {\n        if (elementSafeTagName(child) === \"CAPTION\") {\n          return getTextAlternativeInternal(child, {\n            ...childOptions,\n            embeddedInNativeTextAlternative: { element: child, hidden: isElementHiddenForAria(child) }\n          });\n        }\n      }\n      const summary = element.getAttribute(\"summary\") || \"\";\n      if (summary)\n        return summary;\n    }\n    if (tagName === \"AREA\") {\n      options.visitedElements.add(element);\n      const alt = element.getAttribute(\"alt\") || \"\";\n      if (trimFlatString(alt))\n        return alt;\n      const title = element.getAttribute(\"title\") || \"\";\n      return title;\n    }\n    if (tagName === \"SVG\" || element.ownerSVGElement) {\n      options.visitedElements.add(element);\n      for (let child = element.firstElementChild; child; child = child.nextElementSibling) {\n        if (elementSafeTagName(child) === \"TITLE\" && child.ownerSVGElement) {\n          return getTextAlternativeInternal(child, {\n            ...childOptions,\n            embeddedInLabelledBy: { element: child, hidden: isElementHiddenForAria(child) }\n          });\n        }\n      }\n    }\n    if (element.ownerSVGElement && tagName === \"A\") {\n      const title = element.getAttribute(\"xlink:title\") || \"\";\n      if (trimFlatString(title)) {\n        options.visitedElements.add(element);\n        return title;\n      }\n    }\n  }\n  const shouldNameFromContentForSummary = tagName === \"SUMMARY\" && ![\"presentation\", \"none\"].includes(role);\n  if (allowsNameFromContent(role, options.embeddedInTargetElement === \"descendant\") || shouldNameFromContentForSummary || !!options.embeddedInLabelledBy || !!options.embeddedInDescribedBy || !!options.embeddedInLabel || !!options.embeddedInNativeTextAlternative) {\n    options.visitedElements.add(element);\n    const tokens = [];\n    const visit = (node, skipSlotted) => {\n      var _a2;\n      if (skipSlotted && node.assignedSlot)\n        return;\n      if (node.nodeType === 1) {\n        const display = ((_a2 = getElementComputedStyle(node)) == null ? void 0 : _a2.display) || \"inline\";\n        let token = getTextAlternativeInternal(node, childOptions);\n        if (display !== \"inline\" || node.nodeName === \"BR\")\n          token = \" \" + token + \" \";\n        tokens.push(token);\n      } else if (node.nodeType === 3) {\n        tokens.push(node.textContent || \"\");\n      }\n    };\n    tokens.push(getPseudoContent(element, \"::before\"));\n    const assignedNodes = element.nodeName === \"SLOT\" ? element.assignedNodes() : [];\n    if (assignedNodes.length) {\n      for (const child of assignedNodes)\n        visit(child, false);\n    } else {\n      for (let child = element.firstChild; child; child = child.nextSibling)\n        visit(child, true);\n      if (element.shadowRoot) {\n        for (let child = element.shadowRoot.firstChild; child; child = child.nextSibling)\n          visit(child, true);\n      }\n      for (const owned of getIdRefs(element, element.getAttribute(\"aria-owns\")))\n        visit(owned, true);\n    }\n    tokens.push(getPseudoContent(element, \"::after\"));\n    const accessibleName = tokens.join(\"\");\n    const maybeTrimmedAccessibleName = options.embeddedInTargetElement === \"self\" ? trimFlatString(accessibleName) : accessibleName;\n    if (maybeTrimmedAccessibleName)\n      return accessibleName;\n  }\n  if (![\"presentation\", \"none\"].includes(role) || tagName === \"IFRAME\") {\n    options.visitedElements.add(element);\n    const title = element.getAttribute(\"title\") || \"\";\n    if (trimFlatString(title))\n      return title;\n  }\n  options.visitedElements.add(element);\n  return \"\";\n}\nvar kAriaSelectedRoles = [\"gridcell\", \"option\", \"row\", \"tab\", \"rowheader\", \"columnheader\", \"treeitem\"];\nfunction getAriaSelected(element) {\n  if (elementSafeTagName(element) === \"OPTION\")\n    return element.selected;\n  if (kAriaSelectedRoles.includes(getAriaRole(element) || \"\"))\n    return getAriaBoolean(element.getAttribute(\"aria-selected\")) === true;\n  return false;\n}\nvar kAriaCheckedRoles = [\"checkbox\", \"menuitemcheckbox\", \"option\", \"radio\", \"switch\", \"menuitemradio\", \"treeitem\"];\nfunction getAriaChecked(element) {\n  const result = getChecked(element, true);\n  return result === \"error\" ? false : result;\n}\nfunction getChecked(element, allowMixed) {\n  const tagName = elementSafeTagName(element);\n  if (allowMixed && tagName === \"INPUT\" && element.indeterminate)\n    return \"mixed\";\n  if (tagName === \"INPUT\" && [\"checkbox\", \"radio\"].includes(element.type))\n    return element.checked;\n  if (kAriaCheckedRoles.includes(getAriaRole(element) || \"\")) {\n    const checked = element.getAttribute(\"aria-checked\");\n    if (checked === \"true\")\n      return true;\n    if (allowMixed && checked === \"mixed\")\n      return \"mixed\";\n    return false;\n  }\n  return \"error\";\n}\nvar kAriaPressedRoles = [\"button\"];\nfunction getAriaPressed(element) {\n  if (kAriaPressedRoles.includes(getAriaRole(element) || \"\")) {\n    const pressed = element.getAttribute(\"aria-pressed\");\n    if (pressed === \"true\")\n      return true;\n    if (pressed === \"mixed\")\n      return \"mixed\";\n  }\n  return false;\n}\nvar kAriaExpandedRoles = [\"application\", \"button\", \"checkbox\", \"combobox\", \"gridcell\", \"link\", \"listbox\", \"menuitem\", \"row\", \"rowheader\", \"tab\", \"treeitem\", \"columnheader\", \"menuitemcheckbox\", \"menuitemradio\", \"rowheader\", \"switch\"];\nfunction getAriaExpanded(element) {\n  if (elementSafeTagName(element) === \"DETAILS\")\n    return element.open;\n  if (kAriaExpandedRoles.includes(getAriaRole(element) || \"\")) {\n    const expanded = element.getAttribute(\"aria-expanded\");\n    if (expanded === null)\n      return \"none\";\n    if (expanded === \"true\")\n      return true;\n    return false;\n  }\n  return \"none\";\n}\nvar kAriaLevelRoles = [\"heading\", \"listitem\", \"row\", \"treeitem\"];\nfunction getAriaLevel(element) {\n  const native = { \"H1\": 1, \"H2\": 2, \"H3\": 3, \"H4\": 4, \"H5\": 5, \"H6\": 6 }[elementSafeTagName(element)];\n  if (native)\n    return native;\n  if (kAriaLevelRoles.includes(getAriaRole(element) || \"\")) {\n    const attr = element.getAttribute(\"aria-level\");\n    const value = attr === null ? Number.NaN : Number(attr);\n    if (Number.isInteger(value) && value >= 1)\n      return value;\n  }\n  return 0;\n}\nvar kAriaDisabledRoles = [\"application\", \"button\", \"composite\", \"gridcell\", \"group\", \"input\", \"link\", \"menuitem\", \"scrollbar\", \"separator\", \"tab\", \"checkbox\", \"columnheader\", \"combobox\", \"grid\", \"listbox\", \"menu\", \"menubar\", \"menuitemcheckbox\", \"menuitemradio\", \"option\", \"radio\", \"radiogroup\", \"row\", \"rowheader\", \"searchbox\", \"select\", \"slider\", \"spinbutton\", \"switch\", \"tablist\", \"textbox\", \"toolbar\", \"tree\", \"treegrid\", \"treeitem\"];\nfunction getAriaDisabled(element) {\n  return isNativelyDisabled(element) || hasExplicitAriaDisabled(element);\n}\nfunction isNativelyDisabled(element) {\n  const isNativeFormControl = [\"BUTTON\", \"INPUT\", \"SELECT\", \"TEXTAREA\", \"OPTION\", \"OPTGROUP\"].includes(element.tagName);\n  return isNativeFormControl && (element.hasAttribute(\"disabled\") || belongsToDisabledFieldSet(element));\n}\nfunction belongsToDisabledFieldSet(element) {\n  if (!element)\n    return false;\n  if (elementSafeTagName(element) === \"FIELDSET\" && element.hasAttribute(\"disabled\"))\n    return true;\n  return belongsToDisabledFieldSet(element.parentElement);\n}\nfunction hasExplicitAriaDisabled(element) {\n  if (!element)\n    return false;\n  if (kAriaDisabledRoles.includes(getAriaRole(element) || \"\")) {\n    const attribute = (element.getAttribute(\"aria-disabled\") || \"\").toLowerCase();\n    if (attribute === \"true\")\n      return true;\n    if (attribute === \"false\")\n      return false;\n  }\n  return hasExplicitAriaDisabled(parentElementOrShadowHost(element));\n}\nfunction getAccessibleNameFromAssociatedLabels(labels, options) {\n  return [...labels].map((label) => getTextAlternativeInternal(label, {\n    ...options,\n    embeddedInLabel: { element: label, hidden: isElementHiddenForAria(label) },\n    embeddedInNativeTextAlternative: void 0,\n    embeddedInLabelledBy: void 0,\n    embeddedInDescribedBy: void 0,\n    embeddedInTargetElement: \"none\"\n  })).filter((accessibleName) => !!accessibleName).join(\" \");\n}\nvar cacheAccessibleName;\nvar cacheAccessibleNameHidden;\nvar cacheAccessibleDescription;\nvar cacheAccessibleDescriptionHidden;\nvar cacheIsHidden;\nvar cachePseudoContentBefore;\nvar cachePseudoContentAfter;\nvar cachesCounter = 0;\nfunction beginAriaCaches() {\n  ++cachesCounter;\n  cacheAccessibleName != null ? cacheAccessibleName : cacheAccessibleName = /* @__PURE__ */ new Map();\n  cacheAccessibleNameHidden != null ? cacheAccessibleNameHidden : cacheAccessibleNameHidden = /* @__PURE__ */ new Map();\n  cacheAccessibleDescription != null ? cacheAccessibleDescription : cacheAccessibleDescription = /* @__PURE__ */ new Map();\n  cacheAccessibleDescriptionHidden != null ? cacheAccessibleDescriptionHidden : cacheAccessibleDescriptionHidden = /* @__PURE__ */ new Map();\n  cacheIsHidden != null ? cacheIsHidden : cacheIsHidden = /* @__PURE__ */ new Map();\n  cachePseudoContentBefore != null ? cachePseudoContentBefore : cachePseudoContentBefore = /* @__PURE__ */ new Map();\n  cachePseudoContentAfter != null ? cachePseudoContentAfter : cachePseudoContentAfter = /* @__PURE__ */ new Map();\n}\nfunction endAriaCaches() {\n  if (!--cachesCounter) {\n    cacheAccessibleName = void 0;\n    cacheAccessibleNameHidden = void 0;\n    cacheAccessibleDescription = void 0;\n    cacheAccessibleDescriptionHidden = void 0;\n    cacheIsHidden = void 0;\n    cachePseudoContentBefore = void 0;\n    cachePseudoContentAfter = void 0;\n  }\n}\n\n// packages/playwright-core/src/server/injected/selectorUtils.ts\nfunction matchesComponentAttribute(obj, attr) {\n  for (const token of attr.jsonPath) {\n    if (obj !== void 0 && obj !== null)\n      obj = obj[token];\n  }\n  return matchesAttributePart(obj, attr);\n}\nfunction matchesAttributePart(value, attr) {\n  const objValue = typeof value === \"string\" && !attr.caseSensitive ? value.toUpperCase() : value;\n  const attrValue = typeof attr.value === \"string\" && !attr.caseSensitive ? attr.value.toUpperCase() : attr.value;\n  if (attr.op === \"<truthy>\")\n    return !!objValue;\n  if (attr.op === \"=\") {\n    if (attrValue instanceof RegExp)\n      return typeof objValue === \"string\" && !!objValue.match(attrValue);\n    return objValue === attrValue;\n  }\n  if (typeof objValue !== \"string\" || typeof attrValue !== \"string\")\n    return false;\n  if (attr.op === \"*=\")\n    return objValue.includes(attrValue);\n  if (attr.op === \"^=\")\n    return objValue.startsWith(attrValue);\n  if (attr.op === \"$=\")\n    return objValue.endsWith(attrValue);\n  if (attr.op === \"|=\")\n    return objValue === attrValue || objValue.startsWith(attrValue + \"-\");\n  if (attr.op === \"~=\")\n    return objValue.split(\" \").includes(attrValue);\n  return false;\n}\nfunction shouldSkipForTextMatching(element) {\n  const document = element.ownerDocument;\n  return element.nodeName === \"SCRIPT\" || element.nodeName === \"NOSCRIPT\" || element.nodeName === \"STYLE\" || document.head && document.head.contains(element);\n}\nfunction elementText(cache, root) {\n  let value = cache.get(root);\n  if (value === void 0) {\n    value = { full: \"\", normalized: \"\", immediate: [] };\n    if (!shouldSkipForTextMatching(root)) {\n      let currentImmediate = \"\";\n      if (root instanceof HTMLInputElement && (root.type === \"submit\" || root.type === \"button\")) {\n        value = { full: root.value, normalized: normalizeWhiteSpace(root.value), immediate: [root.value] };\n      } else {\n        for (let child = root.firstChild; child; child = child.nextSibling) {\n          if (child.nodeType === Node.TEXT_NODE) {\n            value.full += child.nodeValue || \"\";\n            currentImmediate += child.nodeValue || \"\";\n          } else {\n            if (currentImmediate)\n              value.immediate.push(currentImmediate);\n            currentImmediate = \"\";\n            if (child.nodeType === Node.ELEMENT_NODE)\n              value.full += elementText(cache, child).full;\n          }\n        }\n        if (currentImmediate)\n          value.immediate.push(currentImmediate);\n        if (root.shadowRoot)\n          value.full += elementText(cache, root.shadowRoot).full;\n        if (value.full)\n          value.normalized = normalizeWhiteSpace(value.full);\n      }\n    }\n    cache.set(root, value);\n  }\n  return value;\n}\nfunction elementMatchesText(cache, element, matcher) {\n  if (shouldSkipForTextMatching(element))\n    return \"none\";\n  if (!matcher(elementText(cache, element)))\n    return \"none\";\n  for (let child = element.firstChild; child; child = child.nextSibling) {\n    if (child.nodeType === Node.ELEMENT_NODE && matcher(elementText(cache, child)))\n      return \"selfAndChildren\";\n  }\n  if (element.shadowRoot && matcher(elementText(cache, element.shadowRoot)))\n    return \"selfAndChildren\";\n  return \"self\";\n}\nfunction getElementLabels(textCache, element) {\n  const labels = getAriaLabelledByElements(element);\n  if (labels)\n    return labels.map((label) => elementText(textCache, label));\n  const ariaLabel = element.getAttribute(\"aria-label\");\n  if (ariaLabel !== null && !!ariaLabel.trim())\n    return [{ full: ariaLabel, normalized: normalizeWhiteSpace(ariaLabel), immediate: [ariaLabel] }];\n  const isNonHiddenInput = element.nodeName === \"INPUT\" && element.type !== \"hidden\";\n  if ([\"BUTTON\", \"METER\", \"OUTPUT\", \"PROGRESS\", \"SELECT\", \"TEXTAREA\"].includes(element.nodeName) || isNonHiddenInput) {\n    const labels2 = element.labels;\n    if (labels2)\n      return [...labels2].map((label) => elementText(textCache, label));\n  }\n  return [];\n}\n\n// packages/playwright-core/src/utils/isomorphic/cssTokenizer.ts\nvar between = function(num, first, last) {\n  return num >= first && num <= last;\n};\nfunction digit(code) {\n  return between(code, 48, 57);\n}\nfunction hexdigit(code) {\n  return digit(code) || between(code, 65, 70) || between(code, 97, 102);\n}\nfunction uppercaseletter(code) {\n  return between(code, 65, 90);\n}\nfunction lowercaseletter(code) {\n  return between(code, 97, 122);\n}\nfunction letter(code) {\n  return uppercaseletter(code) || lowercaseletter(code);\n}\nfunction nonascii(code) {\n  return code >= 128;\n}\nfunction namestartchar(code) {\n  return letter(code) || nonascii(code) || code === 95;\n}\nfunction namechar(code) {\n  return namestartchar(code) || digit(code) || code === 45;\n}\nfunction nonprintable(code) {\n  return between(code, 0, 8) || code === 11 || between(code, 14, 31) || code === 127;\n}\nfunction newline(code) {\n  return code === 10;\n}\nfunction whitespace(code) {\n  return newline(code) || code === 9 || code === 32;\n}\nvar maximumallowedcodepoint = 1114111;\nvar InvalidCharacterError = class extends Error {\n  constructor(message) {\n    super(message);\n    this.name = \"InvalidCharacterError\";\n  }\n};\nfunction preprocess(str) {\n  const codepoints = [];\n  for (let i = 0; i < str.length; i++) {\n    let code = str.charCodeAt(i);\n    if (code === 13 && str.charCodeAt(i + 1) === 10) {\n      code = 10;\n      i++;\n    }\n    if (code === 13 || code === 12)\n      code = 10;\n    if (code === 0)\n      code = 65533;\n    if (between(code, 55296, 56319) && between(str.charCodeAt(i + 1), 56320, 57343)) {\n      const lead = code - 55296;\n      const trail = str.charCodeAt(i + 1) - 56320;\n      code = Math.pow(2, 16) + lead * Math.pow(2, 10) + trail;\n      i++;\n    }\n    codepoints.push(code);\n  }\n  return codepoints;\n}\nfunction stringFromCode(code) {\n  if (code <= 65535)\n    return String.fromCharCode(code);\n  code -= Math.pow(2, 16);\n  const lead = Math.floor(code / Math.pow(2, 10)) + 55296;\n  const trail = code % Math.pow(2, 10) + 56320;\n  return String.fromCharCode(lead) + String.fromCharCode(trail);\n}\nfunction tokenize(str1) {\n  const str = preprocess(str1);\n  let i = -1;\n  const tokens = [];\n  let code;\n  let line = 0;\n  let column = 0;\n  let lastLineLength = 0;\n  const incrLineno = function() {\n    line += 1;\n    lastLineLength = column;\n    column = 0;\n  };\n  const locStart = { line, column };\n  const codepoint = function(i2) {\n    if (i2 >= str.length)\n      return -1;\n    return str[i2];\n  };\n  const next = function(num) {\n    if (num === void 0)\n      num = 1;\n    if (num > 3)\n      throw \"Spec Error: no more than three codepoints of lookahead.\";\n    return codepoint(i + num);\n  };\n  const consume = function(num) {\n    if (num === void 0)\n      num = 1;\n    i += num;\n    code = codepoint(i);\n    if (newline(code))\n      incrLineno();\n    else\n      column += num;\n    return true;\n  };\n  const reconsume = function() {\n    i -= 1;\n    if (newline(code)) {\n      line -= 1;\n      column = lastLineLength;\n    } else {\n      column -= 1;\n    }\n    locStart.line = line;\n    locStart.column = column;\n    return true;\n  };\n  const eof = function(codepoint2) {\n    if (codepoint2 === void 0)\n      codepoint2 = code;\n    return codepoint2 === -1;\n  };\n  const donothing = function() {\n  };\n  const parseerror = function() {\n  };\n  const consumeAToken = function() {\n    consumeComments();\n    consume();\n    if (whitespace(code)) {\n      while (whitespace(next()))\n        consume();\n      return new WhitespaceToken();\n    } else if (code === 34) {\n      return consumeAStringToken();\n    } else if (code === 35) {\n      if (namechar(next()) || areAValidEscape(next(1), next(2))) {\n        const token = new HashToken(\"\");\n        if (wouldStartAnIdentifier(next(1), next(2), next(3)))\n          token.type = \"id\";\n        token.value = consumeAName();\n        return token;\n      } else {\n        return new DelimToken(code);\n      }\n    } else if (code === 36) {\n      if (next() === 61) {\n        consume();\n        return new SuffixMatchToken();\n      } else {\n        return new DelimToken(code);\n      }\n    } else if (code === 39) {\n      return consumeAStringToken();\n    } else if (code === 40) {\n      return new OpenParenToken();\n    } else if (code === 41) {\n      return new CloseParenToken();\n    } else if (code === 42) {\n      if (next() === 61) {\n        consume();\n        return new SubstringMatchToken();\n      } else {\n        return new DelimToken(code);\n      }\n    } else if (code === 43) {\n      if (startsWithANumber()) {\n        reconsume();\n        return consumeANumericToken();\n      } else {\n        return new DelimToken(code);\n      }\n    } else if (code === 44) {\n      return new CommaToken();\n    } else if (code === 45) {\n      if (startsWithANumber()) {\n        reconsume();\n        return consumeANumericToken();\n      } else if (next(1) === 45 && next(2) === 62) {\n        consume(2);\n        return new CDCToken();\n      } else if (startsWithAnIdentifier()) {\n        reconsume();\n        return consumeAnIdentlikeToken();\n      } else {\n        return new DelimToken(code);\n      }\n    } else if (code === 46) {\n      if (startsWithANumber()) {\n        reconsume();\n        return consumeANumericToken();\n      } else {\n        return new DelimToken(code);\n      }\n    } else if (code === 58) {\n      return new ColonToken();\n    } else if (code === 59) {\n      return new SemicolonToken();\n    } else if (code === 60) {\n      if (next(1) === 33 && next(2) === 45 && next(3) === 45) {\n        consume(3);\n        return new CDOToken();\n      } else {\n        return new DelimToken(code);\n      }\n    } else if (code === 64) {\n      if (wouldStartAnIdentifier(next(1), next(2), next(3)))\n        return new AtKeywordToken(consumeAName());\n      else\n        return new DelimToken(code);\n    } else if (code === 91) {\n      return new OpenSquareToken();\n    } else if (code === 92) {\n      if (startsWithAValidEscape()) {\n        reconsume();\n        return consumeAnIdentlikeToken();\n      } else {\n        parseerror();\n        return new DelimToken(code);\n      }\n    } else if (code === 93) {\n      return new CloseSquareToken();\n    } else if (code === 94) {\n      if (next() === 61) {\n        consume();\n        return new PrefixMatchToken();\n      } else {\n        return new DelimToken(code);\n      }\n    } else if (code === 123) {\n      return new OpenCurlyToken();\n    } else if (code === 124) {\n      if (next() === 61) {\n        consume();\n        return new DashMatchToken();\n      } else if (next() === 124) {\n        consume();\n        return new ColumnToken();\n      } else {\n        return new DelimToken(code);\n      }\n    } else if (code === 125) {\n      return new CloseCurlyToken();\n    } else if (code === 126) {\n      if (next() === 61) {\n        consume();\n        return new IncludeMatchToken();\n      } else {\n        return new DelimToken(code);\n      }\n    } else if (digit(code)) {\n      reconsume();\n      return consumeANumericToken();\n    } else if (namestartchar(code)) {\n      reconsume();\n      return consumeAnIdentlikeToken();\n    } else if (eof()) {\n      return new EOFToken();\n    } else {\n      return new DelimToken(code);\n    }\n  };\n  const consumeComments = function() {\n    while (next(1) === 47 && next(2) === 42) {\n      consume(2);\n      while (true) {\n        consume();\n        if (code === 42 && next() === 47) {\n          consume();\n          break;\n        } else if (eof()) {\n          parseerror();\n          return;\n        }\n      }\n    }\n  };\n  const consumeANumericToken = function() {\n    const num = consumeANumber();\n    if (wouldStartAnIdentifier(next(1), next(2), next(3))) {\n      const token = new DimensionToken();\n      token.value = num.value;\n      token.repr = num.repr;\n      token.type = num.type;\n      token.unit = consumeAName();\n      return token;\n    } else if (next() === 37) {\n      consume();\n      const token = new PercentageToken();\n      token.value = num.value;\n      token.repr = num.repr;\n      return token;\n    } else {\n      const token = new NumberToken();\n      token.value = num.value;\n      token.repr = num.repr;\n      token.type = num.type;\n      return token;\n    }\n  };\n  const consumeAnIdentlikeToken = function() {\n    const str2 = consumeAName();\n    if (str2.toLowerCase() === \"url\" && next() === 40) {\n      consume();\n      while (whitespace(next(1)) && whitespace(next(2)))\n        consume();\n      if (next() === 34 || next() === 39)\n        return new FunctionToken(str2);\n      else if (whitespace(next()) && (next(2) === 34 || next(2) === 39))\n        return new FunctionToken(str2);\n      else\n        return consumeAURLToken();\n    } else if (next() === 40) {\n      consume();\n      return new FunctionToken(str2);\n    } else {\n      return new IdentToken(str2);\n    }\n  };\n  const consumeAStringToken = function(endingCodePoint) {\n    if (endingCodePoint === void 0)\n      endingCodePoint = code;\n    let string = \"\";\n    while (consume()) {\n      if (code === endingCodePoint || eof()) {\n        return new StringToken(string);\n      } else if (newline(code)) {\n        parseerror();\n        reconsume();\n        return new BadStringToken();\n      } else if (code === 92) {\n        if (eof(next()))\n          donothing();\n        else if (newline(next()))\n          consume();\n        else\n          string += stringFromCode(consumeEscape());\n      } else {\n        string += stringFromCode(code);\n      }\n    }\n    throw new Error(\"Internal error\");\n  };\n  const consumeAURLToken = function() {\n    const token = new URLToken(\"\");\n    while (whitespace(next()))\n      consume();\n    if (eof(next()))\n      return token;\n    while (consume()) {\n      if (code === 41 || eof()) {\n        return token;\n      } else if (whitespace(code)) {\n        while (whitespace(next()))\n          consume();\n        if (next() === 41 || eof(next())) {\n          consume();\n          return token;\n        } else {\n          consumeTheRemnantsOfABadURL();\n          return new BadURLToken();\n        }\n      } else if (code === 34 || code === 39 || code === 40 || nonprintable(code)) {\n        parseerror();\n        consumeTheRemnantsOfABadURL();\n        return new BadURLToken();\n      } else if (code === 92) {\n        if (startsWithAValidEscape()) {\n          token.value += stringFromCode(consumeEscape());\n        } else {\n          parseerror();\n          consumeTheRemnantsOfABadURL();\n          return new BadURLToken();\n        }\n      } else {\n        token.value += stringFromCode(code);\n      }\n    }\n    throw new Error(\"Internal error\");\n  };\n  const consumeEscape = function() {\n    consume();\n    if (hexdigit(code)) {\n      const digits = [code];\n      for (let total = 0; total < 5; total++) {\n        if (hexdigit(next())) {\n          consume();\n          digits.push(code);\n        } else {\n          break;\n        }\n      }\n      if (whitespace(next()))\n        consume();\n      let value = parseInt(digits.map(function(x) {\n        return String.fromCharCode(x);\n      }).join(\"\"), 16);\n      if (value > maximumallowedcodepoint)\n        value = 65533;\n      return value;\n    } else if (eof()) {\n      return 65533;\n    } else {\n      return code;\n    }\n  };\n  const areAValidEscape = function(c1, c2) {\n    if (c1 !== 92)\n      return false;\n    if (newline(c2))\n      return false;\n    return true;\n  };\n  const startsWithAValidEscape = function() {\n    return areAValidEscape(code, next());\n  };\n  const wouldStartAnIdentifier = function(c1, c2, c3) {\n    if (c1 === 45)\n      return namestartchar(c2) || c2 === 45 || areAValidEscape(c2, c3);\n    else if (namestartchar(c1))\n      return true;\n    else if (c1 === 92)\n      return areAValidEscape(c1, c2);\n    else\n      return false;\n  };\n  const startsWithAnIdentifier = function() {\n    return wouldStartAnIdentifier(code, next(1), next(2));\n  };\n  const wouldStartANumber = function(c1, c2, c3) {\n    if (c1 === 43 || c1 === 45) {\n      if (digit(c2))\n        return true;\n      if (c2 === 46 && digit(c3))\n        return true;\n      return false;\n    } else if (c1 === 46) {\n      if (digit(c2))\n        return true;\n      return false;\n    } else if (digit(c1)) {\n      return true;\n    } else {\n      return false;\n    }\n  };\n  const startsWithANumber = function() {\n    return wouldStartANumber(code, next(1), next(2));\n  };\n  const consumeAName = function() {\n    let result = \"\";\n    while (consume()) {\n      if (namechar(code)) {\n        result += stringFromCode(code);\n      } else if (startsWithAValidEscape()) {\n        result += stringFromCode(consumeEscape());\n      } else {\n        reconsume();\n        return result;\n      }\n    }\n    throw new Error(\"Internal parse error\");\n  };\n  const consumeANumber = function() {\n    let repr = \"\";\n    let type = \"integer\";\n    if (next() === 43 || next() === 45) {\n      consume();\n      repr += stringFromCode(code);\n    }\n    while (digit(next())) {\n      consume();\n      repr += stringFromCode(code);\n    }\n    if (next(1) === 46 && digit(next(2))) {\n      consume();\n      repr += stringFromCode(code);\n      consume();\n      repr += stringFromCode(code);\n      type = \"number\";\n      while (digit(next())) {\n        consume();\n        repr += stringFromCode(code);\n      }\n    }\n    const c1 = next(1), c2 = next(2), c3 = next(3);\n    if ((c1 === 69 || c1 === 101) && digit(c2)) {\n      consume();\n      repr += stringFromCode(code);\n      consume();\n      repr += stringFromCode(code);\n      type = \"number\";\n      while (digit(next())) {\n        consume();\n        repr += stringFromCode(code);\n      }\n    } else if ((c1 === 69 || c1 === 101) && (c2 === 43 || c2 === 45) && digit(c3)) {\n      consume();\n      repr += stringFromCode(code);\n      consume();\n      repr += stringFromCode(code);\n      consume();\n      repr += stringFromCode(code);\n      type = \"number\";\n      while (digit(next())) {\n        consume();\n        repr += stringFromCode(code);\n      }\n    }\n    const value = convertAStringToANumber(repr);\n    return { type, value, repr };\n  };\n  const convertAStringToANumber = function(string) {\n    return +string;\n  };\n  const consumeTheRemnantsOfABadURL = function() {\n    while (consume()) {\n      if (code === 41 || eof()) {\n        return;\n      } else if (startsWithAValidEscape()) {\n        consumeEscape();\n        donothing();\n      } else {\n        donothing();\n      }\n    }\n  };\n  let iterationCount = 0;\n  while (!eof(next())) {\n    tokens.push(consumeAToken());\n    iterationCount++;\n    if (iterationCount > str.length * 2)\n      throw new Error(\"I'm infinite-looping!\");\n  }\n  return tokens;\n}\nvar CSSParserToken = class {\n  constructor() {\n    this.tokenType = \"\";\n  }\n  toJSON() {\n    return { token: this.tokenType };\n  }\n  toString() {\n    return this.tokenType;\n  }\n  toSource() {\n    return \"\" + this;\n  }\n};\nvar BadStringToken = class extends CSSParserToken {\n  constructor() {\n    super(...arguments);\n    this.tokenType = \"BADSTRING\";\n  }\n};\nvar BadURLToken = class extends CSSParserToken {\n  constructor() {\n    super(...arguments);\n    this.tokenType = \"BADURL\";\n  }\n};\nvar WhitespaceToken = class extends CSSParserToken {\n  constructor() {\n    super(...arguments);\n    this.tokenType = \"WHITESPACE\";\n  }\n  toString() {\n    return \"WS\";\n  }\n  toSource() {\n    return \" \";\n  }\n};\nvar CDOToken = class extends CSSParserToken {\n  constructor() {\n    super(...arguments);\n    this.tokenType = \"CDO\";\n  }\n  toSource() {\n    return \"<!--\";\n  }\n};\nvar CDCToken = class extends CSSParserToken {\n  constructor() {\n    super(...arguments);\n    this.tokenType = \"CDC\";\n  }\n  toSource() {\n    return \"-->\";\n  }\n};\nvar ColonToken = class extends CSSParserToken {\n  constructor() {\n    super(...arguments);\n    this.tokenType = \":\";\n  }\n};\nvar SemicolonToken = class extends CSSParserToken {\n  constructor() {\n    super(...arguments);\n    this.tokenType = \";\";\n  }\n};\nvar CommaToken = class extends CSSParserToken {\n  constructor() {\n    super(...arguments);\n    this.tokenType = \",\";\n  }\n};\nvar GroupingToken = class extends CSSParserToken {\n  constructor() {\n    super(...arguments);\n    this.value = \"\";\n    this.mirror = \"\";\n  }\n};\nvar OpenCurlyToken = class extends GroupingToken {\n  constructor() {\n    super();\n    this.tokenType = \"{\";\n    this.value = \"{\";\n    this.mirror = \"}\";\n  }\n};\nvar CloseCurlyToken = class extends GroupingToken {\n  constructor() {\n    super();\n    this.tokenType = \"}\";\n    this.value = \"}\";\n    this.mirror = \"{\";\n  }\n};\nvar OpenSquareToken = class extends GroupingToken {\n  constructor() {\n    super();\n    this.tokenType = \"[\";\n    this.value = \"[\";\n    this.mirror = \"]\";\n  }\n};\nvar CloseSquareToken = class extends GroupingToken {\n  constructor() {\n    super();\n    this.tokenType = \"]\";\n    this.value = \"]\";\n    this.mirror = \"[\";\n  }\n};\nvar OpenParenToken = class extends GroupingToken {\n  constructor() {\n    super();\n    this.tokenType = \"(\";\n    this.value = \"(\";\n    this.mirror = \")\";\n  }\n};\nvar CloseParenToken = class extends GroupingToken {\n  constructor() {\n    super();\n    this.tokenType = \")\";\n    this.value = \")\";\n    this.mirror = \"(\";\n  }\n};\nvar IncludeMatchToken = class extends CSSParserToken {\n  constructor() {\n    super(...arguments);\n    this.tokenType = \"~=\";\n  }\n};\nvar DashMatchToken = class extends CSSParserToken {\n  constructor() {\n    super(...arguments);\n    this.tokenType = \"|=\";\n  }\n};\nvar PrefixMatchToken = class extends CSSParserToken {\n  constructor() {\n    super(...arguments);\n    this.tokenType = \"^=\";\n  }\n};\nvar SuffixMatchToken = class extends CSSParserToken {\n  constructor() {\n    super(...arguments);\n    this.tokenType = \"$=\";\n  }\n};\nvar SubstringMatchToken = class extends CSSParserToken {\n  constructor() {\n    super(...arguments);\n    this.tokenType = \"*=\";\n  }\n};\nvar ColumnToken = class extends CSSParserToken {\n  constructor() {\n    super(...arguments);\n    this.tokenType = \"||\";\n  }\n};\nvar EOFToken = class extends CSSParserToken {\n  constructor() {\n    super(...arguments);\n    this.tokenType = \"EOF\";\n  }\n  toSource() {\n    return \"\";\n  }\n};\nvar DelimToken = class extends CSSParserToken {\n  constructor(code) {\n    super();\n    this.tokenType = \"DELIM\";\n    this.value = \"\";\n    this.value = stringFromCode(code);\n  }\n  toString() {\n    return \"DELIM(\" + this.value + \")\";\n  }\n  toJSON() {\n    const json = this.constructor.prototype.constructor.prototype.toJSON.call(this);\n    json.value = this.value;\n    return json;\n  }\n  toSource() {\n    if (this.value === \"\\\\\")\n      return \"\\\\\\n\";\n    else\n      return this.value;\n  }\n};\nvar StringValuedToken = class extends CSSParserToken {\n  constructor() {\n    super(...arguments);\n    this.value = \"\";\n  }\n  ASCIIMatch(str) {\n    return this.value.toLowerCase() === str.toLowerCase();\n  }\n  toJSON() {\n    const json = this.constructor.prototype.constructor.prototype.toJSON.call(this);\n    json.value = this.value;\n    return json;\n  }\n};\nvar IdentToken = class extends StringValuedToken {\n  constructor(val) {\n    super();\n    this.tokenType = \"IDENT\";\n    this.value = val;\n  }\n  toString() {\n    return \"IDENT(\" + this.value + \")\";\n  }\n  toSource() {\n    return escapeIdent(this.value);\n  }\n};\nvar FunctionToken = class extends StringValuedToken {\n  constructor(val) {\n    super();\n    this.tokenType = \"FUNCTION\";\n    this.value = val;\n    this.mirror = \")\";\n  }\n  toString() {\n    return \"FUNCTION(\" + this.value + \")\";\n  }\n  toSource() {\n    return escapeIdent(this.value) + \"(\";\n  }\n};\nvar AtKeywordToken = class extends StringValuedToken {\n  constructor(val) {\n    super();\n    this.tokenType = \"AT-KEYWORD\";\n    this.value = val;\n  }\n  toString() {\n    return \"AT(\" + this.value + \")\";\n  }\n  toSource() {\n    return \"@\" + escapeIdent(this.value);\n  }\n};\nvar HashToken = class extends StringValuedToken {\n  constructor(val) {\n    super();\n    this.tokenType = \"HASH\";\n    this.value = val;\n    this.type = \"unrestricted\";\n  }\n  toString() {\n    return \"HASH(\" + this.value + \")\";\n  }\n  toJSON() {\n    const json = this.constructor.prototype.constructor.prototype.toJSON.call(this);\n    json.value = this.value;\n    json.type = this.type;\n    return json;\n  }\n  toSource() {\n    if (this.type === \"id\")\n      return \"#\" + escapeIdent(this.value);\n    else\n      return \"#\" + escapeHash(this.value);\n  }\n};\nvar StringToken = class extends StringValuedToken {\n  constructor(val) {\n    super();\n    this.tokenType = \"STRING\";\n    this.value = val;\n  }\n  toString() {\n    return '\"' + escapeString(this.value) + '\"';\n  }\n};\nvar URLToken = class extends StringValuedToken {\n  constructor(val) {\n    super();\n    this.tokenType = \"URL\";\n    this.value = val;\n  }\n  toString() {\n    return \"URL(\" + this.value + \")\";\n  }\n  toSource() {\n    return 'url(\"' + escapeString(this.value) + '\")';\n  }\n};\nvar NumberToken = class extends CSSParserToken {\n  constructor() {\n    super();\n    this.tokenType = \"NUMBER\";\n    this.type = \"integer\";\n    this.repr = \"\";\n  }\n  toString() {\n    if (this.type === \"integer\")\n      return \"INT(\" + this.value + \")\";\n    return \"NUMBER(\" + this.value + \")\";\n  }\n  toJSON() {\n    const json = super.toJSON();\n    json.value = this.value;\n    json.type = this.type;\n    json.repr = this.repr;\n    return json;\n  }\n  toSource() {\n    return this.repr;\n  }\n};\nvar PercentageToken = class extends CSSParserToken {\n  constructor() {\n    super();\n    this.tokenType = \"PERCENTAGE\";\n    this.repr = \"\";\n  }\n  toString() {\n    return \"PERCENTAGE(\" + this.value + \")\";\n  }\n  toJSON() {\n    const json = this.constructor.prototype.constructor.prototype.toJSON.call(this);\n    json.value = this.value;\n    json.repr = this.repr;\n    return json;\n  }\n  toSource() {\n    return this.repr + \"%\";\n  }\n};\nvar DimensionToken = class extends CSSParserToken {\n  constructor() {\n    super();\n    this.tokenType = \"DIMENSION\";\n    this.type = \"integer\";\n    this.repr = \"\";\n    this.unit = \"\";\n  }\n  toString() {\n    return \"DIM(\" + this.value + \",\" + this.unit + \")\";\n  }\n  toJSON() {\n    const json = this.constructor.prototype.constructor.prototype.toJSON.call(this);\n    json.value = this.value;\n    json.type = this.type;\n    json.repr = this.repr;\n    json.unit = this.unit;\n    return json;\n  }\n  toSource() {\n    const source = this.repr;\n    let unit = escapeIdent(this.unit);\n    if (unit[0].toLowerCase() === \"e\" && (unit[1] === \"-\" || between(unit.charCodeAt(1), 48, 57))) {\n      unit = \"\\\\65 \" + unit.slice(1, unit.length);\n    }\n    return source + unit;\n  }\n};\nfunction escapeIdent(string) {\n  string = \"\" + string;\n  let result = \"\";\n  const firstcode = string.charCodeAt(0);\n  for (let i = 0; i < string.length; i++) {\n    const code = string.charCodeAt(i);\n    if (code === 0)\n      throw new InvalidCharacterError(\"Invalid character: the input contains U+0000.\");\n    if (between(code, 1, 31) || code === 127 || i === 0 && between(code, 48, 57) || i === 1 && between(code, 48, 57) && firstcode === 45)\n      result += \"\\\\\" + code.toString(16) + \" \";\n    else if (code >= 128 || code === 45 || code === 95 || between(code, 48, 57) || between(code, 65, 90) || between(code, 97, 122))\n      result += string[i];\n    else\n      result += \"\\\\\" + string[i];\n  }\n  return result;\n}\nfunction escapeHash(string) {\n  string = \"\" + string;\n  let result = \"\";\n  for (let i = 0; i < string.length; i++) {\n    const code = string.charCodeAt(i);\n    if (code === 0)\n      throw new InvalidCharacterError(\"Invalid character: the input contains U+0000.\");\n    if (code >= 128 || code === 45 || code === 95 || between(code, 48, 57) || between(code, 65, 90) || between(code, 97, 122))\n      result += string[i];\n    else\n      result += \"\\\\\" + code.toString(16) + \" \";\n  }\n  return result;\n}\nfunction escapeString(string) {\n  string = \"\" + string;\n  let result = \"\";\n  for (let i = 0; i < string.length; i++) {\n    const code = string.charCodeAt(i);\n    if (code === 0)\n      throw new InvalidCharacterError(\"Invalid character: the input contains U+0000.\");\n    if (between(code, 1, 31) || code === 127)\n      result += \"\\\\\" + code.toString(16) + \" \";\n    else if (code === 34 || code === 92)\n      result += \"\\\\\" + string[i];\n    else\n      result += string[i];\n  }\n  return result;\n}\n\n// packages/playwright-core/src/utils/isomorphic/cssParser.ts\nvar InvalidSelectorError = class extends Error {\n};\nfunction parseCSS(selector, customNames) {\n  let tokens;\n  try {\n    tokens = tokenize(selector);\n    if (!(tokens[tokens.length - 1] instanceof EOFToken))\n      tokens.push(new EOFToken());\n  } catch (e) {\n    const newMessage = e.message + ` while parsing selector \"${selector}\"`;\n    const index = (e.stack || \"\").indexOf(e.message);\n    if (index !== -1)\n      e.stack = e.stack.substring(0, index) + newMessage + e.stack.substring(index + e.message.length);\n    e.message = newMessage;\n    throw e;\n  }\n  const unsupportedToken = tokens.find((token) => {\n    return token instanceof AtKeywordToken || token instanceof BadStringToken || token instanceof BadURLToken || token instanceof ColumnToken || token instanceof CDOToken || token instanceof CDCToken || token instanceof SemicolonToken || // TODO: Consider using these for something, e.g. to escape complex strings.\n    // For example :xpath{ (//div/bar[@attr=\"foo\"])[2]/baz }\n    // Or this way :xpath( {complex-xpath-goes-here(\"hello\")} )\n    token instanceof OpenCurlyToken || token instanceof CloseCurlyToken || // TODO: Consider treating these as strings?\n    token instanceof URLToken || token instanceof PercentageToken;\n  });\n  if (unsupportedToken)\n    throw new InvalidSelectorError(`Unsupported token \"${unsupportedToken.toSource()}\" while parsing selector \"${selector}\"`);\n  let pos = 0;\n  const names = /* @__PURE__ */ new Set();\n  function unexpected() {\n    return new InvalidSelectorError(`Unexpected token \"${tokens[pos].toSource()}\" while parsing selector \"${selector}\"`);\n  }\n  function skipWhitespace() {\n    while (tokens[pos] instanceof WhitespaceToken)\n      pos++;\n  }\n  function isIdent(p = pos) {\n    return tokens[p] instanceof IdentToken;\n  }\n  function isString(p = pos) {\n    return tokens[p] instanceof StringToken;\n  }\n  function isNumber(p = pos) {\n    return tokens[p] instanceof NumberToken;\n  }\n  function isComma(p = pos) {\n    return tokens[p] instanceof CommaToken;\n  }\n  function isOpenParen(p = pos) {\n    return tokens[p] instanceof OpenParenToken;\n  }\n  function isCloseParen(p = pos) {\n    return tokens[p] instanceof CloseParenToken;\n  }\n  function isFunction(p = pos) {\n    return tokens[p] instanceof FunctionToken;\n  }\n  function isStar(p = pos) {\n    return tokens[p] instanceof DelimToken && tokens[p].value === \"*\";\n  }\n  function isEOF(p = pos) {\n    return tokens[p] instanceof EOFToken;\n  }\n  function isClauseCombinator(p = pos) {\n    return tokens[p] instanceof DelimToken && [\">\", \"+\", \"~\"].includes(tokens[p].value);\n  }\n  function isSelectorClauseEnd(p = pos) {\n    return isComma(p) || isCloseParen(p) || isEOF(p) || isClauseCombinator(p) || tokens[p] instanceof WhitespaceToken;\n  }\n  function consumeFunctionArguments() {\n    const result2 = [consumeArgument()];\n    while (true) {\n      skipWhitespace();\n      if (!isComma())\n        break;\n      pos++;\n      result2.push(consumeArgument());\n    }\n    return result2;\n  }\n  function consumeArgument() {\n    skipWhitespace();\n    if (isNumber())\n      return tokens[pos++].value;\n    if (isString())\n      return tokens[pos++].value;\n    return consumeComplexSelector();\n  }\n  function consumeComplexSelector() {\n    const result2 = { simples: [] };\n    skipWhitespace();\n    if (isClauseCombinator()) {\n      result2.simples.push({ selector: { functions: [{ name: \"scope\", args: [] }] }, combinator: \"\" });\n    } else {\n      result2.simples.push({ selector: consumeSimpleSelector(), combinator: \"\" });\n    }\n    while (true) {\n      skipWhitespace();\n      if (isClauseCombinator()) {\n        result2.simples[result2.simples.length - 1].combinator = tokens[pos++].value;\n        skipWhitespace();\n      } else if (isSelectorClauseEnd()) {\n        break;\n      }\n      result2.simples.push({ combinator: \"\", selector: consumeSimpleSelector() });\n    }\n    return result2;\n  }\n  function consumeSimpleSelector() {\n    let rawCSSString = \"\";\n    const functions = [];\n    while (!isSelectorClauseEnd()) {\n      if (isIdent() || isStar()) {\n        rawCSSString += tokens[pos++].toSource();\n      } else if (tokens[pos] instanceof HashToken) {\n        rawCSSString += tokens[pos++].toSource();\n      } else if (tokens[pos] instanceof DelimToken && tokens[pos].value === \".\") {\n        pos++;\n        if (isIdent())\n          rawCSSString += \".\" + tokens[pos++].toSource();\n        else\n          throw unexpected();\n      } else if (tokens[pos] instanceof ColonToken) {\n        pos++;\n        if (isIdent()) {\n          if (!customNames.has(tokens[pos].value.toLowerCase())) {\n            rawCSSString += \":\" + tokens[pos++].toSource();\n          } else {\n            const name = tokens[pos++].value.toLowerCase();\n            functions.push({ name, args: [] });\n            names.add(name);\n          }\n        } else if (isFunction()) {\n          const name = tokens[pos++].value.toLowerCase();\n          if (!customNames.has(name)) {\n            rawCSSString += `:${name}(${consumeBuiltinFunctionArguments()})`;\n          } else {\n            functions.push({ name, args: consumeFunctionArguments() });\n            names.add(name);\n          }\n          skipWhitespace();\n          if (!isCloseParen())\n            throw unexpected();\n          pos++;\n        } else {\n          throw unexpected();\n        }\n      } else if (tokens[pos] instanceof OpenSquareToken) {\n        rawCSSString += \"[\";\n        pos++;\n        while (!(tokens[pos] instanceof CloseSquareToken) && !isEOF())\n          rawCSSString += tokens[pos++].toSource();\n        if (!(tokens[pos] instanceof CloseSquareToken))\n          throw unexpected();\n        rawCSSString += \"]\";\n        pos++;\n      } else {\n        throw unexpected();\n      }\n    }\n    if (!rawCSSString && !functions.length)\n      throw unexpected();\n    return { css: rawCSSString || void 0, functions };\n  }\n  function consumeBuiltinFunctionArguments() {\n    let s = \"\";\n    let balance = 1;\n    while (!isEOF()) {\n      if (isOpenParen() || isFunction())\n        balance++;\n      if (isCloseParen())\n        balance--;\n      if (!balance)\n        break;\n      s += tokens[pos++].toSource();\n    }\n    return s;\n  }\n  const result = consumeFunctionArguments();\n  if (!isEOF())\n    throw unexpected();\n  if (result.some((arg) => typeof arg !== \"object\" || !(\"simples\" in arg)))\n    throw new InvalidSelectorError(`Error while parsing selector \"${selector}\"`);\n  return { selector: result, names: Array.from(names) };\n}\n\n// packages/playwright-core/src/utils/isomorphic/selectorParser.ts\nvar kNestedSelectorNames = /* @__PURE__ */ new Set([\"internal:has\", \"internal:has-not\", \"internal:and\", \"internal:or\", \"internal:chain\", \"left-of\", \"right-of\", \"above\", \"below\", \"near\"]);\nvar kNestedSelectorNamesWithDistance = /* @__PURE__ */ new Set([\"left-of\", \"right-of\", \"above\", \"below\", \"near\"]);\nvar customCSSNames = /* @__PURE__ */ new Set([\"not\", \"is\", \"where\", \"has\", \"scope\", \"light\", \"visible\", \"text\", \"text-matches\", \"text-is\", \"has-text\", \"above\", \"below\", \"right-of\", \"left-of\", \"near\", \"nth-match\"]);\nfunction parseSelector(selector) {\n  const parsedStrings = parseSelectorString(selector);\n  const parts = [];\n  for (const part of parsedStrings.parts) {\n    if (part.name === \"css\" || part.name === \"css:light\") {\n      if (part.name === \"css:light\")\n        part.body = \":light(\" + part.body + \")\";\n      const parsedCSS = parseCSS(part.body, customCSSNames);\n      parts.push({\n        name: \"css\",\n        body: parsedCSS.selector,\n        source: part.body\n      });\n      continue;\n    }\n    if (kNestedSelectorNames.has(part.name)) {\n      let innerSelector;\n      let distance;\n      try {\n        const unescaped = JSON.parse(\"[\" + part.body + \"]\");\n        if (!Array.isArray(unescaped) || unescaped.length < 1 || unescaped.length > 2 || typeof unescaped[0] !== \"string\")\n          throw new InvalidSelectorError(`Malformed selector: ${part.name}=` + part.body);\n        innerSelector = unescaped[0];\n        if (unescaped.length === 2) {\n          if (typeof unescaped[1] !== \"number\" || !kNestedSelectorNamesWithDistance.has(part.name))\n            throw new InvalidSelectorError(`Malformed selector: ${part.name}=` + part.body);\n          distance = unescaped[1];\n        }\n      } catch (e) {\n        throw new InvalidSelectorError(`Malformed selector: ${part.name}=` + part.body);\n      }\n      const nested = { name: part.name, source: part.body, body: { parsed: parseSelector(innerSelector), distance } };\n      const lastFrame = [...nested.body.parsed.parts].reverse().find((part2) => part2.name === \"internal:control\" && part2.body === \"enter-frame\");\n      const lastFrameIndex = lastFrame ? nested.body.parsed.parts.indexOf(lastFrame) : -1;\n      if (lastFrameIndex !== -1 && selectorPartsEqual(nested.body.parsed.parts.slice(0, lastFrameIndex + 1), parts.slice(0, lastFrameIndex + 1)))\n        nested.body.parsed.parts.splice(0, lastFrameIndex + 1);\n      parts.push(nested);\n      continue;\n    }\n    parts.push({ ...part, source: part.body });\n  }\n  if (kNestedSelectorNames.has(parts[0].name))\n    throw new InvalidSelectorError(`\"${parts[0].name}\" selector cannot be first`);\n  return {\n    capture: parsedStrings.capture,\n    parts\n  };\n}\nfunction selectorPartsEqual(list1, list2) {\n  return stringifySelector({ parts: list1 }) === stringifySelector({ parts: list2 });\n}\nfunction stringifySelector(selector, forceEngineName) {\n  if (typeof selector === \"string\")\n    return selector;\n  return selector.parts.map((p, i) => {\n    let includeEngine = true;\n    if (!forceEngineName && i !== selector.capture) {\n      if (p.name === \"css\")\n        includeEngine = false;\n      else if (p.name === \"xpath\" && p.source.startsWith(\"//\") || p.source.startsWith(\"..\"))\n        includeEngine = false;\n    }\n    const prefix = includeEngine ? p.name + \"=\" : \"\";\n    return `${i === selector.capture ? \"*\" : \"\"}${prefix}${p.source}`;\n  }).join(\" >> \");\n}\nfunction visitAllSelectorParts(selector, visitor) {\n  const visit = (selector2, nested) => {\n    for (const part of selector2.parts) {\n      visitor(part, nested);\n      if (kNestedSelectorNames.has(part.name))\n        visit(part.body.parsed, true);\n    }\n  };\n  visit(selector, false);\n}\nfunction parseSelectorString(selector) {\n  let index = 0;\n  let quote;\n  let start = 0;\n  const result = { parts: [] };\n  const append = () => {\n    const part = selector.substring(start, index).trim();\n    const eqIndex = part.indexOf(\"=\");\n    let name;\n    let body;\n    if (eqIndex !== -1 && part.substring(0, eqIndex).trim().match(/^[a-zA-Z_0-9-+:*]+$/)) {\n      name = part.substring(0, eqIndex).trim();\n      body = part.substring(eqIndex + 1);\n    } else if (part.length > 1 && part[0] === '\"' && part[part.length - 1] === '\"') {\n      name = \"text\";\n      body = part;\n    } else if (part.length > 1 && part[0] === \"'\" && part[part.length - 1] === \"'\") {\n      name = \"text\";\n      body = part;\n    } else if (/^\\(*\\/\\//.test(part) || part.startsWith(\"..\")) {\n      name = \"xpath\";\n      body = part;\n    } else {\n      name = \"css\";\n      body = part;\n    }\n    let capture = false;\n    if (name[0] === \"*\") {\n      capture = true;\n      name = name.substring(1);\n    }\n    result.parts.push({ name, body });\n    if (capture) {\n      if (result.capture !== void 0)\n        throw new InvalidSelectorError(`Only one of the selectors can capture using * modifier`);\n      result.capture = result.parts.length - 1;\n    }\n  };\n  if (!selector.includes(\">>\")) {\n    index = selector.length;\n    append();\n    return result;\n  }\n  const shouldIgnoreTextSelectorQuote = () => {\n    const prefix = selector.substring(start, index);\n    const match = prefix.match(/^\\s*text\\s*=(.*)$/);\n    return !!match && !!match[1];\n  };\n  while (index < selector.length) {\n    const c = selector[index];\n    if (c === \"\\\\\" && index + 1 < selector.length) {\n      index += 2;\n    } else if (c === quote) {\n      quote = void 0;\n      index++;\n    } else if (!quote && (c === '\"' || c === \"'\" || c === \"`\") && !shouldIgnoreTextSelectorQuote()) {\n      quote = c;\n      index++;\n    } else if (!quote && c === \">\" && selector[index + 1] === \">\") {\n      append();\n      index += 2;\n      start = index;\n    } else {\n      index++;\n    }\n  }\n  append();\n  return result;\n}\nfunction parseAttributeSelector(selector, allowUnquotedStrings) {\n  let wp = 0;\n  let EOL = selector.length === 0;\n  const next = () => selector[wp] || \"\";\n  const eat1 = () => {\n    const result2 = next();\n    ++wp;\n    EOL = wp >= selector.length;\n    return result2;\n  };\n  const syntaxError = (stage) => {\n    if (EOL)\n      throw new InvalidSelectorError(`Unexpected end of selector while parsing selector \\`${selector}\\``);\n    throw new InvalidSelectorError(`Error while parsing selector \\`${selector}\\` - unexpected symbol \"${next()}\" at position ${wp}` + (stage ? \" during \" + stage : \"\"));\n  };\n  function skipSpaces() {\n    while (!EOL && /\\s/.test(next()))\n      eat1();\n  }\n  function isCSSNameChar(char) {\n    return char >= \"\\x80\" || char >= \"0\" && char <= \"9\" || char >= \"A\" && char <= \"Z\" || char >= \"a\" && char <= \"z\" || char >= \"0\" && char <= \"9\" || char === \"_\" || char === \"-\";\n  }\n  function readIdentifier() {\n    let result2 = \"\";\n    skipSpaces();\n    while (!EOL && isCSSNameChar(next()))\n      result2 += eat1();\n    return result2;\n  }\n  function readQuotedString(quote) {\n    let result2 = eat1();\n    if (result2 !== quote)\n      syntaxError(\"parsing quoted string\");\n    while (!EOL && next() !== quote) {\n      if (next() === \"\\\\\")\n        eat1();\n      result2 += eat1();\n    }\n    if (next() !== quote)\n      syntaxError(\"parsing quoted string\");\n    result2 += eat1();\n    return result2;\n  }\n  function readRegularExpression() {\n    if (eat1() !== \"/\")\n      syntaxError(\"parsing regular expression\");\n    let source = \"\";\n    let inClass = false;\n    while (!EOL) {\n      if (next() === \"\\\\\") {\n        source += eat1();\n        if (EOL)\n          syntaxError(\"parsing regular expression\");\n      } else if (inClass && next() === \"]\") {\n        inClass = false;\n      } else if (!inClass && next() === \"[\") {\n        inClass = true;\n      } else if (!inClass && next() === \"/\") {\n        break;\n      }\n      source += eat1();\n    }\n    if (eat1() !== \"/\")\n      syntaxError(\"parsing regular expression\");\n    let flags = \"\";\n    while (!EOL && next().match(/[dgimsuy]/))\n      flags += eat1();\n    try {\n      return new RegExp(source, flags);\n    } catch (e) {\n      throw new InvalidSelectorError(`Error while parsing selector \\`${selector}\\`: ${e.message}`);\n    }\n  }\n  function readAttributeToken() {\n    let token = \"\";\n    skipSpaces();\n    if (next() === `'` || next() === `\"`)\n      token = readQuotedString(next()).slice(1, -1);\n    else\n      token = readIdentifier();\n    if (!token)\n      syntaxError(\"parsing property path\");\n    return token;\n  }\n  function readOperator() {\n    skipSpaces();\n    let op = \"\";\n    if (!EOL)\n      op += eat1();\n    if (!EOL && op !== \"=\")\n      op += eat1();\n    if (![\"=\", \"*=\", \"^=\", \"$=\", \"|=\", \"~=\"].includes(op))\n      syntaxError(\"parsing operator\");\n    return op;\n  }\n  function readAttribute() {\n    eat1();\n    const jsonPath = [];\n    jsonPath.push(readAttributeToken());\n    skipSpaces();\n    while (next() === \".\") {\n      eat1();\n      jsonPath.push(readAttributeToken());\n      skipSpaces();\n    }\n    if (next() === \"]\") {\n      eat1();\n      return { name: jsonPath.join(\".\"), jsonPath, op: \"<truthy>\", value: null, caseSensitive: false };\n    }\n    const operator = readOperator();\n    let value = void 0;\n    let caseSensitive = true;\n    skipSpaces();\n    if (next() === \"/\") {\n      if (operator !== \"=\")\n        throw new InvalidSelectorError(`Error while parsing selector \\`${selector}\\` - cannot use ${operator} in attribute with regular expression`);\n      value = readRegularExpression();\n    } else if (next() === `'` || next() === `\"`) {\n      value = readQuotedString(next()).slice(1, -1);\n      skipSpaces();\n      if (next() === \"i\" || next() === \"I\") {\n        caseSensitive = false;\n        eat1();\n      } else if (next() === \"s\" || next() === \"S\") {\n        caseSensitive = true;\n        eat1();\n      }\n    } else {\n      value = \"\";\n      while (!EOL && (isCSSNameChar(next()) || next() === \"+\" || next() === \".\"))\n        value += eat1();\n      if (value === \"true\") {\n        value = true;\n      } else if (value === \"false\") {\n        value = false;\n      } else {\n        if (!allowUnquotedStrings) {\n          value = +value;\n          if (Number.isNaN(value))\n            syntaxError(\"parsing attribute value\");\n        }\n      }\n    }\n    skipSpaces();\n    if (next() !== \"]\")\n      syntaxError(\"parsing attribute value\");\n    eat1();\n    if (operator !== \"=\" && typeof value !== \"string\")\n      throw new InvalidSelectorError(`Error while parsing selector \\`${selector}\\` - cannot use ${operator} in attribute with non-string matching value - ${value}`);\n    return { name: jsonPath.join(\".\"), jsonPath, op: operator, value, caseSensitive };\n  }\n  const result = {\n    name: \"\",\n    attributes: []\n  };\n  result.name = readIdentifier();\n  skipSpaces();\n  while (next() === \"[\") {\n    result.attributes.push(readAttribute());\n    skipSpaces();\n  }\n  if (!EOL)\n    syntaxError(void 0);\n  if (!result.name && !result.attributes.length)\n    throw new InvalidSelectorError(`Error while parsing selector \\`${selector}\\` - selector cannot be empty`);\n  return result;\n}\n\n// packages/playwright-core/src/server/injected/reactSelectorEngine.ts\nfunction getFunctionComponentName(component) {\n  return component.displayName || component.name || \"Anonymous\";\n}\nfunction getComponentName(reactElement) {\n  if (reactElement.type) {\n    switch (typeof reactElement.type) {\n      case \"function\":\n        return getFunctionComponentName(reactElement.type);\n      case \"string\":\n        return reactElement.type;\n      case \"object\":\n        return reactElement.type.displayName || (reactElement.type.render ? getFunctionComponentName(reactElement.type.render) : \"\");\n    }\n  }\n  if (reactElement._currentElement) {\n    const elementType = reactElement._currentElement.type;\n    if (typeof elementType === \"string\")\n      return elementType;\n    if (typeof elementType === \"function\")\n      return elementType.displayName || elementType.name || \"Anonymous\";\n  }\n  return \"\";\n}\nfunction getComponentKey(reactElement) {\n  var _a, _b;\n  return (_b = reactElement.key) != null ? _b : (_a = reactElement._currentElement) == null ? void 0 : _a.key;\n}\nfunction getChildren(reactElement) {\n  if (reactElement.child) {\n    const children = [];\n    for (let child = reactElement.child; child; child = child.sibling)\n      children.push(child);\n    return children;\n  }\n  if (!reactElement._currentElement)\n    return [];\n  const isKnownElement = (reactElement2) => {\n    var _a;\n    const elementType = (_a = reactElement2._currentElement) == null ? void 0 : _a.type;\n    return typeof elementType === \"function\" || typeof elementType === \"string\";\n  };\n  if (reactElement._renderedComponent) {\n    const child = reactElement._renderedComponent;\n    return isKnownElement(child) ? [child] : [];\n  }\n  if (reactElement._renderedChildren)\n    return [...Object.values(reactElement._renderedChildren)].filter(isKnownElement);\n  return [];\n}\nfunction getProps(reactElement) {\n  var _a;\n  const props = (\n    // React 16+\n    reactElement.memoizedProps || // React 15\n    ((_a = reactElement._currentElement) == null ? void 0 : _a.props)\n  );\n  if (!props || typeof props === \"string\")\n    return props;\n  const result = { ...props };\n  delete result.children;\n  return result;\n}\nfunction buildComponentsTree(reactElement) {\n  var _a;\n  const treeNode = {\n    key: getComponentKey(reactElement),\n    name: getComponentName(reactElement),\n    children: getChildren(reactElement).map(buildComponentsTree),\n    rootElements: [],\n    props: getProps(reactElement)\n  };\n  const rootElement = (\n    // React 16+\n    // @see https://github.com/baruchvlz/resq/blob/5c15a5e04d3f7174087248f5a158c3d6dcc1ec72/src/utils.js#L29\n    reactElement.stateNode || // React 15\n    reactElement._hostNode || ((_a = reactElement._renderedComponent) == null ? void 0 : _a._hostNode)\n  );\n  if (rootElement instanceof Element) {\n    treeNode.rootElements.push(rootElement);\n  } else {\n    for (const child of treeNode.children)\n      treeNode.rootElements.push(...child.rootElements);\n  }\n  return treeNode;\n}\nfunction filterComponentsTree(treeNode, searchFn, result = []) {\n  if (searchFn(treeNode))\n    result.push(treeNode);\n  for (const child of treeNode.children)\n    filterComponentsTree(child, searchFn, result);\n  return result;\n}\nfunction findReactRoots(root, roots = []) {\n  const document = root.ownerDocument || root;\n  const walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT);\n  do {\n    const node = walker.currentNode;\n    const reactNode = node;\n    const rootKey = Object.keys(reactNode).find((key) => key.startsWith(\"__reactContainer\") && reactNode[key] !== null);\n    if (rootKey) {\n      roots.push(reactNode[rootKey].stateNode.current);\n    } else {\n      const legacyRootKey = \"_reactRootContainer\";\n      if (reactNode.hasOwnProperty(legacyRootKey) && reactNode[legacyRootKey] !== null) {\n        roots.push(reactNode[legacyRootKey]._internalRoot.current);\n      }\n    }\n    if (node instanceof Element && node.hasAttribute(\"data-reactroot\")) {\n      for (const key of Object.keys(node)) {\n        if (key.startsWith(\"__reactInternalInstance\") || key.startsWith(\"__reactFiber\"))\n          roots.push(node[key]);\n      }\n    }\n    const shadowRoot = node instanceof Element ? node.shadowRoot : null;\n    if (shadowRoot)\n      findReactRoots(shadowRoot, roots);\n  } while (walker.nextNode());\n  return roots;\n}\nvar ReactEngine = {\n  queryAll(scope, selector) {\n    const { name, attributes } = parseAttributeSelector(selector, false);\n    const reactRoots = findReactRoots(scope.ownerDocument || scope);\n    const trees = reactRoots.map((reactRoot) => buildComponentsTree(reactRoot));\n    const treeNodes = trees.map((tree) => filterComponentsTree(tree, (treeNode) => {\n      var _a;\n      const props = (_a = treeNode.props) != null ? _a : {};\n      if (treeNode.key !== void 0)\n        props.key = treeNode.key;\n      if (name && treeNode.name !== name)\n        return false;\n      if (treeNode.rootElements.some((domNode) => !isInsideScope(scope, domNode)))\n        return false;\n      for (const attr of attributes) {\n        if (!matchesComponentAttribute(props, attr))\n          return false;\n      }\n      return true;\n    })).flat();\n    const allRootElements = /* @__PURE__ */ new Set();\n    for (const treeNode of treeNodes) {\n      for (const domNode of treeNode.rootElements)\n        allRootElements.add(domNode);\n    }\n    return [...allRootElements];\n  }\n};\n\n// packages/playwright-core/src/server/injected/vueSelectorEngine.ts\nfunction basename(filename, ext) {\n  const normalized = filename.replace(/^[a-zA-Z]:/, \"\").replace(/\\\\/g, \"/\");\n  let result = normalized.substring(normalized.lastIndexOf(\"/\") + 1);\n  if (ext && result.endsWith(ext))\n    result = result.substring(0, result.length - ext.length);\n  return result;\n}\nfunction toUpper(_, c) {\n  return c ? c.toUpperCase() : \"\";\n}\nvar classifyRE = /(?:^|[-_/])(\\w)/g;\nvar classify = (str) => {\n  return str && str.replace(classifyRE, toUpper);\n};\nfunction buildComponentsTreeVue3(instance) {\n  function getComponentTypeName(options) {\n    const name = options.name || options._componentTag || options.__playwright_guessedName;\n    if (name)\n      return name;\n    const file = options.__file;\n    if (file)\n      return classify(basename(file, \".vue\"));\n  }\n  function saveComponentName(instance2, key) {\n    instance2.type.__playwright_guessedName = key;\n    return key;\n  }\n  function getInstanceName(instance2) {\n    var _a, _b, _c, _d;\n    const name = getComponentTypeName(instance2.type || {});\n    if (name)\n      return name;\n    if (instance2.root === instance2)\n      return \"Root\";\n    for (const key in (_b = (_a = instance2.parent) == null ? void 0 : _a.type) == null ? void 0 : _b.components) {\n      if (((_c = instance2.parent) == null ? void 0 : _c.type.components[key]) === instance2.type)\n        return saveComponentName(instance2, key);\n    }\n    for (const key in (_d = instance2.appContext) == null ? void 0 : _d.components) {\n      if (instance2.appContext.components[key] === instance2.type)\n        return saveComponentName(instance2, key);\n    }\n    return \"Anonymous Component\";\n  }\n  function isBeingDestroyed(instance2) {\n    return instance2._isBeingDestroyed || instance2.isUnmounted;\n  }\n  function isFragment(instance2) {\n    return instance2.subTree.type.toString() === \"Symbol(Fragment)\";\n  }\n  function getInternalInstanceChildren(subTree) {\n    const list = [];\n    if (subTree.component)\n      list.push(subTree.component);\n    if (subTree.suspense)\n      list.push(...getInternalInstanceChildren(subTree.suspense.activeBranch));\n    if (Array.isArray(subTree.children)) {\n      subTree.children.forEach((childSubTree) => {\n        if (childSubTree.component)\n          list.push(childSubTree.component);\n        else\n          list.push(...getInternalInstanceChildren(childSubTree));\n      });\n    }\n    return list.filter((child) => {\n      var _a;\n      return !isBeingDestroyed(child) && !((_a = child.type.devtools) == null ? void 0 : _a.hide);\n    });\n  }\n  function getRootElementsFromComponentInstance(instance2) {\n    if (isFragment(instance2))\n      return getFragmentRootElements(instance2.subTree);\n    return [instance2.subTree.el];\n  }\n  function getFragmentRootElements(vnode) {\n    if (!vnode.children)\n      return [];\n    const list = [];\n    for (let i = 0, l = vnode.children.length; i < l; i++) {\n      const childVnode = vnode.children[i];\n      if (childVnode.component)\n        list.push(...getRootElementsFromComponentInstance(childVnode.component));\n      else if (childVnode.el)\n        list.push(childVnode.el);\n    }\n    return list;\n  }\n  function buildComponentsTree2(instance2) {\n    return {\n      name: getInstanceName(instance2),\n      children: getInternalInstanceChildren(instance2.subTree).map(buildComponentsTree2),\n      rootElements: getRootElementsFromComponentInstance(instance2),\n      props: instance2.props\n    };\n  }\n  return buildComponentsTree2(instance);\n}\nfunction buildComponentsTreeVue2(instance) {\n  function getComponentName2(options) {\n    const name = options.displayName || options.name || options._componentTag;\n    if (name)\n      return name;\n    const file = options.__file;\n    if (file)\n      return classify(basename(file, \".vue\"));\n  }\n  function getInstanceName(instance2) {\n    const name = getComponentName2(instance2.$options || instance2.fnOptions || {});\n    if (name)\n      return name;\n    return instance2.$root === instance2 ? \"Root\" : \"Anonymous Component\";\n  }\n  function getInternalInstanceChildren(instance2) {\n    if (instance2.$children)\n      return instance2.$children;\n    if (Array.isArray(instance2.subTree.children))\n      return instance2.subTree.children.filter((vnode) => !!vnode.component).map((vnode) => vnode.component);\n    return [];\n  }\n  function buildComponentsTree2(instance2) {\n    return {\n      name: getInstanceName(instance2),\n      children: getInternalInstanceChildren(instance2).map(buildComponentsTree2),\n      rootElements: [instance2.$el],\n      props: instance2._props\n    };\n  }\n  return buildComponentsTree2(instance);\n}\nfunction filterComponentsTree2(treeNode, searchFn, result = []) {\n  if (searchFn(treeNode))\n    result.push(treeNode);\n  for (const child of treeNode.children)\n    filterComponentsTree2(child, searchFn, result);\n  return result;\n}\nfunction findVueRoots(root, roots = []) {\n  const document = root.ownerDocument || root;\n  const walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT);\n  const vue2Roots = /* @__PURE__ */ new Set();\n  do {\n    const node = walker.currentNode;\n    if (node.__vue__)\n      vue2Roots.add(node.__vue__.$root);\n    if (node.__vue_app__ && node._vnode && node._vnode.component)\n      roots.push({ root: node._vnode.component, version: 3 });\n    const shadowRoot = node instanceof Element ? node.shadowRoot : null;\n    if (shadowRoot)\n      findVueRoots(shadowRoot, roots);\n  } while (walker.nextNode());\n  for (const vue2root of vue2Roots) {\n    roots.push({\n      version: 2,\n      root: vue2root\n    });\n  }\n  return roots;\n}\nvar VueEngine = {\n  queryAll(scope, selector) {\n    const document = scope.ownerDocument || scope;\n    const { name, attributes } = parseAttributeSelector(selector, false);\n    const vueRoots = findVueRoots(document);\n    const trees = vueRoots.map((vueRoot) => vueRoot.version === 3 ? buildComponentsTreeVue3(vueRoot.root) : buildComponentsTreeVue2(vueRoot.root));\n    const treeNodes = trees.map((tree) => filterComponentsTree2(tree, (treeNode) => {\n      if (name && treeNode.name !== name)\n        return false;\n      if (treeNode.rootElements.some((rootElement) => !isInsideScope(scope, rootElement)))\n        return false;\n      for (const attr of attributes) {\n        if (!matchesComponentAttribute(treeNode.props, attr))\n          return false;\n      }\n      return true;\n    })).flat();\n    const allRootElements = /* @__PURE__ */ new Set();\n    for (const treeNode of treeNodes) {\n      for (const rootElement of treeNode.rootElements)\n        allRootElements.add(rootElement);\n    }\n    return [...allRootElements];\n  }\n};\n\n// packages/playwright-core/src/server/injected/roleSelectorEngine.ts\nvar kSupportedAttributes = [\"selected\", \"checked\", \"pressed\", \"expanded\", \"level\", \"disabled\", \"name\", \"include-hidden\"];\nkSupportedAttributes.sort();\nfunction validateSupportedRole(attr, roles, role) {\n  if (!roles.includes(role))\n    throw new Error(`\"${attr}\" attribute is only supported for roles: ${roles.slice().sort().map((role2) => `\"${role2}\"`).join(\", \")}`);\n}\nfunction validateSupportedValues(attr, values) {\n  if (attr.op !== \"<truthy>\" && !values.includes(attr.value))\n    throw new Error(`\"${attr.name}\" must be one of ${values.map((v) => JSON.stringify(v)).join(\", \")}`);\n}\nfunction validateSupportedOp(attr, ops) {\n  if (!ops.includes(attr.op))\n    throw new Error(`\"${attr.name}\" does not support \"${attr.op}\" matcher`);\n}\nfunction validateAttributes(attrs, role) {\n  const options = { role };\n  for (const attr of attrs) {\n    switch (attr.name) {\n      case \"checked\": {\n        validateSupportedRole(attr.name, kAriaCheckedRoles, role);\n        validateSupportedValues(attr, [true, false, \"mixed\"]);\n        validateSupportedOp(attr, [\"<truthy>\", \"=\"]);\n        options.checked = attr.op === \"<truthy>\" ? true : attr.value;\n        break;\n      }\n      case \"pressed\": {\n        validateSupportedRole(attr.name, kAriaPressedRoles, role);\n        validateSupportedValues(attr, [true, false, \"mixed\"]);\n        validateSupportedOp(attr, [\"<truthy>\", \"=\"]);\n        options.pressed = attr.op === \"<truthy>\" ? true : attr.value;\n        break;\n      }\n      case \"selected\": {\n        validateSupportedRole(attr.name, kAriaSelectedRoles, role);\n        validateSupportedValues(attr, [true, false]);\n        validateSupportedOp(attr, [\"<truthy>\", \"=\"]);\n        options.selected = attr.op === \"<truthy>\" ? true : attr.value;\n        break;\n      }\n      case \"expanded\": {\n        validateSupportedRole(attr.name, kAriaExpandedRoles, role);\n        validateSupportedValues(attr, [true, false]);\n        validateSupportedOp(attr, [\"<truthy>\", \"=\"]);\n        options.expanded = attr.op === \"<truthy>\" ? true : attr.value;\n        break;\n      }\n      case \"level\": {\n        validateSupportedRole(attr.name, kAriaLevelRoles, role);\n        if (typeof attr.value === \"string\")\n          attr.value = +attr.value;\n        if (attr.op !== \"=\" || typeof attr.value !== \"number\" || Number.isNaN(attr.value))\n          throw new Error(`\"level\" attribute must be compared to a number`);\n        options.level = attr.value;\n        break;\n      }\n      case \"disabled\": {\n        validateSupportedValues(attr, [true, false]);\n        validateSupportedOp(attr, [\"<truthy>\", \"=\"]);\n        options.disabled = attr.op === \"<truthy>\" ? true : attr.value;\n        break;\n      }\n      case \"name\": {\n        if (attr.op === \"<truthy>\")\n          throw new Error(`\"name\" attribute must have a value`);\n        if (typeof attr.value !== \"string\" && !(attr.value instanceof RegExp))\n          throw new Error(`\"name\" attribute must be a string or a regular expression`);\n        options.name = attr.value;\n        options.nameOp = attr.op;\n        options.exact = attr.caseSensitive;\n        break;\n      }\n      case \"include-hidden\": {\n        validateSupportedValues(attr, [true, false]);\n        validateSupportedOp(attr, [\"<truthy>\", \"=\"]);\n        options.includeHidden = attr.op === \"<truthy>\" ? true : attr.value;\n        break;\n      }\n      default: {\n        throw new Error(`Unknown attribute \"${attr.name}\", must be one of ${kSupportedAttributes.map((a) => `\"${a}\"`).join(\", \")}.`);\n      }\n    }\n  }\n  return options;\n}\nfunction queryRole(scope, options, internal) {\n  const result = [];\n  const match = (element) => {\n    if (getAriaRole(element) !== options.role)\n      return;\n    if (options.selected !== void 0 && getAriaSelected(element) !== options.selected)\n      return;\n    if (options.checked !== void 0 && getAriaChecked(element) !== options.checked)\n      return;\n    if (options.pressed !== void 0 && getAriaPressed(element) !== options.pressed)\n      return;\n    if (options.expanded !== void 0 && getAriaExpanded(element) !== options.expanded)\n      return;\n    if (options.level !== void 0 && getAriaLevel(element) !== options.level)\n      return;\n    if (options.disabled !== void 0 && getAriaDisabled(element) !== options.disabled)\n      return;\n    if (!options.includeHidden) {\n      const isHidden = isElementHiddenForAria(element);\n      if (isHidden)\n        return;\n    }\n    if (options.name !== void 0) {\n      const accessibleName = normalizeWhiteSpace(getElementAccessibleName(element, !!options.includeHidden));\n      if (typeof options.name === \"string\")\n        options.name = normalizeWhiteSpace(options.name);\n      if (internal && !options.exact && options.nameOp === \"=\")\n        options.nameOp = \"*=\";\n      if (!matchesAttributePart(accessibleName, { name: \"\", jsonPath: [], op: options.nameOp || \"=\", value: options.name, caseSensitive: !!options.exact }))\n        return;\n    }\n    result.push(element);\n  };\n  const query = (root) => {\n    const shadows = [];\n    if (root.shadowRoot)\n      shadows.push(root.shadowRoot);\n    for (const element of root.querySelectorAll(\"*\")) {\n      match(element);\n      if (element.shadowRoot)\n        shadows.push(element.shadowRoot);\n    }\n    shadows.forEach(query);\n  };\n  query(scope);\n  return result;\n}\nfunction createRoleEngine(internal) {\n  return {\n    queryAll: (scope, selector) => {\n      const parsed = parseAttributeSelector(selector, true);\n      const role = parsed.name.toLowerCase();\n      if (!role)\n        throw new Error(`Role must not be empty`);\n      const options = validateAttributes(parsed.attributes, role);\n      beginAriaCaches();\n      try {\n        return queryRole(scope, options, internal);\n      } finally {\n        endAriaCaches();\n      }\n    }\n  };\n}\n\n// packages/playwright-core/src/server/injected/layoutSelectorUtils.ts\nfunction boxRightOf(box1, box2, maxDistance) {\n  const distance = box1.left - box2.right;\n  if (distance < 0 || maxDistance !== void 0 && distance > maxDistance)\n    return;\n  return distance + Math.max(box2.bottom - box1.bottom, 0) + Math.max(box1.top - box2.top, 0);\n}\nfunction boxLeftOf(box1, box2, maxDistance) {\n  const distance = box2.left - box1.right;\n  if (distance < 0 || maxDistance !== void 0 && distance > maxDistance)\n    return;\n  return distance + Math.max(box2.bottom - box1.bottom, 0) + Math.max(box1.top - box2.top, 0);\n}\nfunction boxAbove(box1, box2, maxDistance) {\n  const distance = box2.top - box1.bottom;\n  if (distance < 0 || maxDistance !== void 0 && distance > maxDistance)\n    return;\n  return distance + Math.max(box1.left - box2.left, 0) + Math.max(box2.right - box1.right, 0);\n}\nfunction boxBelow(box1, box2, maxDistance) {\n  const distance = box1.top - box2.bottom;\n  if (distance < 0 || maxDistance !== void 0 && distance > maxDistance)\n    return;\n  return distance + Math.max(box1.left - box2.left, 0) + Math.max(box2.right - box1.right, 0);\n}\nfunction boxNear(box1, box2, maxDistance) {\n  const kThreshold = maxDistance === void 0 ? 50 : maxDistance;\n  let score = 0;\n  if (box1.left - box2.right >= 0)\n    score += box1.left - box2.right;\n  if (box2.left - box1.right >= 0)\n    score += box2.left - box1.right;\n  if (box2.top - box1.bottom >= 0)\n    score += box2.top - box1.bottom;\n  if (box1.top - box2.bottom >= 0)\n    score += box1.top - box2.bottom;\n  return score > kThreshold ? void 0 : score;\n}\nvar kLayoutSelectorNames = [\"left-of\", \"right-of\", \"above\", \"below\", \"near\"];\nfunction layoutSelectorScore(name, element, inner, maxDistance) {\n  const box = element.getBoundingClientRect();\n  const scorer = { \"left-of\": boxLeftOf, \"right-of\": boxRightOf, \"above\": boxAbove, \"below\": boxBelow, \"near\": boxNear }[name];\n  let bestScore;\n  for (const e of inner) {\n    if (e === element)\n      continue;\n    const score = scorer(box, e.getBoundingClientRect(), maxDistance);\n    if (score === void 0)\n      continue;\n    if (bestScore === void 0 || score < bestScore)\n      bestScore = score;\n  }\n  return bestScore;\n}\n\n// packages/playwright-core/src/server/injected/selectorEvaluator.ts\nvar SelectorEvaluatorImpl = class {\n  constructor(extraEngines) {\n    this._engines = /* @__PURE__ */ new Map();\n    this._cacheQueryCSS = /* @__PURE__ */ new Map();\n    this._cacheMatches = /* @__PURE__ */ new Map();\n    this._cacheQuery = /* @__PURE__ */ new Map();\n    this._cacheMatchesSimple = /* @__PURE__ */ new Map();\n    this._cacheMatchesParents = /* @__PURE__ */ new Map();\n    this._cacheCallMatches = /* @__PURE__ */ new Map();\n    this._cacheCallQuery = /* @__PURE__ */ new Map();\n    this._cacheQuerySimple = /* @__PURE__ */ new Map();\n    this._cacheText = /* @__PURE__ */ new Map();\n    this._retainCacheCounter = 0;\n    for (const [name, engine] of extraEngines)\n      this._engines.set(name, engine);\n    this._engines.set(\"not\", notEngine);\n    this._engines.set(\"is\", isEngine);\n    this._engines.set(\"where\", isEngine);\n    this._engines.set(\"has\", hasEngine);\n    this._engines.set(\"scope\", scopeEngine);\n    this._engines.set(\"light\", lightEngine);\n    this._engines.set(\"visible\", visibleEngine);\n    this._engines.set(\"text\", textEngine);\n    this._engines.set(\"text-is\", textIsEngine);\n    this._engines.set(\"text-matches\", textMatchesEngine);\n    this._engines.set(\"has-text\", hasTextEngine);\n    this._engines.set(\"right-of\", createLayoutEngine(\"right-of\"));\n    this._engines.set(\"left-of\", createLayoutEngine(\"left-of\"));\n    this._engines.set(\"above\", createLayoutEngine(\"above\"));\n    this._engines.set(\"below\", createLayoutEngine(\"below\"));\n    this._engines.set(\"near\", createLayoutEngine(\"near\"));\n    this._engines.set(\"nth-match\", nthMatchEngine);\n    const allNames = [...this._engines.keys()];\n    allNames.sort();\n    const parserNames = [...customCSSNames];\n    parserNames.sort();\n    if (allNames.join(\"|\") !== parserNames.join(\"|\"))\n      throw new Error(`Please keep customCSSNames in sync with evaluator engines: ${allNames.join(\"|\")} vs ${parserNames.join(\"|\")}`);\n  }\n  begin() {\n    ++this._retainCacheCounter;\n  }\n  end() {\n    --this._retainCacheCounter;\n    if (!this._retainCacheCounter) {\n      this._cacheQueryCSS.clear();\n      this._cacheMatches.clear();\n      this._cacheQuery.clear();\n      this._cacheMatchesSimple.clear();\n      this._cacheMatchesParents.clear();\n      this._cacheCallMatches.clear();\n      this._cacheCallQuery.clear();\n      this._cacheQuerySimple.clear();\n      this._cacheText.clear();\n    }\n  }\n  _cached(cache, main, rest, cb) {\n    if (!cache.has(main))\n      cache.set(main, []);\n    const entries = cache.get(main);\n    const entry = entries.find((e) => rest.every((value, index) => e.rest[index] === value));\n    if (entry)\n      return entry.result;\n    const result = cb();\n    entries.push({ rest, result });\n    return result;\n  }\n  _checkSelector(s) {\n    const wellFormed = typeof s === \"object\" && s && (Array.isArray(s) || \"simples\" in s && s.simples.length);\n    if (!wellFormed)\n      throw new Error(`Malformed selector \"${s}\"`);\n    return s;\n  }\n  matches(element, s, context) {\n    const selector = this._checkSelector(s);\n    this.begin();\n    try {\n      return this._cached(this._cacheMatches, element, [selector, context.scope, context.pierceShadow, context.originalScope], () => {\n        if (Array.isArray(selector))\n          return this._matchesEngine(isEngine, element, selector, context);\n        if (this._hasScopeClause(selector))\n          context = this._expandContextForScopeMatching(context);\n        if (!this._matchesSimple(element, selector.simples[selector.simples.length - 1].selector, context))\n          return false;\n        return this._matchesParents(element, selector, selector.simples.length - 2, context);\n      });\n    } finally {\n      this.end();\n    }\n  }\n  query(context, s) {\n    const selector = this._checkSelector(s);\n    this.begin();\n    try {\n      return this._cached(this._cacheQuery, selector, [context.scope, context.pierceShadow, context.originalScope], () => {\n        if (Array.isArray(selector))\n          return this._queryEngine(isEngine, context, selector);\n        if (this._hasScopeClause(selector))\n          context = this._expandContextForScopeMatching(context);\n        const previousScoreMap = this._scoreMap;\n        this._scoreMap = /* @__PURE__ */ new Map();\n        let elements = this._querySimple(context, selector.simples[selector.simples.length - 1].selector);\n        elements = elements.filter((element) => this._matchesParents(element, selector, selector.simples.length - 2, context));\n        if (this._scoreMap.size) {\n          elements.sort((a, b) => {\n            const aScore = this._scoreMap.get(a);\n            const bScore = this._scoreMap.get(b);\n            if (aScore === bScore)\n              return 0;\n            if (aScore === void 0)\n              return 1;\n            if (bScore === void 0)\n              return -1;\n            return aScore - bScore;\n          });\n        }\n        this._scoreMap = previousScoreMap;\n        return elements;\n      });\n    } finally {\n      this.end();\n    }\n  }\n  _markScore(element, score) {\n    if (this._scoreMap)\n      this._scoreMap.set(element, score);\n  }\n  _hasScopeClause(selector) {\n    return selector.simples.some((simple) => simple.selector.functions.some((f) => f.name === \"scope\"));\n  }\n  _expandContextForScopeMatching(context) {\n    if (context.scope.nodeType !== 1)\n      return context;\n    const scope = parentElementOrShadowHost(context.scope);\n    if (!scope)\n      return context;\n    return { ...context, scope, originalScope: context.originalScope || context.scope };\n  }\n  _matchesSimple(element, simple, context) {\n    return this._cached(this._cacheMatchesSimple, element, [simple, context.scope, context.pierceShadow, context.originalScope], () => {\n      if (element === context.scope)\n        return false;\n      if (simple.css && !this._matchesCSS(element, simple.css))\n        return false;\n      for (const func of simple.functions) {\n        if (!this._matchesEngine(this._getEngine(func.name), element, func.args, context))\n          return false;\n      }\n      return true;\n    });\n  }\n  _querySimple(context, simple) {\n    if (!simple.functions.length)\n      return this._queryCSS(context, simple.css || \"*\");\n    return this._cached(this._cacheQuerySimple, simple, [context.scope, context.pierceShadow, context.originalScope], () => {\n      let css = simple.css;\n      const funcs = simple.functions;\n      if (css === \"*\" && funcs.length)\n        css = void 0;\n      let elements;\n      let firstIndex = -1;\n      if (css !== void 0) {\n        elements = this._queryCSS(context, css);\n      } else {\n        firstIndex = funcs.findIndex((func) => this._getEngine(func.name).query !== void 0);\n        if (firstIndex === -1)\n          firstIndex = 0;\n        elements = this._queryEngine(this._getEngine(funcs[firstIndex].name), context, funcs[firstIndex].args);\n      }\n      for (let i = 0; i < funcs.length; i++) {\n        if (i === firstIndex)\n          continue;\n        const engine = this._getEngine(funcs[i].name);\n        if (engine.matches !== void 0)\n          elements = elements.filter((e) => this._matchesEngine(engine, e, funcs[i].args, context));\n      }\n      for (let i = 0; i < funcs.length; i++) {\n        if (i === firstIndex)\n          continue;\n        const engine = this._getEngine(funcs[i].name);\n        if (engine.matches === void 0)\n          elements = elements.filter((e) => this._matchesEngine(engine, e, funcs[i].args, context));\n      }\n      return elements;\n    });\n  }\n  _matchesParents(element, complex, index, context) {\n    if (index < 0)\n      return true;\n    return this._cached(this._cacheMatchesParents, element, [complex, index, context.scope, context.pierceShadow, context.originalScope], () => {\n      const { selector: simple, combinator } = complex.simples[index];\n      if (combinator === \">\") {\n        const parent = parentElementOrShadowHostInContext(element, context);\n        if (!parent || !this._matchesSimple(parent, simple, context))\n          return false;\n        return this._matchesParents(parent, complex, index - 1, context);\n      }\n      if (combinator === \"+\") {\n        const previousSibling = previousSiblingInContext(element, context);\n        if (!previousSibling || !this._matchesSimple(previousSibling, simple, context))\n          return false;\n        return this._matchesParents(previousSibling, complex, index - 1, context);\n      }\n      if (combinator === \"\") {\n        let parent = parentElementOrShadowHostInContext(element, context);\n        while (parent) {\n          if (this._matchesSimple(parent, simple, context)) {\n            if (this._matchesParents(parent, complex, index - 1, context))\n              return true;\n            if (complex.simples[index - 1].combinator === \"\")\n              break;\n          }\n          parent = parentElementOrShadowHostInContext(parent, context);\n        }\n        return false;\n      }\n      if (combinator === \"~\") {\n        let previousSibling = previousSiblingInContext(element, context);\n        while (previousSibling) {\n          if (this._matchesSimple(previousSibling, simple, context)) {\n            if (this._matchesParents(previousSibling, complex, index - 1, context))\n              return true;\n            if (complex.simples[index - 1].combinator === \"~\")\n              break;\n          }\n          previousSibling = previousSiblingInContext(previousSibling, context);\n        }\n        return false;\n      }\n      if (combinator === \">=\") {\n        let parent = element;\n        while (parent) {\n          if (this._matchesSimple(parent, simple, context)) {\n            if (this._matchesParents(parent, complex, index - 1, context))\n              return true;\n            if (complex.simples[index - 1].combinator === \"\")\n              break;\n          }\n          parent = parentElementOrShadowHostInContext(parent, context);\n        }\n        return false;\n      }\n      throw new Error(`Unsupported combinator \"${combinator}\"`);\n    });\n  }\n  _matchesEngine(engine, element, args, context) {\n    if (engine.matches)\n      return this._callMatches(engine, element, args, context);\n    if (engine.query)\n      return this._callQuery(engine, args, context).includes(element);\n    throw new Error(`Selector engine should implement \"matches\" or \"query\"`);\n  }\n  _queryEngine(engine, context, args) {\n    if (engine.query)\n      return this._callQuery(engine, args, context);\n    if (engine.matches)\n      return this._queryCSS(context, \"*\").filter((element) => this._callMatches(engine, element, args, context));\n    throw new Error(`Selector engine should implement \"matches\" or \"query\"`);\n  }\n  _callMatches(engine, element, args, context) {\n    return this._cached(this._cacheCallMatches, element, [engine, context.scope, context.pierceShadow, context.originalScope, ...args], () => {\n      return engine.matches(element, args, context, this);\n    });\n  }\n  _callQuery(engine, args, context) {\n    return this._cached(this._cacheCallQuery, engine, [context.scope, context.pierceShadow, context.originalScope, ...args], () => {\n      return engine.query(context, args, this);\n    });\n  }\n  _matchesCSS(element, css) {\n    return element.matches(css);\n  }\n  _queryCSS(context, css) {\n    return this._cached(this._cacheQueryCSS, css, [context.scope, context.pierceShadow, context.originalScope], () => {\n      let result = [];\n      function query(root) {\n        result = result.concat([...root.querySelectorAll(css)]);\n        if (!context.pierceShadow)\n          return;\n        if (root.shadowRoot)\n          query(root.shadowRoot);\n        for (const element of root.querySelectorAll(\"*\")) {\n          if (element.shadowRoot)\n            query(element.shadowRoot);\n        }\n      }\n      query(context.scope);\n      return result;\n    });\n  }\n  _getEngine(name) {\n    const engine = this._engines.get(name);\n    if (!engine)\n      throw new Error(`Unknown selector engine \"${name}\"`);\n    return engine;\n  }\n};\nvar isEngine = {\n  matches(element, args, context, evaluator) {\n    if (args.length === 0)\n      throw new Error(`\"is\" engine expects non-empty selector list`);\n    return args.some((selector) => evaluator.matches(element, selector, context));\n  },\n  query(context, args, evaluator) {\n    if (args.length === 0)\n      throw new Error(`\"is\" engine expects non-empty selector list`);\n    let elements = [];\n    for (const arg of args)\n      elements = elements.concat(evaluator.query(context, arg));\n    return args.length === 1 ? elements : sortInDOMOrder(elements);\n  }\n};\nvar hasEngine = {\n  matches(element, args, context, evaluator) {\n    if (args.length === 0)\n      throw new Error(`\"has\" engine expects non-empty selector list`);\n    return evaluator.query({ ...context, scope: element }, args).length > 0;\n  }\n  // TODO: we can implement efficient \"query\" by matching \"args\" and returning\n  // all parents/descendants, just have to be careful with the \":scope\" matching.\n};\nvar scopeEngine = {\n  matches(element, args, context, evaluator) {\n    if (args.length !== 0)\n      throw new Error(`\"scope\" engine expects no arguments`);\n    const actualScope = context.originalScope || context.scope;\n    if (actualScope.nodeType === 9)\n      return element === actualScope.documentElement;\n    return element === actualScope;\n  },\n  query(context, args, evaluator) {\n    if (args.length !== 0)\n      throw new Error(`\"scope\" engine expects no arguments`);\n    const actualScope = context.originalScope || context.scope;\n    if (actualScope.nodeType === 9) {\n      const root = actualScope.documentElement;\n      return root ? [root] : [];\n    }\n    if (actualScope.nodeType === 1)\n      return [actualScope];\n    return [];\n  }\n};\nvar notEngine = {\n  matches(element, args, context, evaluator) {\n    if (args.length === 0)\n      throw new Error(`\"not\" engine expects non-empty selector list`);\n    return !evaluator.matches(element, args, context);\n  }\n};\nvar lightEngine = {\n  query(context, args, evaluator) {\n    return evaluator.query({ ...context, pierceShadow: false }, args);\n  },\n  matches(element, args, context, evaluator) {\n    return evaluator.matches(element, args, { ...context, pierceShadow: false });\n  }\n};\nvar visibleEngine = {\n  matches(element, args, context, evaluator) {\n    if (args.length)\n      throw new Error(`\"visible\" engine expects no arguments`);\n    return isElementVisible(element);\n  }\n};\nvar textEngine = {\n  matches(element, args, context, evaluator) {\n    if (args.length !== 1 || typeof args[0] !== \"string\")\n      throw new Error(`\"text\" engine expects a single string`);\n    const text = normalizeWhiteSpace(args[0]).toLowerCase();\n    const matcher = (elementText2) => elementText2.normalized.toLowerCase().includes(text);\n    return elementMatchesText(evaluator._cacheText, element, matcher) === \"self\";\n  }\n};\nvar textIsEngine = {\n  matches(element, args, context, evaluator) {\n    if (args.length !== 1 || typeof args[0] !== \"string\")\n      throw new Error(`\"text-is\" engine expects a single string`);\n    const text = normalizeWhiteSpace(args[0]);\n    const matcher = (elementText2) => {\n      if (!text && !elementText2.immediate.length)\n        return true;\n      return elementText2.immediate.some((s) => normalizeWhiteSpace(s) === text);\n    };\n    return elementMatchesText(evaluator._cacheText, element, matcher) !== \"none\";\n  }\n};\nvar textMatchesEngine = {\n  matches(element, args, context, evaluator) {\n    if (args.length === 0 || typeof args[0] !== \"string\" || args.length > 2 || args.length === 2 && typeof args[1] !== \"string\")\n      throw new Error(`\"text-matches\" engine expects a regexp body and optional regexp flags`);\n    const re = new RegExp(args[0], args.length === 2 ? args[1] : void 0);\n    const matcher = (elementText2) => re.test(elementText2.full);\n    return elementMatchesText(evaluator._cacheText, element, matcher) === \"self\";\n  }\n};\nvar hasTextEngine = {\n  matches(element, args, context, evaluator) {\n    if (args.length !== 1 || typeof args[0] !== \"string\")\n      throw new Error(`\"has-text\" engine expects a single string`);\n    if (shouldSkipForTextMatching(element))\n      return false;\n    const text = normalizeWhiteSpace(args[0]).toLowerCase();\n    const matcher = (elementText2) => elementText2.normalized.toLowerCase().includes(text);\n    return matcher(elementText(evaluator._cacheText, element));\n  }\n};\nfunction createLayoutEngine(name) {\n  return {\n    matches(element, args, context, evaluator) {\n      const maxDistance = args.length && typeof args[args.length - 1] === \"number\" ? args[args.length - 1] : void 0;\n      const queryArgs = maxDistance === void 0 ? args : args.slice(0, args.length - 1);\n      if (args.length < 1 + (maxDistance === void 0 ? 0 : 1))\n        throw new Error(`\"${name}\" engine expects a selector list and optional maximum distance in pixels`);\n      const inner = evaluator.query(context, queryArgs);\n      const score = layoutSelectorScore(name, element, inner, maxDistance);\n      if (score === void 0)\n        return false;\n      evaluator._markScore(element, score);\n      return true;\n    }\n  };\n}\nvar nthMatchEngine = {\n  query(context, args, evaluator) {\n    let index = args[args.length - 1];\n    if (args.length < 2)\n      throw new Error(`\"nth-match\" engine expects non-empty selector list and an index argument`);\n    if (typeof index !== \"number\" || index < 1)\n      throw new Error(`\"nth-match\" engine expects a one-based index as the last argument`);\n    const elements = isEngine.query(context, args.slice(0, args.length - 1), evaluator);\n    index--;\n    return index < elements.length ? [elements[index]] : [];\n  }\n};\nfunction parentElementOrShadowHostInContext(element, context) {\n  if (element === context.scope)\n    return;\n  if (!context.pierceShadow)\n    return element.parentElement || void 0;\n  return parentElementOrShadowHost(element);\n}\nfunction previousSiblingInContext(element, context) {\n  if (element === context.scope)\n    return;\n  return element.previousElementSibling || void 0;\n}\nfunction sortInDOMOrder(elements) {\n  const elementToEntry = /* @__PURE__ */ new Map();\n  const roots = [];\n  const result = [];\n  function append(element) {\n    let entry = elementToEntry.get(element);\n    if (entry)\n      return entry;\n    const parent = parentElementOrShadowHost(element);\n    if (parent) {\n      const parentEntry = append(parent);\n      parentEntry.children.push(element);\n    } else {\n      roots.push(element);\n    }\n    entry = { children: [], taken: false };\n    elementToEntry.set(element, entry);\n    return entry;\n  }\n  for (const e of elements)\n    append(e).taken = true;\n  function visit(element) {\n    const entry = elementToEntry.get(element);\n    if (entry.taken)\n      result.push(element);\n    if (entry.children.length > 1) {\n      const set = new Set(entry.children);\n      entry.children = [];\n      let child = element.firstElementChild;\n      while (child && entry.children.length < set.size) {\n        if (set.has(child))\n          entry.children.push(child);\n        child = child.nextElementSibling;\n      }\n      child = element.shadowRoot ? element.shadowRoot.firstElementChild : null;\n      while (child && entry.children.length < set.size) {\n        if (set.has(child))\n          entry.children.push(child);\n        child = child.nextElementSibling;\n      }\n    }\n    entry.children.forEach(visit);\n  }\n  roots.forEach(visit);\n  return result;\n}\n\n// packages/playwright-core/src/server/injected/selectorGenerator.ts\nvar cacheAllowText = /* @__PURE__ */ new Map();\nvar cacheDisallowText = /* @__PURE__ */ new Map();\nvar kTextScoreRange = 10;\nvar kExactPenalty = kTextScoreRange / 2;\nvar kTestIdScore = 1;\nvar kOtherTestIdScore = 2;\nvar kIframeByAttributeScore = 10;\nvar kBeginPenalizedScore = 50;\nvar kPlaceholderScore = 100;\nvar kLabelScore = 120;\nvar kRoleWithNameScore = 140;\nvar kAltTextScore = 160;\nvar kTextScore = 180;\nvar kTitleScore = 200;\nvar kTextScoreRegex = 250;\nvar kPlaceholderScoreExact = kPlaceholderScore + kExactPenalty;\nvar kLabelScoreExact = kLabelScore + kExactPenalty;\nvar kRoleWithNameScoreExact = kRoleWithNameScore + kExactPenalty;\nvar kAltTextScoreExact = kAltTextScore + kExactPenalty;\nvar kTextScoreExact = kTextScore + kExactPenalty;\nvar kTitleScoreExact = kTitleScore + kExactPenalty;\nvar kEndPenalizedScore = 300;\nvar kCSSIdScore = 500;\nvar kRoleWithoutNameScore = 510;\nvar kCSSInputTypeNameScore = 520;\nvar kCSSTagNameScore = 530;\nvar kNthScore = 1e4;\nvar kCSSFallbackScore = 1e7;\nvar kScoreThresholdForTextExpect = 1e3;\nfunction generateSelector(injectedScript, targetElement, options) {\n  var _a;\n  injectedScript._evaluator.begin();\n  beginAriaCaches();\n  try {\n    let selectors = [];\n    if (options.forTextExpect) {\n      let targetTokens = cssFallback(injectedScript, targetElement.ownerDocument.documentElement, options);\n      for (let element = targetElement; element; element = parentElementOrShadowHost(element)) {\n        const tokens = generateSelectorFor(injectedScript, element, { ...options, noText: true });\n        if (!tokens)\n          continue;\n        const score = combineScores(tokens);\n        if (score <= kScoreThresholdForTextExpect) {\n          targetTokens = tokens;\n          break;\n        }\n      }\n      selectors = [joinTokens(targetTokens)];\n    } else {\n      targetElement = closestCrossShadow(targetElement, \"button,select,input,[role=button],[role=checkbox],[role=radio],a,[role=link]\", options.root) || targetElement;\n      if (options.multiple) {\n        const withText = generateSelectorFor(injectedScript, targetElement, options);\n        const withoutText = generateSelectorFor(injectedScript, targetElement, { ...options, noText: true });\n        let tokens = [withText, withoutText];\n        cacheAllowText.clear();\n        cacheDisallowText.clear();\n        if (withText && hasCSSIdToken(withText))\n          tokens.push(generateSelectorFor(injectedScript, targetElement, { ...options, noCSSId: true }));\n        if (withoutText && hasCSSIdToken(withoutText))\n          tokens.push(generateSelectorFor(injectedScript, targetElement, { ...options, noText: true, noCSSId: true }));\n        tokens = tokens.filter(Boolean);\n        if (!tokens.length) {\n          const css = cssFallback(injectedScript, targetElement, options);\n          tokens.push(css);\n          if (hasCSSIdToken(css))\n            tokens.push(cssFallback(injectedScript, targetElement, { ...options, noCSSId: true }));\n        }\n        selectors = [...new Set(tokens.map((t) => joinTokens(t)))];\n      } else {\n        const targetTokens = generateSelectorFor(injectedScript, targetElement, options) || cssFallback(injectedScript, targetElement, options);\n        selectors = [joinTokens(targetTokens)];\n      }\n    }\n    const selector = selectors[0];\n    const parsedSelector = injectedScript.parseSelector(selector);\n    return {\n      selector,\n      selectors,\n      elements: injectedScript.querySelectorAll(parsedSelector, (_a = options.root) != null ? _a : targetElement.ownerDocument)\n    };\n  } finally {\n    cacheAllowText.clear();\n    cacheDisallowText.clear();\n    endAriaCaches();\n    injectedScript._evaluator.end();\n  }\n}\nfunction filterRegexTokens(textCandidates) {\n  return textCandidates.filter((c) => c[0].selector[0] !== \"/\");\n}\nfunction generateSelectorFor(injectedScript, targetElement, options) {\n  if (options.root && !isInsideScope(options.root, targetElement))\n    throw new Error(`Target element must belong to the root's subtree`);\n  if (targetElement === options.root)\n    return [{ engine: \"css\", selector: \":scope\", score: 1 }];\n  if (targetElement.ownerDocument.documentElement === targetElement)\n    return [{ engine: \"css\", selector: \"html\", score: 1 }];\n  const calculate = (element, allowText) => {\n    var _a;\n    const allowNthMatch = element === targetElement;\n    let textCandidates = allowText ? buildTextCandidates(injectedScript, element, element === targetElement) : [];\n    if (element !== targetElement) {\n      textCandidates = filterRegexTokens(textCandidates);\n    }\n    const noTextCandidates = buildNoTextCandidates(injectedScript, element, options).filter((token) => !options.omitInternalEngines || !token.engine.startsWith(\"internal:\")).map((token) => [token]);\n    let result = chooseFirstSelector(injectedScript, (_a = options.root) != null ? _a : targetElement.ownerDocument, element, [...textCandidates, ...noTextCandidates], allowNthMatch);\n    textCandidates = filterRegexTokens(textCandidates);\n    const checkWithText = (textCandidatesToUse) => {\n      const allowParentText = allowText && !textCandidatesToUse.length;\n      const candidates = [...textCandidatesToUse, ...noTextCandidates].filter((c) => {\n        if (!result)\n          return true;\n        return combineScores(c) < combineScores(result);\n      });\n      let bestPossibleInParent = candidates[0];\n      if (!bestPossibleInParent)\n        return;\n      for (let parent = parentElementOrShadowHost(element); parent && parent !== options.root; parent = parentElementOrShadowHost(parent)) {\n        const parentTokens = calculateCached(parent, allowParentText);\n        if (!parentTokens)\n          continue;\n        if (result && combineScores([...parentTokens, ...bestPossibleInParent]) >= combineScores(result))\n          continue;\n        bestPossibleInParent = chooseFirstSelector(injectedScript, parent, element, candidates, allowNthMatch);\n        if (!bestPossibleInParent)\n          return;\n        const combined = [...parentTokens, ...bestPossibleInParent];\n        if (!result || combineScores(combined) < combineScores(result))\n          result = combined;\n      }\n    };\n    checkWithText(textCandidates);\n    if (element === targetElement && textCandidates.length)\n      checkWithText([]);\n    return result;\n  };\n  const calculateCached = (element, allowText) => {\n    const cache = allowText ? cacheAllowText : cacheDisallowText;\n    let value = cache.get(element);\n    if (value === void 0) {\n      value = calculate(element, allowText);\n      cache.set(element, value);\n    }\n    return value;\n  };\n  return calculate(targetElement, !options.noText);\n}\nfunction buildNoTextCandidates(injectedScript, element, options) {\n  const candidates = [];\n  {\n    for (const attr of [\"data-testid\", \"data-test-id\", \"data-test\"]) {\n      if (attr !== options.testIdAttributeName && element.getAttribute(attr))\n        candidates.push({ engine: \"css\", selector: `[${attr}=${quoteCSSAttributeValue(element.getAttribute(attr))}]`, score: kOtherTestIdScore });\n    }\n    if (!options.noCSSId) {\n      const idAttr = element.getAttribute(\"id\");\n      if (idAttr && !isGuidLike(idAttr))\n        candidates.push({ engine: \"css\", selector: makeSelectorForId(idAttr), score: kCSSIdScore });\n    }\n    candidates.push({ engine: \"css\", selector: cssEscape(element.nodeName.toLowerCase()), score: kCSSTagNameScore });\n  }\n  if (element.nodeName === \"IFRAME\") {\n    for (const attribute of [\"name\", \"title\"]) {\n      if (element.getAttribute(attribute))\n        candidates.push({ engine: \"css\", selector: `${cssEscape(element.nodeName.toLowerCase())}[${attribute}=${quoteCSSAttributeValue(element.getAttribute(attribute))}]`, score: kIframeByAttributeScore });\n    }\n    if (element.getAttribute(options.testIdAttributeName))\n      candidates.push({ engine: \"css\", selector: `[${options.testIdAttributeName}=${quoteCSSAttributeValue(element.getAttribute(options.testIdAttributeName))}]`, score: kTestIdScore });\n    penalizeScoreForLength([candidates]);\n    return candidates;\n  }\n  if (element.getAttribute(options.testIdAttributeName))\n    candidates.push({ engine: \"internal:testid\", selector: `[${options.testIdAttributeName}=${escapeForAttributeSelector(element.getAttribute(options.testIdAttributeName), true)}]`, score: kTestIdScore });\n  if (element.nodeName === \"INPUT\" || element.nodeName === \"TEXTAREA\") {\n    const input = element;\n    if (input.placeholder) {\n      candidates.push({ engine: \"internal:attr\", selector: `[placeholder=${escapeForAttributeSelector(input.placeholder, true)}]`, score: kPlaceholderScoreExact });\n      for (const alternative of suitableTextAlternatives(input.placeholder))\n        candidates.push({ engine: \"internal:attr\", selector: `[placeholder=${escapeForAttributeSelector(alternative.text, false)}]`, score: kPlaceholderScore - alternative.scoreBouns });\n    }\n  }\n  const labels = getElementLabels(injectedScript._evaluator._cacheText, element);\n  for (const label of labels) {\n    const labelText = label.normalized;\n    candidates.push({ engine: \"internal:label\", selector: escapeForTextSelector(labelText, true), score: kLabelScoreExact });\n    for (const alternative of suitableTextAlternatives(labelText))\n      candidates.push({ engine: \"internal:label\", selector: escapeForTextSelector(alternative.text, false), score: kLabelScore - alternative.scoreBouns });\n  }\n  const ariaRole = getAriaRole(element);\n  if (ariaRole && ![\"none\", \"presentation\"].includes(ariaRole))\n    candidates.push({ engine: \"internal:role\", selector: ariaRole, score: kRoleWithoutNameScore });\n  if (element.getAttribute(\"name\") && [\"BUTTON\", \"FORM\", \"FIELDSET\", \"FRAME\", \"IFRAME\", \"INPUT\", \"KEYGEN\", \"OBJECT\", \"OUTPUT\", \"SELECT\", \"TEXTAREA\", \"MAP\", \"META\", \"PARAM\"].includes(element.nodeName))\n    candidates.push({ engine: \"css\", selector: `${cssEscape(element.nodeName.toLowerCase())}[name=${quoteCSSAttributeValue(element.getAttribute(\"name\"))}]`, score: kCSSInputTypeNameScore });\n  if ([\"INPUT\", \"TEXTAREA\"].includes(element.nodeName) && element.getAttribute(\"type\") !== \"hidden\") {\n    if (element.getAttribute(\"type\"))\n      candidates.push({ engine: \"css\", selector: `${cssEscape(element.nodeName.toLowerCase())}[type=${quoteCSSAttributeValue(element.getAttribute(\"type\"))}]`, score: kCSSInputTypeNameScore });\n  }\n  if ([\"INPUT\", \"TEXTAREA\", \"SELECT\"].includes(element.nodeName) && element.getAttribute(\"type\") !== \"hidden\")\n    candidates.push({ engine: \"css\", selector: cssEscape(element.nodeName.toLowerCase()), score: kCSSInputTypeNameScore + 1 });\n  penalizeScoreForLength([candidates]);\n  return candidates;\n}\nfunction buildTextCandidates(injectedScript, element, isTargetNode) {\n  if (element.nodeName === \"SELECT\")\n    return [];\n  const candidates = [];\n  const title = element.getAttribute(\"title\");\n  if (title) {\n    candidates.push([{ engine: \"internal:attr\", selector: `[title=${escapeForAttributeSelector(title, true)}]`, score: kTitleScoreExact }]);\n    for (const alternative of suitableTextAlternatives(title))\n      candidates.push([{ engine: \"internal:attr\", selector: `[title=${escapeForAttributeSelector(alternative.text, false)}]`, score: kTitleScore - alternative.scoreBouns }]);\n  }\n  const alt = element.getAttribute(\"alt\");\n  if (alt && [\"APPLET\", \"AREA\", \"IMG\", \"INPUT\"].includes(element.nodeName)) {\n    candidates.push([{ engine: \"internal:attr\", selector: `[alt=${escapeForAttributeSelector(alt, true)}]`, score: kAltTextScoreExact }]);\n    for (const alternative of suitableTextAlternatives(alt))\n      candidates.push([{ engine: \"internal:attr\", selector: `[alt=${escapeForAttributeSelector(alternative.text, false)}]`, score: kAltTextScore - alternative.scoreBouns }]);\n  }\n  const text = elementText(injectedScript._evaluator._cacheText, element).normalized;\n  if (text) {\n    const alternatives = suitableTextAlternatives(text);\n    if (isTargetNode) {\n      if (text.length <= 80)\n        candidates.push([{ engine: \"internal:text\", selector: escapeForTextSelector(text, true), score: kTextScoreExact }]);\n      for (const alternative of alternatives)\n        candidates.push([{ engine: \"internal:text\", selector: escapeForTextSelector(alternative.text, false), score: kTextScore - alternative.scoreBouns }]);\n    }\n    const cssToken = { engine: \"css\", selector: cssEscape(element.nodeName.toLowerCase()), score: kCSSTagNameScore };\n    for (const alternative of alternatives)\n      candidates.push([cssToken, { engine: \"internal:has-text\", selector: escapeForTextSelector(alternative.text, false), score: kTextScore - alternative.scoreBouns }]);\n    if (text.length <= 80)\n      candidates.push([cssToken, { engine: \"internal:has-text\", selector: \"/^\" + escapeRegExp(text) + \"$/\", score: kTextScoreRegex }]);\n  }\n  const ariaRole = getAriaRole(element);\n  if (ariaRole && ![\"none\", \"presentation\"].includes(ariaRole)) {\n    const ariaName = getElementAccessibleName(element, false);\n    if (ariaName) {\n      candidates.push([{ engine: \"internal:role\", selector: `${ariaRole}[name=${escapeForAttributeSelector(ariaName, true)}]`, score: kRoleWithNameScoreExact }]);\n      for (const alternative of suitableTextAlternatives(ariaName))\n        candidates.push([{ engine: \"internal:role\", selector: `${ariaRole}[name=${escapeForAttributeSelector(alternative.text, false)}]`, score: kRoleWithNameScore - alternative.scoreBouns }]);\n    }\n  }\n  penalizeScoreForLength(candidates);\n  return candidates;\n}\nfunction makeSelectorForId(id) {\n  return /^[a-zA-Z][a-zA-Z0-9\\-\\_]+$/.test(id) ? \"#\" + id : `[id=\"${cssEscape(id)}\"]`;\n}\nfunction hasCSSIdToken(tokens) {\n  return tokens.some((token) => token.engine === \"css\" && (token.selector.startsWith(\"#\") || token.selector.startsWith('[id=\"')));\n}\nfunction cssFallback(injectedScript, targetElement, options) {\n  var _a;\n  const root = (_a = options.root) != null ? _a : targetElement.ownerDocument;\n  const tokens = [];\n  function uniqueCSSSelector(prefix) {\n    const path = tokens.slice();\n    if (prefix)\n      path.unshift(prefix);\n    const selector = path.join(\" > \");\n    const parsedSelector = injectedScript.parseSelector(selector);\n    const node = injectedScript.querySelector(parsedSelector, root, false);\n    return node === targetElement ? selector : void 0;\n  }\n  function makeStrict(selector) {\n    const token = { engine: \"css\", selector, score: kCSSFallbackScore };\n    const parsedSelector = injectedScript.parseSelector(selector);\n    const elements = injectedScript.querySelectorAll(parsedSelector, root);\n    if (elements.length === 1)\n      return [token];\n    const nth = { engine: \"nth\", selector: String(elements.indexOf(targetElement)), score: kNthScore };\n    return [token, nth];\n  }\n  for (let element = targetElement; element && element !== root; element = parentElementOrShadowHost(element)) {\n    const nodeName = element.nodeName.toLowerCase();\n    let bestTokenForLevel = \"\";\n    if (element.id && !options.noCSSId) {\n      const token = makeSelectorForId(element.id);\n      const selector = uniqueCSSSelector(token);\n      if (selector)\n        return makeStrict(selector);\n      bestTokenForLevel = token;\n    }\n    const parent = element.parentNode;\n    const classes = [...element.classList];\n    for (let i = 0; i < classes.length; ++i) {\n      const token = \".\" + cssEscape(classes.slice(0, i + 1).join(\".\"));\n      const selector = uniqueCSSSelector(token);\n      if (selector)\n        return makeStrict(selector);\n      if (!bestTokenForLevel && parent) {\n        const sameClassSiblings = parent.querySelectorAll(token);\n        if (sameClassSiblings.length === 1)\n          bestTokenForLevel = token;\n      }\n    }\n    if (parent) {\n      const siblings = [...parent.children];\n      const sameTagSiblings = siblings.filter((sibling) => sibling.nodeName.toLowerCase() === nodeName);\n      const token = sameTagSiblings.indexOf(element) === 0 ? cssEscape(nodeName) : `${cssEscape(nodeName)}:nth-child(${1 + siblings.indexOf(element)})`;\n      const selector = uniqueCSSSelector(token);\n      if (selector)\n        return makeStrict(selector);\n      if (!bestTokenForLevel)\n        bestTokenForLevel = token;\n    } else if (!bestTokenForLevel) {\n      bestTokenForLevel = cssEscape(nodeName);\n    }\n    tokens.unshift(bestTokenForLevel);\n  }\n  return makeStrict(uniqueCSSSelector());\n}\nfunction penalizeScoreForLength(groups) {\n  for (const group of groups) {\n    for (const token of group) {\n      if (token.score > kBeginPenalizedScore && token.score < kEndPenalizedScore)\n        token.score += Math.min(kTextScoreRange, token.selector.length / 10 | 0);\n    }\n  }\n}\nfunction joinTokens(tokens) {\n  const parts = [];\n  let lastEngine = \"\";\n  for (const { engine, selector } of tokens) {\n    if (parts.length && (lastEngine !== \"css\" || engine !== \"css\" || selector.startsWith(\":nth-match(\")))\n      parts.push(\">>\");\n    lastEngine = engine;\n    if (engine === \"css\")\n      parts.push(selector);\n    else\n      parts.push(`${engine}=${selector}`);\n  }\n  return parts.join(\" \");\n}\nfunction combineScores(tokens) {\n  let score = 0;\n  for (let i = 0; i < tokens.length; i++)\n    score += tokens[i].score * (tokens.length - i);\n  return score;\n}\nfunction chooseFirstSelector(injectedScript, scope, targetElement, selectors, allowNthMatch) {\n  const joined = selectors.map((tokens) => ({ tokens, score: combineScores(tokens) }));\n  joined.sort((a, b) => a.score - b.score);\n  let bestWithIndex = null;\n  for (const { tokens } of joined) {\n    const parsedSelector = injectedScript.parseSelector(joinTokens(tokens));\n    const result = injectedScript.querySelectorAll(parsedSelector, scope);\n    if (result[0] === targetElement && result.length === 1) {\n      return tokens;\n    }\n    const index = result.indexOf(targetElement);\n    if (!allowNthMatch || bestWithIndex || index === -1 || result.length > 5)\n      continue;\n    const nth = { engine: \"nth\", selector: String(index), score: kNthScore };\n    bestWithIndex = [...tokens, nth];\n  }\n  return bestWithIndex;\n}\nfunction isGuidLike(id) {\n  let lastCharacterType;\n  let transitionCount = 0;\n  for (let i = 0; i < id.length; ++i) {\n    const c = id[i];\n    let characterType;\n    if (c === \"-\" || c === \"_\")\n      continue;\n    if (c >= \"a\" && c <= \"z\")\n      characterType = \"lower\";\n    else if (c >= \"A\" && c <= \"Z\")\n      characterType = \"upper\";\n    else if (c >= \"0\" && c <= \"9\")\n      characterType = \"digit\";\n    else\n      characterType = \"other\";\n    if (characterType === \"lower\" && lastCharacterType === \"upper\") {\n      lastCharacterType = characterType;\n      continue;\n    }\n    if (lastCharacterType && lastCharacterType !== characterType)\n      ++transitionCount;\n    lastCharacterType = characterType;\n  }\n  return transitionCount >= id.length / 4;\n}\nfunction trimWordBoundary(text, maxLength) {\n  if (text.length <= maxLength)\n    return text;\n  text = text.substring(0, maxLength);\n  const match = text.match(/^(.*)\\b(.+?)$/);\n  if (!match)\n    return \"\";\n  return match[1].trimEnd();\n}\nfunction suitableTextAlternatives(text) {\n  let result = [];\n  {\n    const match = text.match(/^([\\d.,]+)[^.,\\w]/);\n    const leadingNumberLength = match ? match[1].length : 0;\n    if (leadingNumberLength) {\n      const alt = text.substring(leadingNumberLength).trimStart();\n      result.push({ text: alt, scoreBouns: alt.length <= 30 ? 2 : 1 });\n    }\n  }\n  {\n    const match = text.match(/[^.,\\w]([\\d.,]+)$/);\n    const trailingNumberLength = match ? match[1].length : 0;\n    if (trailingNumberLength) {\n      const alt = text.substring(0, text.length - trailingNumberLength).trimEnd();\n      result.push({ text: alt, scoreBouns: alt.length <= 30 ? 2 : 1 });\n    }\n  }\n  if (text.length <= 30) {\n    result.push({ text, scoreBouns: 0 });\n  } else {\n    result.push({ text: trimWordBoundary(text, 80), scoreBouns: 0 });\n    result.push({ text: trimWordBoundary(text, 30), scoreBouns: 1 });\n  }\n  result = result.filter((r) => r.text);\n  if (!result.length)\n    result.push({ text: text.substring(0, 80), scoreBouns: 0 });\n  return result;\n}\n\n// packages/playwright-core/src/utils/isomorphic/locatorGenerators.ts\nfunction asLocator(lang, selector, isFrameLocator = false) {\n  return asLocators(lang, selector, isFrameLocator)[0];\n}\nfunction asLocators(lang, selector, isFrameLocator = false, maxOutputSize = 20, preferredQuote) {\n  try {\n    return innerAsLocators(new generators[lang](preferredQuote), parseSelector(selector), isFrameLocator, maxOutputSize);\n  } catch (e) {\n    return [selector];\n  }\n}\nfunction innerAsLocators(factory, parsed, isFrameLocator = false, maxOutputSize = 20) {\n  const parts = [...parsed.parts];\n  for (let index = 0; index < parts.length - 1; index++) {\n    if (parts[index].name === \"nth\" && parts[index + 1].name === \"internal:control\" && parts[index + 1].body === \"enter-frame\") {\n      const [nth] = parts.splice(index, 1);\n      parts.splice(index + 1, 0, nth);\n    }\n  }\n  const tokens = [];\n  let nextBase = isFrameLocator ? \"frame-locator\" : \"page\";\n  for (let index = 0; index < parts.length; index++) {\n    const part = parts[index];\n    const base = nextBase;\n    nextBase = \"locator\";\n    if (part.name === \"nth\") {\n      if (part.body === \"0\")\n        tokens.push([factory.generateLocator(base, \"first\", \"\"), factory.generateLocator(base, \"nth\", \"0\")]);\n      else if (part.body === \"-1\")\n        tokens.push([factory.generateLocator(base, \"last\", \"\"), factory.generateLocator(base, \"nth\", \"-1\")]);\n      else\n        tokens.push([factory.generateLocator(base, \"nth\", part.body)]);\n      continue;\n    }\n    if (part.name === \"internal:text\") {\n      const { exact, text } = detectExact(part.body);\n      tokens.push([factory.generateLocator(base, \"text\", text, { exact })]);\n      continue;\n    }\n    if (part.name === \"internal:has-text\") {\n      const { exact, text } = detectExact(part.body);\n      if (!exact) {\n        tokens.push([factory.generateLocator(base, \"has-text\", text, { exact })]);\n        continue;\n      }\n    }\n    if (part.name === \"internal:has-not-text\") {\n      const { exact, text } = detectExact(part.body);\n      if (!exact) {\n        tokens.push([factory.generateLocator(base, \"has-not-text\", text, { exact })]);\n        continue;\n      }\n    }\n    if (part.name === \"internal:has\") {\n      const inners = innerAsLocators(factory, part.body.parsed, false, maxOutputSize);\n      tokens.push(inners.map((inner) => factory.generateLocator(base, \"has\", inner)));\n      continue;\n    }\n    if (part.name === \"internal:has-not\") {\n      const inners = innerAsLocators(factory, part.body.parsed, false, maxOutputSize);\n      tokens.push(inners.map((inner) => factory.generateLocator(base, \"hasNot\", inner)));\n      continue;\n    }\n    if (part.name === \"internal:and\") {\n      const inners = innerAsLocators(factory, part.body.parsed, false, maxOutputSize);\n      tokens.push(inners.map((inner) => factory.generateLocator(base, \"and\", inner)));\n      continue;\n    }\n    if (part.name === \"internal:or\") {\n      const inners = innerAsLocators(factory, part.body.parsed, false, maxOutputSize);\n      tokens.push(inners.map((inner) => factory.generateLocator(base, \"or\", inner)));\n      continue;\n    }\n    if (part.name === \"internal:chain\") {\n      const inners = innerAsLocators(factory, part.body.parsed, false, maxOutputSize);\n      tokens.push(inners.map((inner) => factory.generateLocator(base, \"chain\", inner)));\n      continue;\n    }\n    if (part.name === \"internal:label\") {\n      const { exact, text } = detectExact(part.body);\n      tokens.push([factory.generateLocator(base, \"label\", text, { exact })]);\n      continue;\n    }\n    if (part.name === \"internal:role\") {\n      const attrSelector = parseAttributeSelector(part.body, true);\n      const options = { attrs: [] };\n      for (const attr of attrSelector.attributes) {\n        if (attr.name === \"name\") {\n          options.exact = attr.caseSensitive;\n          options.name = attr.value;\n        } else {\n          if (attr.name === \"level\" && typeof attr.value === \"string\")\n            attr.value = +attr.value;\n          options.attrs.push({ name: attr.name === \"include-hidden\" ? \"includeHidden\" : attr.name, value: attr.value });\n        }\n      }\n      tokens.push([factory.generateLocator(base, \"role\", attrSelector.name, options)]);\n      continue;\n    }\n    if (part.name === \"internal:testid\") {\n      const attrSelector = parseAttributeSelector(part.body, true);\n      const { value } = attrSelector.attributes[0];\n      tokens.push([factory.generateLocator(base, \"test-id\", value)]);\n      continue;\n    }\n    if (part.name === \"internal:attr\") {\n      const attrSelector = parseAttributeSelector(part.body, true);\n      const { name, value, caseSensitive } = attrSelector.attributes[0];\n      const text = value;\n      const exact = !!caseSensitive;\n      if (name === \"placeholder\") {\n        tokens.push([factory.generateLocator(base, \"placeholder\", text, { exact })]);\n        continue;\n      }\n      if (name === \"alt\") {\n        tokens.push([factory.generateLocator(base, \"alt\", text, { exact })]);\n        continue;\n      }\n      if (name === \"title\") {\n        tokens.push([factory.generateLocator(base, \"title\", text, { exact })]);\n        continue;\n      }\n    }\n    let locatorType = \"default\";\n    const nextPart = parts[index + 1];\n    if (nextPart && nextPart.name === \"internal:control\" && nextPart.body === \"enter-frame\") {\n      locatorType = \"frame\";\n      nextBase = \"frame-locator\";\n      index++;\n    }\n    const selectorPart = stringifySelector({ parts: [part] });\n    const locatorPart = factory.generateLocator(base, locatorType, selectorPart);\n    if (locatorType === \"default\" && nextPart && [\"internal:has-text\", \"internal:has-not-text\"].includes(nextPart.name)) {\n      const { exact, text } = detectExact(nextPart.body);\n      if (!exact) {\n        const nextLocatorPart = factory.generateLocator(\"locator\", nextPart.name === \"internal:has-text\" ? \"has-text\" : \"has-not-text\", text, { exact });\n        const options = {};\n        if (nextPart.name === \"internal:has-text\")\n          options.hasText = text;\n        else\n          options.hasNotText = text;\n        const combinedPart = factory.generateLocator(base, \"default\", selectorPart, options);\n        tokens.push([factory.chainLocators([locatorPart, nextLocatorPart]), combinedPart]);\n        index++;\n        continue;\n      }\n    }\n    let locatorPartWithEngine;\n    if ([\"xpath\", \"css\"].includes(part.name)) {\n      const selectorPart2 = stringifySelector(\n        { parts: [part] },\n        /* forceEngineName */\n        true\n      );\n      locatorPartWithEngine = factory.generateLocator(base, locatorType, selectorPart2);\n    }\n    tokens.push([locatorPart, locatorPartWithEngine].filter(Boolean));\n  }\n  return combineTokens(factory, tokens, maxOutputSize);\n}\nfunction combineTokens(factory, tokens, maxOutputSize) {\n  const currentTokens = tokens.map(() => \"\");\n  const result = [];\n  const visit = (index) => {\n    if (index === tokens.length) {\n      result.push(factory.chainLocators(currentTokens));\n      return currentTokens.length < maxOutputSize;\n    }\n    for (const taken of tokens[index]) {\n      currentTokens[index] = taken;\n      if (!visit(index + 1))\n        return false;\n    }\n    return true;\n  };\n  visit(0);\n  return result;\n}\nfunction detectExact(text) {\n  let exact = false;\n  const match = text.match(/^\\/(.*)\\/([igm]*)$/);\n  if (match)\n    return { text: new RegExp(match[1], match[2]) };\n  if (text.endsWith('\"')) {\n    text = JSON.parse(text);\n    exact = true;\n  } else if (text.endsWith('\"s')) {\n    text = JSON.parse(text.substring(0, text.length - 1));\n    exact = true;\n  } else if (text.endsWith('\"i')) {\n    text = JSON.parse(text.substring(0, text.length - 1));\n    exact = false;\n  }\n  return { exact, text };\n}\nvar JavaScriptLocatorFactory = class {\n  constructor(preferredQuote) {\n    this.preferredQuote = preferredQuote;\n  }\n  generateLocator(base, kind, body, options = {}) {\n    switch (kind) {\n      case \"default\":\n        if (options.hasText !== void 0)\n          return `locator(${this.quote(body)}, { hasText: ${this.toHasText(options.hasText)} })`;\n        if (options.hasNotText !== void 0)\n          return `locator(${this.quote(body)}, { hasNotText: ${this.toHasText(options.hasNotText)} })`;\n        return `locator(${this.quote(body)})`;\n      case \"frame\":\n        return `frameLocator(${this.quote(body)})`;\n      case \"nth\":\n        return `nth(${body})`;\n      case \"first\":\n        return `first()`;\n      case \"last\":\n        return `last()`;\n      case \"role\":\n        const attrs = [];\n        if (isRegExp(options.name)) {\n          attrs.push(`name: ${this.regexToSourceString(options.name)}`);\n        } else if (typeof options.name === \"string\") {\n          attrs.push(`name: ${this.quote(options.name)}`);\n          if (options.exact)\n            attrs.push(`exact: true`);\n        }\n        for (const { name, value } of options.attrs)\n          attrs.push(`${name}: ${typeof value === \"string\" ? this.quote(value) : value}`);\n        const attrString = attrs.length ? `, { ${attrs.join(\", \")} }` : \"\";\n        return `getByRole(${this.quote(body)}${attrString})`;\n      case \"has-text\":\n        return `filter({ hasText: ${this.toHasText(body)} })`;\n      case \"has-not-text\":\n        return `filter({ hasNotText: ${this.toHasText(body)} })`;\n      case \"has\":\n        return `filter({ has: ${body} })`;\n      case \"hasNot\":\n        return `filter({ hasNot: ${body} })`;\n      case \"and\":\n        return `and(${body})`;\n      case \"or\":\n        return `or(${body})`;\n      case \"chain\":\n        return `locator(${body})`;\n      case \"test-id\":\n        return `getByTestId(${this.toTestIdValue(body)})`;\n      case \"text\":\n        return this.toCallWithExact(\"getByText\", body, !!options.exact);\n      case \"alt\":\n        return this.toCallWithExact(\"getByAltText\", body, !!options.exact);\n      case \"placeholder\":\n        return this.toCallWithExact(\"getByPlaceholder\", body, !!options.exact);\n      case \"label\":\n        return this.toCallWithExact(\"getByLabel\", body, !!options.exact);\n      case \"title\":\n        return this.toCallWithExact(\"getByTitle\", body, !!options.exact);\n      default:\n        throw new Error(\"Unknown selector kind \" + kind);\n    }\n  }\n  chainLocators(locators) {\n    return locators.join(\".\");\n  }\n  regexToSourceString(re) {\n    return normalizeEscapedRegexQuotes(String(re));\n  }\n  toCallWithExact(method, body, exact) {\n    if (isRegExp(body))\n      return `${method}(${this.regexToSourceString(body)})`;\n    return exact ? `${method}(${this.quote(body)}, { exact: true })` : `${method}(${this.quote(body)})`;\n  }\n  toHasText(body) {\n    if (isRegExp(body))\n      return this.regexToSourceString(body);\n    return this.quote(body);\n  }\n  toTestIdValue(value) {\n    if (isRegExp(value))\n      return this.regexToSourceString(value);\n    return this.quote(value);\n  }\n  quote(text) {\n    var _a;\n    return escapeWithQuotes(text, (_a = this.preferredQuote) != null ? _a : \"'\");\n  }\n};\nvar PythonLocatorFactory = class {\n  generateLocator(base, kind, body, options = {}) {\n    switch (kind) {\n      case \"default\":\n        if (options.hasText !== void 0)\n          return `locator(${this.quote(body)}, has_text=${this.toHasText(options.hasText)})`;\n        if (options.hasNotText !== void 0)\n          return `locator(${this.quote(body)}, has_not_text=${this.toHasText(options.hasNotText)})`;\n        return `locator(${this.quote(body)})`;\n      case \"frame\":\n        return `frame_locator(${this.quote(body)})`;\n      case \"nth\":\n        return `nth(${body})`;\n      case \"first\":\n        return `first`;\n      case \"last\":\n        return `last`;\n      case \"role\":\n        const attrs = [];\n        if (isRegExp(options.name)) {\n          attrs.push(`name=${this.regexToString(options.name)}`);\n        } else if (typeof options.name === \"string\") {\n          attrs.push(`name=${this.quote(options.name)}`);\n          if (options.exact)\n            attrs.push(`exact=True`);\n        }\n        for (const { name, value } of options.attrs) {\n          let valueString = typeof value === \"string\" ? this.quote(value) : value;\n          if (typeof value === \"boolean\")\n            valueString = value ? \"True\" : \"False\";\n          attrs.push(`${toSnakeCase(name)}=${valueString}`);\n        }\n        const attrString = attrs.length ? `, ${attrs.join(\", \")}` : \"\";\n        return `get_by_role(${this.quote(body)}${attrString})`;\n      case \"has-text\":\n        return `filter(has_text=${this.toHasText(body)})`;\n      case \"has-not-text\":\n        return `filter(has_not_text=${this.toHasText(body)})`;\n      case \"has\":\n        return `filter(has=${body})`;\n      case \"hasNot\":\n        return `filter(has_not=${body})`;\n      case \"and\":\n        return `and_(${body})`;\n      case \"or\":\n        return `or_(${body})`;\n      case \"chain\":\n        return `locator(${body})`;\n      case \"test-id\":\n        return `get_by_test_id(${this.toTestIdValue(body)})`;\n      case \"text\":\n        return this.toCallWithExact(\"get_by_text\", body, !!options.exact);\n      case \"alt\":\n        return this.toCallWithExact(\"get_by_alt_text\", body, !!options.exact);\n      case \"placeholder\":\n        return this.toCallWithExact(\"get_by_placeholder\", body, !!options.exact);\n      case \"label\":\n        return this.toCallWithExact(\"get_by_label\", body, !!options.exact);\n      case \"title\":\n        return this.toCallWithExact(\"get_by_title\", body, !!options.exact);\n      default:\n        throw new Error(\"Unknown selector kind \" + kind);\n    }\n  }\n  chainLocators(locators) {\n    return locators.join(\".\");\n  }\n  regexToString(body) {\n    const suffix = body.flags.includes(\"i\") ? \", re.IGNORECASE\" : \"\";\n    return `re.compile(r\"${normalizeEscapedRegexQuotes(body.source).replace(/\\\\\\//, \"/\").replace(/\"/g, '\\\\\"')}\"${suffix})`;\n  }\n  toCallWithExact(method, body, exact) {\n    if (isRegExp(body))\n      return `${method}(${this.regexToString(body)})`;\n    if (exact)\n      return `${method}(${this.quote(body)}, exact=True)`;\n    return `${method}(${this.quote(body)})`;\n  }\n  toHasText(body) {\n    if (isRegExp(body))\n      return this.regexToString(body);\n    return `${this.quote(body)}`;\n  }\n  toTestIdValue(value) {\n    if (isRegExp(value))\n      return this.regexToString(value);\n    return this.quote(value);\n  }\n  quote(text) {\n    return escapeWithQuotes(text, '\"');\n  }\n};\nvar JavaLocatorFactory = class {\n  generateLocator(base, kind, body, options = {}) {\n    let clazz;\n    switch (base) {\n      case \"page\":\n        clazz = \"Page\";\n        break;\n      case \"frame-locator\":\n        clazz = \"FrameLocator\";\n        break;\n      case \"locator\":\n        clazz = \"Locator\";\n        break;\n    }\n    switch (kind) {\n      case \"default\":\n        if (options.hasText !== void 0)\n          return `locator(${this.quote(body)}, new ${clazz}.LocatorOptions().setHasText(${this.toHasText(options.hasText)}))`;\n        if (options.hasNotText !== void 0)\n          return `locator(${this.quote(body)}, new ${clazz}.LocatorOptions().setHasNotText(${this.toHasText(options.hasNotText)}))`;\n        return `locator(${this.quote(body)})`;\n      case \"frame\":\n        return `frameLocator(${this.quote(body)})`;\n      case \"nth\":\n        return `nth(${body})`;\n      case \"first\":\n        return `first()`;\n      case \"last\":\n        return `last()`;\n      case \"role\":\n        const attrs = [];\n        if (isRegExp(options.name)) {\n          attrs.push(`.setName(${this.regexToString(options.name)})`);\n        } else if (typeof options.name === \"string\") {\n          attrs.push(`.setName(${this.quote(options.name)})`);\n          if (options.exact)\n            attrs.push(`.setExact(true)`);\n        }\n        for (const { name, value } of options.attrs)\n          attrs.push(`.set${toTitleCase(name)}(${typeof value === \"string\" ? this.quote(value) : value})`);\n        const attrString = attrs.length ? `, new ${clazz}.GetByRoleOptions()${attrs.join(\"\")}` : \"\";\n        return `getByRole(AriaRole.${toSnakeCase(body).toUpperCase()}${attrString})`;\n      case \"has-text\":\n        return `filter(new ${clazz}.FilterOptions().setHasText(${this.toHasText(body)}))`;\n      case \"has-not-text\":\n        return `filter(new ${clazz}.FilterOptions().setHasNotText(${this.toHasText(body)}))`;\n      case \"has\":\n        return `filter(new ${clazz}.FilterOptions().setHas(${body}))`;\n      case \"hasNot\":\n        return `filter(new ${clazz}.FilterOptions().setHasNot(${body}))`;\n      case \"and\":\n        return `and(${body})`;\n      case \"or\":\n        return `or(${body})`;\n      case \"chain\":\n        return `locator(${body})`;\n      case \"test-id\":\n        return `getByTestId(${this.toTestIdValue(body)})`;\n      case \"text\":\n        return this.toCallWithExact(clazz, \"getByText\", body, !!options.exact);\n      case \"alt\":\n        return this.toCallWithExact(clazz, \"getByAltText\", body, !!options.exact);\n      case \"placeholder\":\n        return this.toCallWithExact(clazz, \"getByPlaceholder\", body, !!options.exact);\n      case \"label\":\n        return this.toCallWithExact(clazz, \"getByLabel\", body, !!options.exact);\n      case \"title\":\n        return this.toCallWithExact(clazz, \"getByTitle\", body, !!options.exact);\n      default:\n        throw new Error(\"Unknown selector kind \" + kind);\n    }\n  }\n  chainLocators(locators) {\n    return locators.join(\".\");\n  }\n  regexToString(body) {\n    const suffix = body.flags.includes(\"i\") ? \", Pattern.CASE_INSENSITIVE\" : \"\";\n    return `Pattern.compile(${this.quote(normalizeEscapedRegexQuotes(body.source))}${suffix})`;\n  }\n  toCallWithExact(clazz, method, body, exact) {\n    if (isRegExp(body))\n      return `${method}(${this.regexToString(body)})`;\n    if (exact)\n      return `${method}(${this.quote(body)}, new ${clazz}.${toTitleCase(method)}Options().setExact(true))`;\n    return `${method}(${this.quote(body)})`;\n  }\n  toHasText(body) {\n    if (isRegExp(body))\n      return this.regexToString(body);\n    return this.quote(body);\n  }\n  toTestIdValue(value) {\n    if (isRegExp(value))\n      return this.regexToString(value);\n    return this.quote(value);\n  }\n  quote(text) {\n    return escapeWithQuotes(text, '\"');\n  }\n};\nvar CSharpLocatorFactory = class {\n  generateLocator(base, kind, body, options = {}) {\n    switch (kind) {\n      case \"default\":\n        if (options.hasText !== void 0)\n          return `Locator(${this.quote(body)}, new() { ${this.toHasText(options.hasText)} })`;\n        if (options.hasNotText !== void 0)\n          return `Locator(${this.quote(body)}, new() { ${this.toHasNotText(options.hasNotText)} })`;\n        return `Locator(${this.quote(body)})`;\n      case \"frame\":\n        return `FrameLocator(${this.quote(body)})`;\n      case \"nth\":\n        return `Nth(${body})`;\n      case \"first\":\n        return `First`;\n      case \"last\":\n        return `Last`;\n      case \"role\":\n        const attrs = [];\n        if (isRegExp(options.name)) {\n          attrs.push(`NameRegex = ${this.regexToString(options.name)}`);\n        } else if (typeof options.name === \"string\") {\n          attrs.push(`Name = ${this.quote(options.name)}`);\n          if (options.exact)\n            attrs.push(`Exact = true`);\n        }\n        for (const { name, value } of options.attrs)\n          attrs.push(`${toTitleCase(name)} = ${typeof value === \"string\" ? this.quote(value) : value}`);\n        const attrString = attrs.length ? `, new() { ${attrs.join(\", \")} }` : \"\";\n        return `GetByRole(AriaRole.${toTitleCase(body)}${attrString})`;\n      case \"has-text\":\n        return `Filter(new() { ${this.toHasText(body)} })`;\n      case \"has-not-text\":\n        return `Filter(new() { ${this.toHasNotText(body)} })`;\n      case \"has\":\n        return `Filter(new() { Has = ${body} })`;\n      case \"hasNot\":\n        return `Filter(new() { HasNot = ${body} })`;\n      case \"and\":\n        return `And(${body})`;\n      case \"or\":\n        return `Or(${body})`;\n      case \"chain\":\n        return `Locator(${body})`;\n      case \"test-id\":\n        return `GetByTestId(${this.toTestIdValue(body)})`;\n      case \"text\":\n        return this.toCallWithExact(\"GetByText\", body, !!options.exact);\n      case \"alt\":\n        return this.toCallWithExact(\"GetByAltText\", body, !!options.exact);\n      case \"placeholder\":\n        return this.toCallWithExact(\"GetByPlaceholder\", body, !!options.exact);\n      case \"label\":\n        return this.toCallWithExact(\"GetByLabel\", body, !!options.exact);\n      case \"title\":\n        return this.toCallWithExact(\"GetByTitle\", body, !!options.exact);\n      default:\n        throw new Error(\"Unknown selector kind \" + kind);\n    }\n  }\n  chainLocators(locators) {\n    return locators.join(\".\");\n  }\n  regexToString(body) {\n    const suffix = body.flags.includes(\"i\") ? \", RegexOptions.IgnoreCase\" : \"\";\n    return `new Regex(${this.quote(normalizeEscapedRegexQuotes(body.source))}${suffix})`;\n  }\n  toCallWithExact(method, body, exact) {\n    if (isRegExp(body))\n      return `${method}(${this.regexToString(body)})`;\n    if (exact)\n      return `${method}(${this.quote(body)}, new() { Exact = true })`;\n    return `${method}(${this.quote(body)})`;\n  }\n  toHasText(body) {\n    if (isRegExp(body))\n      return `HasTextRegex = ${this.regexToString(body)}`;\n    return `HasText = ${this.quote(body)}`;\n  }\n  toTestIdValue(value) {\n    if (isRegExp(value))\n      return this.regexToString(value);\n    return this.quote(value);\n  }\n  toHasNotText(body) {\n    if (isRegExp(body))\n      return `HasNotTextRegex = ${this.regexToString(body)}`;\n    return `HasNotText = ${this.quote(body)}`;\n  }\n  quote(text) {\n    return escapeWithQuotes(text, '\"');\n  }\n};\nvar JsonlLocatorFactory = class {\n  generateLocator(base, kind, body, options = {}) {\n    return JSON.stringify({\n      kind,\n      body,\n      options\n    });\n  }\n  chainLocators(locators) {\n    const objects = locators.map((l) => JSON.parse(l));\n    for (let i = 0; i < objects.length - 1; ++i)\n      objects[i].next = objects[i + 1];\n    return JSON.stringify(objects[0]);\n  }\n};\nvar generators = {\n  javascript: JavaScriptLocatorFactory,\n  python: PythonLocatorFactory,\n  java: JavaLocatorFactory,\n  csharp: CSharpLocatorFactory,\n  jsonl: JsonlLocatorFactory\n};\nfunction isRegExp(obj) {\n  return obj instanceof RegExp;\n}\n\n// packages/playwright-core/src/server/injected/highlight.css?inline\nvar highlight_default = \":host{font-size:13px;font-family:system-ui,Ubuntu,Droid Sans,sans-serif;color:#333}svg{position:absolute;height:0}x-pw-tooltip{backdrop-filter:blur(5px);background-color:#fff;border-radius:6px;box-shadow:0 .5rem 1.2rem #0000004d;display:none;font-size:12.8px;font-weight:400;left:0;line-height:1.5;max-width:600px;position:absolute;top:0;padding:0;flex-direction:column;overflow:hidden}x-pw-tooltip-line{display:flex;max-width:600px;padding:6px;user-select:none;cursor:pointer}x-pw-tooltip-line.selectable:hover{background-color:#f2f2f2;overflow:hidden}x-pw-tooltip-footer{display:flex;max-width:600px;padding:6px;user-select:none;color:#777}x-pw-dialog{background-color:#fff;pointer-events:auto;border-radius:6px;box-shadow:0 .5rem 1.2rem #0000004d;display:flex;flex-direction:column;position:absolute;width:400px;height:150px;z-index:10;font-size:13px}x-pw-dialog-body{display:flex;flex-direction:column;flex:auto}x-pw-dialog-body label{margin:5px 8px;display:flex;flex-direction:row;align-items:center}x-pw-highlight{position:absolute;top:0;left:0;width:0;height:0}x-pw-action-point{position:absolute;width:20px;height:20px;background:red;border-radius:10px;margin:-10px 0 0 -10px;z-index:2}x-pw-separator{height:1px;margin:6px 9px;background:rgb(148 148 148 / 90%)}x-pw-tool-gripper{height:28px;width:24px;margin:2px 0;cursor:grab}x-pw-tool-gripper:active{cursor:grabbing}x-pw-tool-gripper>x-div{width:16px;height:16px;margin:6px 4px;clip-path:url(#icon-gripper);background-color:#555}x-pw-tools-list>label{display:flex;align-items:center;margin:0 10px;user-select:none}x-pw-tools-list{display:flex;width:100%;border-bottom:1px solid #dddddd}x-pw-tool-item{pointer-events:auto;cursor:pointer;height:28px;width:28px;border-radius:3px}x-pw-tool-item:not(.disabled):hover{background-color:#dbdbdb}x-pw-tool-item.active{background-color:#8acae480}x-pw-tool-item.active:not(.disabled):hover{background-color:#8acae4c4}x-pw-tool-item>x-div{width:16px;height:16px;margin:6px;background-color:#3a3a3a}x-pw-tool-item.disabled>x-div{background-color:#61616180;cursor:default}x-pw-tool-item.record.active{background-color:transparent}x-pw-tool-item.record.active:hover{background-color:#dbdbdb}x-pw-tool-item.record.active>x-div{background-color:#a1260d}x-pw-tool-item.accept>x-div{background-color:#388a34}x-pw-tool-item.record>x-div{clip-path:url(#icon-circle-large-filled)}x-pw-tool-item.pick-locator>x-div{clip-path:url(#icon-inspect)}x-pw-tool-item.text>x-div{clip-path:url(#icon-whole-word)}x-pw-tool-item.visibility>x-div{clip-path:url(#icon-eye)}x-pw-tool-item.value>x-div{clip-path:url(#icon-symbol-constant)}x-pw-tool-item.accept>x-div{clip-path:url(#icon-check)}x-pw-tool-item.cancel>x-div{clip-path:url(#icon-close)}x-pw-tool-item.succeeded>x-div{clip-path:url(#icon-pass);background-color:#388a34!important}x-pw-overlay{position:absolute;top:0;max-width:min-content;z-index:2147483647;background:transparent;pointer-events:auto}x-pw-overlay x-pw-tools-list{background-color:#fffd;box-shadow:#0000001a 0 5px 5px;border-radius:3px;border-bottom:none}x-pw-overlay x-pw-tool-item{margin:2px}textarea.text-editor{font-family:system-ui,Ubuntu,Droid Sans,sans-serif;flex:auto;border:none;margin:6px 10px;color:#333;outline:1px solid transparent!important;resize:none;padding:0;font-size:13px}textarea.text-editor.does-not-match{outline:1px solid red!important}x-div{display:block}x-spacer{flex:auto}*{box-sizing:border-box}*[hidden]{display:none!important}x-locator-editor{flex:none;width:100%;height:60px;padding:4px;border-bottom:1px solid #dddddd;outline:1px solid transparent}x-locator-editor.does-not-match{outline:1px solid red}.CodeMirror{width:100%!important;height:100%!important}\\n\";\n\n// packages/playwright-core/src/server/injected/highlight.ts\nvar Highlight = class {\n  constructor(injectedScript) {\n    this._highlightEntries = [];\n    this._highlightOptions = {};\n    this._language = \"javascript\";\n    this._injectedScript = injectedScript;\n    const document = injectedScript.document;\n    this._isUnderTest = injectedScript.isUnderTest;\n    this._glassPaneElement = document.createElement(\"x-pw-glass\");\n    this._glassPaneElement.style.position = \"fixed\";\n    this._glassPaneElement.style.top = \"0\";\n    this._glassPaneElement.style.right = \"0\";\n    this._glassPaneElement.style.bottom = \"0\";\n    this._glassPaneElement.style.left = \"0\";\n    this._glassPaneElement.style.zIndex = \"2147483646\";\n    this._glassPaneElement.style.pointerEvents = \"none\";\n    this._glassPaneElement.style.display = \"flex\";\n    this._glassPaneElement.style.backgroundColor = \"transparent\";\n    for (const eventName of [\"click\", \"auxclick\", \"dragstart\", \"input\", \"keydown\", \"keyup\", \"pointerdown\", \"pointerup\", \"mousedown\", \"mouseup\", \"mouseleave\", \"focus\", \"scroll\"]) {\n      this._glassPaneElement.addEventListener(eventName, (e) => {\n        e.stopPropagation();\n        e.stopImmediatePropagation();\n        if (e.type === \"click\" && e.button === 0 && this._highlightOptions.tooltipListItemSelected)\n          this._highlightOptions.tooltipListItemSelected(void 0);\n      });\n    }\n    this._actionPointElement = document.createElement(\"x-pw-action-point\");\n    this._actionPointElement.setAttribute(\"hidden\", \"true\");\n    this._glassPaneShadow = this._glassPaneElement.attachShadow({ mode: this._isUnderTest ? \"open\" : \"closed\" });\n    if (typeof this._glassPaneShadow.adoptedStyleSheets.push === \"function\") {\n      const sheet = new this._injectedScript.window.CSSStyleSheet();\n      sheet.replaceSync(highlight_default);\n      this._glassPaneShadow.adoptedStyleSheets.push(sheet);\n    } else {\n      const styleElement = this._injectedScript.document.createElement(\"style\");\n      styleElement.textContent = highlight_default;\n      this._glassPaneShadow.appendChild(styleElement);\n    }\n    this._glassPaneShadow.appendChild(this._actionPointElement);\n  }\n  install() {\n    this._injectedScript.document.documentElement.appendChild(this._glassPaneElement);\n  }\n  setLanguage(language) {\n    this._language = language;\n  }\n  runHighlightOnRaf(selector) {\n    if (this._rafRequest)\n      cancelAnimationFrame(this._rafRequest);\n    this.updateHighlight(this._injectedScript.querySelectorAll(selector, this._injectedScript.document.documentElement), { tooltipText: asLocator(this._language, stringifySelector(selector)) });\n    this._rafRequest = requestAnimationFrame(() => this.runHighlightOnRaf(selector));\n  }\n  uninstall() {\n    if (this._rafRequest)\n      cancelAnimationFrame(this._rafRequest);\n    this._glassPaneElement.remove();\n  }\n  showActionPoint(x, y) {\n    this._actionPointElement.style.top = y + \"px\";\n    this._actionPointElement.style.left = x + \"px\";\n    this._actionPointElement.hidden = false;\n  }\n  hideActionPoint() {\n    this._actionPointElement.hidden = true;\n  }\n  clearHighlight() {\n    var _a, _b;\n    for (const entry of this._highlightEntries) {\n      (_a = entry.highlightElement) == null ? void 0 : _a.remove();\n      (_b = entry.tooltipElement) == null ? void 0 : _b.remove();\n    }\n    this._highlightEntries = [];\n    this._highlightOptions = {};\n    this._glassPaneElement.style.pointerEvents = \"none\";\n  }\n  updateHighlight(elements, options) {\n    this._innerUpdateHighlight(elements, options);\n  }\n  maskElements(elements, color) {\n    this._innerUpdateHighlight(elements, { color });\n  }\n  _innerUpdateHighlight(elements, options) {\n    let color = options.color;\n    if (!color)\n      color = elements.length > 1 ? \"#f6b26b7f\" : \"#6fa8dc7f\";\n    if (this._highlightIsUpToDate(elements, options))\n      return;\n    this.clearHighlight();\n    this._highlightOptions = options;\n    this._glassPaneElement.style.pointerEvents = options.tooltipListItemSelected ? \"initial\" : \"none\";\n    for (let i = 0; i < elements.length; ++i) {\n      const highlightElement = this._createHighlightElement();\n      this._glassPaneShadow.appendChild(highlightElement);\n      let tooltipElement;\n      if (options.tooltipList || options.tooltipText || options.tooltipFooter) {\n        tooltipElement = this._injectedScript.document.createElement(\"x-pw-tooltip\");\n        this._glassPaneShadow.appendChild(tooltipElement);\n        tooltipElement.style.top = \"0\";\n        tooltipElement.style.left = \"0\";\n        tooltipElement.style.display = \"flex\";\n        let lines = [];\n        if (options.tooltipList) {\n          lines = options.tooltipList;\n        } else if (options.tooltipText) {\n          const suffix = elements.length > 1 ? ` [${i + 1} of ${elements.length}]` : \"\";\n          lines = [options.tooltipText + suffix];\n        }\n        for (let index = 0; index < lines.length; index++) {\n          const element = this._injectedScript.document.createElement(\"x-pw-tooltip-line\");\n          element.textContent = lines[index];\n          tooltipElement.appendChild(element);\n          if (options.tooltipListItemSelected) {\n            element.classList.add(\"selectable\");\n            element.addEventListener(\"click\", () => {\n              var _a;\n              return (_a = options.tooltipListItemSelected) == null ? void 0 : _a.call(options, index);\n            });\n          }\n        }\n        if (options.tooltipFooter) {\n          const footer = this._injectedScript.document.createElement(\"x-pw-tooltip-footer\");\n          footer.textContent = options.tooltipFooter;\n          tooltipElement.appendChild(footer);\n        }\n      }\n      this._highlightEntries.push({ targetElement: elements[i], tooltipElement, highlightElement });\n    }\n    for (const entry of this._highlightEntries) {\n      entry.box = entry.targetElement.getBoundingClientRect();\n      if (!entry.tooltipElement)\n        continue;\n      const { anchorLeft, anchorTop } = this.tooltipPosition(entry.box, entry.tooltipElement);\n      entry.tooltipTop = anchorTop;\n      entry.tooltipLeft = anchorLeft;\n    }\n    for (const entry of this._highlightEntries) {\n      if (entry.tooltipElement) {\n        entry.tooltipElement.style.top = entry.tooltipTop + \"px\";\n        entry.tooltipElement.style.left = entry.tooltipLeft + \"px\";\n      }\n      const box = entry.box;\n      entry.highlightElement.style.backgroundColor = color;\n      entry.highlightElement.style.left = box.x + \"px\";\n      entry.highlightElement.style.top = box.y + \"px\";\n      entry.highlightElement.style.width = box.width + \"px\";\n      entry.highlightElement.style.height = box.height + \"px\";\n      entry.highlightElement.style.display = \"block\";\n      if (this._isUnderTest)\n        console.error(\"Highlight box for test: \" + JSON.stringify({ x: box.x, y: box.y, width: box.width, height: box.height }));\n    }\n  }\n  firstBox() {\n    var _a;\n    return (_a = this._highlightEntries[0]) == null ? void 0 : _a.box;\n  }\n  tooltipPosition(box, tooltipElement) {\n    const tooltipWidth = tooltipElement.offsetWidth;\n    const tooltipHeight = tooltipElement.offsetHeight;\n    const totalWidth = this._glassPaneElement.offsetWidth;\n    const totalHeight = this._glassPaneElement.offsetHeight;\n    let anchorLeft = box.left;\n    if (anchorLeft + tooltipWidth > totalWidth - 5)\n      anchorLeft = totalWidth - tooltipWidth - 5;\n    let anchorTop = box.bottom + 5;\n    if (anchorTop + tooltipHeight > totalHeight - 5) {\n      if (box.top > tooltipHeight + 5) {\n        anchorTop = box.top - tooltipHeight - 5;\n      } else {\n        anchorTop = totalHeight - 5 - tooltipHeight;\n      }\n    }\n    return { anchorLeft, anchorTop };\n  }\n  _highlightIsUpToDate(elements, options) {\n    var _a, _b;\n    if (options.tooltipText !== this._highlightOptions.tooltipText)\n      return false;\n    if (options.tooltipListItemSelected !== this._highlightOptions.tooltipListItemSelected)\n      return false;\n    if (options.tooltipFooter !== this._highlightOptions.tooltipFooter)\n      return false;\n    if (((_a = options.tooltipList) == null ? void 0 : _a.length) !== ((_b = this._highlightOptions.tooltipList) == null ? void 0 : _b.length))\n      return false;\n    if (options.tooltipList && this._highlightOptions.tooltipList) {\n      for (let i = 0; i < options.tooltipList.length; i++) {\n        if (options.tooltipList[i] !== this._highlightOptions.tooltipList[i])\n          return false;\n      }\n    }\n    if (elements.length !== this._highlightEntries.length)\n      return false;\n    for (let i = 0; i < this._highlightEntries.length; ++i) {\n      if (elements[i] !== this._highlightEntries[i].targetElement)\n        return false;\n      const oldBox = this._highlightEntries[i].box;\n      if (!oldBox)\n        return false;\n      const box = elements[i].getBoundingClientRect();\n      if (box.top !== oldBox.top || box.right !== oldBox.right || box.bottom !== oldBox.bottom || box.left !== oldBox.left)\n        return false;\n    }\n    return true;\n  }\n  _createHighlightElement() {\n    return this._injectedScript.document.createElement(\"x-pw-highlight\");\n  }\n  appendChild(element) {\n    this._glassPaneShadow.appendChild(element);\n  }\n};\n\n// packages/playwright-core/src/server/injected/injectedScript.ts\nvar InjectedScript = class {\n  // eslint-disable-next-line no-restricted-globals\n  constructor(window, isUnderTest, sdkLanguage, testIdAttributeNameForStrictErrorAndConsoleCodegen, stableRafCount, browserName, customEngines) {\n    this.onGlobalListenersRemoved = /* @__PURE__ */ new Set();\n    this._testIdAttributeNameForStrictErrorAndConsoleCodegen = \"data-testid\";\n    this.utils = { isInsideScope, elementText, asLocator, normalizeWhiteSpace };\n    this.window = window;\n    this.document = window.document;\n    this.isUnderTest = isUnderTest;\n    this._sdkLanguage = sdkLanguage;\n    this._testIdAttributeNameForStrictErrorAndConsoleCodegen = testIdAttributeNameForStrictErrorAndConsoleCodegen;\n    this._evaluator = new SelectorEvaluatorImpl(/* @__PURE__ */ new Map());\n    this._engines = /* @__PURE__ */ new Map();\n    this._engines.set(\"xpath\", XPathEngine);\n    this._engines.set(\"xpath:light\", XPathEngine);\n    this._engines.set(\"_react\", ReactEngine);\n    this._engines.set(\"_vue\", VueEngine);\n    this._engines.set(\"role\", createRoleEngine(false));\n    this._engines.set(\"text\", this._createTextEngine(true, false));\n    this._engines.set(\"text:light\", this._createTextEngine(false, false));\n    this._engines.set(\"id\", this._createAttributeEngine(\"id\", true));\n    this._engines.set(\"id:light\", this._createAttributeEngine(\"id\", false));\n    this._engines.set(\"data-testid\", this._createAttributeEngine(\"data-testid\", true));\n    this._engines.set(\"data-testid:light\", this._createAttributeEngine(\"data-testid\", false));\n    this._engines.set(\"data-test-id\", this._createAttributeEngine(\"data-test-id\", true));\n    this._engines.set(\"data-test-id:light\", this._createAttributeEngine(\"data-test-id\", false));\n    this._engines.set(\"data-test\", this._createAttributeEngine(\"data-test\", true));\n    this._engines.set(\"data-test:light\", this._createAttributeEngine(\"data-test\", false));\n    this._engines.set(\"css\", this._createCSSEngine());\n    this._engines.set(\"nth\", { queryAll: () => [] });\n    this._engines.set(\"visible\", this._createVisibleEngine());\n    this._engines.set(\"internal:control\", this._createControlEngine());\n    this._engines.set(\"internal:has\", this._createHasEngine());\n    this._engines.set(\"internal:has-not\", this._createHasNotEngine());\n    this._engines.set(\"internal:and\", { queryAll: () => [] });\n    this._engines.set(\"internal:or\", { queryAll: () => [] });\n    this._engines.set(\"internal:chain\", this._createInternalChainEngine());\n    this._engines.set(\"internal:label\", this._createInternalLabelEngine());\n    this._engines.set(\"internal:text\", this._createTextEngine(true, true));\n    this._engines.set(\"internal:has-text\", this._createInternalHasTextEngine());\n    this._engines.set(\"internal:has-not-text\", this._createInternalHasNotTextEngine());\n    this._engines.set(\"internal:attr\", this._createNamedAttributeEngine());\n    this._engines.set(\"internal:testid\", this._createNamedAttributeEngine());\n    this._engines.set(\"internal:role\", createRoleEngine(true));\n    for (const { name, engine } of customEngines)\n      this._engines.set(name, engine);\n    this._stableRafCount = stableRafCount;\n    this._browserName = browserName;\n    setBrowserName(browserName);\n    this._setupGlobalListenersRemovalDetection();\n    this._setupHitTargetInterceptors();\n    if (isUnderTest)\n      this.window.__injectedScript = this;\n  }\n  eval(expression) {\n    return this.window.eval(expression);\n  }\n  testIdAttributeNameForStrictErrorAndConsoleCodegen() {\n    return this._testIdAttributeNameForStrictErrorAndConsoleCodegen;\n  }\n  parseSelector(selector) {\n    const result = parseSelector(selector);\n    visitAllSelectorParts(result, (part) => {\n      if (!this._engines.has(part.name))\n        throw this.createStacklessError(`Unknown engine \"${part.name}\" while parsing selector ${selector}`);\n    });\n    return result;\n  }\n  generateSelector(targetElement, options) {\n    return generateSelector(this, targetElement, options);\n  }\n  generateSelectorSimple(targetElement, options) {\n    return generateSelector(this, targetElement, { ...options, testIdAttributeName: this._testIdAttributeNameForStrictErrorAndConsoleCodegen }).selector;\n  }\n  querySelector(selector, root, strict) {\n    const result = this.querySelectorAll(selector, root);\n    if (strict && result.length > 1)\n      throw this.strictModeViolationError(selector, result);\n    return result[0];\n  }\n  _queryNth(elements, part) {\n    const list = [...elements];\n    let nth = +part.body;\n    if (nth === -1)\n      nth = list.length - 1;\n    return new Set(list.slice(nth, nth + 1));\n  }\n  _queryLayoutSelector(elements, part, originalRoot) {\n    const name = part.name;\n    const body = part.body;\n    const result = [];\n    const inner = this.querySelectorAll(body.parsed, originalRoot);\n    for (const element of elements) {\n      const score = layoutSelectorScore(name, element, inner, body.distance);\n      if (score !== void 0)\n        result.push({ element, score });\n    }\n    result.sort((a, b) => a.score - b.score);\n    return new Set(result.map((r) => r.element));\n  }\n  querySelectorAll(selector, root) {\n    if (selector.capture !== void 0) {\n      if (selector.parts.some((part) => part.name === \"nth\"))\n        throw this.createStacklessError(`Can't query n-th element in a request with the capture.`);\n      const withHas = { parts: selector.parts.slice(0, selector.capture + 1) };\n      if (selector.capture < selector.parts.length - 1) {\n        const parsed = { parts: selector.parts.slice(selector.capture + 1) };\n        const has = { name: \"internal:has\", body: { parsed }, source: stringifySelector(parsed) };\n        withHas.parts.push(has);\n      }\n      return this.querySelectorAll(withHas, root);\n    }\n    if (!root[\"querySelectorAll\"])\n      throw this.createStacklessError(\"Node is not queryable.\");\n    if (selector.capture !== void 0) {\n      throw this.createStacklessError(\"Internal error: there should not be a capture in the selector.\");\n    }\n    if (root.nodeType === 11 && selector.parts.length === 1 && selector.parts[0].name === \"css\" && selector.parts[0].source === \":scope\")\n      return [root];\n    this._evaluator.begin();\n    try {\n      let roots = /* @__PURE__ */ new Set([root]);\n      for (const part of selector.parts) {\n        if (part.name === \"nth\") {\n          roots = this._queryNth(roots, part);\n        } else if (part.name === \"internal:and\") {\n          const andElements = this.querySelectorAll(part.body.parsed, root);\n          roots = new Set(andElements.filter((e) => roots.has(e)));\n        } else if (part.name === \"internal:or\") {\n          const orElements = this.querySelectorAll(part.body.parsed, root);\n          roots = new Set(sortInDOMOrder(/* @__PURE__ */ new Set([...roots, ...orElements])));\n        } else if (kLayoutSelectorNames.includes(part.name)) {\n          roots = this._queryLayoutSelector(roots, part, root);\n        } else {\n          const next = /* @__PURE__ */ new Set();\n          for (const root2 of roots) {\n            const all = this._queryEngineAll(part, root2);\n            for (const one of all)\n              next.add(one);\n          }\n          roots = next;\n        }\n      }\n      return [...roots];\n    } finally {\n      this._evaluator.end();\n    }\n  }\n  _queryEngineAll(part, root) {\n    const result = this._engines.get(part.name).queryAll(root, part.body);\n    for (const element of result) {\n      if (!(\"nodeName\" in element))\n        throw this.createStacklessError(`Expected a Node but got ${Object.prototype.toString.call(element)}`);\n    }\n    return result;\n  }\n  _createAttributeEngine(attribute, shadow) {\n    const toCSS = (selector) => {\n      const css = `[${attribute}=${JSON.stringify(selector)}]`;\n      return [{ simples: [{ selector: { css, functions: [] }, combinator: \"\" }] }];\n    };\n    return {\n      queryAll: (root, selector) => {\n        return this._evaluator.query({ scope: root, pierceShadow: shadow }, toCSS(selector));\n      }\n    };\n  }\n  _createCSSEngine() {\n    return {\n      queryAll: (root, body) => {\n        return this._evaluator.query({ scope: root, pierceShadow: true }, body);\n      }\n    };\n  }\n  _createTextEngine(shadow, internal) {\n    const queryAll = (root, selector) => {\n      const { matcher, kind } = createTextMatcher(selector, internal);\n      const result = [];\n      let lastDidNotMatchSelf = null;\n      const appendElement = (element) => {\n        if (kind === \"lax\" && lastDidNotMatchSelf && lastDidNotMatchSelf.contains(element))\n          return false;\n        const matches = elementMatchesText(this._evaluator._cacheText, element, matcher);\n        if (matches === \"none\")\n          lastDidNotMatchSelf = element;\n        if (matches === \"self\" || matches === \"selfAndChildren\" && kind === \"strict\" && !internal)\n          result.push(element);\n      };\n      if (root.nodeType === Node.ELEMENT_NODE)\n        appendElement(root);\n      const elements = this._evaluator._queryCSS({ scope: root, pierceShadow: shadow }, \"*\");\n      for (const element of elements)\n        appendElement(element);\n      return result;\n    };\n    return { queryAll };\n  }\n  _createInternalHasTextEngine() {\n    return {\n      queryAll: (root, selector) => {\n        if (root.nodeType !== 1)\n          return [];\n        const element = root;\n        const text = elementText(this._evaluator._cacheText, element);\n        const { matcher } = createTextMatcher(selector, true);\n        return matcher(text) ? [element] : [];\n      }\n    };\n  }\n  _createInternalHasNotTextEngine() {\n    return {\n      queryAll: (root, selector) => {\n        if (root.nodeType !== 1)\n          return [];\n        const element = root;\n        const text = elementText(this._evaluator._cacheText, element);\n        const { matcher } = createTextMatcher(selector, true);\n        return matcher(text) ? [] : [element];\n      }\n    };\n  }\n  _createInternalLabelEngine() {\n    return {\n      queryAll: (root, selector) => {\n        const { matcher } = createTextMatcher(selector, true);\n        const allElements = this._evaluator._queryCSS({ scope: root, pierceShadow: true }, \"*\");\n        return allElements.filter((element) => {\n          return getElementLabels(this._evaluator._cacheText, element).some((label) => matcher(label));\n        });\n      }\n    };\n  }\n  _createNamedAttributeEngine() {\n    const queryAll = (root, selector) => {\n      const parsed = parseAttributeSelector(selector, true);\n      if (parsed.name || parsed.attributes.length !== 1)\n        throw new Error(\"Malformed attribute selector: \" + selector);\n      const { name, value, caseSensitive } = parsed.attributes[0];\n      const lowerCaseValue = caseSensitive ? null : value.toLowerCase();\n      let matcher;\n      if (value instanceof RegExp)\n        matcher = (s) => !!s.match(value);\n      else if (caseSensitive)\n        matcher = (s) => s === value;\n      else\n        matcher = (s) => s.toLowerCase().includes(lowerCaseValue);\n      const elements = this._evaluator._queryCSS({ scope: root, pierceShadow: true }, `[${name}]`);\n      return elements.filter((e) => matcher(e.getAttribute(name)));\n    };\n    return { queryAll };\n  }\n  _createControlEngine() {\n    return {\n      queryAll(root, body) {\n        if (body === \"enter-frame\")\n          return [];\n        if (body === \"return-empty\")\n          return [];\n        if (body === \"component\") {\n          if (root.nodeType !== 1)\n            return [];\n          return [root.childElementCount === 1 ? root.firstElementChild : root];\n        }\n        throw new Error(`Internal error, unknown internal:control selector ${body}`);\n      }\n    };\n  }\n  _createHasEngine() {\n    const queryAll = (root, body) => {\n      if (root.nodeType !== 1)\n        return [];\n      const has = !!this.querySelector(body.parsed, root, false);\n      return has ? [root] : [];\n    };\n    return { queryAll };\n  }\n  _createHasNotEngine() {\n    const queryAll = (root, body) => {\n      if (root.nodeType !== 1)\n        return [];\n      const has = !!this.querySelector(body.parsed, root, false);\n      return has ? [] : [root];\n    };\n    return { queryAll };\n  }\n  _createVisibleEngine() {\n    const queryAll = (root, body) => {\n      if (root.nodeType !== 1)\n        return [];\n      return isElementVisible(root) === Boolean(body) ? [root] : [];\n    };\n    return { queryAll };\n  }\n  _createInternalChainEngine() {\n    const queryAll = (root, body) => {\n      return this.querySelectorAll(body.parsed, root);\n    };\n    return { queryAll };\n  }\n  extend(source, params) {\n    const constrFunction = this.window.eval(`\n    (() => {\n      const module = {};\n      ${source}\n      return module.exports.default();\n    })()`);\n    return new constrFunction(this, params);\n  }\n  isVisible(element) {\n    return isElementVisible(element);\n  }\n  async viewportRatio(element) {\n    return await new Promise((resolve) => {\n      const observer = new IntersectionObserver((entries) => {\n        resolve(entries[0].intersectionRatio);\n        observer.disconnect();\n      });\n      observer.observe(element);\n      requestAnimationFrame(() => {\n      });\n    });\n  }\n  getElementBorderWidth(node) {\n    if (node.nodeType !== Node.ELEMENT_NODE || !node.ownerDocument || !node.ownerDocument.defaultView)\n      return { left: 0, top: 0 };\n    const style = node.ownerDocument.defaultView.getComputedStyle(node);\n    return { left: parseInt(style.borderLeftWidth || \"\", 10), top: parseInt(style.borderTopWidth || \"\", 10) };\n  }\n  describeIFrameStyle(iframe) {\n    if (!iframe.ownerDocument || !iframe.ownerDocument.defaultView)\n      return \"error:notconnected\";\n    const defaultView = iframe.ownerDocument.defaultView;\n    for (let e = iframe; e; e = parentElementOrShadowHost(e)) {\n      if (defaultView.getComputedStyle(e).transform !== \"none\")\n        return \"transformed\";\n    }\n    const iframeStyle = defaultView.getComputedStyle(iframe);\n    return {\n      left: parseInt(iframeStyle.borderLeftWidth || \"\", 10) + parseInt(iframeStyle.paddingLeft || \"\", 10),\n      top: parseInt(iframeStyle.borderTopWidth || \"\", 10) + parseInt(iframeStyle.paddingTop || \"\", 10)\n    };\n  }\n  retarget(node, behavior) {\n    let element = node.nodeType === Node.ELEMENT_NODE ? node : node.parentElement;\n    if (!element)\n      return null;\n    if (behavior === \"none\")\n      return element;\n    if (!element.matches(\"input, textarea, select\") && !element.isContentEditable) {\n      if (behavior === \"button-link\")\n        element = element.closest(\"button, [role=button], a, [role=link]\") || element;\n      else\n        element = element.closest(\"button, [role=button], [role=checkbox], [role=radio]\") || element;\n    }\n    if (behavior === \"follow-label\") {\n      if (!element.matches(\"input, textarea, button, select, [role=button], [role=checkbox], [role=radio]\") && !element.isContentEditable) {\n        element = element.closest(\"label\") || element;\n      }\n      if (element.nodeName === \"LABEL\")\n        element = element.control || element;\n    }\n    return element;\n  }\n  async checkElementStates(node, states) {\n    if (states.includes(\"stable\")) {\n      const stableResult = await this._checkElementIsStable(node);\n      if (stableResult === false)\n        return { missingState: \"stable\" };\n      if (stableResult === \"error:notconnected\")\n        return stableResult;\n    }\n    for (const state of states) {\n      if (state !== \"stable\") {\n        const result = this.elementState(node, state);\n        if (result === false)\n          return { missingState: state };\n        if (result === \"error:notconnected\")\n          return result;\n      }\n    }\n  }\n  async _checkElementIsStable(node) {\n    const continuePolling = Symbol(\"continuePolling\");\n    let lastRect;\n    let stableRafCounter = 0;\n    let lastTime = 0;\n    const check = () => {\n      const element = this.retarget(node, \"no-follow-label\");\n      if (!element)\n        return \"error:notconnected\";\n      const time = performance.now();\n      if (this._stableRafCount > 1 && time - lastTime < 15)\n        return continuePolling;\n      lastTime = time;\n      const clientRect = element.getBoundingClientRect();\n      const rect = { x: clientRect.top, y: clientRect.left, width: clientRect.width, height: clientRect.height };\n      if (lastRect) {\n        const samePosition = rect.x === lastRect.x && rect.y === lastRect.y && rect.width === lastRect.width && rect.height === lastRect.height;\n        if (!samePosition)\n          return false;\n        if (++stableRafCounter >= this._stableRafCount)\n          return true;\n      }\n      lastRect = rect;\n      return continuePolling;\n    };\n    let fulfill;\n    let reject;\n    const result = new Promise((f, r) => {\n      fulfill = f;\n      reject = r;\n    });\n    const raf = () => {\n      try {\n        const success = check();\n        if (success !== continuePolling)\n          fulfill(success);\n        else\n          requestAnimationFrame(raf);\n      } catch (e) {\n        reject(e);\n      }\n    };\n    requestAnimationFrame(raf);\n    return result;\n  }\n  elementState(node, state) {\n    const element = this.retarget(node, [\"stable\", \"visible\", \"hidden\"].includes(state) ? \"none\" : \"follow-label\");\n    if (!element || !element.isConnected) {\n      if (state === \"hidden\")\n        return true;\n      return \"error:notconnected\";\n    }\n    if (state === \"visible\")\n      return this.isVisible(element);\n    if (state === \"hidden\")\n      return !this.isVisible(element);\n    const disabled = getAriaDisabled(element);\n    if (state === \"disabled\")\n      return disabled;\n    if (state === \"enabled\")\n      return !disabled;\n    const editable = !([\"INPUT\", \"TEXTAREA\", \"SELECT\"].includes(element.nodeName) && element.hasAttribute(\"readonly\"));\n    if (state === \"editable\")\n      return !disabled && editable;\n    if (state === \"checked\" || state === \"unchecked\") {\n      const need = state === \"checked\";\n      const checked = getChecked(element, false);\n      if (checked === \"error\")\n        throw this.createStacklessError(\"Not a checkbox or radio button\");\n      return need === checked;\n    }\n    throw this.createStacklessError(`Unexpected element state \"${state}\"`);\n  }\n  selectOptions(node, optionsToSelect) {\n    const element = this.retarget(node, \"follow-label\");\n    if (!element)\n      return \"error:notconnected\";\n    if (element.nodeName.toLowerCase() !== \"select\")\n      throw this.createStacklessError(\"Element is not a <select> element\");\n    const select = element;\n    const options = [...select.options];\n    const selectedOptions = [];\n    let remainingOptionsToSelect = optionsToSelect.slice();\n    for (let index = 0; index < options.length; index++) {\n      const option = options[index];\n      const filter = (optionToSelect) => {\n        if (optionToSelect instanceof Node)\n          return option === optionToSelect;\n        let matches = true;\n        if (optionToSelect.valueOrLabel !== void 0)\n          matches = matches && (optionToSelect.valueOrLabel === option.value || optionToSelect.valueOrLabel === option.label);\n        if (optionToSelect.value !== void 0)\n          matches = matches && optionToSelect.value === option.value;\n        if (optionToSelect.label !== void 0)\n          matches = matches && optionToSelect.label === option.label;\n        if (optionToSelect.index !== void 0)\n          matches = matches && optionToSelect.index === index;\n        return matches;\n      };\n      if (!remainingOptionsToSelect.some(filter))\n        continue;\n      selectedOptions.push(option);\n      if (select.multiple) {\n        remainingOptionsToSelect = remainingOptionsToSelect.filter((o) => !filter(o));\n      } else {\n        remainingOptionsToSelect = [];\n        break;\n      }\n    }\n    if (remainingOptionsToSelect.length)\n      return \"error:optionsnotfound\";\n    select.value = void 0;\n    selectedOptions.forEach((option) => option.selected = true);\n    select.dispatchEvent(new Event(\"input\", { bubbles: true, composed: true }));\n    select.dispatchEvent(new Event(\"change\", { bubbles: true }));\n    return selectedOptions.map((option) => option.value);\n  }\n  fill(node, value) {\n    const element = this.retarget(node, \"follow-label\");\n    if (!element)\n      return \"error:notconnected\";\n    if (element.nodeName.toLowerCase() === \"input\") {\n      const input = element;\n      const type = input.type.toLowerCase();\n      const kInputTypesToSetValue = /* @__PURE__ */ new Set([\"color\", \"date\", \"time\", \"datetime-local\", \"month\", \"range\", \"week\"]);\n      const kInputTypesToTypeInto = /* @__PURE__ */ new Set([\"\", \"email\", \"number\", \"password\", \"search\", \"tel\", \"text\", \"url\"]);\n      if (!kInputTypesToTypeInto.has(type) && !kInputTypesToSetValue.has(type))\n        throw this.createStacklessError(`Input of type \"${type}\" cannot be filled`);\n      if (type === \"number\") {\n        value = value.trim();\n        if (isNaN(Number(value)))\n          throw this.createStacklessError(\"Cannot type text into input[type=number]\");\n      }\n      if (kInputTypesToSetValue.has(type)) {\n        value = value.trim();\n        input.focus();\n        input.value = value;\n        if (input.value !== value)\n          throw this.createStacklessError(\"Malformed value\");\n        element.dispatchEvent(new Event(\"input\", { bubbles: true, composed: true }));\n        element.dispatchEvent(new Event(\"change\", { bubbles: true }));\n        return \"done\";\n      }\n    } else if (element.nodeName.toLowerCase() === \"textarea\") {\n    } else if (!element.isContentEditable) {\n      throw this.createStacklessError(\"Element is not an <input>, <textarea> or [contenteditable] element\");\n    }\n    this.selectText(element);\n    return \"needsinput\";\n  }\n  selectText(node) {\n    const element = this.retarget(node, \"follow-label\");\n    if (!element)\n      return \"error:notconnected\";\n    if (element.nodeName.toLowerCase() === \"input\") {\n      const input = element;\n      input.select();\n      input.focus();\n      return \"done\";\n    }\n    if (element.nodeName.toLowerCase() === \"textarea\") {\n      const textarea = element;\n      textarea.selectionStart = 0;\n      textarea.selectionEnd = textarea.value.length;\n      textarea.focus();\n      return \"done\";\n    }\n    const range = element.ownerDocument.createRange();\n    range.selectNodeContents(element);\n    const selection = element.ownerDocument.defaultView.getSelection();\n    if (selection) {\n      selection.removeAllRanges();\n      selection.addRange(range);\n    }\n    element.focus();\n    return \"done\";\n  }\n  _activelyFocused(node) {\n    const activeElement = node.getRootNode().activeElement;\n    const isFocused = activeElement === node && !!node.ownerDocument && node.ownerDocument.hasFocus();\n    return { activeElement, isFocused };\n  }\n  focusNode(node, resetSelectionIfNotFocused) {\n    if (!node.isConnected)\n      return \"error:notconnected\";\n    if (node.nodeType !== Node.ELEMENT_NODE)\n      throw this.createStacklessError(\"Node is not an element\");\n    const { activeElement, isFocused: wasFocused } = this._activelyFocused(node);\n    if (node.isContentEditable && !wasFocused && activeElement && activeElement.blur) {\n      activeElement.blur();\n    }\n    node.focus();\n    node.focus();\n    if (resetSelectionIfNotFocused && !wasFocused && node.nodeName.toLowerCase() === \"input\") {\n      try {\n        const input = node;\n        input.setSelectionRange(0, 0);\n      } catch (e) {\n      }\n    }\n    return \"done\";\n  }\n  blurNode(node) {\n    if (!node.isConnected)\n      return \"error:notconnected\";\n    if (node.nodeType !== Node.ELEMENT_NODE)\n      throw this.createStacklessError(\"Node is not an element\");\n    node.blur();\n    return \"done\";\n  }\n  setInputFiles(node, payloads) {\n    if (node.nodeType !== Node.ELEMENT_NODE)\n      return \"Node is not of type HTMLElement\";\n    const element = node;\n    if (element.nodeName !== \"INPUT\")\n      return \"Not an <input> element\";\n    const input = element;\n    const type = (input.getAttribute(\"type\") || \"\").toLowerCase();\n    if (type !== \"file\")\n      return \"Not an input[type=file] element\";\n    const files = payloads.map((file) => {\n      const bytes = Uint8Array.from(atob(file.buffer), (c) => c.charCodeAt(0));\n      return new File([bytes], file.name, { type: file.mimeType, lastModified: file.lastModifiedMs });\n    });\n    const dt = new DataTransfer();\n    for (const file of files)\n      dt.items.add(file);\n    input.files = dt.files;\n    input.dispatchEvent(new Event(\"input\", { bubbles: true, composed: true }));\n    input.dispatchEvent(new Event(\"change\", { bubbles: true }));\n  }\n  expectHitTarget(hitPoint, targetElement) {\n    const roots = [];\n    let parentElement = targetElement;\n    while (parentElement) {\n      const root = enclosingShadowRootOrDocument(parentElement);\n      if (!root)\n        break;\n      roots.push(root);\n      if (root.nodeType === 9)\n        break;\n      parentElement = root.host;\n    }\n    let hitElement;\n    for (let index = roots.length - 1; index >= 0; index--) {\n      const root = roots[index];\n      const elements = root.elementsFromPoint(hitPoint.x, hitPoint.y);\n      const singleElement = root.elementFromPoint(hitPoint.x, hitPoint.y);\n      if (singleElement && elements[0] && parentElementOrShadowHost(singleElement) === elements[0]) {\n        const style = this.window.getComputedStyle(singleElement);\n        if ((style == null ? void 0 : style.display) === \"contents\") {\n          elements.unshift(singleElement);\n        }\n      }\n      if (elements[0] && elements[0].shadowRoot === root && elements[1] === singleElement) {\n        elements.shift();\n      }\n      const innerElement = elements[0];\n      if (!innerElement)\n        break;\n      hitElement = innerElement;\n      if (index && innerElement !== roots[index - 1].host)\n        break;\n    }\n    const hitParents = [];\n    while (hitElement && hitElement !== targetElement) {\n      hitParents.push(hitElement);\n      hitElement = parentElementOrShadowHost(hitElement);\n    }\n    if (hitElement === targetElement)\n      return \"done\";\n    const hitTargetDescription = this.previewNode(hitParents[0] || this.document.documentElement);\n    let rootHitTargetDescription;\n    let element = targetElement;\n    while (element) {\n      const index = hitParents.indexOf(element);\n      if (index !== -1) {\n        if (index > 1)\n          rootHitTargetDescription = this.previewNode(hitParents[index - 1]);\n        break;\n      }\n      element = parentElementOrShadowHost(element);\n    }\n    if (rootHitTargetDescription)\n      return { hitTargetDescription: `${hitTargetDescription} from ${rootHitTargetDescription} subtree` };\n    return { hitTargetDescription };\n  }\n  // Life of a pointer action, for example click.\n  //\n  // 0. Retry items 1 and 2 while action fails due to navigation or element being detached.\n  //   1. Resolve selector to an element.\n  //   2. Retry the following steps until the element is detached or frame navigates away.\n  //     2a. Wait for the element to be stable (not moving), visible and enabled.\n  //     2b. Scroll element into view. Scrolling alternates between:\n  //         - Built-in protocol scrolling.\n  //         - Anchoring to the top/left, bottom/right and center/center.\n  //         This is to scroll elements from under sticky headers/footers.\n  //     2c. Click point is calculated, either based on explicitly specified position,\n  //         or some visible point of the element based on protocol content quads.\n  //     2d. Click point relative to page viewport is converted relative to the target iframe\n  //         for the next hit-point check.\n  //     2e. (injected) Hit target at the click point must be a descendant of the target element.\n  //         This prevents mis-clicking in edge cases like <iframe> overlaying the target.\n  //     2f. (injected) Events specific for click (or some other action type) are intercepted on\n  //         the Window with capture:true. See 2i for details.\n  //         Note: this step is skipped for drag&drop (see inline comments for the reason).\n  //     2g. Necessary keyboard modifiers are pressed.\n  //     2h. Click event is issued (mousemove + mousedown + mouseup).\n  //     2i. (injected) For each event, we check that hit target at the event point\n  //         is a descendant of the target element.\n  //         This guarantees no race between issuing the event and handling it in the page,\n  //         for example due to layout shift.\n  //         When hit target check fails, we block all future events in the page.\n  //     2j. Keyboard modifiers are restored.\n  //     2k. (injected) Event interceptor is removed.\n  //     2l. All navigations triggered between 2g-2k are awaited to be either committed or canceled.\n  //     2m. If failed, wait for increasing amount of time before the next retry.\n  setupHitTargetInterceptor(node, action, hitPoint, blockAllEvents) {\n    const element = this.retarget(node, \"button-link\");\n    if (!element || !element.isConnected)\n      return \"error:notconnected\";\n    if (hitPoint) {\n      const preliminaryResult = this.expectHitTarget(hitPoint, element);\n      if (preliminaryResult !== \"done\")\n        return preliminaryResult.hitTargetDescription;\n    }\n    if (action === \"drag\")\n      return { stop: () => \"done\" };\n    const events = {\n      \"hover\": kHoverHitTargetInterceptorEvents,\n      \"tap\": kTapHitTargetInterceptorEvents,\n      \"mouse\": kMouseHitTargetInterceptorEvents\n    }[action];\n    let result;\n    const listener = (event) => {\n      if (!events.has(event.type))\n        return;\n      if (!event.isTrusted)\n        return;\n      const point = !!this.window.TouchEvent && event instanceof this.window.TouchEvent ? event.touches[0] : event;\n      if (result === void 0 && point)\n        result = this.expectHitTarget({ x: point.clientX, y: point.clientY }, element);\n      if (blockAllEvents || result !== \"done\" && result !== void 0) {\n        event.preventDefault();\n        event.stopPropagation();\n        event.stopImmediatePropagation();\n      }\n    };\n    const stop = () => {\n      if (this._hitTargetInterceptor === listener)\n        this._hitTargetInterceptor = void 0;\n      return result || \"done\";\n    };\n    this._hitTargetInterceptor = listener;\n    return { stop };\n  }\n  dispatchEvent(node, type, eventInit) {\n    let event;\n    eventInit = { bubbles: true, cancelable: true, composed: true, ...eventInit };\n    switch (eventType.get(type)) {\n      case \"mouse\":\n        event = new MouseEvent(type, eventInit);\n        break;\n      case \"keyboard\":\n        event = new KeyboardEvent(type, eventInit);\n        break;\n      case \"touch\":\n        event = new TouchEvent(type, eventInit);\n        break;\n      case \"pointer\":\n        event = new PointerEvent(type, eventInit);\n        break;\n      case \"focus\":\n        event = new FocusEvent(type, eventInit);\n        break;\n      case \"drag\":\n        event = new DragEvent(type, eventInit);\n        break;\n      case \"wheel\":\n        event = new WheelEvent(type, eventInit);\n        break;\n      case \"deviceorientation\":\n        try {\n          event = new DeviceOrientationEvent(type, eventInit);\n        } catch {\n          const { bubbles, cancelable, alpha, beta, gamma, absolute } = eventInit;\n          event = this.document.createEvent(\"DeviceOrientationEvent\");\n          event.initDeviceOrientationEvent(type, bubbles, cancelable, alpha, beta, gamma, absolute);\n        }\n        break;\n      case \"devicemotion\":\n        try {\n          event = new DeviceMotionEvent(type, eventInit);\n        } catch {\n          const { bubbles, cancelable, acceleration, accelerationIncludingGravity, rotationRate, interval } = eventInit;\n          event = this.document.createEvent(\"DeviceMotionEvent\");\n          event.initDeviceMotionEvent(type, bubbles, cancelable, acceleration, accelerationIncludingGravity, rotationRate, interval);\n        }\n        break;\n      default:\n        event = new Event(type, eventInit);\n        break;\n    }\n    node.dispatchEvent(event);\n  }\n  previewNode(node) {\n    if (node.nodeType === Node.TEXT_NODE)\n      return oneLine(`#text=${node.nodeValue || \"\"}`);\n    if (node.nodeType !== Node.ELEMENT_NODE)\n      return oneLine(`<${node.nodeName.toLowerCase()} />`);\n    const element = node;\n    const attrs = [];\n    for (let i = 0; i < element.attributes.length; i++) {\n      const { name, value } = element.attributes[i];\n      if (name === \"style\")\n        continue;\n      if (!value && booleanAttributes.has(name))\n        attrs.push(` ${name}`);\n      else\n        attrs.push(` ${name}=\"${value}\"`);\n    }\n    attrs.sort((a, b) => a.length - b.length);\n    const attrText = trimStringWithEllipsis(attrs.join(\"\"), 50);\n    if (autoClosingTags.has(element.nodeName))\n      return oneLine(`<${element.nodeName.toLowerCase()}${attrText}/>`);\n    const children = element.childNodes;\n    let onlyText = false;\n    if (children.length <= 5) {\n      onlyText = true;\n      for (let i = 0; i < children.length; i++)\n        onlyText = onlyText && children[i].nodeType === Node.TEXT_NODE;\n    }\n    const text = onlyText ? element.textContent || \"\" : children.length ? \"\\u2026\" : \"\";\n    return oneLine(`<${element.nodeName.toLowerCase()}${attrText}>${trimStringWithEllipsis(text, 50)}</${element.nodeName.toLowerCase()}>`);\n  }\n  strictModeViolationError(selector, matches) {\n    const infos = matches.slice(0, 10).map((m) => ({\n      preview: this.previewNode(m),\n      selector: this.generateSelectorSimple(m)\n    }));\n    const lines = infos.map((info, i) => `\n    ${i + 1}) ${info.preview} aka ${asLocator(this._sdkLanguage, info.selector)}`);\n    if (infos.length < matches.length)\n      lines.push(\"\\n    ...\");\n    return this.createStacklessError(`strict mode violation: ${asLocator(this._sdkLanguage, stringifySelector(selector))} resolved to ${matches.length} elements:${lines.join(\"\")}\n`);\n  }\n  createStacklessError(message) {\n    if (this._browserName === \"firefox\") {\n      const error2 = new Error(\"Error: \" + message);\n      error2.stack = \"\";\n      return error2;\n    }\n    const error = new Error(message);\n    delete error.stack;\n    return error;\n  }\n  createHighlight() {\n    return new Highlight(this);\n  }\n  maskSelectors(selectors, color) {\n    if (this._highlight)\n      this.hideHighlight();\n    this._highlight = new Highlight(this);\n    this._highlight.install();\n    const elements = [];\n    for (const selector of selectors)\n      elements.push(this.querySelectorAll(selector, this.document.documentElement));\n    this._highlight.maskElements(elements.flat(), color);\n  }\n  highlight(selector) {\n    if (!this._highlight) {\n      this._highlight = new Highlight(this);\n      this._highlight.install();\n    }\n    this._highlight.runHighlightOnRaf(selector);\n  }\n  hideHighlight() {\n    if (this._highlight) {\n      this._highlight.uninstall();\n      delete this._highlight;\n    }\n  }\n  markTargetElements(markedElements, callId) {\n    const customEvent = new CustomEvent(\"__playwright_target__\", {\n      bubbles: true,\n      cancelable: true,\n      detail: callId,\n      composed: true\n    });\n    for (const element of markedElements)\n      element.dispatchEvent(customEvent);\n  }\n  _setupGlobalListenersRemovalDetection() {\n    const customEventName = \"__playwright_global_listeners_check__\";\n    let seenEvent = false;\n    const handleCustomEvent = () => seenEvent = true;\n    this.window.addEventListener(customEventName, handleCustomEvent);\n    new MutationObserver((entries) => {\n      const newDocumentElement = entries.some((entry) => Array.from(entry.addedNodes).includes(this.document.documentElement));\n      if (!newDocumentElement)\n        return;\n      seenEvent = false;\n      this.window.dispatchEvent(new CustomEvent(customEventName));\n      if (seenEvent)\n        return;\n      this.window.addEventListener(customEventName, handleCustomEvent);\n      for (const callback of this.onGlobalListenersRemoved)\n        callback();\n    }).observe(this.document, { childList: true });\n  }\n  _setupHitTargetInterceptors() {\n    const listener = (event) => {\n      var _a;\n      return (_a = this._hitTargetInterceptor) == null ? void 0 : _a.call(this, event);\n    };\n    const addHitTargetInterceptorListeners = () => {\n      for (const event of kAllHitTargetInterceptorEvents)\n        this.window.addEventListener(event, listener, { capture: true, passive: false });\n    };\n    addHitTargetInterceptorListeners();\n    this.onGlobalListenersRemoved.add(addHitTargetInterceptorListeners);\n  }\n  async expect(element, options, elements) {\n    const isArray = options.expression === \"to.have.count\" || options.expression.endsWith(\".array\");\n    if (isArray)\n      return this.expectArray(elements, options);\n    if (!element) {\n      if (!options.isNot && options.expression === \"to.be.hidden\")\n        return { matches: true };\n      if (options.isNot && options.expression === \"to.be.visible\")\n        return { matches: false };\n      if (!options.isNot && options.expression === \"to.be.detached\")\n        return { matches: true };\n      if (options.isNot && options.expression === \"to.be.attached\")\n        return { matches: false };\n      if (options.isNot && options.expression === \"to.be.in.viewport\")\n        return { matches: false };\n      return { matches: options.isNot, missingReceived: true };\n    }\n    return await this.expectSingleElement(element, options);\n  }\n  async expectSingleElement(element, options) {\n    var _a, _b;\n    const expression = options.expression;\n    {\n      let elementState;\n      if (expression === \"to.have.attribute\") {\n        elementState = element.hasAttribute(options.expressionArg);\n      } else if (expression === \"to.be.checked\") {\n        elementState = this.elementState(element, \"checked\");\n      } else if (expression === \"to.be.unchecked\") {\n        elementState = this.elementState(element, \"unchecked\");\n      } else if (expression === \"to.be.disabled\") {\n        elementState = this.elementState(element, \"disabled\");\n      } else if (expression === \"to.be.editable\") {\n        elementState = this.elementState(element, \"editable\");\n      } else if (expression === \"to.be.readonly\") {\n        elementState = !this.elementState(element, \"editable\");\n      } else if (expression === \"to.be.empty\") {\n        if (element.nodeName === \"INPUT\" || element.nodeName === \"TEXTAREA\")\n          elementState = !element.value;\n        else\n          elementState = !((_a = element.textContent) == null ? void 0 : _a.trim());\n      } else if (expression === \"to.be.enabled\") {\n        elementState = this.elementState(element, \"enabled\");\n      } else if (expression === \"to.be.focused\") {\n        elementState = this._activelyFocused(element).isFocused;\n      } else if (expression === \"to.be.hidden\") {\n        elementState = this.elementState(element, \"hidden\");\n      } else if (expression === \"to.be.visible\") {\n        elementState = this.elementState(element, \"visible\");\n      } else if (expression === \"to.be.attached\") {\n        elementState = true;\n      } else if (expression === \"to.be.detached\") {\n        elementState = false;\n      }\n      if (elementState !== void 0) {\n        if (elementState === \"error:notcheckbox\")\n          throw this.createStacklessError(\"Element is not a checkbox\");\n        if (elementState === \"error:notconnected\")\n          throw this.createStacklessError(\"Element is not connected\");\n        return { received: elementState, matches: elementState };\n      }\n    }\n    {\n      if (expression === \"to.have.property\") {\n        let target = element;\n        const properties = options.expressionArg.split(\".\");\n        for (let i = 0; i < properties.length - 1; i++) {\n          if (typeof target !== \"object\" || !(properties[i] in target))\n            return { received: void 0, matches: false };\n          target = target[properties[i]];\n        }\n        const received = target[properties[properties.length - 1]];\n        const matches = deepEquals(received, options.expectedValue);\n        return { received, matches };\n      }\n    }\n    {\n      if (expression === \"to.be.in.viewport\") {\n        const ratio = await this.viewportRatio(element);\n        return { received: `viewport ratio ${ratio}`, matches: ratio > 0 && ratio > ((_b = options.expectedNumber) != null ? _b : 0) - 1e-9 };\n      }\n    }\n    {\n      if (expression === \"to.have.values\") {\n        element = this.retarget(element, \"follow-label\");\n        if (element.nodeName !== \"SELECT\" || !element.multiple)\n          throw this.createStacklessError(\"Not a select element with a multiple attribute\");\n        const received = [...element.selectedOptions].map((o) => o.value);\n        if (received.length !== options.expectedText.length)\n          return { received, matches: false };\n        return { received, matches: received.map((r, i) => new ExpectedTextMatcher(options.expectedText[i]).matches(r)).every(Boolean) };\n      }\n    }\n    {\n      let received;\n      if (expression === \"to.have.attribute.value\") {\n        const value = element.getAttribute(options.expressionArg);\n        if (value === null)\n          return { received: null, matches: false };\n        received = value;\n      } else if (expression === \"to.have.class\") {\n        received = element.classList.toString();\n      } else if (expression === \"to.have.css\") {\n        received = this.window.getComputedStyle(element).getPropertyValue(options.expressionArg);\n      } else if (expression === \"to.have.id\") {\n        received = element.id;\n      } else if (expression === \"to.have.text\") {\n        received = options.useInnerText ? element.innerText : elementText(/* @__PURE__ */ new Map(), element).full;\n      } else if (expression === \"to.have.accessible.name\") {\n        received = getElementAccessibleName(\n          element,\n          false\n          /* includeHidden */\n        );\n      } else if (expression === \"to.have.accessible.description\") {\n        received = getElementAccessibleDescription(\n          element,\n          false\n          /* includeHidden */\n        );\n      } else if (expression === \"to.have.role\") {\n        received = getAriaRole(element) || \"\";\n      } else if (expression === \"to.have.title\") {\n        received = this.document.title;\n      } else if (expression === \"to.have.url\") {\n        received = this.document.location.href;\n      } else if (expression === \"to.have.value\") {\n        element = this.retarget(element, \"follow-label\");\n        if (element.nodeName !== \"INPUT\" && element.nodeName !== \"TEXTAREA\" && element.nodeName !== \"SELECT\")\n          throw this.createStacklessError(\"Not an input element\");\n        received = element.value;\n      }\n      if (received !== void 0 && options.expectedText) {\n        const matcher = new ExpectedTextMatcher(options.expectedText[0]);\n        return { received, matches: matcher.matches(received) };\n      }\n    }\n    throw this.createStacklessError(\"Unknown expect matcher: \" + expression);\n  }\n  expectArray(elements, options) {\n    const expression = options.expression;\n    if (expression === \"to.have.count\") {\n      const received2 = elements.length;\n      const matches = received2 === options.expectedNumber;\n      return { received: received2, matches };\n    }\n    let received;\n    if (expression === \"to.have.text.array\" || expression === \"to.contain.text.array\")\n      received = elements.map((e) => options.useInnerText ? e.innerText : elementText(/* @__PURE__ */ new Map(), e).full);\n    else if (expression === \"to.have.class.array\")\n      received = elements.map((e) => e.classList.toString());\n    if (received && options.expectedText) {\n      const lengthShouldMatch = expression !== \"to.contain.text.array\";\n      const matchesLength = received.length === options.expectedText.length || !lengthShouldMatch;\n      if (!matchesLength)\n        return { received, matches: false };\n      const matchers = options.expectedText.map((e) => new ExpectedTextMatcher(e));\n      let mIndex = 0, rIndex = 0;\n      while (mIndex < matchers.length && rIndex < received.length) {\n        if (matchers[mIndex].matches(received[rIndex]))\n          ++mIndex;\n        ++rIndex;\n      }\n      return { received, matches: mIndex === matchers.length };\n    }\n    throw this.createStacklessError(\"Unknown expect matcher: \" + expression);\n  }\n  getElementAccessibleName(element, includeHidden) {\n    return getElementAccessibleName(element, !!includeHidden);\n  }\n  getElementAccessibleDescription(element, includeHidden) {\n    return getElementAccessibleDescription(element, !!includeHidden);\n  }\n  getAriaRole(element) {\n    return getAriaRole(element);\n  }\n};\nvar autoClosingTags = /* @__PURE__ */ new Set([\"AREA\", \"BASE\", \"BR\", \"COL\", \"COMMAND\", \"EMBED\", \"HR\", \"IMG\", \"INPUT\", \"KEYGEN\", \"LINK\", \"MENUITEM\", \"META\", \"PARAM\", \"SOURCE\", \"TRACK\", \"WBR\"]);\nvar booleanAttributes = /* @__PURE__ */ new Set([\"checked\", \"selected\", \"disabled\", \"readonly\", \"multiple\"]);\nfunction oneLine(s) {\n  return s.replace(/\\n/g, \"\\u21B5\").replace(/\\t/g, \"\\u21C6\");\n}\nvar eventType = /* @__PURE__ */ new Map([\n  [\"auxclick\", \"mouse\"],\n  [\"click\", \"mouse\"],\n  [\"dblclick\", \"mouse\"],\n  [\"mousedown\", \"mouse\"],\n  [\"mouseeenter\", \"mouse\"],\n  [\"mouseleave\", \"mouse\"],\n  [\"mousemove\", \"mouse\"],\n  [\"mouseout\", \"mouse\"],\n  [\"mouseover\", \"mouse\"],\n  [\"mouseup\", \"mouse\"],\n  [\"mouseleave\", \"mouse\"],\n  [\"mousewheel\", \"mouse\"],\n  [\"keydown\", \"keyboard\"],\n  [\"keyup\", \"keyboard\"],\n  [\"keypress\", \"keyboard\"],\n  [\"textInput\", \"keyboard\"],\n  [\"touchstart\", \"touch\"],\n  [\"touchmove\", \"touch\"],\n  [\"touchend\", \"touch\"],\n  [\"touchcancel\", \"touch\"],\n  [\"pointerover\", \"pointer\"],\n  [\"pointerout\", \"pointer\"],\n  [\"pointerenter\", \"pointer\"],\n  [\"pointerleave\", \"pointer\"],\n  [\"pointerdown\", \"pointer\"],\n  [\"pointerup\", \"pointer\"],\n  [\"pointermove\", \"pointer\"],\n  [\"pointercancel\", \"pointer\"],\n  [\"gotpointercapture\", \"pointer\"],\n  [\"lostpointercapture\", \"pointer\"],\n  [\"focus\", \"focus\"],\n  [\"blur\", \"focus\"],\n  [\"drag\", \"drag\"],\n  [\"dragstart\", \"drag\"],\n  [\"dragend\", \"drag\"],\n  [\"dragover\", \"drag\"],\n  [\"dragenter\", \"drag\"],\n  [\"dragleave\", \"drag\"],\n  [\"dragexit\", \"drag\"],\n  [\"drop\", \"drag\"],\n  [\"wheel\", \"wheel\"],\n  [\"deviceorientation\", \"deviceorientation\"],\n  [\"deviceorientationabsolute\", \"deviceorientation\"],\n  [\"devicemotion\", \"devicemotion\"]\n]);\nvar kHoverHitTargetInterceptorEvents = /* @__PURE__ */ new Set([\"mousemove\"]);\nvar kTapHitTargetInterceptorEvents = /* @__PURE__ */ new Set([\"pointerdown\", \"pointerup\", \"touchstart\", \"touchend\", \"touchcancel\"]);\nvar kMouseHitTargetInterceptorEvents = /* @__PURE__ */ new Set([\"mousedown\", \"mouseup\", \"pointerdown\", \"pointerup\", \"click\", \"auxclick\", \"dblclick\", \"contextmenu\"]);\nvar kAllHitTargetInterceptorEvents = /* @__PURE__ */ new Set([...kHoverHitTargetInterceptorEvents, ...kTapHitTargetInterceptorEvents, ...kMouseHitTargetInterceptorEvents]);\nfunction cssUnquote(s) {\n  s = s.substring(1, s.length - 1);\n  if (!s.includes(\"\\\\\"))\n    return s;\n  const r = [];\n  let i = 0;\n  while (i < s.length) {\n    if (s[i] === \"\\\\\" && i + 1 < s.length)\n      i++;\n    r.push(s[i++]);\n  }\n  return r.join(\"\");\n}\nfunction createTextMatcher(selector, internal) {\n  if (selector[0] === \"/\" && selector.lastIndexOf(\"/\") > 0) {\n    const lastSlash = selector.lastIndexOf(\"/\");\n    const re = new RegExp(selector.substring(1, lastSlash), selector.substring(lastSlash + 1));\n    return { matcher: (elementText2) => re.test(elementText2.full), kind: \"regex\" };\n  }\n  const unquote = internal ? JSON.parse.bind(JSON) : cssUnquote;\n  let strict = false;\n  if (selector.length > 1 && selector[0] === '\"' && selector[selector.length - 1] === '\"') {\n    selector = unquote(selector);\n    strict = true;\n  } else if (internal && selector.length > 1 && selector[0] === '\"' && selector[selector.length - 2] === '\"' && selector[selector.length - 1] === \"i\") {\n    selector = unquote(selector.substring(0, selector.length - 1));\n    strict = false;\n  } else if (internal && selector.length > 1 && selector[0] === '\"' && selector[selector.length - 2] === '\"' && selector[selector.length - 1] === \"s\") {\n    selector = unquote(selector.substring(0, selector.length - 1));\n    strict = true;\n  } else if (selector.length > 1 && selector[0] === \"'\" && selector[selector.length - 1] === \"'\") {\n    selector = unquote(selector);\n    strict = true;\n  }\n  selector = normalizeWhiteSpace(selector);\n  if (strict) {\n    if (internal)\n      return { kind: \"strict\", matcher: (elementText2) => elementText2.normalized === selector };\n    const strictTextNodeMatcher = (elementText2) => {\n      if (!selector && !elementText2.immediate.length)\n        return true;\n      return elementText2.immediate.some((s) => normalizeWhiteSpace(s) === selector);\n    };\n    return { matcher: strictTextNodeMatcher, kind: \"strict\" };\n  }\n  selector = selector.toLowerCase();\n  return { kind: \"lax\", matcher: (elementText2) => elementText2.normalized.toLowerCase().includes(selector) };\n}\nvar ExpectedTextMatcher = class {\n  constructor(expected) {\n    this._normalizeWhiteSpace = expected.normalizeWhiteSpace;\n    this._ignoreCase = expected.ignoreCase;\n    this._string = expected.matchSubstring ? void 0 : this.normalize(expected.string);\n    this._substring = expected.matchSubstring ? this.normalize(expected.string) : void 0;\n    if (expected.regexSource) {\n      const flags = new Set((expected.regexFlags || \"\").split(\"\"));\n      if (expected.ignoreCase === false)\n        flags.delete(\"i\");\n      if (expected.ignoreCase === true)\n        flags.add(\"i\");\n      this._regex = new RegExp(expected.regexSource, [...flags].join(\"\"));\n    }\n  }\n  matches(text) {\n    if (!this._regex)\n      text = this.normalize(text);\n    if (this._string !== void 0)\n      return text === this._string;\n    if (this._substring !== void 0)\n      return text.includes(this._substring);\n    if (this._regex)\n      return !!this._regex.test(text);\n    return false;\n  }\n  normalize(s) {\n    if (!s)\n      return s;\n    if (this._normalizeWhiteSpace)\n      s = normalizeWhiteSpace(s);\n    if (this._ignoreCase)\n      s = s.toLocaleLowerCase();\n    return s;\n  }\n};\nfunction deepEquals(a, b) {\n  if (a === b)\n    return true;\n  if (a && b && typeof a === \"object\" && typeof b === \"object\") {\n    if (a.constructor !== b.constructor)\n      return false;\n    if (Array.isArray(a)) {\n      if (a.length !== b.length)\n        return false;\n      for (let i = 0; i < a.length; ++i) {\n        if (!deepEquals(a[i], b[i]))\n          return false;\n      }\n      return true;\n    }\n    if (a instanceof RegExp)\n      return a.source === b.source && a.flags === b.flags;\n    if (a.valueOf !== Object.prototype.valueOf)\n      return a.valueOf() === b.valueOf();\n    if (a.toString !== Object.prototype.toString)\n      return a.toString() === b.toString();\n    const keys = Object.keys(a);\n    if (keys.length !== Object.keys(b).length)\n      return false;\n    for (let i = 0; i < keys.length; ++i) {\n      if (!b.hasOwnProperty(keys[i]))\n        return false;\n    }\n    for (const key of keys) {\n      if (!deepEquals(a[key], b[key]))\n        return false;\n    }\n    return true;\n  }\n  if (typeof a === \"number\" && typeof b === \"number\")\n    return isNaN(a) && isNaN(b);\n  return false;\n}\n";

:: Command execute ::

Enter:
 
Select:
 

:: Search ::
  - regexp 

:: Upload ::
 
[ Read-Only ]

:: Make Dir ::
 
[ Read-Only ]
:: Make File ::
 
[ Read-Only ]

:: Go Dir ::
 
:: Go File ::
 

--[ c99shell v. 2.5 [PHP 8 Update] [24.05.2025] | Generation time: 0.0228 ]--