[
  {
    "path": ".editorconfig",
    "content": "[*]\nend_of_line = lf\ninsert_final_newline = true\nindent_style = space\nindent_size = 2\ntrim_trailing_whitespace = true\n\n[*.{js,css}]\ncharset = utf-8\n"
  },
  {
    "path": ".github/workflows/build.yml",
    "content": "on:\n  push:\n    branches:\n      - dev\n  pull_request:\n\njobs:\n  build:\n    name: Build\n    runs-on: ubuntu-latest\n\n    steps:\n      - uses: actions/checkout@v2\n\n      - name: Install, build and upload\n        uses: withastro/action@v0\n\n      - name: Upload artifacts\n        uses: actions/upload-pages-artifact@v1\n        with:\n          path: dist\n\n  publish:\n    name: Publish\n    needs: build\n    runs-on: ubuntu-latest\n    if: ${{ github.ref == 'refs/heads/dev' }}\n\n    permissions:\n      pages: write\n      id-token: write\n\n    environment:\n      name: github-pages\n      url: ${{ steps.deployment.outputs.page_url }}\n\n    steps:\n      - name: Deploy to GitHub Pages\n        id: deployment\n        uses: actions/deploy-pages@v1\n"
  },
  {
    "path": ".gitignore",
    "content": "node_modules\n.DS_Store\n.vscode\n.idea\n\n# Generated files\ndist\n"
  },
  {
    "path": ".prettierignore",
    "content": "# Generated files\ndist/*\n"
  },
  {
    "path": ".prettierrc.json",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"none\",\n  \"bracketSpacing\": false,\n  \"plugins\": [\"prettier-plugin-astro\"]\n}\n"
  },
  {
    "path": "LICENSE",
    "content": "Copyright (c) 2014 HubSpot, Inc.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n"
  },
  {
    "path": "README.md",
    "content": "# You Might Not Need jQuery\n\n![Build Workflow](https://github.com/HubSpot/youmightnotneedjquery/actions/workflows/build.yml/badge.svg)\n\nA resource for doing things _au naturel_.\n\n### [YouMightNotNeedjQuery.com](https://youmightnotneedjquery.com)\n\n## Contributing\n\nTo add a new section, just create a folder for it, and add `jquery.js`, and `ie8.js`, `ie9.js`, `ie10.js`, `ie11.js`, and `modern.js` (for Chrome/Safari/Firefox) as needed. For example, if you have `ie8.js` and `ie9.js`, the ie9 version will be shown to people looking for a solution that works in ie9, ie10, ie11, or modern JS.\n\n## Building\n\nBuilding YMNNJQ requires Node.js\n\n1. In the project directory, run `npm install`\n1. To build the project and watch for changes, run `npm run dev`.\n1. To build the project without watching for changes, use `npm run build`.\n"
  },
  {
    "path": "astro.config.ts",
    "content": "import {defineConfig} from 'astro/config';\nimport compress from 'astro-compress';\n\nexport default defineConfig({\n  integrations: [compress()]\n});\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"private\": true,\n  \"scripts\": {\n    \"dev\": \"astro dev\",\n    \"build\": \"astro build\",\n    \"format\": \"prettier -w .\"\n  },\n  \"devDependencies\": {\n    \"@astrojs/prism\": \"^1.0.1\",\n    \"@sindresorhus/class-names\": \"^2.0.0\",\n    \"@types/node\": \"^18.7.16\",\n    \"astro\": \"^1.1.7\",\n    \"astro-compress\": \"^1.0.7\",\n    \"modern-normalize\": \"^1.1.0\",\n    \"prettier\": \"^2.7.1\",\n    \"prettier-plugin-astro\": \"^0.5.4\",\n    \"readfiletree\": \"^1.0.0\",\n    \"sass\": \"^1.54.9\",\n    \"sort-keys\": \"^5.0.0\"\n  }\n}\n"
  },
  {
    "path": "src/comparisons/ajax/alternatives.json",
    "content": "{\n  \"fetch\": \"https://github.com/github/fetch\"\n}\n"
  },
  {
    "path": "src/comparisons/ajax/json/ie10.js",
    "content": "var request = new XMLHttpRequest();\nrequest.open('GET', '/my/url', true);\n\nrequest.onload = function () {\n  if (this.status >= 200 && this.status < 400) {\n    // Success!\n    var data = JSON.parse(this.response);\n  } else {\n    // We reached our target server, but it returned an error\n  }\n};\n\nrequest.onerror = function () {\n  // There was a connection error of some sort\n};\n\nrequest.send();\n"
  },
  {
    "path": "src/comparisons/ajax/json/ie8.js",
    "content": "var request = new XMLHttpRequest();\nrequest.open('GET', '/my/url', true);\n\nrequest.onreadystatechange = function () {\n  if (this.readyState === 4) {\n    if (this.status >= 200 && this.status < 400) {\n      // Success!\n      var data = JSON.parse(this.responseText);\n    } else {\n      // Error :(\n    }\n  }\n};\n\nrequest.send();\nrequest = null;\n"
  },
  {
    "path": "src/comparisons/ajax/json/ie9.js",
    "content": "var request = new XMLHttpRequest();\nrequest.open('GET', '/my/url', true);\n\nrequest.onload = function () {\n  if (request.status >= 200 && request.status < 400) {\n    // Success!\n    var data = JSON.parse(request.responseText);\n  } else {\n    // We reached our target server, but it returned an error\n  }\n};\n\nrequest.onerror = function () {\n  // There was a connection error of some sort\n};\n\nrequest.send();\n"
  },
  {
    "path": "src/comparisons/ajax/json/jquery.js",
    "content": "$.getJSON('/my/url', function (data) {});\n"
  },
  {
    "path": "src/comparisons/ajax/json/modern.js",
    "content": "const response = await fetch('/my/url');\nconst data = await response.json();\n"
  },
  {
    "path": "src/comparisons/ajax/load/ie8.js",
    "content": "function load(selector, path) {\n  var request = new XMLHttpRequest();\n  request.open('GET', path, true);\n  request.onreadystatechange = function () {\n    if (this.readyState === 4) {\n      if (this.status >= 200 && this.status < 400) {\n        // Success!\n        var elements = document.querySelector(selector);\n        for (var i = 0; i < elements.length; i++) {\n          elements[i].innerHTML = this.responseText;\n        }\n      } else {\n        // Error :(\n      }\n    }\n  };\n}\n\nload('#some.selector', '/path/to/template.html');\n"
  },
  {
    "path": "src/comparisons/ajax/load/jquery.js",
    "content": "$('#some.selector').load('/path/to/template.html');\n"
  },
  {
    "path": "src/comparisons/ajax/load/modern.js",
    "content": "const response = await fetch('/path/to/template.html');\nconst body = await response.text();\n\ndocument.querySelector('#some.selector').innerHTML = body;\n"
  },
  {
    "path": "src/comparisons/ajax/post/ie8.js",
    "content": "var request = new XMLHttpRequest();\nrequest.open('POST', '/my/url', true);\nrequest.setRequestHeader(\n  'Content-Type',\n  'application/x-www-form-urlencoded; charset=UTF-8'\n);\nrequest.send(data);\n"
  },
  {
    "path": "src/comparisons/ajax/post/jquery.js",
    "content": "$.ajax({\n  type: 'POST',\n  url: '/my/url',\n  data: data\n});\n"
  },
  {
    "path": "src/comparisons/ajax/post/modern.js",
    "content": "await fetch('/my/url', {\n  method: 'POST',\n  headers: {\n    'Content-Type': 'application/json'\n  },\n  body: JSON.stringify(data)\n});\n"
  },
  {
    "path": "src/comparisons/ajax/request/ie8.js",
    "content": "function request(success, error) {\n  var request = new XMLHttpRequest();\n  request.open('GET', '/my/url', true);\n\n  request.onreadystatechange = function () {\n    if (this.readyState === 4) {\n      if (this.status >= 200 && this.status < 400) {\n        // Success! If you expect this to be JSON, use JSON.parse!\n        success(this.responseText, this.status);\n      } else {\n        error();\n      }\n    }\n  };\n\n  request.send();\n}\n"
  },
  {
    "path": "src/comparisons/ajax/request/ie9.js",
    "content": "function request(success, error) {\n  var request = new XMLHttpRequest();\n  request.open('GET', '/my/url', true);\n\n  request.onload = function () {\n    if (this.status >= 200 && this.status < 400) {\n      // Success! If you expect this to be JSON, use JSON.parse!\n      success(this.responseText, this.status);\n    } else {\n      // We reached our target server, but it returned an error\n      error();\n    }\n  };\n\n  request.onerror = function () {\n    error();\n  };\n\n  request.send();\n}\n"
  },
  {
    "path": "src/comparisons/ajax/request/jquery.js",
    "content": "$.ajax({\n  type: 'GET',\n  url: '/my/url',\n  success: function (resp) {},\n  error: function () {}\n});\n"
  },
  {
    "path": "src/comparisons/ajax/request/modern.js",
    "content": "const response = await fetch('/my/url');\n\nif (!response.ok) {\n}\n\nconst body = await response.text();\n"
  },
  {
    "path": "src/comparisons/effects/alternatives.json",
    "content": "{\n  \"animate.css\": \"https://animate.style\",\n  \"move.js\": \"https://github.com/visionmedia/move.js\",\n  \"velocity.js\": \"https://julian.com/research/velocity/\"\n}\n"
  },
  {
    "path": "src/comparisons/effects/fade_in/ie10.css",
    "content": ".show {\n  transition: opacity 400ms;\n}\n.hide {\n  opacity: 0;\n}\n"
  },
  {
    "path": "src/comparisons/effects/fade_in/ie10.js",
    "content": "el.classList.add('show');\nel.classList.remove('hide');\n"
  },
  {
    "path": "src/comparisons/effects/fade_in/ie8.js",
    "content": "function fadeIn(el, speed = 400) {\n  var opacity = 0;\n\n  el.style.opacity = 0;\n  el.style.filter = '';\n\n  var last = +new Date();\n  var tick = function () {\n    opacity += (new Date() - last) / speed;\n    if (opacity > 1) opacity = 1;\n    el.style.opacity = opacity;\n    el.style.filter = 'alpha(opacity=' + (100 * opacity || 0) + ')';\n\n    last = +new Date();\n\n    if (opacity < 1) {\n      (window.requestAnimationFrame && requestAnimationFrame(tick)) ||\n        setTimeout(tick, 16);\n    }\n  };\n\n  tick();\n}\n\nfadeIn(el);\n"
  },
  {
    "path": "src/comparisons/effects/fade_in/ie9.js",
    "content": "function fadeIn(el, speed = 400) {\n  el.style.opacity = 0;\n\n  var last = +new Date();\n  var tick = function () {\n    el.style.opacity = +el.style.opacity + (new Date() - last) / speed;\n    if (opacity > 1) opacity = 1;\n    last = +new Date();\n\n    if (+el.style.opacity < 1) {\n      (window.requestAnimationFrame && requestAnimationFrame(tick)) ||\n        setTimeout(tick, 16);\n    }\n  };\n\n  tick();\n}\n\nfadeIn(el);\n"
  },
  {
    "path": "src/comparisons/effects/fade_in/jquery.js",
    "content": "$(el).fadeIn();\n"
  },
  {
    "path": "src/comparisons/effects/fade_in/modern.css",
    "content": ".show {\n  transition: opacity 400ms;\n}\n.hide {\n  opacity: 0;\n}\n"
  },
  {
    "path": "src/comparisons/effects/fade_in/modern.js",
    "content": "el.classList.replace('hide', 'show');\n"
  },
  {
    "path": "src/comparisons/effects/fade_out/ie10.css",
    "content": ".show {\n  opacity: 1;\n}\n.hide {\n  opacity: 0;\n  transition: opacity 400ms;\n}\n"
  },
  {
    "path": "src/comparisons/effects/fade_out/ie10.js",
    "content": "el.classList.add('hide');\nel.classList.remove('show');\n"
  },
  {
    "path": "src/comparisons/effects/fade_out/ie8.js",
    "content": "function fadeOut(el, speed = 400) {\n  var opacity = 1;\n\n  el.style.opacity = 1;\n  el.style.filter = '';\n\n  var last = +new Date();\n  var tick = function () {\n    opacity -= (new Date() - last) / speed;\n    if (opacity < 0) opacity = 0;\n    el.style.opacity = opacity;\n    el.style.filter = 'alpha(opacity=' + 100 * opacity + ')';\n\n    last = +new Date();\n\n    if (opacity > 0) {\n      (window.requestAnimationFrame && requestAnimationFrame(tick)) ||\n        setTimeout(tick, 16);\n    }\n  };\n\n  tick();\n}\n\nfadeOut(el);\n"
  },
  {
    "path": "src/comparisons/effects/fade_out/ie9.js",
    "content": "function fadeOut(el, speed = 400) {\n  el.style.opacity = 1;\n\n  var last = +new Date();\n  var tick = function () {\n    el.style.opacity = +el.style.opacity - (new Date() - last) / speed;\n    if (opacity < 0) opacity = 0;\n    last = +new Date();\n\n    if (+el.style.opacity > 0) {\n      (window.requestAnimationFrame && requestAnimationFrame(tick)) ||\n        setTimeout(tick, 16);\n    }\n  };\n\n  tick();\n}\n\nfadeOut(el);\n"
  },
  {
    "path": "src/comparisons/effects/fade_out/jquery.js",
    "content": "$(el).fadeOut();\n"
  },
  {
    "path": "src/comparisons/effects/fade_out/modern.css",
    "content": ".show {\n  opacity: 1;\n}\n.hide {\n  opacity: 0;\n  transition: opacity 400ms;\n}\n"
  },
  {
    "path": "src/comparisons/effects/fade_out/modern.js",
    "content": "el.classList.replace('show', 'hide');\n"
  },
  {
    "path": "src/comparisons/effects/hide/ie8.js",
    "content": "el.style.display = 'none';\n"
  },
  {
    "path": "src/comparisons/effects/hide/jquery.js",
    "content": "$(el).hide();\n"
  },
  {
    "path": "src/comparisons/effects/show/ie8.js",
    "content": "el.style.display = '';\n"
  },
  {
    "path": "src/comparisons/effects/show/jquery.js",
    "content": "$(el).show();\n"
  },
  {
    "path": "src/comparisons/effects/toggle/ie8.js",
    "content": "function toggle(el) {\n  if (el.style.display == 'none') {\n    el.style.display = '';\n  } else {\n    el.style.display = 'none';\n  }\n}\n"
  },
  {
    "path": "src/comparisons/effects/toggle/jquery.js",
    "content": "$(el).toggle();\n"
  },
  {
    "path": "src/comparisons/elements/add_class/ie10.js",
    "content": "el.classList.add(className);\n"
  },
  {
    "path": "src/comparisons/elements/add_class/ie8.js",
    "content": "if (el.classList) {\n  el.classList.add(className);\n} else {\n  var current = el.className,\n    found = false;\n  var all = current.split(' ');\n  for (var i = 0; i < all.length, !found; i++) found = all[i] === className;\n  if (!found) {\n    if (current === '') el.className = className;\n    else el.className += ' ' + className;\n  }\n}\n"
  },
  {
    "path": "src/comparisons/elements/add_class/jquery.js",
    "content": "$(el).addClass(className);\n"
  },
  {
    "path": "src/comparisons/elements/after/ie8.js",
    "content": "target.insertAdjacentElement('afterend', element);\n"
  },
  {
    "path": "src/comparisons/elements/after/jquery.js",
    "content": "$(target).after(element);\n"
  },
  {
    "path": "src/comparisons/elements/after/modern.js",
    "content": "target.after(element);\n"
  },
  {
    "path": "src/comparisons/elements/alternatives.json",
    "content": "{\n  \"bonzo\": \"https://github.com/ded/bonzo\",\n  \"$dom\": \"https://github.com/julienw/dollardom\"\n}\n"
  },
  {
    "path": "src/comparisons/elements/append/ie8.js",
    "content": "parent.appendChild(el);\n"
  },
  {
    "path": "src/comparisons/elements/append/jquery.js",
    "content": "$(parent).append(el);\n"
  },
  {
    "path": "src/comparisons/elements/append/modern.js",
    "content": "parent.append(el);\n"
  },
  {
    "path": "src/comparisons/elements/append_to/ie8.js",
    "content": "parent.appendChild(el);\n"
  },
  {
    "path": "src/comparisons/elements/append_to/jquery.js",
    "content": "$(el).appendTo(parent);\n"
  },
  {
    "path": "src/comparisons/elements/append_to/modern.js",
    "content": "parent.append(el);\n"
  },
  {
    "path": "src/comparisons/elements/before/ie8.js",
    "content": "target.insertAdjacentElement('beforebegin', element);\n"
  },
  {
    "path": "src/comparisons/elements/before/jquery.js",
    "content": "$(target).before(element);\n"
  },
  {
    "path": "src/comparisons/elements/before/modern.js",
    "content": "target.before(el);\n"
  },
  {
    "path": "src/comparisons/elements/children/ie8.js",
    "content": "var children = [];\nfor (var i = el.children.length; i--; ) {\n  // Skip comment nodes on IE8\n  if (el.children[i].nodeType != 8) children.unshift(el.children[i]);\n}\n"
  },
  {
    "path": "src/comparisons/elements/children/ie9.js",
    "content": "el.children;\n"
  },
  {
    "path": "src/comparisons/elements/children/jquery.js",
    "content": "$(el).children();\n"
  },
  {
    "path": "src/comparisons/elements/clone/ie8.js",
    "content": "el.cloneNode(true);\n"
  },
  {
    "path": "src/comparisons/elements/clone/jquery.js",
    "content": "$(el).clone();\n"
  },
  {
    "path": "src/comparisons/elements/closest/ie10.js",
    "content": "el.closest(sel);\n"
  },
  {
    "path": "src/comparisons/elements/closest/ie8.js",
    "content": "function closest(el, sel) {\n  Element.prototype.matches ||\n    (Element.prototype.matches =\n      Element.prototype.matchesSelector ||\n      Element.prototype.mozMatchesSelector ||\n      Element.prototype.msMatchesSelector ||\n      Element.prototype.oMatchesSelector ||\n      Element.prototype.webkitMatchesSelector ||\n      function (b) {\n        b = (this.document || this.ownerDocument).querySelectorAll(b);\n        for (var a = b.length; 0 <= --a && b.item(a) !== this; );\n        return -1 < a;\n      });\n  Element.prototype.closest ||\n    (Element.prototype.closest = function (b) {\n      var a = this;\n      do {\n        if (a.matches(b)) return a;\n        a = a.parentElement || a.parentNode;\n      } while (null !== a && 1 === a.nodeType);\n      return null;\n    });\n  return el.closest(sel);\n}\n\nclosest(el, sel);\n"
  },
  {
    "path": "src/comparisons/elements/closest/ie9.js",
    "content": "function closest(el, sel) {\n  Element.prototype.matches ||\n    (Element.prototype.matches =\n      Element.prototype.msMatchesSelector ||\n      Element.prototype.webkitMatchesSelector);\n  Element.prototype.closest ||\n    (Element.prototype.closest = function (c) {\n      var a = this;\n      do {\n        if (a.matches(c)) return a;\n        a = a.parentElement || a.parentNode;\n      } while (null !== a && 1 === a.nodeType);\n      return null;\n    });\n  return el.closest(sel);\n}\n\nclosest(el, sel);\n"
  },
  {
    "path": "src/comparisons/elements/closest/jquery.js",
    "content": "$(el).closest(sel);\n"
  },
  {
    "path": "src/comparisons/elements/contains/ie8.js",
    "content": "el !== child && el.contains(child);\n"
  },
  {
    "path": "src/comparisons/elements/contains/jquery.js",
    "content": "$.contains(el, child);\n"
  },
  {
    "path": "src/comparisons/elements/contains/modern.js",
    "content": "node.contains(anotherNode);\n"
  },
  {
    "path": "src/comparisons/elements/contains_selector/alternatives.json",
    "content": "{\n  \"xpath\": \"https://www.w3schools.com/xml/xpath_intro.asp\"\n}\n"
  },
  {
    "path": "src/comparisons/elements/contains_selector/jquery.js",
    "content": "$(\"div:contains('my text')\");\n"
  },
  {
    "path": "src/comparisons/elements/contains_selector/modern.js",
    "content": "[...document.querySelectorAll('div')].filter((el) =>\n  el.textContent.includes('my text')\n);\n"
  },
  {
    "path": "src/comparisons/elements/contents/jquery.js",
    "content": "$(el).contents();\n"
  },
  {
    "path": "src/comparisons/elements/contents/modern.js",
    "content": "el.childNodes;\n"
  },
  {
    "path": "src/comparisons/elements/create_elements/ie8.js",
    "content": "function generateElements(html) {\n  var div = document.createElement('div');\n  div.innerHTML = html;\n  return div.children;\n}\n\ngenerateElements('<div>Hello World!</div>');\n"
  },
  {
    "path": "src/comparisons/elements/create_elements/jquery.js",
    "content": "$('<div>Hello World!</div>');\n"
  },
  {
    "path": "src/comparisons/elements/create_elements/modern.js",
    "content": "function generateElements(html) {\n  const template = document.createElement('template');\n  template.innerHTML = html.trim();\n  return template.content.children;\n}\n\ngenerateElements('<div>Hello World!</div>');\n"
  },
  {
    "path": "src/comparisons/elements/each/ie8.js",
    "content": "function forEachElement(selector, fn) {\n  var elements = document.querySelectorAll(selector);\n  for (var i = 0; i < elements.length; i++) fn(elements[i], i);\n}\n\nforEachElement(selector, function (el, i) {});\n"
  },
  {
    "path": "src/comparisons/elements/each/ie9.js",
    "content": "var elements = document.querySelectorAll(selector);\nArray.prototype.forEach.call(elements, function (el, i) {});\n"
  },
  {
    "path": "src/comparisons/elements/each/jquery.js",
    "content": "$(selector).each(function (i, el) {});\n"
  },
  {
    "path": "src/comparisons/elements/each/modern.js",
    "content": "document.querySelectorAll(selector).forEach((el, i) => {});\n"
  },
  {
    "path": "src/comparisons/elements/empty/ie8.js",
    "content": "while (el.firstChild) el.removeChild(el.firstChild);\n"
  },
  {
    "path": "src/comparisons/elements/empty/jquery.js",
    "content": "$(el).empty();\n"
  },
  {
    "path": "src/comparisons/elements/empty/modern.js",
    "content": "el.replaceChildren();\n"
  },
  {
    "path": "src/comparisons/elements/filter/ie8.js",
    "content": "function filter(selector, filterFn) {\n  var elements = document.querySelectorAll(selector);\n  var out = [];\n  for (var i = elements.length; i--; ) {\n    if (filterFn(elements[i])) out.unshift(elements[i]);\n  }\n  return out;\n}\n\nfilter(selector, filterFn);\n"
  },
  {
    "path": "src/comparisons/elements/filter/ie9.js",
    "content": "Array.prototype.filter.call(document.querySelectorAll(selector), filterFn);\n"
  },
  {
    "path": "src/comparisons/elements/filter/jquery.js",
    "content": "$(selector).filter(filterFn);\n"
  },
  {
    "path": "src/comparisons/elements/filter/modern.js",
    "content": "[...document.querySelectorAll(selector)].filter(filterFn);\n"
  },
  {
    "path": "src/comparisons/elements/find_children/ie8.js",
    "content": "el.querySelectorAll(selector);\n"
  },
  {
    "path": "src/comparisons/elements/find_children/jquery.js",
    "content": "$(el).find(selector);\n"
  },
  {
    "path": "src/comparisons/elements/find_children/modern.js",
    "content": "// For direct descendants only, see https://developer.mozilla.org/en-US/docs/Web/API/Element/querySelectorAll#user_notes\nel.querySelectorAll(`:scope ${selector}`);\n"
  },
  {
    "path": "src/comparisons/elements/find_elements/alternatives.json",
    "content": "{\n  \"qwery\": \"https://github.com/ded/qwery\",\n  \"sizzle\": \"https://sizzlejs.com/\"\n}\n"
  },
  {
    "path": "src/comparisons/elements/find_elements/ie8.js",
    "content": "document.querySelectorAll('.my #awesome selector');\n"
  },
  {
    "path": "src/comparisons/elements/find_elements/jquery.js",
    "content": "$('.my #awesome selector');\n"
  },
  {
    "path": "src/comparisons/elements/find_selector/ie8.js",
    "content": "!!el.querySelector(selector);\n"
  },
  {
    "path": "src/comparisons/elements/find_selector/jquery.js",
    "content": "$(el).find(selector).length;\n"
  },
  {
    "path": "src/comparisons/elements/first/ie8.js",
    "content": "document.querySelector(el);\n"
  },
  {
    "path": "src/comparisons/elements/first/jquery.js",
    "content": "$(el).first();\n"
  },
  {
    "path": "src/comparisons/elements/get_attributes/ie8.js",
    "content": "el.getAttribute('tabindex');\n"
  },
  {
    "path": "src/comparisons/elements/get_attributes/jquery.js",
    "content": "$(el).attr('tabindex');\n"
  },
  {
    "path": "src/comparisons/elements/get_height/ie8.js",
    "content": "function getHeight(el) {\n  var d = /^\\d+(px)?$/i;\n  if (window.getComputedStyle)\n    el = parseFloat(getComputedStyle(el, null).height.replace('px', ''));\n  else {\n    var c = el.currentStyle.height;\n    if (d.test(c)) el = parseInt(c);\n    else {\n      d = el.style.left;\n      var e = el.runtimeStyle.left;\n      el.runtimeStyle.left = el.currentStyle.left;\n      el.style.left = c || 0;\n      c = el.style.pixelLeft;\n      el.style.left = d;\n      el.runtimeStyle.left = e;\n      el = c;\n    }\n  }\n  return el;\n}\n\ngetHeight(el);\n"
  },
  {
    "path": "src/comparisons/elements/get_height/ie9.js",
    "content": "parseFloat(getComputedStyle(el, null).height.replace('px', ''));\n"
  },
  {
    "path": "src/comparisons/elements/get_height/jquery.js",
    "content": "$(el).height();\n"
  },
  {
    "path": "src/comparisons/elements/get_height/modern.js",
    "content": "el.getBoundingClientRect().height;\n"
  },
  {
    "path": "src/comparisons/elements/get_html/ie8.js",
    "content": "el.innerHTML;\n"
  },
  {
    "path": "src/comparisons/elements/get_html/jquery.js",
    "content": "$(el).html();\n"
  },
  {
    "path": "src/comparisons/elements/get_outer_html/ie8.js",
    "content": "el.outerHTML;\n"
  },
  {
    "path": "src/comparisons/elements/get_outer_html/jquery.js",
    "content": "$(el).prop('outerHTML');\n"
  },
  {
    "path": "src/comparisons/elements/get_style/ie8.js",
    "content": "// Varies based on the properties being retrieved, some can be retrieved from el.currentStyle\n// https://github.com/jonathantneal/Polyfills-for-IE8/blob/master/getComputedStyle.js\n"
  },
  {
    "path": "src/comparisons/elements/get_style/ie9.js",
    "content": "getComputedStyle(el)[ruleName];\n"
  },
  {
    "path": "src/comparisons/elements/get_style/jquery.js",
    "content": "$(el).css(ruleName);\n"
  },
  {
    "path": "src/comparisons/elements/get_text/ie8.js",
    "content": "el.textContent || el.innerText;\n"
  },
  {
    "path": "src/comparisons/elements/get_text/ie9.js",
    "content": "el.textContent;\n"
  },
  {
    "path": "src/comparisons/elements/get_text/jquery.js",
    "content": "$(el).text();\n"
  },
  {
    "path": "src/comparisons/elements/get_width/ie8.js",
    "content": "function getWidth(el) {\n  var d = /^\\d+(px)?$/i;\n  if (window.getComputedStyle)\n    el = parseFloat(getComputedStyle(el, null).width.replace('px', ''));\n  else {\n    var c = el.currentStyle.width;\n    if (d.test(c)) el = parseInt(c);\n    else {\n      d = el.style.left;\n      var e = el.runtimeStyle.left;\n      el.runtimeStyle.left = el.currentStyle.left;\n      el.style.left = c || 0;\n      c = el.style.pixelLeft;\n      el.style.left = d;\n      el.runtimeStyle.left = e;\n      el = c;\n    }\n  }\n  return el;\n}\n\ngetWidth(el);\n"
  },
  {
    "path": "src/comparisons/elements/get_width/ie9.js",
    "content": "parseFloat(getComputedStyle(el, null).width.replace('px', ''));\n"
  },
  {
    "path": "src/comparisons/elements/get_width/jquery.js",
    "content": "$(el).width();\n"
  },
  {
    "path": "src/comparisons/elements/get_width/modern.js",
    "content": "el.getBoundingClientRect().width;\n"
  },
  {
    "path": "src/comparisons/elements/has_class/ie10.js",
    "content": "el.classList.contains(className);\n"
  },
  {
    "path": "src/comparisons/elements/has_class/ie8.js",
    "content": "if (el.classList) el.classList.contains(className);\nelse new RegExp('(^| )' + className + '( |$)', 'gi').test(el.className);\n"
  },
  {
    "path": "src/comparisons/elements/has_class/jquery.js",
    "content": "$(el).hasClass(className);\n"
  },
  {
    "path": "src/comparisons/elements/index/ie8.js",
    "content": "function index(el) {\n  if (!el) return -1;\n  var i = 0;\n  while (el) {\n    el = el.previousSibling;\n    if (el && el.nodeType === 1) i++;\n  }\n  return i;\n}\n"
  },
  {
    "path": "src/comparisons/elements/index/ie9.js",
    "content": "function index(el) {\n  if (!el) return -1;\n  var i = 0;\n  while ((el = el.previousElementSibling)) {\n    i++;\n  }\n  return i;\n}\n"
  },
  {
    "path": "src/comparisons/elements/index/jquery.js",
    "content": "$(el).index();\n"
  },
  {
    "path": "src/comparisons/elements/index/modern.js",
    "content": "[...el.parentNode.children].indexOf(el);\n"
  },
  {
    "path": "src/comparisons/elements/inner_height/jquery.js",
    "content": "$(el).innerHeight();\n$(el).innerHeight(150);\n"
  },
  {
    "path": "src/comparisons/elements/inner_height/modern.js",
    "content": "function innerHeight(el, value) {\n  if (value === undefined) {\n    return el.clientHeight;\n  } else {\n    el.style.height = value;\n  }\n}\n\ninnerHeight(el);\ninnerHeight(el, 150);\n"
  },
  {
    "path": "src/comparisons/elements/inner_width/jquery.js",
    "content": "$(el).innerWidth();\n$(el).innerWidth(150);\n"
  },
  {
    "path": "src/comparisons/elements/inner_width/modern.js",
    "content": "function innerWidth(el, value) {\n  if (value === undefined) {\n    return el.clientWidth;\n  } else {\n    el.style.width = value;\n  }\n}\n\ninnerWidth(el);\ninnerWidth(el, 150);\n"
  },
  {
    "path": "src/comparisons/elements/is_hidden/jquery.js",
    "content": "$(el).is(':hidden');\n"
  },
  {
    "path": "src/comparisons/elements/is_hidden/modern.js",
    "content": "function isHidden(el) {\n  return !(el.offsetWidth || el.offsetHeight || el.getClientRects().length);\n}\n"
  },
  {
    "path": "src/comparisons/elements/is_visible/jquery.js",
    "content": "$(el).is(':visible');\n"
  },
  {
    "path": "src/comparisons/elements/is_visible/modern.js",
    "content": "function isVisible(el) {\n  return !!(el.offsetWidth || el.offsetHeight || el.getClientRects().length);\n}\n"
  },
  {
    "path": "src/comparisons/elements/last/ie8.js",
    "content": "var els = document.querySelectorAll(el);\nels[els.length - 1];\n"
  },
  {
    "path": "src/comparisons/elements/last/jquery.js",
    "content": "$(el).last();\n"
  },
  {
    "path": "src/comparisons/elements/last/modern.js",
    "content": "[...document.querySelectorAll(el)].at(-1);\n"
  },
  {
    "path": "src/comparisons/elements/matches/ie8.js",
    "content": "el === otherEl;\n"
  },
  {
    "path": "src/comparisons/elements/matches/jquery.js",
    "content": "$(el).is($(otherEl));\n"
  },
  {
    "path": "src/comparisons/elements/matches_selector/ie8.js",
    "content": "var matches = function (el, selector) {\n  var _matches =\n    el.matches ||\n    el.matchesSelector ||\n    el.msMatchesSelector ||\n    el.mozMatchesSelector ||\n    el.webkitMatchesSelector ||\n    el.oMatchesSelector;\n\n  if (_matches) {\n    return _matches.call(el, selector);\n  } else {\n    if (el.parentNode === null) return false;\n    var nodes = el.parentNode.querySelectorAll(selector);\n    for (var i = nodes.length; i--; ) {\n      if (nodes[i] === el) return true;\n    }\n    return false;\n  }\n};\n\nmatches(el, '.my-class');\n"
  },
  {
    "path": "src/comparisons/elements/matches_selector/ie9.js",
    "content": "var matches = function (el, selector) {\n  return (\n    el.matches ||\n    el.matchesSelector ||\n    el.msMatchesSelector ||\n    el.mozMatchesSelector ||\n    el.webkitMatchesSelector ||\n    el.oMatchesSelector\n  ).call(el, selector);\n};\n\nmatches(el, '.my-class');\n"
  },
  {
    "path": "src/comparisons/elements/matches_selector/jquery.js",
    "content": "$(el).is('.my-class');\n"
  },
  {
    "path": "src/comparisons/elements/matches_selector/modern.js",
    "content": "el.matches('.my-class');\n"
  },
  {
    "path": "src/comparisons/elements/next/ie8.js",
    "content": "// nextSibling can include text nodes\nfunction nextElementSibling(el) {\n  do {\n    el = el.nextSibling;\n  } while (el && el.nodeType !== 1);\n  return el;\n}\n\nel.nextElementSibling || nextElementSibling(el);\n"
  },
  {
    "path": "src/comparisons/elements/next/ie9.js",
    "content": "el.nextElementSibling;\n"
  },
  {
    "path": "src/comparisons/elements/next/jquery.js",
    "content": "$(el).next();\n"
  },
  {
    "path": "src/comparisons/elements/next/modern.js",
    "content": "function next(el, selector) {\n  const nextEl = el.nextElementSibling;\n  if (!selector || (nextEl && nextEl.matches(selector))) {\n    return nextEl;\n  }\n  return null;\n}\n\nnext(el);\n// Or, with an optional selector\nnext(el, '.my-selector');\n"
  },
  {
    "path": "src/comparisons/elements/offset/ie8.js",
    "content": "function offset(el) {\n  var docElem = document.documentElement;\n  var rect = el.getBoundingClientRect();\n  return {\n    top:\n      rect.top +\n      (window.pageYOffset || docElem.scrollTop) -\n      (docElem.clientTop || 0),\n    left:\n      rect.left +\n      (window.pageXOffset || docElem.scrollLeft) -\n      (docElem.clientLeft || 0)\n  };\n}\n"
  },
  {
    "path": "src/comparisons/elements/offset/ie9.js",
    "content": "function offset(el) {\n  box = el.getBoundingClientRect();\n  docElem = document.documentElement;\n  return {\n    top: box.top + window.pageYOffset - docElem.clientTop,\n    left: box.left + window.pageXOffset - docElem.clientLeft\n  };\n}\n"
  },
  {
    "path": "src/comparisons/elements/offset/jquery.js",
    "content": "$(el).offset();\n"
  },
  {
    "path": "src/comparisons/elements/offset_parent/ie8.js",
    "content": "el.offsetParent || el;\n"
  },
  {
    "path": "src/comparisons/elements/offset_parent/jquery.js",
    "content": "$(el).offsetParent();\n"
  },
  {
    "path": "src/comparisons/elements/outer_height/ie8.js",
    "content": "el.offsetHeight;\n"
  },
  {
    "path": "src/comparisons/elements/outer_height/jquery.js",
    "content": "$(el).outerHeight();\n"
  },
  {
    "path": "src/comparisons/elements/outer_height_with_margin/ie8.js",
    "content": "function outerHeight(el) {\n  var height = el.offsetHeight;\n  var style = el.currentStyle || getComputedStyle(el);\n\n  height += parseFloat(style.marginTop) + parseFloat(style.marginBottom);\n  return height;\n}\n\nouterHeight(el);\n"
  },
  {
    "path": "src/comparisons/elements/outer_height_with_margin/ie9.js",
    "content": "function outerHeight(el) {\n  var height = el.offsetHeight;\n  var style = getComputedStyle(el);\n\n  height += parseFloat(style.marginTop) + parseFloat(style.marginBottom);\n  return height;\n}\n\nouterHeight(el);\n"
  },
  {
    "path": "src/comparisons/elements/outer_height_with_margin/jquery.js",
    "content": "$(el).outerHeight(true);\n"
  },
  {
    "path": "src/comparisons/elements/outer_height_with_margin/modern.js",
    "content": "function outerHeight(el) {\n  const style = getComputedStyle(el);\n\n  return (\n    el.getBoundingClientRect().height +\n    parseFloat(style.marginTop) +\n    parseFloat(style.marginBottom)\n  );\n}\n\nouterHeight(el);\n"
  },
  {
    "path": "src/comparisons/elements/outer_width/ie8.js",
    "content": "el.offsetWidth;\n"
  },
  {
    "path": "src/comparisons/elements/outer_width/jquery.js",
    "content": "$(el).outerWidth();\n"
  },
  {
    "path": "src/comparisons/elements/outer_width_with_margin/ie8.js",
    "content": "function outerWidth(el) {\n  var width = el.offsetWidth;\n  var style = el.currentStyle || getComputedStyle(el);\n\n  width += parseFloat(style.marginLeft) + parseFloat(style.marginRight);\n  return width;\n}\n\nouterWidth(el);\n"
  },
  {
    "path": "src/comparisons/elements/outer_width_with_margin/ie9.js",
    "content": "function outerWidth(el) {\n  var width = el.offsetWidth;\n  var style = getComputedStyle(el);\n\n  width += parseFloat(style.marginLeft) + parseFloat(style.marginRight);\n  return width;\n}\n\nouterWidth(el);\n"
  },
  {
    "path": "src/comparisons/elements/outer_width_with_margin/jquery.js",
    "content": "$(el).outerWidth(true);\n"
  },
  {
    "path": "src/comparisons/elements/outer_width_with_margin/modern.js",
    "content": "function outerWidth(el) {\n  const style = getComputedStyle(el);\n\n  return (\n    el.getBoundingClientRect().width +\n    parseFloat(style.marginLeft) +\n    parseFloat(style.marginRight)\n  );\n}\n\nouterWidth(el);\n"
  },
  {
    "path": "src/comparisons/elements/parent/ie8.js",
    "content": "el.parentNode;\n"
  },
  {
    "path": "src/comparisons/elements/parent/jquery.js",
    "content": "$(el).parent();\n"
  },
  {
    "path": "src/comparisons/elements/parents/ie9.js",
    "content": "function parents(el, selector) {\n  var parents = [];\n  while ((el = el.parentNode) && el !== document) {\n    // See \"Matches Selector\" above\n    if (!selector || matches(el, selector)) parents.push(el);\n  }\n  return parents;\n}\n"
  },
  {
    "path": "src/comparisons/elements/parents/jquery.js",
    "content": "$(el).parents(selector);\n"
  },
  {
    "path": "src/comparisons/elements/parents/modern.js",
    "content": "function parents(el, selector) {\n  const parents = [];\n  while ((el = el.parentNode) && el !== document) {\n    if (!selector || el.matches(selector)) parents.push(el);\n  }\n  return parents;\n}\n"
  },
  {
    "path": "src/comparisons/elements/position/ie8.js",
    "content": "function position(el) {\n  var box = el.getBoundingClientRect();\n  var docElem = document.documentElement;\n  var marginLeft = 0;\n  var marginTop = 0;\n  if (typeof getComputedStyle === 'function') {\n    var style = window.getComputedStyle(el);\n    marginLeft = parseInt(style.marginLeft, 10);\n    marginTop = parseInt(style.marginTop, 10);\n  } else if (el.currentStyle) {\n    marginLeft = el.currentStyle['marginLeft']\n      ? parseInt(el.currentStyle['marginLeft'], 10)\n      : 0;\n    marginTop = el.currentStyle['marginTop']\n      ? parseInt(el.currentStyle['marginTop'], 10)\n      : 0;\n  }\n  return {\n    top: box.top + (window.pageYOffset || docElem.scrollTop) - marginTop,\n    left: box.left + (window.pageXOffset || docElem.scrollLeft) - marginLeft\n  };\n}\n"
  },
  {
    "path": "src/comparisons/elements/position/jquery.js",
    "content": "$(el).position();\n"
  },
  {
    "path": "src/comparisons/elements/position/modern.js",
    "content": "function position(el) {\n  const {top, left} = el.getBoundingClientRect();\n  const {marginTop, marginLeft} = getComputedStyle(el);\n  return {\n    top: top - parseInt(marginTop, 10),\n    left: left - parseInt(marginLeft, 10)\n  };\n}\n"
  },
  {
    "path": "src/comparisons/elements/position_relative_to_viewport/ie8.js",
    "content": "el.getBoundingClientRect();\n"
  },
  {
    "path": "src/comparisons/elements/position_relative_to_viewport/jquery.js",
    "content": "function offset(el) {\n  var offset = $(el).offset();\n  return {\n    top: offset.top - document.body.scrollTop,\n    left: offset.left - document.body.scrollLeft\n  };\n}\n"
  },
  {
    "path": "src/comparisons/elements/prepend/ie8.js",
    "content": "parent.insertBefore(el, parent.firstChild);\n"
  },
  {
    "path": "src/comparisons/elements/prepend/jquery.js",
    "content": "$(parent).prepend(el);\n"
  },
  {
    "path": "src/comparisons/elements/prepend/modern.js",
    "content": "parent.prepend(el);\n"
  },
  {
    "path": "src/comparisons/elements/prev/ie8.js",
    "content": "// prevSibling can include text nodes\nfunction previousElementSibling(el) {\n  do {\n    el = el.previousSibling;\n  } while (el && el.nodeType !== 1);\n  return el;\n}\n\nel.previousElementSibling || previousElementSibling(el);\n"
  },
  {
    "path": "src/comparisons/elements/prev/ie9.js",
    "content": "el.previousElementSibling;\n"
  },
  {
    "path": "src/comparisons/elements/prev/jquery.js",
    "content": "$(el).prev();\n// Or, with an optional selector\n$(el).prev('.my-selector');\n"
  },
  {
    "path": "src/comparisons/elements/prev/modern.js",
    "content": "function prev(el, selector) {\n  const prevEl = el.previousElementSibling;\n  if (!selector || (prevEl && prevEl.matches(selector))) {\n    return prevEl;\n  }\n  return null;\n}\n\nprev(el);\n// Or, with an optional selector\nprev(el, '.my-selector');\n"
  },
  {
    "path": "src/comparisons/elements/remove/ie8.js",
    "content": "if (el.parentNode !== null) {\n  el.parentNode.removeChild(el);\n}\n"
  },
  {
    "path": "src/comparisons/elements/remove/jquery.js",
    "content": "$(el).remove();\n\n// multiple elements\n$(selector).remove();\n"
  },
  {
    "path": "src/comparisons/elements/remove/modern.js",
    "content": "el.remove();\n\n// multiple elements\nfor (const el of document.querySelectorAll(selector)) {\n  el.remove();\n}\n"
  },
  {
    "path": "src/comparisons/elements/remove_attributes/ie8.js",
    "content": "el.removeAttribute('tabindex');\n"
  },
  {
    "path": "src/comparisons/elements/remove_attributes/jquery.js",
    "content": "$(el).removeAttr('tabindex');\n"
  },
  {
    "path": "src/comparisons/elements/remove_class/ie10.js",
    "content": "el.classList.remove(className);\n"
  },
  {
    "path": "src/comparisons/elements/remove_class/ie8.js",
    "content": "function removeClass(el, className) {\n  var classes = className.split(' ');\n  for (var i = 0; i < classes.length; i++) {\n    if (el.classList) {\n      el.classList.remove(classes[i]);\n    } else {\n      el.className = el.className\n        .replace(new RegExp('(?:^|\\\\s)' + classes[i] + '(?:\\\\s|$)'), ' ')\n        .replace(new RegExp(/^\\s+|\\s+$/g), '');\n    }\n  }\n}\n"
  },
  {
    "path": "src/comparisons/elements/remove_class/jquery.js",
    "content": "$(el).removeClass(className);\n"
  },
  {
    "path": "src/comparisons/elements/replace_from_html/ie8.js",
    "content": "el.outerHTML = string;\n"
  },
  {
    "path": "src/comparisons/elements/replace_from_html/jquery.js",
    "content": "$(el).replaceWith(string);\n"
  },
  {
    "path": "src/comparisons/elements/scroll_left/jquery.js",
    "content": "$(window).scrollLeft();\n"
  },
  {
    "path": "src/comparisons/elements/scroll_left/modern.js",
    "content": "function scrollLeft(el, value) {\n  var win;\n  if (el.window === el) {\n    win = el;\n  } else if (el.nodeType === 9) {\n    win = el.defaultView;\n  }\n\n  if (value === undefined) {\n    return win ? win.pageXOffset : el.scrollLeft;\n  }\n\n  if (win) {\n    win.scrollTo(value, win.pageYOffset);\n  } else {\n    el.scrollLeft = value;\n  }\n}\n"
  },
  {
    "path": "src/comparisons/elements/scroll_top/jquery.js",
    "content": "$(window).scrollTop();\n"
  },
  {
    "path": "src/comparisons/elements/scroll_top/modern.js",
    "content": "function scrollTop(el, value) {\n  var win;\n  if (el.window === el) {\n    win = el;\n  } else if (el.nodeType === 9) {\n    win = el.defaultView;\n  }\n\n  if (value === undefined) {\n    return win ? win.pageYOffset : el.scrollTop;\n  }\n\n  if (win) {\n    win.scrollTo(win.pageXOffset, value);\n  } else {\n    el.scrollTop = value;\n  }\n}\n"
  },
  {
    "path": "src/comparisons/elements/serialize/jquery.js",
    "content": "$(formElement).serialize();\n"
  },
  {
    "path": "src/comparisons/elements/serialize/modern.js",
    "content": "new URLSearchParams(new FormData(formElement)).toString();\n"
  },
  {
    "path": "src/comparisons/elements/set_attributes/ie8.js",
    "content": "el.setAttribute('tabindex', 3);\n"
  },
  {
    "path": "src/comparisons/elements/set_attributes/jquery.js",
    "content": "$(el).attr('tabindex', 3);\n"
  },
  {
    "path": "src/comparisons/elements/set_height/ie8.js",
    "content": "function setHeight(el, val) {\n  if (typeof val === 'function') val = val();\n  if (typeof val === 'string') el.style.height = val;\n  else el.style.height = val + 'px';\n}\n\nsetHeight(el, val);\n"
  },
  {
    "path": "src/comparisons/elements/set_height/jquery.js",
    "content": "$(el).height(val);\n"
  },
  {
    "path": "src/comparisons/elements/set_html/ie8.js",
    "content": "el.innerHTML = string;\n"
  },
  {
    "path": "src/comparisons/elements/set_html/jquery.js",
    "content": "$(el).html(string);\n"
  },
  {
    "path": "src/comparisons/elements/set_style/ie8.js",
    "content": "// Use a class if possible\nel.style.borderWidth = '20px';\n"
  },
  {
    "path": "src/comparisons/elements/set_style/jquery.js",
    "content": "$(el).css('border-width', '20px');\n"
  },
  {
    "path": "src/comparisons/elements/set_text/ie8.js",
    "content": "if (el.textContent !== undefined) el.textContent = string;\nelse el.innerText = string;\n"
  },
  {
    "path": "src/comparisons/elements/set_text/ie9.js",
    "content": "el.textContent = string;\n"
  },
  {
    "path": "src/comparisons/elements/set_text/jquery.js",
    "content": "$(el).text(string);\n"
  },
  {
    "path": "src/comparisons/elements/set_width/ie8.js",
    "content": "function setWidth(el, val) {\n  if (typeof val === 'function') val = val();\n  if (typeof val === 'string') el.style.width = val;\n  else el.style.width = val + 'px';\n}\n\nsetWidth(el, val);\n"
  },
  {
    "path": "src/comparisons/elements/set_width/jquery.js",
    "content": "$(el).width(val);\n"
  },
  {
    "path": "src/comparisons/elements/siblings/ie8.js",
    "content": "var siblings = function (el) {\n  if (el.parentNode === null) return [];\n\n  var siblingElements = Array.prototype.slice.call(el.parentNode.children);\n\n  for (var i = siblingElements.length; i--; ) {\n    if (siblingElements[i] === el) {\n      return siblingElements.splice(i, 1);\n    }\n  }\n\n  return siblingElements;\n};\n\nsiblings(el);\n"
  },
  {
    "path": "src/comparisons/elements/siblings/ie9.js",
    "content": "var siblings = function (el) {\n  if (el.parentNode === null) return [];\n\n  return Array.prototype.filter.call(el.parentNode.children, function (child) {\n    return child !== el;\n  });\n};\n\nsiblings(el);\n"
  },
  {
    "path": "src/comparisons/elements/siblings/jquery.js",
    "content": "$(el).siblings();\n"
  },
  {
    "path": "src/comparisons/elements/siblings/modern.js",
    "content": "[...el.parentNode.children].filter((child) => child !== el);\n"
  },
  {
    "path": "src/comparisons/elements/toggle_class/ie10.js",
    "content": "el.classList.toggle(className);\n"
  },
  {
    "path": "src/comparisons/elements/toggle_class/ie8.js",
    "content": "if (el.classList) {\n  el.classList.toggle(className);\n} else {\n  var classes = el.className.split(' ');\n  var existingIndex = -1;\n  for (var i = classes.length; i--; ) {\n    if (classes[i] === className) existingIndex = i;\n  }\n\n  if (existingIndex >= 0) classes.splice(existingIndex, 1);\n  else classes.push(className);\n\n  el.className = classes.join(' ');\n}\n"
  },
  {
    "path": "src/comparisons/elements/toggle_class/ie9.js",
    "content": "if (el.classList) {\n  el.classList.toggle(className);\n} else {\n  var classes = el.className.split(' ');\n  var existingIndex = classes.indexOf(className);\n\n  if (existingIndex >= 0) classes.splice(existingIndex, 1);\n  else classes.push(className);\n\n  el.className = classes.join(' ');\n}\n"
  },
  {
    "path": "src/comparisons/elements/toggle_class/jquery.js",
    "content": "$(el).toggleClass(className);\n"
  },
  {
    "path": "src/comparisons/elements/unwrap/jquery.js",
    "content": "$(el).unwrap();\n"
  },
  {
    "path": "src/comparisons/elements/unwrap/modern.js",
    "content": "el.replaceWith(...el.childNodes);\n"
  },
  {
    "path": "src/comparisons/elements/val/jquery.js",
    "content": "$(el).val();\n"
  },
  {
    "path": "src/comparisons/elements/val/modern.js",
    "content": "function val(el) {\n  if (el.options && el.multiple) {\n    return el.options\n      .filter((option) => option.selected)\n      .map((option) => option.value);\n  } else {\n    return el.value;\n  }\n}\n"
  },
  {
    "path": "src/comparisons/elements/wrap/jquery.js",
    "content": "el.wrap('<div></div>');\n"
  },
  {
    "path": "src/comparisons/elements/wrap/modern.js",
    "content": "function wrap(el) {\n  const wrappingElement = document.createElement('div');\n  el.replaceWith(wrappingElement);\n  wrappingElement.appendChild(el);\n}\n"
  },
  {
    "path": "src/comparisons/events/alternatives.json",
    "content": "{\n  \"ftdomdelegate\": \"https://github.com/ftlabs/ftdomdelegate\",\n  \"defer\": \"https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script#attr-defer\",\n  \"modules\": \"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules\"\n}\n"
  },
  {
    "path": "src/comparisons/events/click/ie8.js",
    "content": "var onClick = function (element, handler) {\n  if (element.addEventListener) {\n    element.addEventListener('click', handler, false);\n  } else {\n    element.attachEvent('onclick', handler);\n  }\n};\n\nonClick(el, function () {});\n"
  },
  {
    "path": "src/comparisons/events/click/ie9.js",
    "content": "el.addEventListener('click', function () {});\n"
  },
  {
    "path": "src/comparisons/events/click/jquery.js",
    "content": "$(el).click(function () {});\n"
  },
  {
    "path": "src/comparisons/events/click/modern.js",
    "content": "el.addEventListener('click', () => {});\n"
  },
  {
    "path": "src/comparisons/events/delegate/ie8.js",
    "content": "document.addEventListener(\n  eventName,\n  function (e) {\n    // loop parent nodes from the target to the delegation node\n    for (\n      var target = e.target;\n      target && target != this;\n      target = target.parentNode\n    ) {\n      if (target.matches(elementSelector)) {\n        handler.call(target, e);\n        break;\n      }\n    }\n  },\n  false\n);\n"
  },
  {
    "path": "src/comparisons/events/delegate/jquery.js",
    "content": "$(document).on(eventName, elementSelector, handler);\n"
  },
  {
    "path": "src/comparisons/events/delegate/modern.js",
    "content": "document.addEventListener(eventName, (event) => {\n  if (event.target.closest(elementSelector)) {\n    handler.call(event.target, event);\n  }\n});\n"
  },
  {
    "path": "src/comparisons/events/off/ie8.js",
    "content": "function removeEventListener(el, eventName, handler) {\n  if (el.removeEventListener) el.removeEventListener(eventName, handler);\n  else el.detachEvent('on' + eventName, handler);\n}\n\nremoveEventListener(el, eventName, handler);\n"
  },
  {
    "path": "src/comparisons/events/off/ie9.js",
    "content": "el.removeEventListener(eventName, eventHandler);\n"
  },
  {
    "path": "src/comparisons/events/off/jquery.js",
    "content": "$(el).off(eventName, eventHandler);\n"
  },
  {
    "path": "src/comparisons/events/on/ie8.js",
    "content": "function addEventListener(el, eventName, handler) {\n  if (el.addEventListener) {\n    el.addEventListener(eventName, handler);\n    return handler;\n  } else {\n    var wrappedHandler = function (event) {\n      handler.call(el, event);\n    };\n    el.attachEvent('on' + eventName, wrappedHandler);\n    return wrappedHandler;\n  }\n}\n\n// Use the return value to remove that event listener, see #off\nvar handlerToRemove = addEventListener(el, eventName, handler);\n"
  },
  {
    "path": "src/comparisons/events/on/ie9.js",
    "content": "function addEventListener(el, eventName, eventHandler, selector) {\n  if (selector) {\n    var wrappedHandler = function (e) {\n      if (e.target && e.target.matches(selector)) {\n        eventHandler(e);\n      }\n    };\n    el.addEventListener(eventName, wrappedHandler);\n    return wrappedHandler;\n  } else {\n    el.addEventListener(eventName, eventHandler);\n    return eventHandler;\n  }\n}\n\n// Use the return value to remove that event listener, see #off\naddEventListener(el, eventName, eventHandler);\n// Or when you want to delegate event handling\naddEventListener(el, eventName, eventHandler, selector);\n"
  },
  {
    "path": "src/comparisons/events/on/jquery.js",
    "content": "$(el).on(eventName, eventHandler);\n// Or when you want to delegate event handling\n$(el).on(eventName, selector, eventHandler);\n"
  },
  {
    "path": "src/comparisons/events/on/modern.js",
    "content": "function addEventListener(el, eventName, eventHandler, selector) {\n  if (selector) {\n    const wrappedHandler = (e) => {\n      if (!e.target) return;\n      const el = e.target.closest(selector);\n      if (el) {\n        eventHandler.call(el, e);\n      }\n    };\n    el.addEventListener(eventName, wrappedHandler);\n    return wrappedHandler;\n  } else {\n    const wrappedHandler = (e) => {\n      eventHandler.call(el, e);\n    };\n    el.addEventListener(eventName, wrappedHandler);\n    return wrappedHandler;\n  }\n}\n\n// Use the return value to remove that event listener, see #off\naddEventListener(el, eventName, eventHandler);\n// Or when you want to delegate event handling\naddEventListener(el, eventName, eventHandler, selector);\n"
  },
  {
    "path": "src/comparisons/events/ready/ie8.js",
    "content": "function ready(fn) {\n  if (document.readyState != 'loading') {\n    fn();\n  } else if (document.addEventListener) {\n    document.addEventListener('DOMContentLoaded', fn);\n  } else {\n    document.attachEvent('onreadystatechange', function () {\n      if (document.readyState != 'loading') fn();\n    });\n  }\n}\n"
  },
  {
    "path": "src/comparisons/events/ready/ie9.js",
    "content": "function ready(fn) {\n  if (\n    document.attachEvent\n      ? document.readyState === 'complete'\n      : document.readyState !== 'loading'\n  ) {\n    fn();\n  } else {\n    document.addEventListener('DOMContentLoaded', fn);\n  }\n}\n"
  },
  {
    "path": "src/comparisons/events/ready/jquery.js",
    "content": "$(document).ready(function () {});\n"
  },
  {
    "path": "src/comparisons/events/ready/modern.js",
    "content": "function ready(fn) {\n  if (document.readyState !== 'loading') {\n    fn();\n  } else {\n    document.addEventListener('DOMContentLoaded', fn);\n  }\n}\n"
  },
  {
    "path": "src/comparisons/events/trigger_custom/alternatives.json",
    "content": "{\n  \"EventEmitter\": \"https://github.com/Wolfy87/EventEmitter\",\n  \"Vine\": \"https://github.com/arextar/Vine\",\n  \"microevent\": \"https://github.com/jeromeetienne/microevent.js\"\n}\n"
  },
  {
    "path": "src/comparisons/events/trigger_custom/ie8.js",
    "content": "// Custom events are not natively supported, so you have to hijack a random\n// event.\n//\n// Just use jQuery.\n"
  },
  {
    "path": "src/comparisons/events/trigger_custom/ie9.js",
    "content": "if (window.CustomEvent && typeof window.CustomEvent === 'function') {\n  var event = new CustomEvent('my-event', {detail: {some: 'data'}});\n} else {\n  var event = document.createEvent('CustomEvent');\n  event.initCustomEvent('my-event', true, true, {some: 'data'});\n}\n\nel.dispatchEvent(event);\n"
  },
  {
    "path": "src/comparisons/events/trigger_custom/jquery.js",
    "content": "$(el).trigger('my-event', {some: 'data'});\n"
  },
  {
    "path": "src/comparisons/events/trigger_custom/modern.js",
    "content": "const event = new CustomEvent('my-event', {detail: {some: 'data'}});\nel.dispatchEvent(event);\n"
  },
  {
    "path": "src/comparisons/events/trigger_native/ie8.js",
    "content": "function trigger(el, eventType) {\n  if (typeof eventType === 'string' && typeof el[eventType] === 'function') {\n    el[eventType]();\n  } else if (eventType === 'string') {\n    if (document.createEvent) {\n      var event = document.createEvent('HTMLEvents');\n      event.initEvent(eventType, true, false);\n      el.dispatchEvent(event);\n    } else {\n      el.fireEvent('on' + eventType);\n    }\n  } else {\n    el.dispatchEvent(eventType);\n  }\n}\n\n// For a full list of event types: https://developer.mozilla.org/en-US/docs/Web/API/document.createEvent\ntrigger(el, 'focus');\n"
  },
  {
    "path": "src/comparisons/events/trigger_native/ie9.js",
    "content": "function trigger(el, eventType) {\n  if (typeof eventType === 'string' && typeof el[eventType] === 'function') {\n    el[eventType]();\n  } else {\n    var event;\n    if (eventType === 'string') {\n      event = document.createEvent('HTMLEvents');\n      event.initEvent(eventType, true, false);\n    } else {\n      event = eventType;\n    }\n    el.dispatchEvent(event);\n  }\n}\n\n// For a full list of event types: https://developer.mozilla.org/en-US/docs/Web/API/document.createEvent\ntrigger(el, 'focus');\n"
  },
  {
    "path": "src/comparisons/events/trigger_native/jquery.js",
    "content": "$(el).trigger('focus');\n"
  },
  {
    "path": "src/comparisons/events/trigger_native/modern.js",
    "content": "function trigger(el, eventType) {\n  if (typeof eventType === 'string' && typeof el[eventType] === 'function') {\n    el[eventType]();\n  } else {\n    const event =\n      typeof eventType === 'string'\n        ? new Event(eventType, {bubbles: true})\n        : eventType;\n    el.dispatchEvent(event);\n  }\n}\n\ntrigger(el, 'focus');\n// For a full list of event types: https://developer.mozilla.org/en-US/docs/Web/API/Event\ntrigger(el, new PointerEvent('pointerover'));\n"
  },
  {
    "path": "src/comparisons/utils/array_each/ie8.js",
    "content": "function forEach(array, fn) {\n  for (var i = 0; i < array.length; i++) fn(array[i], i);\n}\n\nforEach(array, function (item, i) {});\n"
  },
  {
    "path": "src/comparisons/utils/array_each/ie9.js",
    "content": "array.forEach(function (item, i) {});\n"
  },
  {
    "path": "src/comparisons/utils/array_each/jquery.js",
    "content": "$.each(array, function (i, item) {});\n"
  },
  {
    "path": "src/comparisons/utils/array_each/modern.js",
    "content": "array.forEach((item, i) => {});\n"
  },
  {
    "path": "src/comparisons/utils/bind/ie8.js",
    "content": "fn.apply(context, arguments);\n"
  },
  {
    "path": "src/comparisons/utils/bind/ie9.js",
    "content": "fn.bind(context);\n"
  },
  {
    "path": "src/comparisons/utils/bind/jquery.js",
    "content": "$.proxy(fn, context);\n"
  },
  {
    "path": "src/comparisons/utils/deep_extend/ie8.js",
    "content": "function deepExtend(out) {\n  out = out || {};\n\n  for (var i = 1; i < arguments.length; i++) {\n    var obj = arguments[i];\n\n    if (!obj) continue;\n\n    for (var key in obj) {\n      if (obj.hasOwnProperty(key)) {\n        var rawType = Object.prototype.toString.call(obj[key]);\n        if (rawType === '[object Object]') {\n          out[key] = deepExtend(out[key], obj[key]);\n        } else if (rawType === '[object Array]') {\n          out[key] = deepExtend(new Array(obj[key].length), obj[key]);\n        } else {\n          out[key] = obj[key];\n        }\n      }\n    }\n  }\n\n  return out;\n}\n\ndeepExtend({}, objA, objB);\n"
  },
  {
    "path": "src/comparisons/utils/deep_extend/jquery.js",
    "content": "$.extend(true, {}, objA, objB);\n"
  },
  {
    "path": "src/comparisons/utils/deep_extend/modern.js",
    "content": "function deepExtend(out, ...arguments_) {\n  if (!out) {\n    return {};\n  }\n\n  for (const obj of arguments_) {\n    if (!obj) {\n      continue;\n    }\n\n    for (const [key, value] of Object.entries(obj)) {\n      switch (Object.prototype.toString.call(value)) {\n        case '[object Object]':\n          out[key] = out[key] || {};\n          out[key] = deepExtend(out[key], value);\n          break;\n        case '[object Array]':\n          out[key] = deepExtend(new Array(value.length), value);\n          break;\n        default:\n          out[key] = value;\n      }\n    }\n  }\n\n  return out;\n}\n\ndeepExtend({}, objA, objB);\n"
  },
  {
    "path": "src/comparisons/utils/extend/alternatives.json",
    "content": "{\n  \"Lodash\": \"https://lodash.com/docs#assign\",\n  \"Underscore\": \"https://underscorejs.org/#extend\",\n  \"ECMA6\": \"https://www.2ality.com/2014/01/object-assign.html\"\n}\n"
  },
  {
    "path": "src/comparisons/utils/extend/ie8.js",
    "content": "var extend = function (out) {\n  out = out || {};\n\n  for (var i = 1; i < arguments.length; i++) {\n    if (!arguments[i]) continue;\n\n    for (var key in arguments[i]) {\n      if (arguments[i].hasOwnProperty(key)) out[key] = arguments[i][key];\n    }\n  }\n\n  return out;\n};\n\nextend({}, objA, objB);\n"
  },
  {
    "path": "src/comparisons/utils/extend/jquery.js",
    "content": "$.extend({}, objA, objB);\n"
  },
  {
    "path": "src/comparisons/utils/extend/modern.js",
    "content": "const result = {...objA, ...objB};\n"
  },
  {
    "path": "src/comparisons/utils/index_of/ie8.js",
    "content": "function indexOf(array, item) {\n  for (var i = 0; i < array.length; i++) {\n    if (array[i] === item) return i;\n  }\n  return -1;\n}\n\nindexOf(array, item);\n"
  },
  {
    "path": "src/comparisons/utils/index_of/ie9.js",
    "content": "array.indexOf(item);\n"
  },
  {
    "path": "src/comparisons/utils/index_of/jquery.js",
    "content": "$.inArray(item, array);\n"
  },
  {
    "path": "src/comparisons/utils/is_array/ie8.js",
    "content": "isArray =\n  Array.isArray ||\n  function (arr) {\n    return Object.prototype.toString.call(arr) == '[object Array]';\n  };\n\nisArray(arr);\n"
  },
  {
    "path": "src/comparisons/utils/is_array/ie9.js",
    "content": "Array.isArray(arr);\n"
  },
  {
    "path": "src/comparisons/utils/is_array/jquery.js",
    "content": "$.isArray(arr);\n"
  },
  {
    "path": "src/comparisons/utils/is_numeric/ie8.js",
    "content": "function isNumeric(num) {\n  if (typeof num === 'number') return num - num === 0;\n  if (typeof num === 'string' && num.trim() !== '')\n    return Number.isFinite ? Number.isFinite(+num) : isFinite(+num);\n  return false;\n}\n\nisNumeric(val);\n"
  },
  {
    "path": "src/comparisons/utils/is_numeric/jquery.js",
    "content": "$.isNumeric(val);\n"
  },
  {
    "path": "src/comparisons/utils/is_numeric/modern.js",
    "content": "function isNumeric(num) {\n  if (typeof num === 'number') return num - num === 0;\n  if (typeof num === 'string' && num.trim() !== '')\n    return Number.isFinite(+num);\n  return false;\n}\n\nisNumeric(val);\n"
  },
  {
    "path": "src/comparisons/utils/map/ie8.js",
    "content": "function map(arr, fn) {\n  var results = [];\n  for (var i = 0; i < arr.length; i++) results.push(fn(arr[i], i));\n  return results;\n}\n\nmap(array, function (value, index) {});\n"
  },
  {
    "path": "src/comparisons/utils/map/ie9.js",
    "content": "array.map(function (value, index) {});\n"
  },
  {
    "path": "src/comparisons/utils/map/jquery.js",
    "content": "$.map(array, function (value, index) {});\n"
  },
  {
    "path": "src/comparisons/utils/map/modern.js",
    "content": "array.map((value, index) => {});\n"
  },
  {
    "path": "src/comparisons/utils/now/ie8.js",
    "content": "new Date().getTime();\n"
  },
  {
    "path": "src/comparisons/utils/now/ie9.js",
    "content": "Date.now();\n"
  },
  {
    "path": "src/comparisons/utils/now/jquery.js",
    "content": "$.now();\n"
  },
  {
    "path": "src/comparisons/utils/object_each/ie8.js",
    "content": "function objectEach(obj, callback) {\n  for (var key in obj) {\n    if (Object.prototype.hasOwnProperty.call(obj, key)) {\n      callback(key, obj[key]);\n    }\n  }\n}\n\nobjectEach(obj, function (key, value) {});\n"
  },
  {
    "path": "src/comparisons/utils/object_each/jquery.js",
    "content": "$.each(obj, function (key, value) {});\n"
  },
  {
    "path": "src/comparisons/utils/object_each/modern.js",
    "content": "for (const [key, value] of Object.entries(obj)) {\n}\n"
  },
  {
    "path": "src/comparisons/utils/parse_html/ie8.js",
    "content": "var parseHTML = function (str) {\n  var el = document.createElement('div');\n  el.innerHTML = str;\n  return el.childNodes;\n};\n\nparseHTML(htmlString);\n"
  },
  {
    "path": "src/comparisons/utils/parse_html/ie9.js",
    "content": "var parseHTML = function (str) {\n  var tmp = document.implementation.createHTMLDocument('');\n  tmp.body.innerHTML = str;\n  return Array.prototype.slice.call(tmp.body.childNodes);\n};\n\nparseHTML(htmlString);\n"
  },
  {
    "path": "src/comparisons/utils/parse_html/jquery.js",
    "content": "$.parseHTML(htmlString);\n"
  },
  {
    "path": "src/comparisons/utils/parse_html/modern.js",
    "content": "function parseHTML(str) {\n  const tmp = document.implementation.createHTMLDocument('');\n  tmp.body.innerHTML = str;\n  return [...tmp.body.childNodes];\n}\n\nparseHTML(htmlString);\n"
  },
  {
    "path": "src/comparisons/utils/parse_json/ie8.js",
    "content": "JSON.parse(string);\n"
  },
  {
    "path": "src/comparisons/utils/parse_json/jquery.js",
    "content": "$.parseJSON(string);\n"
  },
  {
    "path": "src/comparisons/utils/slice/ie8.js",
    "content": "function slice(els, start, end) {\n  var f = Array.prototype.slice;\n  try {\n    f.call(document.documentElement);\n  } catch (h) {\n    Array.prototype.slice = function (g, b) {\n      b = 'undefined' !== typeof b ? b : this.length;\n      if ('[object Array]' === Object.prototype.toString.call(this))\n        return f.call(this, g, b);\n      var e = [];\n      var a = this.length;\n      var c = g || 0;\n      c = 0 <= c ? c : Math.max(0, a + c);\n      var d = 'number' == typeof b ? Math.min(b, a) : a;\n      0 > b && (d = a + b);\n      d -= c;\n      if (0 < d)\n        if (((e = Array(d)), this.charAt))\n          for (a = 0; a < d; a++) e[a] = this.charAt(c + a);\n        else for (a = 0; a < d; a++) e[a] = this[c + a];\n      return e;\n    };\n  }\n  return els.slice(start, end);\n}\n\nslice(els, start, end);\n"
  },
  {
    "path": "src/comparisons/utils/slice/ie9.js",
    "content": "els.slice(begin, end);\n"
  },
  {
    "path": "src/comparisons/utils/slice/jquery.js",
    "content": "$(els).slice(begin, end);\n"
  },
  {
    "path": "src/comparisons/utils/to_array/ie8.js",
    "content": "function toArray(selector) {\n  var array = [];\n  var elements = document.querySelectorAll(selector);\n  for (var i = 0; i < elements.length; i++) array.push(elements[i]);\n  return array;\n}\n"
  },
  {
    "path": "src/comparisons/utils/to_array/jquery.js",
    "content": "$(selector).toArray();\n"
  },
  {
    "path": "src/comparisons/utils/to_array/modern.js",
    "content": "const array = [...document.querySelectorAll(selector)];\n"
  },
  {
    "path": "src/comparisons/utils/trim/ie8.js",
    "content": "string.replace(/^\\s+|\\s+$/g, '');\n"
  },
  {
    "path": "src/comparisons/utils/trim/ie9.js",
    "content": "string.trim();\n"
  },
  {
    "path": "src/comparisons/utils/trim/jquery.js",
    "content": "$.trim(string);\n"
  },
  {
    "path": "src/comparisons/utils/type/ie8.js",
    "content": "Object.prototype.toString\n  .call(obj)\n  .replace(/^\\[object (.+)\\]$/, '$1')\n  .toLowerCase();\n"
  },
  {
    "path": "src/comparisons/utils/type/jquery.js",
    "content": "$.type(obj);\n"
  },
  {
    "path": "src/components/CodeBlock.astro",
    "content": "---\nimport {Prism} from '@astrojs/prism';\n\nexport interface Props {\n  lang?: string;\n  code?: string;\n}\n\nconst {lang, code} = Astro.props as Props;\n---\n\n<div class=\"code-wrapper\">\n  <button title=\"Copy code snippet\" class=\"copy-code\">📋</button>\n  {code && <Prism class=\"code\" lang={lang} code={code} />}\n</div>\n\n<style lang=\"scss\">\n  .code-wrapper {\n    position: relative;\n  }\n\n  button {\n    position: absolute;\n    top: 0;\n    right: 0;\n    opacity: 0.2;\n    cursor: pointer;\n    background: #eee;\n    border: 1px solid transparent;\n    padding: 6px;\n\n    &:hover {\n      opacity: 1;\n      border-color: #ccc;\n    }\n  }\n</style>\n\n<script>\n  function oldCopyText(text: string) {\n    const textArea = document.createElement('textarea');\n    textArea.value = text;\n    textArea.style.top = '0';\n    textArea.style.left = '0';\n    textArea.style.position = 'fixed'; // Avoids scrolling on focus\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n\n    try {\n      document.execCommand('copy');\n    } finally {\n      document.body.removeChild(textArea);\n    }\n  }\n\n  function copyText(text: string) {\n    if (!navigator.clipboard) {\n      oldCopyText(text);\n      return;\n    }\n    navigator.clipboard.writeText(text).catch(() => {\n      oldCopyText(text);\n    });\n  }\n\n  const buttonElements = document.querySelectorAll('.copy-code');\n  buttonElements.forEach((el) => {\n    el.setAttribute('data-label', el.innerHTML);\n    el.addEventListener('click', (event) => {\n      const currentEl = event.target as HTMLElement;\n      const pre = currentEl.nextElementSibling;\n      if (pre) {\n        copyText(pre.textContent);\n        const range = document.createRange();\n        range.selectNode(pre);\n        getSelection().removeAllRanges();\n        getSelection().addRange(range);\n        currentEl.innerHTML = 'Copied!';\n        setTimeout(() => {\n          currentEl.innerHTML = currentEl.getAttribute('data-label');\n        }, 1000);\n      } else {\n        currentEl.innerHTML = 'Failed to copy :(';\n        setTimeout(() => {\n          currentEl.innerHTML = currentEl.getAttribute('data-label');\n        }, 1000);\n      }\n    });\n  });\n</script>\n"
  },
  {
    "path": "src/env.d.ts",
    "content": "/// <reference types=\"astro/client\" />\n"
  },
  {
    "path": "src/lib/comparisons.ts",
    "content": "import path from 'node:path';\nimport process from 'node:process'; // Astro must be run while the current working directory is the repository root so that the comparison files can be detected.\nimport readFileTree from 'readfiletree';\nimport sortKeys from 'sort-keys';\nimport {engineOrder} from './newest-engine';\n\ntype FileTree = {[fileName: string]: string | FileTree};\n\ntype Engine = Array<{\n  language: string;\n  code: string;\n}>;\n\ninterface Comparison {\n  engines: {\n    ie8?: Engine;\n    ie9?: Engine;\n    ie10?: Engine;\n    ie11?: Engine;\n    jquery: Engine;\n    modern?: Engine;\n  };\n  alternatives?: Record<string, string>;\n}\n\ninterface Category {\n  comparisons: Record<string, Comparison>;\n  alternatives?: Record<string, string>;\n}\n\ntype Comparisons = Record<string, Category>;\n\nexport default async function getComparisons(): Promise<Comparisons> {\n  const fileTree: FileTree = await readFileTree(\n    path.join(process.cwd(), 'src', 'comparisons')\n  );\n  const categories = {};\n\n  for (const [categoryName, comparisons] of Object.entries(fileTree)) {\n    const category: Category = {\n      comparisons: {}\n    };\n\n    if (comparisons['alternatives.json']) {\n      category.alternatives = JSON.parse(comparisons['alternatives.json']);\n      delete comparisons['alternatives.json'];\n    }\n\n    for (const [comparisonName, engines] of Object.entries(comparisons)) {\n      const comparison: Comparison = {\n        engines: {\n          jquery: [\n            {\n              language: 'js',\n              code: engines['jquery.js']\n            }\n          ]\n        }\n      };\n\n      delete engines['jquery.js'];\n\n      if (engines['alternatives.json']) {\n        comparison.alternatives = JSON.parse(engines['alternatives.json']);\n        delete engines['alternatives.json'];\n      }\n\n      for (const [engineFile, code] of Object.entries(engines)) {\n        const [engineName, extension] = engineFile.split('.');\n\n        if (!comparison.engines[engineName]) {\n          comparison.engines[engineName] = [];\n        }\n\n        comparison.engines[engineName].push({\n          language: extension,\n          code\n        });\n      }\n\n      for (const engines of Object.values(comparison.engines)) {\n        // Sorted in-place\n        engines.sort((a, b) => {\n          if (a.language === 'js') {\n            return -1;\n          }\n\n          if (b.language === 'js') {\n            return 1;\n          }\n\n          return a.language.localeCompare(b.language);\n        });\n      }\n\n      comparison.engines = sortKeys(comparison.engines, {\n        compare: (a, b) => engineOrder.indexOf(a) - engineOrder.indexOf(b)\n      });\n\n      category.comparisons[comparisonName] = comparison;\n    }\n\n    category.comparisons = sortKeys(category.comparisons);\n\n    categories[categoryName] = category;\n  }\n\n  return sortKeys(categories);\n}\n"
  },
  {
    "path": "src/lib/newest-engine.ts",
    "content": "export const engineOrder = ['jquery', 'ie8', 'ie9', 'ie10', 'ie11', 'modern'];\n\nexport default function getNewestEngine(\n  engines: string[],\n  targetEngine?: string\n): string {\n  engines = [...engines];\n\n  engines.sort((a, b) => engineOrder.indexOf(b) - engineOrder.indexOf(a));\n  engines = engines.filter((engine) => engine !== 'jquery');\n\n  if (!targetEngine) {\n    return engines[0];\n  }\n\n  return (\n    engines.find(\n      (engine) =>\n        engineOrder.indexOf(engine) <= engineOrder.indexOf(targetEngine)\n    ) || engines[0]\n  );\n}\n"
  },
  {
    "path": "src/pages/index.astro",
    "content": "---\nimport classNames from '@sindresorhus/class-names';\nimport CodeBlock from '../components/CodeBlock.astro';\nimport getNewestEngine from '../lib/newest-engine';\nimport getComparisons from '../lib/comparisons';\nimport isEven from '../utils/is-even';\nimport titleCase from '../utils/title-case';\n\nconst comparisons = await getComparisons();\n---\n\n<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n\n    <title>You Might Not Need jQuery</title>\n\n    <meta\n      name=\"description\"\n      content=\"Examples of how to do common event, element, ajax and utility operations with plain javascript.\"\n    />\n    <link rel=\"icon\" href=\"https://static.hubspot.com/favicon.ico\" />\n  </head>\n  <body>\n    <div class=\"main-wrapper\">\n      <input id=\"sidebar-toggle\" type=\"checkbox\" />\n      <nav id=\"navbar\">\n        <label id=\"sidebar-toggle-label\" for=\"sidebar-toggle\">\n          <span></span>\n        </label>\n      </nav>\n      <nav id=\"sidebar\">\n        <ul class=\"sidebar-categories\">\n          {\n            Object.entries(comparisons).map(([categoryName, category]) => (\n              <li class=\"sidebar-category\">\n                <div class=\"sidebar-category-title\">\n                  <a href={`#${categoryName}`}>{titleCase(categoryName)}</a>\n                </div>\n                <ul class=\"sidebar-comparisons\">\n                  {Object.keys(category.comparisons).map((comparisonName) => (\n                    <li class=\"sidebar-comparison-title\">\n                      <a href={`#${comparisonName}`}>\n                        {titleCase(comparisonName.replaceAll('_', ' '))}\n                      </a>\n                    </li>\n                  ))}\n                </ul>\n              </li>\n            ))\n          }\n        </ul>\n      </nav>\n      <main id=\"main-content\">\n        <div id=\"top\">\n          <header id=\"top-header\">\n            <h1 class=\"title\">You might not need jQuery</h1>\n          </header>\n          <article class=\"explanation\">\n            <p>\n              jQuery and its cousins are great, and by all means use them if it\n              makes it easier to develop your application.\n              <br /><br />\n              If you're developing a library on the other hand, please take a moment\n              to consider if you actually need jQuery as a dependency. Maybe you\n              can include a few lines of utility code, and forgo the requirement.\n              If you're only targeting more modern browsers, you might not need anything\n              more than what the browser ships with.\n              <br /><br />\n              At the very least, make sure you know what <a\n                href=\"https://docs.google.com/document/d/1LPaPA30bLUB_publLIMF0RlhdnPx_ePXm7oW02iiT6o\"\n                >jQuery is doing for you</a\n              >, and what it's not. Some developers believe that jQuery is\n              protecting us from a great demon of browser incompatibility when,\n              in truth, post-IE8, browsers are pretty easy to deal with on their\n              own; and after the Internet Explorer era, the browsers do even\n              more.\n            </p>\n          </article>\n          <address class=\"share-buttons\">\n            <a\n              href=\"https://github.com/HubSpot/YouMightNotNeedjQuery\"\n              class=\"share-button-github\"\n            >\n              <span class=\"share-button-github-message\">★ Star on Github</span>\n              <span class=\"github-stars\"></span>\n            </a>\n          </address>\n          <nav>\n            <input\n              id=\"search\"\n              type=\"text\"\n              role=\"searchbox\"\n              placeholder=\"Search...\"\n              required\n            />\n            <div class=\"input-box\">\n              <label for=\"ie-question\">Do you need to support IE?</label>\n              <input type=\"checkbox\" id=\"ie-question\" name=\"ie-question\" />\n            </div>\n            <div id=\"ie-version-box\" class=\"input-box hidden\">\n              <label for=\"ie-min-version\"\n                >What's the oldest version of IE you need to support?</label\n              >\n              <div class=\"slider\">\n                <input\n                  type=\"range\"\n                  id=\"ie-min-version\"\n                  name=\"ie-min-version\"\n                  min={8}\n                  max={11}\n                  value={11}\n                />\n                <table class=\"slider-labels\" aria-hidden={true}>\n                  <tr>\n                    {\n                      [8, 9, 10, 11].map((version) => (\n                        <td class=\"slider-label ie-slider-label\">{version}</td>\n                      ))\n                    }\n                  </tr>\n\n\n                </table>\n              </div>\n            </div>\n          </nav>\n        </div>\n\n        <article id=\"comparisons\">\n          <div class=\"empty-message\">\n            Your search didn't match any comparisons.\n          </div>\n\n          <div class=\"categories\">\n            {\n              Object.entries(comparisons).map(\n                ([categoryName, category], index) => (\n                  <section\n                    class={classNames('category', {\n                      even: isEven(index)\n                    })}\n                    id={categoryName}\n                  >\n                    <header class=\"comparisons-header\">\n                      <h2 class=\"category-name\">\n                        <a href={`#${categoryName}`}>\n                          {titleCase(categoryName)}\n                        </a>\n                      </h2>\n                      {category.alternatives && (\n                        <div class=\"alternatives\">\n                          <h3 class=\"alternatives-title\">Alternatives:</h3>\n                          <ul class=\"alternatives-list\">\n                            {Object.entries(category.alternatives).map(\n                              ([alternativeName, alternativeUrl]) => (\n                                <li>\n                                  <a\n                                    href={alternativeUrl}\n                                    target=\"_blank\"\n                                    rel=\"noopener\"\n                                    class=\"alternative-link\"\n                                  >\n                                    {alternativeName}\n                                  </a>\n                                </li>\n                              )\n                            )}\n                          </ul>\n                        </div>\n                      )}\n                    </header>\n                    <div class=\"category-comparisons\">\n                      {Object.entries(category.comparisons).map(\n                        ([comparisonName, comparison]) => {\n                          const newestEngine = getNewestEngine(\n                            Object.keys(comparison.engines)\n                          );\n\n                          return (\n                            <div class=\"comparison\" id={comparisonName}>\n                              <header class=\"comparisons-header\">\n                                <h3 class=\"comparison-title\">\n                                  <a href={`#${comparisonName}`}>\n                                    {titleCase(\n                                      comparisonName.replaceAll('_', ' ')\n                                    )}\n                                  </a>\n                                </h3>\n                                {comparison.alternatives && (\n                                  <div class=\"alternatives\">\n                                    <h4 class=\"alternatives-title\">\n                                      Alternatives:\n                                    </h4>\n                                    <ul class=\"alternatives-list\">\n                                      {Object.entries(\n                                        comparison.alternatives\n                                      ).map(\n                                        ([alternativeName, alternativeUrl]) => (\n                                          <li>\n                                            <a\n                                              href={alternativeUrl}\n                                              target=\"_blank\"\n                                              rel=\"noopener\"\n                                              class=\"alternative-link\"\n                                            >\n                                              {alternativeName}\n                                            </a>\n                                          </li>\n                                        )\n                                      )}\n                                    </ul>\n                                  </div>\n                                )}\n                              </header>\n                              <div class=\"engines\">\n                                {Object.entries(comparison.engines).map(\n                                  ([engineName, allCode]) => (\n                                    <div\n                                      class={classNames('engine', {\n                                        hidden:\n                                          engineName !== newestEngine &&\n                                          engineName !== 'jquery'\n                                      })}\n                                      data-engine={engineName}\n                                    >\n                                      <h4 class=\"engine-name\">\n                                        {`${engineName}${\n                                          engineName.startsWith('ie') ? '+' : ''\n                                        }`}\n                                      </h4>\n                                      {allCode.map(({language, code}) => (\n                                        <CodeBlock\n                                          lang={language}\n                                          code={code}\n                                        />\n                                      ))}\n                                    </div>\n                                  )\n                                )}\n                              </div>\n                            </div>\n                          );\n                        }\n                      )}\n                    </div>\n                  </section>\n                )\n              )\n            }\n          </div>\n        </article>\n\n        <footer>\n          <p>\n            Made by <span id=\"credit-a\"></span>, <span id=\"credit-b\"></span> and\n            some engineer gamers at <a href=\"https://dev.hubspot.com\">HubSpot</a\n            >.\n          </p>\n        </footer>\n      </main>\n    </div>\n\n    <style is:global lang=\"scss\">\n      @use 'modern-normalize';\n      @use 'prismjs/themes/prism.css';\n    </style>\n\n    <style lang=\"scss\">\n      $border-color: #eee;\n      $sidebar-width: 300px;\n      $sidebar-collapsed-screen-width: 828px;\n      $navbar-height: 60px;\n      $transition-duration: 0.25s;\n\n      ::placeholder {\n        color: rgba(0, 0, 0, 0.5);\n      }\n\n      html {\n        scroll-behavior: smooth;\n        scroll-padding-top: $navbar-height;\n      }\n\n      body {\n        font-family: system-ui, sans-serif;\n        line-height: 1.5;\n        display: flex;\n        flex-direction: column;\n        align-items: center;\n      }\n\n      .hidden {\n        display: none !important;\n      }\n\n      .main-wrapper {\n        width: 100%;\n      }\n\n      #sidebar-toggle {\n        display: none;\n      }\n\n      #sidebar-toggle:checked ~ #sidebar {\n        left: 0;\n      }\n\n      #sidebar-toggle:checked ~ #main-content {\n        margin-left: $sidebar-width;\n      }\n\n      #sidebar-toggle-label {\n        position: fixed;\n        z-index: 2;\n        top: 16px;\n        left: 20px;\n        width: 26px;\n        height: 26px;\n        cursor: pointer;\n\n        span,\n        span::before,\n        span::after {\n          display: block;\n          position: absolute;\n          width: 100%;\n          height: 2px;\n          background-color: #333;\n          transition-duration: $transition-duration;\n          top: 50%;\n        }\n\n        span::before {\n          content: '';\n          top: -8px;\n        }\n\n        span::after {\n          content: '';\n          top: 8px;\n        }\n      }\n\n      #sidebar-toggle:checked + #navbar {\n        #sidebar-toggle-label span {\n          transform: rotate(45deg);\n          &::before {\n            top: 0;\n            transform: rotate(0deg);\n          }\n          &::after {\n            top: 0;\n            transform: rotate(90deg);\n          }\n        }\n      }\n\n      #navbar {\n        position: fixed;\n        left: 0;\n        right: 0;\n        background-color: #fff;\n        height: $navbar-height;\n        border-bottom: 1px solid $border-color;\n        z-index: 1;\n        display: block;\n      }\n\n      #sidebar {\n        flex: 0;\n        background-color: #fff;\n        z-index: 1;\n        width: $sidebar-width;\n        position: fixed;\n        left: 0;\n        top: 0;\n        bottom: 0;\n        overflow: auto;\n        padding: 2em;\n        transition-duration: $transition-duration;\n        margin-top: $navbar-height;\n        border-right: 1px solid $border-color;\n        left: -100%;\n\n        @media screen and (max-width: $sidebar-collapsed-screen-width) {\n          width: 100%;\n        }\n\n        ul {\n          list-style: none;\n          padding-left: 0;\n        }\n\n        a {\n          display: block;\n          padding: 4px;\n          text-decoration: none;\n          color: inherit;\n\n          &.active {\n            background: rgba(0, 0, 0, 0.1);\n          }\n\n          &:hover {\n            background: rgba(0, 0, 0, 0.05);\n          }\n        }\n\n        .sidebar-category {\n          margin-bottom: 1em;\n\n          .sidebar-category-title {\n            font-size: 20px;\n          }\n\n          .sidebar-comparison-title {\n            color: #666;\n          }\n\n          .sidebar-category-title,\n          .sidebar-comparison-title {\n            font-weight: 300;\n          }\n        }\n      }\n\n      #main-content {\n        align-items: center;\n        display: flex;\n        flex-direction: column;\n        margin-left: 0;\n        margin-top: $navbar-height;\n        transition-duration: $transition-duration;\n      }\n\n      #top {\n        display: flex;\n        flex-direction: column;\n        max-width: 40rem;\n        gap: 2rem;\n        margin-left: 16px;\n        margin-right: 16px;\n        margin-top: 4rem;\n        margin-bottom: 3rem;\n\n        @media (max-width: 42rem) {\n          margin-top: 16px;\n        }\n\n        #top-header {\n          text-align: center;\n\n          .title {\n            padding: 2rem 2rem;\n            border: 0.25rem solid;\n            font-size: 2.5rem;\n            font-weight: 300;\n            margin: 0;\n            line-height: 1;\n          }\n        }\n\n        .explanation {\n          max-width: 100%;\n\n          a {\n            color: inherit;\n            text-decoration: none;\n            box-shadow: inset 0 -0.125rem;\n          }\n\n          p {\n            margin: 0;\n          }\n        }\n\n        .share-buttons {\n          display: flex;\n          justify-content: center;\n\n          .share-button-github {\n            display: flex;\n            color: inherit;\n            margin-left: auto;\n            margin-right: auto;\n            text-decoration: none;\n            font-style: normal;\n\n            > span {\n              border: 1px solid #ccc;\n              padding: 0.5rem 0.8rem;\n\n              &.share-button-github-message {\n                margin-right: -1px;\n                background: #eee;\n              }\n\n              &.github-stars {\n                text-align: center;\n                min-width: 3rem;\n\n                &:empty::after {\n                  content: '···';\n                }\n              }\n            }\n          }\n        }\n\n        nav {\n          display: flex;\n          flex-direction: column;\n          gap: 10px;\n\n          #search {\n            max-width: 40rem;\n\n            border: 0;\n            font-family: inherit;\n            font-weight: 400;\n            color: inherit;\n            background: rgba(0, 0, 0, 0.1);\n            width: 100%;\n            padding: 1rem;\n\n            &:focus {\n              background: rgba(0, 0, 0, 0.05);\n              outline: none;\n            }\n          }\n\n          @media print {\n            display: none;\n          }\n        }\n\n        .input-box {\n          display: flex;\n          justify-content: space-between;\n          align-items: center;\n\n          input[type='checkbox'] {\n            height: 20px;\n            width: 20px;\n          }\n\n          input {\n            accent-color: black;\n          }\n\n          .slider {\n            .slider-labels {\n              border-collapse: collapse;\n              min-width: 100%;\n              margin-left: 3px;\n              margin-right: 3px;\n\n              .slider-label {\n                text-align: center;\n\n                &:first-child {\n                  text-align: left;\n                }\n\n                &:last-child {\n                  text-align: right;\n                }\n\n                &.ie-slider-label {\n                  // 25% for each of the 4 versions\n                  width: 25%;\n\n                  &.ie-slider-label:nth-child(2) {\n                    padding-right: 12px;\n                  }\n                }\n              }\n            }\n          }\n        }\n      }\n\n      #comparisons {\n        width: 100%;\n\n        .empty-message {\n          text-align: center;\n          background: #eee;\n          padding-top: 5.5rem;\n          padding-bottom: 5.5rem;\n          font-weight: 500;\n          font-size: 1.2rem;\n          display: none;\n        }\n\n        &.no-search-results {\n          .empty-message {\n            display: block;\n          }\n        }\n\n        .categories {\n          .comparisons-header {\n            display: flex;\n            flex-direction: column;\n            gap: 10px;\n          }\n\n          .category {\n            padding-top: 5.5rem;\n            padding-bottom: 5.5rem;\n            padding-left: 16px;\n            padding-right: 16px;\n            display: flex;\n            flex-direction: column;\n            gap: 5.5rem;\n\n            @mixin section-symbol {\n              // :after is used to ensure the text is centered - this is never shown\n              &:before,\n              &:after {\n                content: '§';\n                visibility: hidden;\n              }\n\n              &:hover:before {\n                visibility: visible;\n              }\n            }\n\n            .category-name {\n              font-size: 3rem;\n              font-weight: 200;\n              letter-spacing: 1rem;\n              text-transform: uppercase;\n              color: #888;\n              text-align: center;\n              margin: 0;\n              word-wrap: break-word;\n\n              a {\n                color: inherit;\n                text-decoration: none;\n\n                @include section-symbol;\n\n                // At such a small screen size, we have to remove this text so that the title remains centered\n                @media (max-width: 28rem) {\n                  &:before,\n                  &:after {\n                    content: '';\n                  }\n                }\n              }\n            }\n\n            .category-comparisons {\n              display: flex;\n              flex-direction: column;\n              gap: 5.5rem;\n\n              .comparison {\n                display: flex;\n                flex-direction: column;\n                gap: 16px;\n\n                .comparison-title {\n                  text-align: center;\n                  font-size: 2em;\n                  font-weight: normal;\n                  margin: 0;\n\n                  a {\n                    color: inherit;\n                    text-decoration: none;\n\n                    @include section-symbol;\n                  }\n                }\n              }\n            }\n\n            .alternatives {\n              display: flex;\n              justify-content: center;\n              gap: 10px;\n              flex-wrap: wrap;\n\n              .alternatives-title {\n                font-size: 1.1rem;\n                font-weight: 300;\n                color: #666;\n                letter-spacing: 0.07em;\n                font-size: 1.4em;\n                text-transform: uppercase;\n                margin: 0;\n                line-height: 1;\n                word-wrap: break-word;\n              }\n\n              .alternatives-list {\n                margin: 0;\n                font-size: 1.1em;\n                list-style: none;\n                padding: 0;\n                display: flex;\n                gap: 10px;\n                flex-wrap: wrap;\n                justify-content: center;\n\n                .alternative-link {\n                  color: inherit;\n                  text-decoration-thickness: 3px;\n                  text-decoration-line: underline;\n                  text-decoration-skip-ink: none;\n                }\n              }\n            }\n\n            &.even {\n              background: #eee;\n\n              :global(.code) {\n                background: white;\n              }\n            }\n\n            .engines {\n              display: flex;\n              flex-direction: row;\n              flex-wrap: wrap;\n              justify-content: center;\n              gap: 24px;\n              margin: 0 auto;\n              width: 100%;\n\n              .engine {\n                width: 30rem;\n                min-width: 0;\n\n                .engine-name {\n                  font-weight: 300;\n                  color: #666;\n                  letter-spacing: 0.07em;\n                  font-size: 1.4em;\n                  text-transform: uppercase;\n                  margin-bottom: 0;\n                  margin-top: 8px;\n                  line-height: 1;\n                }\n              }\n            }\n          }\n        }\n      }\n\n      footer {\n        margin: 3em auto;\n        font-size: 1.4em;\n        text-align: center;\n        padding-left: 16px;\n        padding-right: 16px;\n\n        a {\n          color: inherit;\n        }\n      }\n    </style>\n\n    <script>\n      import getNewestEngine from '../lib/newest-engine';\n      import isEven from '../utils/is-even';\n      import throttle from '../utils/throttle';\n\n      const adamfschwartz = document.createElement('a');\n      adamfschwartz.href = 'https://twitter.com/adamfschwartz';\n      adamfschwartz.textContent = '@adamfschwartz';\n      adamfschwartz.style.color = 'inherit';\n\n      const zackbloom = document.createElement('a');\n      zackbloom.href = 'https://twitter.com/zackbloom';\n      zackbloom.textContent = '@zackbloom';\n      zackbloom.style.color = 'inherit';\n\n      const creditA = document.querySelector('#credit-a');\n      const creditB = document.querySelector('#credit-b');\n\n      if (Math.random() >= 0.5) {\n        creditA.replaceWith(adamfschwartz);\n        creditB.replaceWith(zackbloom);\n      } else {\n        creditA.replaceWith(zackbloom);\n        creditB.replaceWith(adamfschwartz);\n      }\n\n      const searchInput: HTMLInputElement = document.querySelector('#search');\n      const comparisonsParent = document.querySelector('#comparisons');\n      const versionBox = document.querySelector('#ie-version-box');\n      const ieQuestion =\n        document.querySelector<HTMLInputElement>('#ie-question');\n      const ieMinVersion =\n        document.querySelector<HTMLInputElement>('#ie-min-version');\n\n      document.addEventListener('keydown', (event) => {\n        if (event.key === '/' && searchInput !== document.activeElement) {\n          event.preventDefault(); // Firefox uses this for quick find\n          searchInput.focus();\n        }\n      });\n\n      function resetResults() {\n        comparisonsParent.classList.remove('no-search-results');\n\n        for (const hiddenCategoryOrComparison of document.querySelectorAll(\n          '.category.hidden, .comparison.hidden'\n        )) {\n          hiddenCategoryOrComparison.classList.remove('hidden');\n        }\n\n        for (const [index, category] of document\n          .querySelectorAll('.category')\n          .entries()) {\n          category.classList.toggle('even', isEven(index));\n        }\n      }\n\n      searchInput.addEventListener('input', (event) => {\n        const query = (event.target as HTMLInputElement).value.toLowerCase();\n\n        resetResults();\n\n        if (query.length === 0) {\n          return;\n        }\n\n        const categories = document.querySelectorAll('.category');\n        let hiddenCategories = 0;\n\n        for (const [index, category] of categories.entries()) {\n          const comparisons = category.querySelectorAll('.comparison');\n          let hiddenComparisons = 0;\n\n          for (const comparison of comparisons) {\n            if (!comparison.textContent.toLowerCase().includes(query)) {\n              comparison.classList.add('hidden');\n              hiddenComparisons++;\n            }\n          }\n\n          if (hiddenComparisons === comparisons.length) {\n            category.classList.add('hidden');\n            hiddenCategories++;\n          }\n          {\n            category.classList.toggle('even', isEven(index - hiddenCategories));\n          }\n        }\n\n        if (hiddenCategories === categories.length) {\n          comparisonsParent.classList.add('no-search-results');\n        }\n      });\n\n      function setQueryString(supportedVersion?: string) {\n        if (supportedVersion) {\n          const urlParams = new URLSearchParams(location.search);\n          urlParams.set('support', supportedVersion);\n          history.replaceState({}, '', '?' + urlParams);\n        } else {\n          history.replaceState({}, '', location.pathname);\n        }\n      }\n\n      function updateEngines(targetVersion?: string) {\n        setQueryString(targetVersion);\n\n        for (const engine of document.querySelectorAll(\n          '[data-engine].hidden'\n        )) {\n          engine.classList.remove('hidden');\n        }\n\n        for (const engines of document.querySelectorAll('.engines')) {\n          const engineElements = [\n            ...engines.querySelectorAll<HTMLDivElement>(\n              `[data-engine=ie8], [data-engine=ie9], [data-engine=ie10], [data-engine=ie11], [data-engine=modern]`\n            )\n          ];\n\n          const bestEngine = getNewestEngine(\n            engineElements.map((engine) => engine.dataset.engine),\n            targetVersion\n          );\n\n          for (const engine of engines.querySelectorAll(\n            `.engine:not([data-engine=${bestEngine}]):not([data-engine=jquery])`\n          )) {\n            engine.classList.add('hidden');\n          }\n        }\n      }\n\n      function getInitialSliderState(): string | undefined {\n        const urlParams = new URLSearchParams(location.search);\n        return urlParams.get('support');\n      }\n      const initialSliderState = getInitialSliderState();\n      if (initialSliderState) {\n        if (initialSliderState.includes('ie')) {\n          ieQuestion.checked = true;\n          ieMinVersion.value = initialSliderState.replace('ie', '');\n          versionBox.classList.remove('hidden');\n        }\n        updateEngines(initialSliderState);\n      }\n\n      ieQuestion.addEventListener('change', () => {\n        const isChecked = ieQuestion.checked;\n\n        versionBox.classList.toggle('hidden', !isChecked);\n\n        if (isChecked) {\n          updateEngines(`ie${ieMinVersion.value}`);\n        } else {\n          updateEngines();\n        }\n      });\n\n      ieMinVersion.addEventListener('change', () => {\n        updateEngines(`ie${ieMinVersion.value}`);\n      });\n\n      function findActiveCategoryOrComparison(): string | undefined {\n        let closestElementY = 0;\n        let anchor: string;\n        // First, check category names\n        for (let el of document.querySelectorAll('.category-name')) {\n          const elementY = (el as HTMLElement).offsetTop;\n          // Element is hidden\n          if (elementY === 0) {\n            continue;\n          }\n          if (elementY >= window.scrollY) {\n            closestElementY = elementY;\n            anchor = el.querySelector('a').href.split('#').pop();\n            break;\n          }\n        }\n        for (let el of document.querySelectorAll('.comparison-title')) {\n          const elementY = (el as HTMLElement).offsetTop;\n          // Don't evaluate nodes beyond the closest category\n          if (elementY > closestElementY) {\n            break;\n          }\n          // Element is hidden\n          if (elementY === 0) {\n            continue;\n          }\n          const diff = elementY - window.scrollY;\n          const isCloser =\n            diff >= 0 &&\n            (!closestElementY || diff < closestElementY - window.scrollY);\n          if (isCloser) {\n            anchor = el.querySelector('a').href.split('#').pop();\n            break;\n          }\n        }\n        return anchor;\n      }\n      function markSidebarAnchorActive(anchorName?: string) {\n        // Clear out active anchors first\n        const sidebar: HTMLDivElement = document.querySelector('#sidebar');\n        sidebar.querySelectorAll('a').forEach((el) => {\n          if (!anchorName || el.href !== `#${anchorName}`)\n            el.classList.remove('active');\n        });\n        if (anchorName) {\n          const maybeAnchor: HTMLAnchorElement | null = sidebar.querySelector(\n            `a[href='#${anchorName}']`\n          );\n          if (maybeAnchor) {\n            maybeAnchor.classList.add('active');\n          }\n        }\n      }\n      window.addEventListener(\n        'scroll',\n        throttle(() => {\n          const activeCategoryOrComparison = findActiveCategoryOrComparison();\n          markSidebarAnchorActive(activeCategoryOrComparison);\n        }, 100)\n      );\n      const activeCategoryOrComparison = findActiveCategoryOrComparison();\n      markSidebarAnchorActive(activeCategoryOrComparison);\n\n      function readLocalStorage<T>(key: string, defaultValue: T): T {\n        try {\n          const rawItem = window.localStorage.getItem(key);\n          if (rawItem == null) return defaultValue;\n          return JSON.parse(rawItem);\n        } catch (err) {\n          return defaultValue;\n        }\n      }\n      function writeLocalStorage<T>(key: string, value: T) {\n        try {\n          window.localStorage.setItem(key, JSON.stringify(value));\n        } catch (err) {\n          // Swallow error\n        }\n      }\n\n      const MOBILE_WIDTH = 828;\n      const sidebar: HTMLDivElement = document.querySelector('#sidebar');\n      const sidebarToggle: HTMLInputElement =\n        document.querySelector('#sidebar-toggle');\n      const SIDEBAR_LOCAL_STORAGE_KEY = 'sidebar-open';\n      const sidebarDefaultChecked = readLocalStorage(\n        SIDEBAR_LOCAL_STORAGE_KEY,\n        // Default the sidebar toggle open when on larger screens\n        window.innerWidth >= MOBILE_WIDTH\n      );\n      sidebarToggle.checked = sidebarDefaultChecked;\n      sidebarToggle.addEventListener('change', () => {\n        const isChecked = sidebarToggle.checked;\n        writeLocalStorage(SIDEBAR_LOCAL_STORAGE_KEY, isChecked);\n      });\n      sidebar.querySelectorAll('a').forEach((el) => {\n        el.addEventListener('click', () => {\n          const sidebarToggle: HTMLInputElement =\n            document.querySelector('#sidebar-toggle');\n          // Only close the sidebar automatically on mobile\n          if (window.innerWidth < MOBILE_WIDTH) {\n            sidebarToggle.checked = false;\n          }\n        });\n      });\n\n      const numberFormat = new Intl.NumberFormat('en-US');\n      const starsText = document.querySelector('.github-stars');\n\n      async function getStars(): Promise<number> {\n        const response = await fetch(\n          'https://api.github.com/repos/HubSpot/youmightnotneedjquery'\n        );\n\n        if (!response.ok) {\n          throw new Error('Failed to fetch GitHub stars');\n        }\n\n        const {stargazers_count: stars} = await response.json();\n\n        return stars;\n      }\n\n      try {\n        starsText.textContent = numberFormat.format(await getStars());\n      } catch {\n        starsText.textContent = '10k+';\n      }\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "src/utils/is-even.ts",
    "content": "export default function isEven(value: number) {\n  // This is a certified hood classic\n  return value % 2 === 0;\n}\n"
  },
  {
    "path": "src/utils/throttle.ts",
    "content": "/**\n * Throttle function with a trailing edge.\n *\n * @param func function to execute\n * @param wait time in milliseconds to wait before calling again\n * @returns\n */\nexport default function throttle(func: () => void, wait: number = 100) {\n  let context: any, args: any;\n  let waiting = false;\n  let doTrailing = false;\n  return function () {\n    context = this;\n    args = arguments;\n    if (!waiting) {\n      func.apply(context, args);\n      waiting = true;\n      window.setTimeout(function () {\n        if (doTrailing) {\n          func.apply(context, args);\n        }\n        waiting = false;\n        doTrailing = false;\n        context = args = null;\n      }, wait);\n    } else {\n      doTrailing = true;\n    }\n  };\n}\n"
  },
  {
    "path": "src/utils/title-case.ts",
    "content": "const capsWords = ['JSON', 'HTML', 'AJAX'];\n\nexport default function titleCase(str: string) {\n  return str\n    .replace(\n      /(^|\\b)([a-z])([a-z]+)/g,\n      (_match, space, first, rest) => `${space}${first.toUpperCase()}${rest}`\n    )\n    .replace(new RegExp(`(${capsWords.join('|')})`, 'ig'), (_match, word) =>\n      word.toUpperCase()\n    );\n}\n"
  }
]