[
  {
    "path": ".eslintrc.json",
    "content": "{\n  \"parser\": \"@typescript-eslint/parser\",\n  \"env\": {\n    \"browser\": true\n  },\n  \"plugins\": [\"@typescript-eslint\"],\n  \"extends\": [\n    \"eslint:recommended\",\n    \"plugin:@typescript-eslint/recommended\",\n    \"plugin:react/recommended\",\n    \"plugin:react-hooks/recommended\",\n    \"prettier\"\n  ],\n  \"overrides\": [],\n  \"parserOptions\": {\n    \"ecmaVersion\": \"latest\",\n    \"sourceType\": \"module\"\n  },\n  \"rules\": {\n    \"react/react-in-jsx-scope\": \"off\"\n  },\n  \"ignorePatterns\": [\"build/**\"]\n}\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "content": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Describe the bug**\nA clear and concise description of what the bug is.\n\n**Desktop (please complete the following information):**\n - OS: [e.g. Windows]\n - Browser [e.g. chrome, brave]\n - ChatHub Version [you can find it in ChatHub Settings]\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "content": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n\n"
  },
  {
    "path": ".github/dependabot.yml",
    "content": "# To get started with Dependabot version updates, you'll need to specify which\n# package ecosystems to update and where the package manifests are located.\n# Please see the documentation for all configuration options:\n# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates\n\nversion: 2\nupdates:\n  - package-ecosystem: \"npm\" # See documentation for possible values\n    directory: \"/\" # Location of package manifests\n    schedule:\n      interval: \"weekly\"\n"
  },
  {
    "path": ".github/workflows/close-inactive-issues.yml",
    "content": "name: Close inactive issues\non:\n  schedule:\n    - cron: \"30 1 * * *\"\n\njobs:\n  close-issues:\n    runs-on: ubuntu-latest\n    permissions:\n      issues: write\n      pull-requests: write\n    steps:\n      - uses: actions/stale@v5\n        with:\n          days-before-issue-stale: 30\n          days-before-issue-close: 14\n          stale-issue-label: \"stale\"\n          stale-issue-message: \"This issue is stale because it has been open for 30 days with no activity.\"\n          close-issue-message: \"This issue was closed because it has been inactive for 14 days since being marked as stale.\"\n          days-before-pr-stale: -1\n          days-before-pr-close: -1\n          repo-token: ${{ secrets.GITHUB_TOKEN }}\n"
  },
  {
    "path": ".github/workflows/release.yml",
    "content": "name: Release Workflow\n\npermissions:\n  contents: write\n\non:\n  push:\n    tags:\n      - 'v*.*.*'\n\nenv:\n  VITE_PLAUSIBLE_API_HOST: ${{ vars.VITE_PLAUSIBLE_API_HOST }}\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@v4\n\n      - name: Setup Node.js\n        uses: actions/setup-node@v3\n        with:\n          node-version: '20'\n\n      - name: Setup yarn\n        run: corepack enable\n\n      - name: Install dependencies\n        run: yarn install\n\n      - name: Build\n        run: yarn build\n\n      - name: Package\n        uses: vimtor/action-zip@v1.1\n        with:\n          files: dist/\n          dest: chathub.zip\n\n      - name: Release\n        uses: softprops/action-gh-release@v1\n        with:\n          files: chathub.zip\n"
  },
  {
    "path": ".gitignore",
    "content": "# Logs\nlogs\n*.log\nnpm-debug.log*\npnpm-debug.log*\nlerna-debug.log*\n\nnode_modules\ndist\ndist-ssr\n*.local\n\n# Editor directories and files\n.vscode/*\n!.vscode/extensions.json\n.idea\n.DS_Store\n*.suo\n*.ntvs*\n*.njsproj\n*.sln\n*.sw?\n\n.env\n\n.yarn/*\n!.yarn/cache\n!.yarn/patches\n!.yarn/plugins\n!.yarn/releases\n!.yarn/sdks\n!.yarn/versions\n"
  },
  {
    "path": ".prettierignore",
    "content": "geeguard.js\n"
  },
  {
    "path": ".prettierrc",
    "content": "{\n  \"printWidth\": 120,\n  \"semi\": false,\n  \"tabWidth\": 2,\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\",\n  \"bracketSpacing\": true,\n  \"overrides\": [\n    {\n      \"files\": \".prettierrc\",\n      \"options\": {\n        \"parser\": \"json\"\n      }\n    }\n  ]\n}\n"
  },
  {
    "path": ".yarnrc.yml",
    "content": "nodeLinker: node-modules\n"
  },
  {
    "path": "LICENSE",
    "content": "                    GNU GENERAL PUBLIC LICENSE\n                       Version 3, 29 June 2007\n\n Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n                            Preamble\n\n  The GNU General Public License is a free, copyleft license for\nsoftware and other kinds of works.\n\n  The licenses for most software and other practical works are designed\nto take away your freedom to share and change the works.  By contrast,\nthe GNU General Public License is intended to guarantee your freedom to\nshare and change all versions of a program--to make sure it remains free\nsoftware for all its users.  We, the Free Software Foundation, use the\nGNU General Public License for most of our software; it applies also to\nany other work released this way by its authors.  You can apply it to\nyour programs, too.\n\n  When we speak of free software, we are referring to freedom, not\nprice.  Our General Public Licenses are designed to make sure that you\nhave the freedom to distribute copies of free software (and charge for\nthem if you wish), that you receive source code or can get it if you\nwant it, that you can change the software or use pieces of it in new\nfree programs, and that you know you can do these things.\n\n  To protect your rights, we need to prevent others from denying you\nthese rights or asking you to surrender the rights.  Therefore, you have\ncertain responsibilities if you distribute copies of the software, or if\nyou modify it: responsibilities to respect the freedom of others.\n\n  For example, if you distribute copies of such a program, whether\ngratis or for a fee, you must pass on to the recipients the same\nfreedoms that you received.  You must make sure that they, too, receive\nor can get the source code.  And you must show them these terms so they\nknow their rights.\n\n  Developers that use the GNU GPL protect your rights with two steps:\n(1) assert copyright on the software, and (2) offer you this License\ngiving you legal permission to copy, distribute and/or modify it.\n\n  For the developers' and authors' protection, the GPL clearly explains\nthat there is no warranty for this free software.  For both users' and\nauthors' sake, the GPL requires that modified versions be marked as\nchanged, so that their problems will not be attributed erroneously to\nauthors of previous versions.\n\n  Some devices are designed to deny users access to install or run\nmodified versions of the software inside them, although the manufacturer\ncan do so.  This is fundamentally incompatible with the aim of\nprotecting users' freedom to change the software.  The systematic\npattern of such abuse occurs in the area of products for individuals to\nuse, which is precisely where it is most unacceptable.  Therefore, we\nhave designed this version of the GPL to prohibit the practice for those\nproducts.  If such problems arise substantially in other domains, we\nstand ready to extend this provision to those domains in future versions\nof the GPL, as needed to protect the freedom of users.\n\n  Finally, every program is threatened constantly by software patents.\nStates should not allow patents to restrict development and use of\nsoftware on general-purpose computers, but in those that do, we wish to\navoid the special danger that patents applied to a free program could\nmake it effectively proprietary.  To prevent this, the GPL assures that\npatents cannot be used to render the program non-free.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.\n\n                       TERMS AND CONDITIONS\n\n  0. Definitions.\n\n  \"This License\" refers to version 3 of the GNU General Public License.\n\n  \"Copyright\" also means copyright-like laws that apply to other kinds of\nworks, such as semiconductor masks.\n\n  \"The Program\" refers to any copyrightable work licensed under this\nLicense.  Each licensee is addressed as \"you\".  \"Licensees\" and\n\"recipients\" may be individuals or organizations.\n\n  To \"modify\" a work means to copy from or adapt all or part of the work\nin a fashion requiring copyright permission, other than the making of an\nexact copy.  The resulting work is called a \"modified version\" of the\nearlier work or a work \"based on\" the earlier work.\n\n  A \"covered work\" means either the unmodified Program or a work based\non the Program.\n\n  To \"propagate\" a work means to do anything with it that, without\npermission, would make you directly or secondarily liable for\ninfringement under applicable copyright law, except executing it on a\ncomputer or modifying a private copy.  Propagation includes copying,\ndistribution (with or without modification), making available to the\npublic, and in some countries other activities as well.\n\n  To \"convey\" a work means any kind of propagation that enables other\nparties to make or receive copies.  Mere interaction with a user through\na computer network, with no transfer of a copy, is not conveying.\n\n  An interactive user interface displays \"Appropriate Legal Notices\"\nto the extent that it includes a convenient and prominently visible\nfeature that (1) displays an appropriate copyright notice, and (2)\ntells the user that there is no warranty for the work (except to the\nextent that warranties are provided), that licensees may convey the\nwork under this License, and how to view a copy of this License.  If\nthe interface presents a list of user commands or options, such as a\nmenu, a prominent item in the list meets this criterion.\n\n  1. Source Code.\n\n  The \"source code\" for a work means the preferred form of the work\nfor making modifications to it.  \"Object code\" means any non-source\nform of a work.\n\n  A \"Standard Interface\" means an interface that either is an official\nstandard defined by a recognized standards body, or, in the case of\ninterfaces specified for a particular programming language, one that\nis widely used among developers working in that language.\n\n  The \"System Libraries\" of an executable work include anything, other\nthan the work as a whole, that (a) is included in the normal form of\npackaging a Major Component, but which is not part of that Major\nComponent, and (b) serves only to enable use of the work with that\nMajor Component, or to implement a Standard Interface for which an\nimplementation is available to the public in source code form.  A\n\"Major Component\", in this context, means a major essential component\n(kernel, window system, and so on) of the specific operating system\n(if any) on which the executable work runs, or a compiler used to\nproduce the work, or an object code interpreter used to run it.\n\n  The \"Corresponding Source\" for a work in object code form means all\nthe source code needed to generate, install, and (for an executable\nwork) run the object code and to modify the work, including scripts to\ncontrol those activities.  However, it does not include the work's\nSystem Libraries, or general-purpose tools or generally available free\nprograms which are used unmodified in performing those activities but\nwhich are not part of the work.  For example, Corresponding Source\nincludes interface definition files associated with source files for\nthe work, and the source code for shared libraries and dynamically\nlinked subprograms that the work is specifically designed to require,\nsuch as by intimate data communication or control flow between those\nsubprograms and other parts of the work.\n\n  The Corresponding Source need not include anything that users\ncan regenerate automatically from other parts of the Corresponding\nSource.\n\n  The Corresponding Source for a work in source code form is that\nsame work.\n\n  2. Basic Permissions.\n\n  All rights granted under this License are granted for the term of\ncopyright on the Program, and are irrevocable provided the stated\nconditions are met.  This License explicitly affirms your unlimited\npermission to run the unmodified Program.  The output from running a\ncovered work is covered by this License only if the output, given its\ncontent, constitutes a covered work.  This License acknowledges your\nrights of fair use or other equivalent, as provided by copyright law.\n\n  You may make, run and propagate covered works that you do not\nconvey, without conditions so long as your license otherwise remains\nin force.  You may convey covered works to others for the sole purpose\nof having them make modifications exclusively for you, or provide you\nwith facilities for running those works, provided that you comply with\nthe terms of this License in conveying all material for which you do\nnot control copyright.  Those thus making or running the covered works\nfor you must do so exclusively on your behalf, under your direction\nand control, on terms that prohibit them from making any copies of\nyour copyrighted material outside their relationship with you.\n\n  Conveying under any other circumstances is permitted solely under\nthe conditions stated below.  Sublicensing is not allowed; section 10\nmakes it unnecessary.\n\n  3. Protecting Users' Legal Rights From Anti-Circumvention Law.\n\n  No covered work shall be deemed part of an effective technological\nmeasure under any applicable law fulfilling obligations under article\n11 of the WIPO copyright treaty adopted on 20 December 1996, or\nsimilar laws prohibiting or restricting circumvention of such\nmeasures.\n\n  When you convey a covered work, you waive any legal power to forbid\ncircumvention of technological measures to the extent such circumvention\nis effected by exercising rights under this License with respect to\nthe covered work, and you disclaim any intention to limit operation or\nmodification of the work as a means of enforcing, against the work's\nusers, your or third parties' legal rights to forbid circumvention of\ntechnological measures.\n\n  4. Conveying Verbatim Copies.\n\n  You may convey verbatim copies of the Program's source code as you\nreceive it, in any medium, provided that you conspicuously and\nappropriately publish on each copy an appropriate copyright notice;\nkeep intact all notices stating that this License and any\nnon-permissive terms added in accord with section 7 apply to the code;\nkeep intact all notices of the absence of any warranty; and give all\nrecipients a copy of this License along with the Program.\n\n  You may charge any price or no price for each copy that you convey,\nand you may offer support or warranty protection for a fee.\n\n  5. Conveying Modified Source Versions.\n\n  You may convey a work based on the Program, or the modifications to\nproduce it from the Program, in the form of source code under the\nterms of section 4, provided that you also meet all of these conditions:\n\n    a) The work must carry prominent notices stating that you modified\n    it, and giving a relevant date.\n\n    b) The work must carry prominent notices stating that it is\n    released under this License and any conditions added under section\n    7.  This requirement modifies the requirement in section 4 to\n    \"keep intact all notices\".\n\n    c) You must license the entire work, as a whole, under this\n    License to anyone who comes into possession of a copy.  This\n    License will therefore apply, along with any applicable section 7\n    additional terms, to the whole of the work, and all its parts,\n    regardless of how they are packaged.  This License gives no\n    permission to license the work in any other way, but it does not\n    invalidate such permission if you have separately received it.\n\n    d) If the work has interactive user interfaces, each must display\n    Appropriate Legal Notices; however, if the Program has interactive\n    interfaces that do not display Appropriate Legal Notices, your\n    work need not make them do so.\n\n  A compilation of a covered work with other separate and independent\nworks, which are not by their nature extensions of the covered work,\nand which are not combined with it such as to form a larger program,\nin or on a volume of a storage or distribution medium, is called an\n\"aggregate\" if the compilation and its resulting copyright are not\nused to limit the access or legal rights of the compilation's users\nbeyond what the individual works permit.  Inclusion of a covered work\nin an aggregate does not cause this License to apply to the other\nparts of the aggregate.\n\n  6. Conveying Non-Source Forms.\n\n  You may convey a covered work in object code form under the terms\nof sections 4 and 5, provided that you also convey the\nmachine-readable Corresponding Source under the terms of this License,\nin one of these ways:\n\n    a) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by the\n    Corresponding Source fixed on a durable physical medium\n    customarily used for software interchange.\n\n    b) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by a\n    written offer, valid for at least three years and valid for as\n    long as you offer spare parts or customer support for that product\n    model, to give anyone who possesses the object code either (1) a\n    copy of the Corresponding Source for all the software in the\n    product that is covered by this License, on a durable physical\n    medium customarily used for software interchange, for a price no\n    more than your reasonable cost of physically performing this\n    conveying of source, or (2) access to copy the\n    Corresponding Source from a network server at no charge.\n\n    c) Convey individual copies of the object code with a copy of the\n    written offer to provide the Corresponding Source.  This\n    alternative is allowed only occasionally and noncommercially, and\n    only if you received the object code with such an offer, in accord\n    with subsection 6b.\n\n    d) Convey the object code by offering access from a designated\n    place (gratis or for a charge), and offer equivalent access to the\n    Corresponding Source in the same way through the same place at no\n    further charge.  You need not require recipients to copy the\n    Corresponding Source along with the object code.  If the place to\n    copy the object code is a network server, the Corresponding Source\n    may be on a different server (operated by you or a third party)\n    that supports equivalent copying facilities, provided you maintain\n    clear directions next to the object code saying where to find the\n    Corresponding Source.  Regardless of what server hosts the\n    Corresponding Source, you remain obligated to ensure that it is\n    available for as long as needed to satisfy these requirements.\n\n    e) Convey the object code using peer-to-peer transmission, provided\n    you inform other peers where the object code and Corresponding\n    Source of the work are being offered to the general public at no\n    charge under subsection 6d.\n\n  A separable portion of the object code, whose source code is excluded\nfrom the Corresponding Source as a System Library, need not be\nincluded in conveying the object code work.\n\n  A \"User Product\" is either (1) a \"consumer product\", which means any\ntangible personal property which is normally used for personal, family,\nor household purposes, or (2) anything designed or sold for incorporation\ninto a dwelling.  In determining whether a product is a consumer product,\ndoubtful cases shall be resolved in favor of coverage.  For a particular\nproduct received by a particular user, \"normally used\" refers to a\ntypical or common use of that class of product, regardless of the status\nof the particular user or of the way in which the particular user\nactually uses, or expects or is expected to use, the product.  A product\nis a consumer product regardless of whether the product has substantial\ncommercial, industrial or non-consumer uses, unless such uses represent\nthe only significant mode of use of the product.\n\n  \"Installation Information\" for a User Product means any methods,\nprocedures, authorization keys, or other information required to install\nand execute modified versions of a covered work in that User Product from\na modified version of its Corresponding Source.  The information must\nsuffice to ensure that the continued functioning of the modified object\ncode is in no case prevented or interfered with solely because\nmodification has been made.\n\n  If you convey an object code work under this section in, or with, or\nspecifically for use in, a User Product, and the conveying occurs as\npart of a transaction in which the right of possession and use of the\nUser Product is transferred to the recipient in perpetuity or for a\nfixed term (regardless of how the transaction is characterized), the\nCorresponding Source conveyed under this section must be accompanied\nby the Installation Information.  But this requirement does not apply\nif neither you nor any third party retains the ability to install\nmodified object code on the User Product (for example, the work has\nbeen installed in ROM).\n\n  The requirement to provide Installation Information does not include a\nrequirement to continue to provide support service, warranty, or updates\nfor a work that has been modified or installed by the recipient, or for\nthe User Product in which it has been modified or installed.  Access to a\nnetwork may be denied when the modification itself materially and\nadversely affects the operation of the network or violates the rules and\nprotocols for communication across the network.\n\n  Corresponding Source conveyed, and Installation Information provided,\nin accord with this section must be in a format that is publicly\ndocumented (and with an implementation available to the public in\nsource code form), and must require no special password or key for\nunpacking, reading or copying.\n\n  7. Additional Terms.\n\n  \"Additional permissions\" are terms that supplement the terms of this\nLicense by making exceptions from one or more of its conditions.\nAdditional permissions that are applicable to the entire Program shall\nbe treated as though they were included in this License, to the extent\nthat they are valid under applicable law.  If additional permissions\napply only to part of the Program, that part may be used separately\nunder those permissions, but the entire Program remains governed by\nthis License without regard to the additional permissions.\n\n  When you convey a copy of a covered work, you may at your option\nremove any additional permissions from that copy, or from any part of\nit.  (Additional permissions may be written to require their own\nremoval in certain cases when you modify the work.)  You may place\nadditional permissions on material, added by you to a covered work,\nfor which you have or can give appropriate copyright permission.\n\n  Notwithstanding any other provision of this License, for material you\nadd to a covered work, you may (if authorized by the copyright holders of\nthat material) supplement the terms of this License with terms:\n\n    a) Disclaiming warranty or limiting liability differently from the\n    terms of sections 15 and 16 of this License; or\n\n    b) Requiring preservation of specified reasonable legal notices or\n    author attributions in that material or in the Appropriate Legal\n    Notices displayed by works containing it; or\n\n    c) Prohibiting misrepresentation of the origin of that material, or\n    requiring that modified versions of such material be marked in\n    reasonable ways as different from the original version; or\n\n    d) Limiting the use for publicity purposes of names of licensors or\n    authors of the material; or\n\n    e) Declining to grant rights under trademark law for use of some\n    trade names, trademarks, or service marks; or\n\n    f) Requiring indemnification of licensors and authors of that\n    material by anyone who conveys the material (or modified versions of\n    it) with contractual assumptions of liability to the recipient, for\n    any liability that these contractual assumptions directly impose on\n    those licensors and authors.\n\n  All other non-permissive additional terms are considered \"further\nrestrictions\" within the meaning of section 10.  If the Program as you\nreceived it, or any part of it, contains a notice stating that it is\ngoverned by this License along with a term that is a further\nrestriction, you may remove that term.  If a license document contains\na further restriction but permits relicensing or conveying under this\nLicense, you may add to a covered work material governed by the terms\nof that license document, provided that the further restriction does\nnot survive such relicensing or conveying.\n\n  If you add terms to a covered work in accord with this section, you\nmust place, in the relevant source files, a statement of the\nadditional terms that apply to those files, or a notice indicating\nwhere to find the applicable terms.\n\n  Additional terms, permissive or non-permissive, may be stated in the\nform of a separately written license, or stated as exceptions;\nthe above requirements apply either way.\n\n  8. Termination.\n\n  You may not propagate or modify a covered work except as expressly\nprovided under this License.  Any attempt otherwise to propagate or\nmodify it is void, and will automatically terminate your rights under\nthis License (including any patent licenses granted under the third\nparagraph of section 11).\n\n  However, if you cease all violation of this License, then your\nlicense from a particular copyright holder is reinstated (a)\nprovisionally, unless and until the copyright holder explicitly and\nfinally terminates your license, and (b) permanently, if the copyright\nholder fails to notify you of the violation by some reasonable means\nprior to 60 days after the cessation.\n\n  Moreover, your license from a particular copyright holder is\nreinstated permanently if the copyright holder notifies you of the\nviolation by some reasonable means, this is the first time you have\nreceived notice of violation of this License (for any work) from that\ncopyright holder, and you cure the violation prior to 30 days after\nyour receipt of the notice.\n\n  Termination of your rights under this section does not terminate the\nlicenses of parties who have received copies or rights from you under\nthis License.  If your rights have been terminated and not permanently\nreinstated, you do not qualify to receive new licenses for the same\nmaterial under section 10.\n\n  9. Acceptance Not Required for Having Copies.\n\n  You are not required to accept this License in order to receive or\nrun a copy of the Program.  Ancillary propagation of a covered work\noccurring solely as a consequence of using peer-to-peer transmission\nto receive a copy likewise does not require acceptance.  However,\nnothing other than this License grants you permission to propagate or\nmodify any covered work.  These actions infringe copyright if you do\nnot accept this License.  Therefore, by modifying or propagating a\ncovered work, you indicate your acceptance of this License to do so.\n\n  10. Automatic Licensing of Downstream Recipients.\n\n  Each time you convey a covered work, the recipient automatically\nreceives a license from the original licensors, to run, modify and\npropagate that work, subject to this License.  You are not responsible\nfor enforcing compliance by third parties with this License.\n\n  An \"entity transaction\" is a transaction transferring control of an\norganization, or substantially all assets of one, or subdividing an\norganization, or merging organizations.  If propagation of a covered\nwork results from an entity transaction, each party to that\ntransaction who receives a copy of the work also receives whatever\nlicenses to the work the party's predecessor in interest had or could\ngive under the previous paragraph, plus a right to possession of the\nCorresponding Source of the work from the predecessor in interest, if\nthe predecessor has it or can get it with reasonable efforts.\n\n  You may not impose any further restrictions on the exercise of the\nrights granted or affirmed under this License.  For example, you may\nnot impose a license fee, royalty, or other charge for exercise of\nrights granted under this License, and you may not initiate litigation\n(including a cross-claim or counterclaim in a lawsuit) alleging that\nany patent claim is infringed by making, using, selling, offering for\nsale, or importing the Program or any portion of it.\n\n  11. Patents.\n\n  A \"contributor\" is a copyright holder who authorizes use under this\nLicense of the Program or a work on which the Program is based.  The\nwork thus licensed is called the contributor's \"contributor version\".\n\n  A contributor's \"essential patent claims\" are all patent claims\nowned or controlled by the contributor, whether already acquired or\nhereafter acquired, that would be infringed by some manner, permitted\nby this License, of making, using, or selling its contributor version,\nbut do not include claims that would be infringed only as a\nconsequence of further modification of the contributor version.  For\npurposes of this definition, \"control\" includes the right to grant\npatent sublicenses in a manner consistent with the requirements of\nthis License.\n\n  Each contributor grants you a non-exclusive, worldwide, royalty-free\npatent license under the contributor's essential patent claims, to\nmake, use, sell, offer for sale, import and otherwise run, modify and\npropagate the contents of its contributor version.\n\n  In the following three paragraphs, a \"patent license\" is any express\nagreement or commitment, however denominated, not to enforce a patent\n(such as an express permission to practice a patent or covenant not to\nsue for patent infringement).  To \"grant\" such a patent license to a\nparty means to make such an agreement or commitment not to enforce a\npatent against the party.\n\n  If you convey a covered work, knowingly relying on a patent license,\nand the Corresponding Source of the work is not available for anyone\nto copy, free of charge and under the terms of this License, through a\npublicly available network server or other readily accessible means,\nthen you must either (1) cause the Corresponding Source to be so\navailable, or (2) arrange to deprive yourself of the benefit of the\npatent license for this particular work, or (3) arrange, in a manner\nconsistent with the requirements of this License, to extend the patent\nlicense to downstream recipients.  \"Knowingly relying\" means you have\nactual knowledge that, but for the patent license, your conveying the\ncovered work in a country, or your recipient's use of the covered work\nin a country, would infringe one or more identifiable patents in that\ncountry that you have reason to believe are valid.\n\n  If, pursuant to or in connection with a single transaction or\narrangement, you convey, or propagate by procuring conveyance of, a\ncovered work, and grant a patent license to some of the parties\nreceiving the covered work authorizing them to use, propagate, modify\nor convey a specific copy of the covered work, then the patent license\nyou grant is automatically extended to all recipients of the covered\nwork and works based on it.\n\n  A patent license is \"discriminatory\" if it does not include within\nthe scope of its coverage, prohibits the exercise of, or is\nconditioned on the non-exercise of one or more of the rights that are\nspecifically granted under this License.  You may not convey a covered\nwork if you are a party to an arrangement with a third party that is\nin the business of distributing software, under which you make payment\nto the third party based on the extent of your activity of conveying\nthe work, and under which the third party grants, to any of the\nparties who would receive the covered work from you, a discriminatory\npatent license (a) in connection with copies of the covered work\nconveyed by you (or copies made from those copies), or (b) primarily\nfor and in connection with specific products or compilations that\ncontain the covered work, unless you entered into that arrangement,\nor that patent license was granted, prior to 28 March 2007.\n\n  Nothing in this License shall be construed as excluding or limiting\nany implied license or other defenses to infringement that may\notherwise be available to you under applicable patent law.\n\n  12. No Surrender of Others' Freedom.\n\n  If conditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot convey a\ncovered work so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you may\nnot convey it at all.  For example, if you agree to terms that obligate you\nto collect a royalty for further conveying from those to whom you convey\nthe Program, the only way you could satisfy both those terms and this\nLicense would be to refrain entirely from conveying the Program.\n\n  13. Use with the GNU Affero General Public License.\n\n  Notwithstanding any other provision of this License, you have\npermission to link or combine any covered work with a work licensed\nunder version 3 of the GNU Affero General Public License into a single\ncombined work, and to convey the resulting work.  The terms of this\nLicense will continue to apply to the part which is the covered work,\nbut the special requirements of the GNU Affero General Public License,\nsection 13, concerning interaction through a network will apply to the\ncombination as such.\n\n  14. Revised Versions of this License.\n\n  The Free Software Foundation may publish revised and/or new versions of\nthe GNU General Public License from time to time.  Such new versions will\nbe similar in spirit to the present version, but may differ in detail to\naddress new problems or concerns.\n\n  Each version is given a distinguishing version number.  If the\nProgram specifies that a certain numbered version of the GNU General\nPublic License \"or any later version\" applies to it, you have the\noption of following the terms and conditions either of that numbered\nversion or of any later version published by the Free Software\nFoundation.  If the Program does not specify a version number of the\nGNU General Public License, you may choose any version ever published\nby the Free Software Foundation.\n\n  If the Program specifies that a proxy can decide which future\nversions of the GNU General Public License can be used, that proxy's\npublic statement of acceptance of a version permanently authorizes you\nto choose that version for the Program.\n\n  Later license versions may give you additional or different\npermissions.  However, no additional obligations are imposed on any\nauthor or copyright holder as a result of your choosing to follow a\nlater version.\n\n  15. Disclaimer of Warranty.\n\n  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY\nAPPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT\nHOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY\nOF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,\nTHE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\nPURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM\nIS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF\nALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n  16. Limitation of Liability.\n\n  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\nWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS\nTHE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY\nGENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE\nUSE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF\nDATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD\nPARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),\nEVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF\nSUCH DAMAGES.\n\n  17. Interpretation of Sections 15 and 16.\n\n  If the disclaimer of warranty and limitation of liability provided\nabove cannot be given local legal effect according to their terms,\nreviewing courts shall apply local law that most closely approximates\nan absolute waiver of all civil liability in connection with the\nProgram, unless a warranty or assumption of liability accompanies a\ncopy of the Program in return for a fee.\n\n                     END OF TERMS AND CONDITIONS\n\n            How to Apply These Terms to Your New Programs\n\n  If you develop a new program, and you want it to be of the greatest\npossible use to the public, the best way to achieve this is to make it\nfree software which everyone can redistribute and change under these terms.\n\n  To do so, attach the following notices to the program.  It is safest\nto attach them to the start of each source file to most effectively\nstate the exclusion of warranty; and each file should have at least\nthe \"copyright\" line and a pointer to where the full notice is found.\n\n    <one line to give the program's name and a brief idea of what it does.>\n    Copyright (C) <year>  <name of author>\n\n    This program is free software: you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation, either version 3 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License\n    along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\nAlso add information on how to contact you by electronic and paper mail.\n\n  If the program does terminal interaction, make it output a short\nnotice like this when it starts in an interactive mode:\n\n    <program>  Copyright (C) <year>  <name of author>\n    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\n    This is free software, and you are welcome to redistribute it\n    under certain conditions; type `show c' for details.\n\nThe hypothetical commands `show w' and `show c' should show the appropriate\nparts of the General Public License.  Of course, your program's commands\nmight be different; for a GUI interface, you would use an \"about box\".\n\n  You should also get your employer (if you work as a programmer) or school,\nif any, to sign a \"copyright disclaimer\" for the program, if necessary.\nFor more information on this, and how to apply and follow the GNU GPL, see\n<https://www.gnu.org/licenses/>.\n\n  The GNU General Public License does not permit incorporating your program\ninto proprietary programs.  If your program is a subroutine library, you\nmay consider it more useful to permit linking proprietary applications with\nthe library.  If this is what you want to do, use the GNU Lesser General\nPublic License instead of this License.  But first, please read\n<https://www.gnu.org/licenses/why-not-lgpl.html>.\n"
  },
  {
    "path": "README.md",
    "content": "<p align=\"center\">\n    <img src=\"./src/assets/icon.png\" width=\"150\">\n</p>\n\n<h1 align=\"center\">ChatHub</h1>\n\n<div align=\"center\">\n\n### Install\n\n<a href=\"https://chrome.google.com/webstore/detail/chathub-all-in-one-chatbo/iaakpnchhognanibcahlpcplchdfmgma?utm_source=github\"><img src=\"https://user-images.githubusercontent.com/64502893/231991498-8df6dd63-727c-41d0-916f-c90c15127de3.png\" width=\"200\" alt=\"Get ChatHub for Chromium\"></a>\n\n</div>\n\n## 📷 Screenshot\n\n![Screenshot](screenshots/extension.png?raw=true)\n\n## 🤝 Sponsors\n\n<a href=\"https://getstream.io/chat/sdk/react/?utm_source=github&utm_medium=referral&utm_content=&utm_campaign=wong2\">\n  <img src=\"screenshots/stream-logo.jpg\" width=\"200\" />\n</a>\n\n## ✨ Features\n\n- 🤖 Use different chatbots in one app, currently supporting ChatGPT, new Bing Chat, Google Bard, Claude, and open-source models including LLama2, Vicuna, ChatGLM etc\n- 💬 Chat with multiple chatbots at the same time, making it easy to compare their answers\n- 🚀 Support ChatGPT API and GPT-4 Browsing\n- 🔍 Shortcut to quickly activate the app anywhere in the browser\n- 🎨 Markdown and code highlight support\n- 📚 Prompt Library for custom prompts and community prompts\n- 💾 Conversation history saved locally\n- 📥 Export and Import all your data\n- 🔗 Share conversation to markdown\n- 🌙 Dark mode\n- 🌐 Web access\n\n## 🤖 Supported Bots\n\n- ChatGPT (via Webapp/API)\n- Gemini\n- Claude (via Webapp/API)\n- Grok\n- DeepSeek\n- Qianwen\n- Llama\n- ...\n\n## 🔨 Build from Source\n\n- Clone the source code\n- `corepack enable`\n- `yarn install`\n- `yarn build`\n- In Chrome/Edge go to the Extensions page (chrome://extensions or edge://extensions)\n- Enable Developer Mode\n- Drag the `dist` folder anywhere on the page to import it (do not delete the folder afterward)\n"
  },
  {
    "path": "README_IN.md",
    "content": "<p align=\"center\">\n    <img src=\"./src/assets/icon.png\" width=\"150\">\n</p>\n\n<h1 align=\"center\">ChatHub</h1>\n\n<div align=\"center\">\n\n### ChatHub adalah klien chatbot all-in-one\n\n[![author][author-image]][author-url]\n[![license][license-image]][license-url]\n[![release][release-image]][release-url]\n[![last commit][last-commit-image]][last-commit-url]  \n\n[Inggris](README.md) &nbsp;&nbsp;|&nbsp;&nbsp; Indonesia &nbsp;&nbsp;|&nbsp;&nbsp; [简体中文](README_ZH-CN.md) &nbsp;&nbsp;|&nbsp;&nbsp; [繁體中文](README_ZH-TW.md) &nbsp;&nbsp;|&nbsp;&nbsp; [日本語](README_JA.md)\n\n##    \n    \n### Instal\n    \n<a href=\"https://chrome.google.com/webstore/detail/chathub-all-in-one-chatbo/iaakpnchhognanibcahlpcplchdfmgma?utm_source=github\"><img src=\"https://user-images.githubusercontent.com/64502893/231991498-8df6dd63-727c-41d0-916f-c90c15127de3.png\" width=\"200\" alt=\"Dapatkan ChatHub untuk Chromium\"></a>\n<a href=\"https://microsoftedge.microsoft.com/addons/detail/chathub-allinone-chat/kdlmggoacmfoombiokflpeompajfljga?utm_source=github\"><img src=\"https://user-images.githubusercontent.com/64502893/231991158-1b54f831-2fdc-43b6-bf9a-f894000e5aa8.png\" width=\"160\" alt=\"Dapatkan ChatHub untuk Microsoft Edge\"></a>\n    \n##\n\n[Tangkapan Layar](#-tangkapan-layar) &nbsp;&nbsp;|&nbsp;&nbsp; [Fitur](#-fitur) &nbsp;&nbsp;|&nbsp;&nbsp; [Bot yang Didukung](#-supported-bots) &nbsp;&nbsp;|&nbsp;&nbsp; [Instalasi Manual](#-instalasi-manual) &nbsp;&nbsp;|&nbsp;&nbsp; [Membangun dari Source](#-membangun-dari-source) &nbsp;&nbsp;|&nbsp;&nbsp; [Changelog](#-changelog)\n    \n[author-image]: https://img.shields.io/badge/author-wong2-blue.svg\n[author-url]: https://github.com/wong2\n[license-image]: https://img.shields.io/github/license/chathub-dev/chathub?color=blue\n[license-url]: https://github.com/chathub-dev/chathub/blob/main/LICENSE\n[release-image]: https://img.shields.io/github/v/release/chathub-dev/chathub?color=blue\n[release-url]: https://github.com/chathub-dev/chathub/releases/latest\n[last-commit-image]: https://img.shields.io/github/last-commit/chathub-dev/chathub?label=last%20commit\n[last-commit-url]: https://github.com/chathub-dev/chathub/commits\n\n</div>\n\n##\n\n## 📷 Tangkapan Layar\n\n![Tangkapan Layar](screenshots/extension.png?raw=true)\n\n![Tangkapan Layar (Mode Gelap)](screenshots/dark.png?raw=true)\n\n## ✨ Fitur\n\n- 🤖 Gunakan chatbot yang berbeda dalam satu aplikasi, saat ini mendukung ChatGPT, Bing Chat baru, Google Bard, Claude, dan 10+ model open-source termasuk Alpaca, Vicuna, ChatGLM, dll\n- 💬 Chat dengan beberapa chatbot secara bersamaan, sehingga mudah untuk membandingkan jawaban mereka\n- 🚀 Mendukung API ChatGPT dan Browsing GPT-4\n- 🔍 Pintasan untuk dengan cepat mengaktifkan aplikasi di mana saja di browser\n- 🎨 Mendukung penyorotan markdown dan kode\n- 📚 Perpustakaan Prompt untuk prompt kustom dan prompt komunitas\n- 💾 Riwayat percakapan tersimpan secara lokal\n- 📥 Ekspor dan Impor semua data Anda\n- 🔗 Bagikan percakapan ke markdown\n- 🌙 Mode gelap\n\n## 🤖 Bot yang Didukung\n\n* ChatGPT (melalui Webapp/API/Azure/Poe)\n* Bing Chat\n* Google Bard\n* Claude (melalui Poe)\n* iFlytek Spark\n* ChatGLM\n* Alpaca\n* Vicuna\n* Koala\n* Dolly\n* LLaMA\n* StableLM\n* OpenAssistant\n* ChatRWKV\n* ...\n\n## 🔧 Instalasi Manual\n\n- Unduh chathub.zip dari [Release](https://github.com/chathub-dev/chathub/releases)\n- Ekstrak file\n- Di Chrome/Edge, buka halaman ekstensi (chrome://extensions atau edge://extensions)\n- Aktifkan Mode Pengembang\n- Seret folder yang telah diekstrak ke mana saja di halaman untuk mengimpor (jangan hapus folder setelah itu)\n\n## 🔨 Membangun dari Source\n\n- Clone source code\n- `yarn install`\n- `yarn build`\n- Muat folder `dist` ke browser dengan mengikuti langkah-langkah dalam _Instalasi Manual_\n\n## 📜 Changelog\n\n### v1.22.0\n\n- Mendukung Claude API\n\n### v1.21.0\n\n- Menambahkan lebih banyak model open-source\n\n### v1.20.0\n\n- Akses dari panel samping Chrome\n\n### v1.19.0\n\n- Akses cepat ke prompt\n\n### v1.18.0\n\n- Mendukung Alpaca, Vicuna, dan ChatGLM\n\n### v1.17.0\n\n- Mendukung model Browsing GPT-4\n\n### v1.16.5\n\n- Menambahkan dukungan layanan Azure OpenAI\n\n### v1.16.0\n\n- Menambahkan pengaturan tema kustom\n\n### v1.15.0\n\n- Menambahkan bot Xunfei Spark\n\n### v1.14.0\n\n- Mendukung lebih banyak bot dalam mode all-in-one untuk pengguna premium\n\n### v1.12.0\n\n- Menambahkan lisensi premium\n\n### v1.11.0\n\n- Dukungan Claude (melalui Poe)\n\n### v1.10.0\n\n- Command + K\n\n### v1.9.4\n\n- Mode gelap\n\n### v1.9.3\n\n- Dukungan rumus matematika dengan katex\n- Simpan prompt komunitas ke lokal\n\n### v1.9.2\n\n- Hapus riwayat pesan\n\n### v1.9.0\n\n- Bagikan percakapan sebagai markdown atau melalui sharegpt.com\n\n### v1.8.0\n\n- Impor/Ekspor semua data\n- Edit prompt lokal\n- Mengalihkan chatbot untuk dibandingkan\n\n### v1.7.0\n\n- Menambahkan riwayat percakapan\n\n### v1.6.0\n\n- Menambahkan dukungan untuk Google Bard\n\n### v1.5.4\n\n- Dukungan model GPT-4 dalam mode api ChatGPT\n\n### v1.5.1\n\n- Menambahkan pengaturan i18n\n\n### v1.5.0\n\n- Dukungan model GPT-4 dalam mode Webapp ChatGPT\n\n### v1.4.0\n\n- Menambahkan Prompt Library\n\n### v1.3.0\n\n- Menambahkan tombol salin kode\n- Sinkronisasi status chat antara all-in-one dan mode mandiri\n- Memungkinkan input sambil menghasilkan jawaban\n\n### v1.2.0\n\n- Dukungan untuk menyalin teks pesan\n- Perbaiki gaya elemen formulir halaman pengaturan\n"
  },
  {
    "path": "README_JA.md",
    "content": "<p align=\"center\">\n    <img src=\"./src/assets/icon.png\" width=\"150\">\n</p>\n\n<h1 align=\"center\">ChatHub</h1>\n\n<div align=\"center\">\n\n### ChatHub はオールインワンのチャットボットクライアントです\n\n[![author][author-image]][author-url]\n[![license][license-image]][license-url]\n[![release][release-image]][release-url]\n[![last commit][last-commit-image]][last-commit-url]    \n    \n[English](README.md) &nbsp;&nbsp;|&nbsp;&nbsp; [Indonesia](README_IN.md) &nbsp;&nbsp;|&nbsp;&nbsp; [简体中文](README_ZH-CN.md) &nbsp;&nbsp;|&nbsp;&nbsp; [繁體中文](README_ZH-TW.md) &nbsp;&nbsp;|&nbsp;&nbsp; 日本語\n\n##    \n    \n### インストール\n    \n<a href=\"https://chrome.google.com/webstore/detail/chathub-all-in-one-chatbo/iaakpnchhognanibcahlpcplchdfmgma?utm_source=github\"><img src=\"https://user-images.githubusercontent.com/64502893/231991498-8df6dd63-727c-41d0-916f-c90c15127de3.png\" width=\"200\" alt=\"Chromium 用の ChatHub を入手してください\"></a>\n<a href=\"https://microsoftedge.microsoft.com/addons/detail/chathub-allinone-chat/kdlmggoacmfoombiokflpeompajfljga?utm_source=github\"><img src=\"https://user-images.githubusercontent.com/64502893/231991158-1b54f831-2fdc-43b6-bf9a-f894000e5aa8.png\" width=\"160\" alt=\"Microsoft Edge 用の ChatHub を入手してください\"></a>\n    \n##\n\n[スクリーンショット](#-スクリーンショット) &nbsp;&nbsp;|&nbsp;&nbsp; [特徴](#-特徴) &nbsp;&nbsp;|&nbsp;&nbsp; [サポートされているボット](#-サポートされているボット) &nbsp;&nbsp;|&nbsp;&nbsp; [手動インストール](#-手動インストール) &nbsp;&nbsp;|&nbsp;&nbsp; [ソースからビルドする](#-ソースからビルドする) &nbsp;&nbsp;|&nbsp;&nbsp; [変更ログ](#-変更ログ)\n\n[author-image]: https://img.shields.io/badge/author-wong2-blue.svg\n[author-url]: https://github.com/wong2    \n[license-image]: https://img.shields.io/github/license/chathub-dev/chathub?color=blue\n[license-url]: https://github.com/chathub-dev/chathub/blob/main/LICENSE\n[release-image]: https://img.shields.io/github/v/release/chathub-dev/chathub?color=blue\n[release-url]: https://github.com/chathub-dev/chathub/releases/latest   \n[last-commit-image]: https://img.shields.io/github/last-commit/chathub-dev/chathub?label=last%20commit\n[last-commit-url]: https://github.com/chathub-dev/chathub/commits\n\n</div>\n\n##\n\n## 📷 スクリーンショット\n\n![Screenshot](screenshots/extension.png?raw=true)\n\n![Screenshot (Dark Mode)](screenshots/dark.png?raw=true)\n\n\n## ✨ 特徴\n\n- 🤖 アプリ内で異なるチャットボットを使用できます。現在は ChatGPT、新しい Bing Chat、Google Bard、Claude、および Alpaca、Vicuna、ChatGLM などを含む10以上のオープンソースモデルをサポートしています\n- 💬 複数のチャットボットと同時にチャットすることで、回答を比較しやすくします\n- 🚀 ChatGPT API および GPT-4 Browsing をサポートします\n- 🔍 ブラウザのどこからでもアプリを素早くアクティブにするためのショートカット\n- 🎨 Markdown とコードのハイライトのサポート\n- 📚 カスタムプロンプトとコミュニティプロンプトのためのプロンプトライブラリ\n- 💾 ローカルに保存された会話履歴\n- 📥 データのエクスポートとインポート\n- 🔗 マークダウン形式で会話を共有\n- 🌙 ダークモード\n\n## 🤖 サポートされているボット\n\n* ChatGPT（Web アプリ/API/Azure/Poe経由）\n* Bing Chat\n* Google Bard\n* Claude（Poe 経由）\n* iFlytek Spark\n* ChatGLM\n* Alpaca\n* Vicuna\n* Koala\n* Dolly\n* LLaMA\n* StableLM\n* OpenAssistant\n* ChatRWKV\n* ...\n\n## 🔧 手動インストール\n\n- [リリース](https://github.com/chathub-dev/chathub/releases)から chathub.zip をダウンロード\n- ファイルを解凍\n- Chrome/Edge で拡張機能ページに移動します (chrome://extensions または edge://extensions)\n- 開発者モードを有効にする\n- 解凍したフォルダーをページ上の任意の場所にドラッグしてインポートします (後でフォルダーを削除しないでください)\n\n## 🔨 ソースからビルドする\n\n- ソースコードをクローン\n- `yarn install`\n- `yarn build`\n- _マニュアルインストール_ の手順に従って、`dist` _フォルダをブラウザに読み込みます_\n\n## 📜 変更ログ\n\n### v1.22.0\n\n- Claude API のサポートを追加\n\n### v1.21.0\n\n- より多くのオープンソースモデルを追加\n\n### v1.20.0\n\n- Chrome のサイドパネルからアクセスできるようにしました\n\n### v1.19.0\n\n- プロンプトへの簡単アクセス\n\n### v1.18.0\n\n- Alpaca、Vicuna、ChatGLM のサポート\n\n### v1.17.0\n\n- GPT-4 Browsing モデルのサポート\n\n### v1.16.5\n\n- Azure OpenAI サービスのサポートを追加\n\n### v1.16.0\n\n- カスタムテーマ設定を追加\n\n### v1.15.0\n\n- Xunfei Spark ボットを追加\n\n### v1.14.0\n\n- プレミアムユーザー向けのオールインワンモードで、より多くのボットをサポート\n\n### v1.12.0\n\n- プレミアムライセンスを追加\n\n### v1.11.0\n\n- クロードのサポートを追加 (Poe経由で)\n\n### v1.10.0\n\n- Command + K\n\n### v1.9.4\n\n- ダークモード\n\n### v1.9.3\n\n- katex で数式をサポート\n- コミュニティプロンプトをローカルに保存\n\n### v1.9.2\n\n- 履歴メッセージを削除する\n\n### v1.9.0\n\n- markdown として、または sharegpt.com 経由でチャットを共有する\n\n### v1.8.0\n\n- すべてのデータのインポート/エクスポート\n- ローカルプロンプトを編集する\n- 比較のためにチャットボットを切り替える\n\n### v1.7.0\n\n- 会話履歴を追加する\n\n### v1.6.0\n\n- Google Bard のサポートを追加\n\n### v1.5.4\n\n- ChatGPT api モードで GPT-4 モデルをサポート\n\n### v1.5.1\n\n- i18n 設定を追加\n\n### v1.5.0\n\n- ChatGPT Webapp モードで GPT-4 モデルをサポート\n\n### v1.4.0\n\n- プロンプトライブラリを追加\n\n### v1.3.0\n\n- コピーコードボタンを追加\n- オールインワンモードとスタンドアロンモードの間でチャット状態を同期\n- 回答の生成中に入力を許可\n\n### v1.2.0\n\n- コピーメッセージテキストのサポート\n- ページフォーム要素スタイルの設定を改善\n"
  },
  {
    "path": "README_ZH-CN.md",
    "content": "<p align=\"center\">\n    <img src=\"./src/assets/icon.png\" width=\"150\">\n</p>\n\n<h1 align=\"center\">ChatHub</h1>\n\n<div align=\"center\">\n\n### ChatHub 是款全能聊天机器人客户端\n\n[![作者][作者-image]][作者-url]\n[![许可证][许可证-image]][许可证-url]\n[![发布][发布-image]][发布-url]\n[![最后提交][最后提交-image]][最后提交-url]\n\n[English](README.md) &nbsp;&nbsp;|&nbsp;&nbsp; [Indonesia](README_IN.md) &nbsp;&nbsp;|&nbsp;&nbsp; 简体中文 &nbsp;&nbsp;|&nbsp;&nbsp; [繁體中文](README_ZH-TW.md) &nbsp;&nbsp;|&nbsp;&nbsp; [日本語](README_JA.md)\n\n##\n\n### 安装\n\n<a href=\"https://chrome.google.com/webstore/detail/chathub-all-in-one-chatbo/iaakpnchhognanibcahlpcplchdfmgma?utm_source=website\"><img src=\"https://user-images.githubusercontent.com/64502893/231991498-8df6dd63-727c-41d0-916f-c90c15127de3.png\" width=\"200\" alt=\"获取 Chromium 版 ChatHub\"></a>&nbsp;&nbsp;\n<a href=\"https://microsoftedge.microsoft.com/addons/detail/chathub-allinone-chat/kdlmggoacmfoombiokflpeompajfljga\"><img src=\"https://user-images.githubusercontent.com/64502893/231991158-1b54f831-2fdc-43b6-bf9a-f894000e5aa8.png\" width=\"160\" alt=\"获取 Microsoft Edge 版 ChatHub\"></a>\n\n##\n\n[截图](#-截图) &nbsp;&nbsp;|&nbsp;&nbsp; [特点](#-特点) &nbsp;&nbsp;|&nbsp;&nbsp; [支持的聊天机器人](#-支持的聊天机器人) &nbsp;&nbsp;|&nbsp;&nbsp; [手动安装](#-手动安装) &nbsp;&nbsp;|&nbsp;&nbsp; [从源代码构建](#-从源代码构建) &nbsp;&nbsp;|&nbsp;&nbsp; [更新日志](#-更新日志)\n\n[作者-image]: https://img.shields.io/badge/author-wong2-blue.svg\n[作者-url]: https://github.com/wong2\n[许可证-image]: https://img.shields.io/github/license/chathub-dev/chathub?color=blue\n[许可证-url]: https://github.com/chathub-dev/chathub/blob/main/LICENSE\n[发布-image]: https://img.shields.io/github/v/release/chathub-dev/chathub?color=blue\n[发布-url]: https://github.com/chathub-dev/chathub/releases/latest\n[最后提交-image]: https://img.shields.io/github/last-commit/chathub-dev/chathub?label=last%20commit\n[最后提交-url]: https://github.com/chathub-dev/chathub/commits\n\n</div>\n\n##\n\n## 📷 截图\n\n![截图](screenshots/extension.png?raw=true)\n\n![截图 (暗黑模式)](screenshots/dark.png?raw=true)\n\n## ✨ 特点\n\n- 🤖 在一个应用中使用不同的聊天机器人，目前支持 ChatGPT、新的 Bing Chat、Google Bard、Claude 以及包括 Alpaca、Vicuna、ChatGLM 等在内的 10 多个开源模型\n- 💬 同时与多个聊天机器人进行对话，方便比较它们的回答\n- 🚀 支持 ChatGPT API 和 GPT-4 浏览\n- 🔍 快捷方式，可在浏览器的任何位置快速激活应用\n- 🎨 支持 Markdown 和代码高亮显示\n- 📚 自定义提示和社区提示的提示库\n- 💾 本地保存对话历史\n- 📥 导出和导入所有数据\n- 🔗 将对话转为 Markdown 并分享\n- 🌙 暗黑模式\n\n## 🤖 支持的聊天机器人\n\n* ChatGPT（通过 Web 应用/API/Azure/Poe）\n* Bing Chat\n* Google Bard\n* Claude（通过 Poe）\n* iFlytek Spark\n* ChatGLM\n* Alpaca\n* Vicuna\n* Koala\n* Dolly\n* LLaMA\n* StableLM\n* OpenAssistant\n* ChatRWKV\n* ...\n\n## 🔧 手动安装\n\n- 从 [Releases](https://github.com/chathub-dev/chathub/releases) 下载 chathub.zip\n- 解压文件\n- 在 Chrome/Edge 中进入扩展页面 (chrome://extensions 或 edge://extensions)\n- 启用开发者模式\n- 将解压后的文件夹拖到页面上的任何位置进行导入（导入后不要删除文件夹）\n\n## 🔨 从源代码构建\n\n- 克隆源代码\n- 运行 `yarn install`\n- 运行 `yarn build`\n- 按照 _手动安装_ 中的步骤将 `dist` _文件夹加载到浏览器中_\n\n## 📜 更新日志\n\n### v1.22.0\n\n- 支持 Claude API\n\n### v1.21.0\n\n- 添加更多开源模型\n\n### v1.20.0\n\n- 从 Chrome 侧边栏访问\n\n### v1.19.0\n\n- 快速访问提示\n\n### v1.18.0\n\n- 支持 Alpaca、Vicuna 和 ChatGLM\n\n### v1.17.0\n\n- 支持 GPT-4 浏览模型\n\n### v1.16.5\n\n- 增加 Azure OpenAI 服务支持\n\n### v1.16.0\n\n- 增加自定义主题设置\n\n### v1.15.0\n\n- 增加讯飞 Spark 机器人\n\n### v1.14.0\n\n- 为高级用户在全能模式中支持更多机器人\n\n### v1.12.0\n\n- 增加高级许可证\n\n### v1.11.0\n\n- 支持 Claude (via Poe)\n\n### v1.10.0\n\n- 新增了快捷键 Command + K\n\n### v1.9.4\n\n- 新增了暗黑模式\n\n### v1.9.3\n\n- 支持使用 katex 插件输入数学公式\n- 可以将社区提示保存到本地\n\n### v1.9.2\n\n- 可以删除历史消息\n\n### v1.9.0\n\n- 可以将聊天记录分享为 Markdown 或通过 sharegpt.com 分享\n\n### v1.8.0\n\n- 可以导入/导出所有数据\n- 可以编辑本地提示\n- 可以切换聊天机器人进行比较\n\n### v1.7.0\n\n- 新增了对话历史记录\n\n### v1.6.0\n\n- 增加了对 Google Bard 的支持\n\n### v1.5.4\n\n- 在 ChatGPT API 模式下支持 GPT-4 模型\n\n### v1.5.1\n\n- 增加了国际化设置\n\n### v1.5.0\n\n- 在 ChatGPT Webapp 模式下支持 GPT-4 模型\n\n### v1.4.0\n\n- 新增了 Prompt 库\n\n### v1.3.0\n\n- 增加了复制代码按钮\n- 在全合一模式和独立模式之间同步聊天状态\n- 允许在生成答案时输入\n\n### v1.2.0\n\n- 支持复制消息文本\n- 改进了设置页面表单元素的样式\n"
  },
  {
    "path": "README_ZH-TW.md",
    "content": "<p align=\"center\">\n    <img src=\"./src/assets/icon.png\" width=\"150\">\n</p>\n\n<h1 align=\"center\">ChatHub</h1>\n\n<div align=\"center\">\n\n### ChatHub 是個全能的聊天機器人客戶端\n\n[![作者][作者-image]][作者-url]\n[![許可證][許可證-image]][許可證-url]\n[![發布][發布-image]][發布-url]\n[![版本發佈][版本發佈-image]][版本發佈-url]    \n    \n[English](README.md) &nbsp;&nbsp;|&nbsp;&nbsp; [Indonesia](README_IN.md) &nbsp;&nbsp;|&nbsp;&nbsp; [简体中文](README_ZH-CN.md) &nbsp;&nbsp;|&nbsp;&nbsp; 繁體中文 &nbsp;&nbsp;|&nbsp;&nbsp; [日本語](README_JA.md)\n\n##    \n    \n### 安装\n    \n<a href=\"https://chrome.google.com/webstore/detail/chathub-all-in-one-chatbo/iaakpnchhognanibcahlpcplchdfmgma?utm_source=website\"><img src=\"https://user-images.githubusercontent.com/64502893/231991498-8df6dd63-727c-41d0-916f-c90c15127de3.png\" width=\"200\" alt=\"获取 Chromium 版本的 ChatHub\"></a>&nbsp;&nbsp;\n<a href=\"https://microsoftedge.microsoft.com/addons/detail/chathub-allinone-chat/kdlmggoacmfoombiokflpeompajfljga\"><img src=\"https://user-images.githubusercontent.com/64502893/231991158-1b54f831-2fdc-43b6-bf9a-f894000e5aa8.png\" width=\"160\" alt=\"获取 Microsoft Edge 版本的 ChatHub\"></a>\n    \n##\n\n[螢幕截圖](#-螢幕截圖) &nbsp;&nbsp;|&nbsp;&nbsp; [功能特色](#-功能特色) &nbsp;&nbsp;|&nbsp;&nbsp; [支援的聊天機器人](#-支援的聊天機器人) &nbsp;&nbsp;|&nbsp;&nbsp; [手動安裝](#-手動安裝) &nbsp;&nbsp;|&nbsp;&nbsp; [從原始碼建立](#-從原始碼建立) &nbsp;&nbsp;|&nbsp;&nbsp; [更新日誌](#-更新日誌)\n\n[作者-image]: https://img.shields.io/badge/author-wong2-blue.svg\n[作者-url]: https://github.com/wong2    \n[許可證-image]: https://img.shields.io/github/license/chathub-dev/chathub?color=blue\n[許可證-url]: https://github.com/chathub-dev/chathub/blob/main/LICENSE\n[發布-image]: https://img.shields.io/github/v/release/chathub-dev/chathub?color=blue\n[發布-url]: https://github.com/chathub-dev/chathub/releases/latest\n[版本發佈-image]: https://img.shields.io/github/last-commit/chathub-dev/chathub?label=last%20commit\n[版本發佈-url]: https://github.com/chathub-dev/chathub/commits\n\n</div>\n\n##\n\n## 📷 螢幕截圖\n\n![螢幕截圖](screenshots/extension.png?raw=true)\n\n![螢幕截圖 (暗模式)](screenshots/dark.png?raw=true)\n\n## ✨ 功能特色\n\n- 🤖 在一個應用程式中使用不同的聊天機器人，目前支援 ChatGPT、新的 Bing Chat、Google Bard、Claude，還有 10 多個開源模型，包括 Alpaca、Vicuna、ChatGLM 等\n- 💬 同時與多個聊天機器人進行對話，輕鬆比較它們的回答\n- 🚀 支援 ChatGPT API 和 GPT-4 瀏覽\n- 🔍 快速啟動應用程式的捷徑，可在瀏覽器中的任何地方使用\n- 🎨 支援 Markdown 和程式碼高亮顯示\n- 📚 自訂提示和社群提示的提示庫\n- 💾 本地保存對話歷史\n- 📥 匯出和匯入所有資料\n- 🔗 將對話分享為 Markdown 格式\n- 🌙 黑暗模式\n\n## 🤖 支援的聊天機器人\n\n* ChatGPT（透過網頁應用程式/API/Azure/Poe）\n* Bing Chat\n* Google Bard\n* Claude（透過 Poe）\n* iFlytek Spark\n* ChatGLM\n* Alpaca\n* Vicuna\n* Koala\n* Dolly\n* LLaMA\n* StableLM\n* OpenAssistant\n* ChatRWKV\n* ...\n\n## 🔧 手動安裝\n\n- 從 [Releases](https://github.com/chathub-dev/chathub/releases) 下載 chathub.zip\n- 解壓縮該文件\n- 在 Chrome/Edge 瀏覽器中，前往擴展功能頁面 (chrome://extensions 或 edge://extensions)\n- 啟用開發人員模式\n- 拖動解壓縮後的文件夾到頁面上的任何位置以導入它 (導入後不要刪除文件夾)\n\n## 🔨 從原始碼建立\n\n- 複製原始碼\n- `yarn install`\n- `yarn build`\n- 按照「手動安裝」中的步驟將 `dist` _資料夾載入瀏覽器_\n\n## 📜 更新日誌\n\n### v1.22.0\n\n- 支援 Claude API\n\n### v1.21.0\n\n- 新增更多開源模型\n\n### v1.20.0\n\n- 從 Chrome 側邊面板進入\n\n### v1.19.0\n\n- 快速存取提示\n\n### v1.18.0\n\n- 支援 Alpaca、Vicuna 和 ChatGLM\n\n### v1.17.0\n\n- 支援 GPT-4 瀏覽模型\n\n### v1.16.5\n\n- 新增支援 Azure OpenAI 服務\n\n### v1.16.0\n\n- 新增自訂主題設定\n\n### v1.15.0\n\n- 新增訊飛 Spark 機器人\n\n### v1.14.0\n\n- 支援高級用戶的全能模式中的更多機器人\n\n### v1.12.0\n\n- 新增高級授權\n\n### v1.11.0\n\n- 支援 Claude (透過 Poe)\n\n### v1.10.0\n\n- 新增 Command + K 功能\n\n### v1.9.4\n\n- 新增暗模式\n\n### v1.9.3\n\n- 支援使用 katex 的數學公式\n- 將社區提示保存到本地\n\n### v1.9.2\n\n- 刪除對話歷史消息\n\n### v1.9.0\n\n- 可將聊天記錄以 Markdown 格式或通過 sharegpt.com 分享\n\n### v1.8.0\n\n- 匯出/匯入所有數據\n- 編輯本地提示\n- 切換聊天機器人以進行比較\n\n### v1.7.0\n\n- 新增對話歷史\n\n### v1.6.0\n\n- 新增支援 Google Bard\n\n### v1.5.4\n\n- 支援 ChatGPT API 模式下的 GPT-4 模型\n\n### v1.5.1\n\n- 新增 i18n 設置\n\n### v1.5.0\n\n- 支援 ChatGPT Webapp 模式下的 GPT-4 模型\n\n### v1.4.0\n\n- 新增提示庫\n\n### v1.3.0\n\n- 新增複製代碼按鈕\n- 在全能模式和獨立模式之間同步聊天狀態\n- 允許在生成答案時輸入\n\n### v1.2.0\n\n- 支援複製消息文本\n- 改善設置頁面表單元素樣式\n"
  },
  {
    "path": "_locales/de/messages.json",
    "content": "{\n  \"appName\": {\n    \"message\": \"ChatHub - All-in-One Chatbot Klient\"\n  },\n  \"appDesc\": {\n    \"message\": \"Bessere Benutzeroberfläche für Ihre Lieblings-Chatbots\"\n  }\n}"
  },
  {
    "path": "_locales/en/messages.json",
    "content": "{\n  \"appName\": {\n    \"message\": \"ChatHub - All-in-one chatbot client\"\n  },\n  \"appDesc\": {\n    \"message\": \"Use ChatGPT, Bing, Bard, Claude and more chatbots simultaneously\"\n  }\n}\n"
  },
  {
    "path": "_locales/es/messages.json",
    "content": "{\n  \"appName\": {\n    \"message\": \"ChatHub - Cliente de chatbot todo en uno\"\n  },\n  \"appDesc\": {\n    \"message\": \"Utiliza ChatGPT, Bing, Bard, Claude y más chatbots simultáneamente\"\n  }\n}\n"
  },
  {
    "path": "_locales/fr/messages.json",
    "content": "{\n  \"appName\": {\n    \"message\": \"ChatHub - Client de chatbot tout-en-un\"\n  },\n  \"appDesc\": {\n    \"message\": \"Une meilleure interface utilisateur pour vos chatbots préférés\"\n  }\n}"
  },
  {
    "path": "_locales/in/messages.json",
    "content": "{\n  \"appName\": {\n    \"message\": \"ChatHub - Semua klien chatbot dalam satu tempat\"\n  },\n  \"appDesc\": {\n    \"message\": \"Semua chatbot favorit Anda dalam satu tempat\"\n  }\n}\n"
  },
  {
    "path": "_locales/ja/messages.json",
    "content": "{\n  \"appName\": {\n    \"message\": \"ChatHub - オールインワンチャットボットクライアント\"\n  },\n  \"appDesc\": {\n    \"message\": \"ChatGPT、Bing、Bard、およびClaudeを一つのプラットフォームで使用します\"\n  }\n}\n"
  },
  {
    "path": "_locales/pt_BR/messages.json",
    "content": "{\n  \"appName\": {\n    \"message\": \"ChatHub - All-in-one chatbot client\"\n  },\n  \"appDesc\": {\n    \"message\": \"Use o ChatGPT, Bing, Bard, Claude e mais chatbots simultaneamente\"\n  }\n}\n"
  },
  {
    "path": "_locales/pt_PT/messages.json",
    "content": "{\n  \"appName\": {\n    \"message\": \"ChatHub - All-in-one chatbot client\"\n  },\n  \"appDesc\": {\n    \"message\": \"Use o ChatGPT, Bing, Bard, Claude e mais chatbots simultaneamente\"\n  }\n}\n"
  },
  {
    "path": "_locales/ru/messages.json",
    "content": "{\n  \"appName\": {\n    \"message\": \"ChatHub — универсальный клиент для чат-ботов\"\n  },\n  \"appDesc\": {\n    \"message\": \"Улучшенный UI для ваших любимых чат-ботов\"\n  }\n}\n"
  },
  {
    "path": "_locales/th/messages.json",
    "content": "{\r\n  \"appName\": {\r\n    \"message\": \"ChatHub - ไคลเอนต์แชทบอทแบบครบวงจร\"\r\n  },\r\n  \"appDesc\": {\r\n    \"message\": \"UI ที่ดีกว่ากับแชทบอทที่คุณชื่นชอบ\"\r\n  }\r\n}\r\n"
  },
  {
    "path": "_locales/zh_CN/messages.json",
    "content": "{\n  \"appName\": {\n    \"message\": \"ChatHub - All-in-one chatbot client\"\n  },\n  \"appDesc\": {\n    \"message\": \"同时使用ChatGPT, Bing, Bard和更多机器人\"\n  }\n}\n"
  },
  {
    "path": "_locales/zh_TW/messages.json",
    "content": "{\n  \"appName\": {\n    \"message\": \"ChatHub - 全方位聊天機器人客戶端\"\n  },\n  \"appDesc\": {\n    \"message\": \"為您最喜愛的聊天機器人提供更好的用戶界面\"\n  }\n}"
  },
  {
    "path": "app.html",
    "content": "<!DOCTYPE html>\n<html translate=\"no\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <meta content=\"width=device-width,initial-scale=1.0\" name=\"viewport\" />\n    <title>ChatHub</title>\n    <script type=\"module\" src=\"./src/app/theme.ts\"></script>\n  </head>\n  <body>\n    <div id=\"app\"></div>\n    <script type=\"module\" src=\"./src/app/main.tsx\"></script>\n  </body>\n</html>\n"
  },
  {
    "path": "global.d.ts",
    "content": "declare module '*.gql'\n"
  },
  {
    "path": "manifest.config.ts",
    "content": "import { defineManifest } from '@crxjs/vite-plugin'\n\nexport default defineManifest(async () => {\n  return {\n    manifest_version: 3,\n    name: '__MSG_appName__',\n    description: '__MSG_appDesc__',\n    default_locale: 'en',\n    version: '1.45.7',\n    icons: {\n      '16': 'src/assets/icon.png',\n      '32': 'src/assets/icon.png',\n      '48': 'src/assets/icon.png',\n      '128': 'src/assets/icon.png',\n    },\n    background: {\n      service_worker: 'src/background/index.ts',\n      type: 'module',\n    },\n    action: {},\n    host_permissions: [\n      'https://*.bing.com/',\n      'https://*.openai.com/',\n      'https://bard.google.com/',\n      'https://*.chathub.gg/',\n      'https://*.duckduckgo.com/',\n      'https://*.poe.com/',\n      'https://*.anthropic.com/',\n      'https://*.claude.ai/',\n    ],\n    optional_host_permissions: ['https://*/*', 'wss://*/*'],\n    permissions: ['storage', 'unlimitedStorage', 'sidePanel', 'declarativeNetRequestWithHostAccess', 'scripting'],\n    content_scripts: [\n      {\n        matches: ['https://chat.openai.com/*'],\n        js: ['src/content-script/chatgpt-inpage-proxy.ts'],\n      },\n    ],\n    commands: {\n      'open-app': {\n        suggested_key: {\n          default: 'Alt+J',\n          windows: 'Alt+J',\n          linux: 'Alt+J',\n          mac: 'Command+J',\n        },\n        description: 'Open ChatHub app',\n      },\n    },\n    side_panel: {\n      default_path: 'sidepanel.html',\n    },\n    declarative_net_request: {\n      rule_resources: [\n        {\n          id: 'ruleset_bing',\n          enabled: true,\n          path: 'src/rules/bing.json',\n        },\n        {\n          id: 'ruleset_ddg',\n          enabled: true,\n          path: 'src/rules/ddg.json',\n        },\n        {\n          id: 'ruleset_qianwen',\n          enabled: true,\n          path: 'src/rules/qianwen.json',\n        },\n        {\n          id: 'ruleset_baichuan',\n          enabled: true,\n          path: 'src/rules/baichuan.json',\n        },\n        {\n          id: 'ruleset_pplx',\n          enabled: true,\n          path: 'src/rules/pplx.json',\n        },\n      ],\n    },\n  }\n})\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"chathub-extension\",\n  \"private\": true,\n  \"version\": \"0.0.0\",\n  \"type\": \"module\",\n  \"scripts\": {\n    \"dev\": \"vite\",\n    \"build\": \"tsc && vite build\"\n  },\n  \"devDependencies\": {\n    \"@crxjs/vite-plugin\": \"2.0.0-beta.21\",\n    \"@headlessui/tailwindcss\": \"^0.2.0\",\n    \"@types/cookie\": \"^0.6.0\",\n    \"@types/humanize-duration\": \"^3.27.3\",\n    \"@types/lodash-es\": \"^4.17.12\",\n    \"@types/md5\": \"^2.3.5\",\n    \"@types/react\": \"18.2.18\",\n    \"@types/react-color\": \"^3.0.10\",\n    \"@types/react-copy-to-clipboard\": \"^5.0.7\",\n    \"@types/react-dom\": \"^18.2.18\",\n    \"@types/react-scroll-to-bottom\": \"^4.2.4\",\n    \"@types/turndown\": \"^5.0.4\",\n    \"@types/uuid\": \"^9.0.7\",\n    \"@types/webextension-polyfill\": \"^0.10.7\",\n    \"@typescript-eslint/eslint-plugin\": \"^6.15.0\",\n    \"@typescript-eslint/parser\": \"^6.15.0\",\n    \"@vitejs/plugin-react\": \"^4.2.1\",\n    \"autoprefixer\": \"^10.4.16\",\n    \"chrome-types\": \"^0.1.246\",\n    \"eslint\": \"^8.56.0\",\n    \"eslint-config-prettier\": \"^9.1.0\",\n    \"eslint-plugin-react\": \"^7.33.2\",\n    \"eslint-plugin-react-hooks\": \"^4.6.0\",\n    \"postcss\": \"^8.4.32\",\n    \"postcss-import\": \"^15.1.0\",\n    \"postcss-nesting\": \"^12.0.2\",\n    \"prettier\": \"^3.1.1\",\n    \"process\": \"^0.11.10\",\n    \"sass\": \"^1.69.5\",\n    \"tailwind-scrollbar\": \"^3.0.5\",\n    \"tailwindcss\": \"^3.4.0\",\n    \"typescript\": \"^5.3.3\",\n    \"vite\": \"4.5.1\",\n    \"vite-tsconfig-paths\": \"^4.2.2\"\n  },\n  \"dependencies\": {\n    \"@epic-web/cachified\": \"^4.0.0\",\n    \"@floating-ui/react\": \"^0.26.4\",\n    \"@google/generative-ai\": \"^0.1.3\",\n    \"@headlessui/react\": \"^1.7.17\",\n    \"@heroicons/react\": \"^2.1.1\",\n    \"@radix-ui/react-tooltip\": \"^1.0.7\",\n    \"@sentry/integrations\": \"^7.90.0\",\n    \"@sentry/react\": \"^7.90.0\",\n    \"@tanstack/react-router\": \"^1.43.6\",\n    \"async-cache-dedupe\": \"^2.0.0\",\n    \"browser-fs-access\": \"^0.35.0\",\n    \"browser-image-compression\": \"^2.0.2\",\n    \"clsx\": \"^2.0.0\",\n    \"compare-versions\": \"^6.1.0\",\n    \"cookie\": \"^0.6.0\",\n    \"dayjs\": \"^1.11.10\",\n    \"eventsource-parser\": \"^1.1.1\",\n    \"framer-motion\": \"^10.16.16\",\n    \"fuse.js\": \"^7.0.0\",\n    \"github-markdown-css\": \"^5.5.0\",\n    \"gpt3-tokenizer\": \"^1.1.5\",\n    \"highlight.js\": \"^11.9.0\",\n    \"humanize-duration\": \"^3.31.0\",\n    \"i18next\": \"^23.7.11\",\n    \"i18next-browser-languagedetector\": \"^7.2.0\",\n    \"immer\": \"^10.0.3\",\n    \"inter-ui\": \"^3.19.3\",\n    \"jotai\": \"^2.6.0\",\n    \"jotai-immer\": \"^0.2.0\",\n    \"js-base64\": \"^3.7.5\",\n    \"lodash-es\": \"^4.17.21\",\n    \"md5\": \"^2.3.0\",\n    \"nanoid\": \"^5.0.4\",\n    \"ofetch\": \"^1.3.3\",\n    \"plausible-tracker\": \"^0.3.8\",\n    \"react\": \"^18.2.0\",\n    \"react-color\": \"^2.19.3\",\n    \"react-confetti-explosion\": \"^2.1.2\",\n    \"react-copy-to-clipboard\": \"^5.1.0\",\n    \"react-dom\": \"^18.2.0\",\n    \"react-hot-toast\": \"^2.4.1\",\n    \"react-i18next\": \"^13.5.0\",\n    \"react-icons\": \"^4.12.0\",\n    \"react-markdown\": \"^8.0.7\",\n    \"react-node-to-string\": \"^0.1.2\",\n    \"react-scroll-to-bottom\": \"^4.2.0\",\n    \"react-spinners\": \"^0.13.8\",\n    \"react-textarea-autosize\": \"^8.5.3\",\n    \"react-viewport-list\": \"^7.1.2\",\n    \"rehype-highlight\": \"^6.0.0\",\n    \"rehype-stringify\": \"^9.0.4\",\n    \"remark-breaks\": \"^3.0.3\",\n    \"remark-gfm\": \"^3.0.1\",\n    \"remark-math\": \"^5.1.1\",\n    \"remark-parse\": \"^10.0.2\",\n    \"remark-rehype\": \"^10.1.0\",\n    \"remark-supersub\": \"^1.0.0\",\n    \"slashes\": \"^3.0.12\",\n    \"swr\": \"^2.2.4\",\n    \"tailwind-merge\": \"^2.1.0\",\n    \"turndown\": \"^7.1.2\",\n    \"unified\": \"^10.1.2\",\n    \"uuid\": \"^9.0.1\",\n    \"webextension-polyfill\": \"^0.10.0\",\n    \"websocket-as-promised\": \"^2.0.1\"\n  },\n  \"packageManager\": \"yarn@4.0.1\"\n}\n"
  },
  {
    "path": "postcss.config.cjs",
    "content": "module.exports = {\n  plugins: {\n    'postcss-import': {},\n    'tailwindcss/nesting': 'postcss-nesting',\n    tailwindcss: {},\n    autoprefixer: {},\n  },\n}\n"
  },
  {
    "path": "public/js/v2/35536E1E-65B4-4D96-9D97-6ADB7EFF8147/api.js",
    "content": "var arkoseLabsClientApi2c145230;!function(){var e={7983:function(e,t){\"use strict\";t.N=void 0;var n=/^([^\\w]*)(javascript|data|vbscript)/im,r=/&#(\\w+)(^\\w|;)?/g,i=/&tab;/gi,o=/[\\u0000-\\u001F\\u007F-\\u009F\\u2000-\\u200D\\uFEFF]/gim,a=/^.+(:|&colon;)/gim,c=[\".\",\"/\"];t.N=function(e){var t,s=(t=e||\"\",(t=t.replace(i,\"&#9;\")).replace(r,(function(e,t){return String.fromCharCode(t)}))).replace(o,\"\").trim();if(!s)return\"about:blank\";if(function(e){return c.indexOf(e[0])>-1}(s))return s;var u=s.match(a);if(!u)return s;var l=u[0];return n.test(l)?\"about:blank\":s}},3940:function(e,t){var n;!function(){\"use strict\";var r={}.hasOwnProperty;function i(){for(var e=[],t=0;t<arguments.length;t++){var n=arguments[t];if(n){var o=typeof n;if(\"string\"===o||\"number\"===o)e.push(n);else if(Array.isArray(n)){if(n.length){var a=i.apply(null,n);a&&e.push(a)}}else if(\"object\"===o)if(n.toString===Object.prototype.toString)for(var c in n)r.call(n,c)&&n[c]&&e.push(c);else e.push(n.toString())}}return e.join(\" \")}e.exports?(i.default=i,e.exports=i):void 0===(n=function(){return i}.apply(t,[]))||(e.exports=n)}()},8645:function(e){\"use strict\";e.exports=function(e){var t=[];return t.toString=function(){return this.map((function(t){var n=\"\",r=void 0!==t[5];return t[4]&&(n+=\"@supports (\".concat(t[4],\") {\")),t[2]&&(n+=\"@media \".concat(t[2],\" {\")),r&&(n+=\"@layer\".concat(t[5].length>0?\" \".concat(t[5]):\"\",\" {\")),n+=e(t),r&&(n+=\"}\"),t[2]&&(n+=\"}\"),t[4]&&(n+=\"}\"),n})).join(\"\")},t.i=function(e,n,r,i,o){\"string\"==typeof e&&(e=[[null,e,void 0]]);var a={};if(r)for(var c=0;c<this.length;c++){var s=this[c][0];null!=s&&(a[s]=!0)}for(var u=0;u<e.length;u++){var l=[].concat(e[u]);r&&a[l[0]]||(void 0!==o&&(void 0===l[5]||(l[1]=\"@layer\".concat(l[5].length>0?\" \".concat(l[5]):\"\",\" {\").concat(l[1],\"}\")),l[5]=o),n&&(l[2]?(l[1]=\"@media \".concat(l[2],\" {\").concat(l[1],\"}\"),l[2]=n):l[2]=n),i&&(l[4]?(l[1]=\"@supports (\".concat(l[4],\") {\").concat(l[1],\"}\"),l[4]=i):l[4]=\"\".concat(i)),t.push(l))}},t}},3835:function(e){\"use strict\";e.exports=function(e){return e[1]}},913:function(e,t,n){var r,i,o;!function(a,c){\"use strict\";i=[n(4486)],void 0===(o=\"function\"==typeof(r=function(e){var t=/(^|@)\\S+:\\d+/,n=/^\\s*at .*(\\S+:\\d+|\\(native\\))/m,r=/^(eval@)?(\\[native code])?$/;return{parse:function(e){if(void 0!==e.stacktrace||void 0!==e[\"opera#sourceloc\"])return this.parseOpera(e);if(e.stack&&e.stack.match(n))return this.parseV8OrIE(e);if(e.stack)return this.parseFFOrSafari(e);throw new Error(\"Cannot parse given Error object\")},extractLocation:function(e){if(-1===e.indexOf(\":\"))return[e];var t=/(.+?)(?::(\\d+))?(?::(\\d+))?$/.exec(e.replace(/[()]/g,\"\"));return[t[1],t[2]||void 0,t[3]||void 0]},parseV8OrIE:function(t){return t.stack.split(\"\\n\").filter((function(e){return!!e.match(n)}),this).map((function(t){t.indexOf(\"(eval \")>-1&&(t=t.replace(/eval code/g,\"eval\").replace(/(\\(eval at [^()]*)|(,.*$)/g,\"\"));var n=t.replace(/^\\s+/,\"\").replace(/\\(eval code/g,\"(\").replace(/^.*?\\s+/,\"\"),r=n.match(/ (\\(.+\\)$)/);n=r?n.replace(r[0],\"\"):n;var i=this.extractLocation(r?r[1]:n),o=r&&n||void 0,a=[\"eval\",\"<anonymous>\"].indexOf(i[0])>-1?void 0:i[0];return new e({functionName:o,fileName:a,lineNumber:i[1],columnNumber:i[2],source:t})}),this)},parseFFOrSafari:function(t){return t.stack.split(\"\\n\").filter((function(e){return!e.match(r)}),this).map((function(t){if(t.indexOf(\" > eval\")>-1&&(t=t.replace(/ line (\\d+)(?: > eval line \\d+)* > eval:\\d+:\\d+/g,\":$1\")),-1===t.indexOf(\"@\")&&-1===t.indexOf(\":\"))return new e({functionName:t});var n=/((.*\".+\"[^@]*)?[^@]*)(?:@)/,r=t.match(n),i=r&&r[1]?r[1]:void 0,o=this.extractLocation(t.replace(n,\"\"));return new e({functionName:i,fileName:o[0],lineNumber:o[1],columnNumber:o[2],source:t})}),this)},parseOpera:function(e){return!e.stacktrace||e.message.indexOf(\"\\n\")>-1&&e.message.split(\"\\n\").length>e.stacktrace.split(\"\\n\").length?this.parseOpera9(e):e.stack?this.parseOpera11(e):this.parseOpera10(e)},parseOpera9:function(t){for(var n=/Line (\\d+).*script (?:in )?(\\S+)/i,r=t.message.split(\"\\n\"),i=[],o=2,a=r.length;o<a;o+=2){var c=n.exec(r[o]);c&&i.push(new e({fileName:c[2],lineNumber:c[1],source:r[o]}))}return i},parseOpera10:function(t){for(var n=/Line (\\d+).*script (?:in )?(\\S+)(?:: In function (\\S+))?$/i,r=t.stacktrace.split(\"\\n\"),i=[],o=0,a=r.length;o<a;o+=2){var c=n.exec(r[o]);c&&i.push(new e({functionName:c[3]||void 0,fileName:c[2],lineNumber:c[1],source:r[o]}))}return i},parseOpera11:function(n){return n.stack.split(\"\\n\").filter((function(e){return!!e.match(t)&&!e.match(/^Error created at/)}),this).map((function(t){var n,r=t.split(\"@\"),i=this.extractLocation(r.pop()),o=r.shift()||\"\",a=o.replace(/<anonymous function(: (\\w+))?>/,\"$2\").replace(/\\([^)]*\\)/g,\"\")||void 0;o.match(/\\(([^)]*)\\)/)&&(n=o.replace(/^[^(]+\\(([^)]*)\\)$/,\"$1\"));var c=void 0===n||\"[arguments not available]\"===n?void 0:n.split(\",\");return new e({functionName:a,args:c,fileName:i[0],lineNumber:i[1],columnNumber:i[2],source:t})}),this)}}})?r.apply(t,i):r)||(e.exports=o)}()},2265:function(e){\"use strict\";var t=Object.prototype.hasOwnProperty,n=\"~\";function r(){}function i(e,t,n){this.fn=e,this.context=t,this.once=n||!1}function o(e,t,r,o,a){if(\"function\"!=typeof r)throw new TypeError(\"The listener must be a function\");var c=new i(r,o||e,a),s=n?n+t:t;return e._events[s]?e._events[s].fn?e._events[s]=[e._events[s],c]:e._events[s].push(c):(e._events[s]=c,e._eventsCount++),e}function a(e,t){0==--e._eventsCount?e._events=new r:delete e._events[t]}function c(){this._events=new r,this._eventsCount=0}Object.create&&(r.prototype=Object.create(null),(new r).__proto__||(n=!1)),c.prototype.eventNames=function(){var e,r,i=[];if(0===this._eventsCount)return i;for(r in e=this._events)t.call(e,r)&&i.push(n?r.slice(1):r);return Object.getOwnPropertySymbols?i.concat(Object.getOwnPropertySymbols(e)):i},c.prototype.listeners=function(e){var t=n?n+e:e,r=this._events[t];if(!r)return[];if(r.fn)return[r.fn];for(var i=0,o=r.length,a=new Array(o);i<o;i++)a[i]=r[i].fn;return a},c.prototype.listenerCount=function(e){var t=n?n+e:e,r=this._events[t];return r?r.fn?1:r.length:0},c.prototype.emit=function(e,t,r,i,o,a){var c=n?n+e:e;if(!this._events[c])return!1;var s,u,l=this._events[c],f=arguments.length;if(l.fn){switch(l.once&&this.removeListener(e,l.fn,void 0,!0),f){case 1:return l.fn.call(l.context),!0;case 2:return l.fn.call(l.context,t),!0;case 3:return l.fn.call(l.context,t,r),!0;case 4:return l.fn.call(l.context,t,r,i),!0;case 5:return l.fn.call(l.context,t,r,i,o),!0;case 6:return l.fn.call(l.context,t,r,i,o,a),!0}for(u=1,s=new Array(f-1);u<f;u++)s[u-1]=arguments[u];l.fn.apply(l.context,s)}else{var d,p=l.length;for(u=0;u<p;u++)switch(l[u].once&&this.removeListener(e,l[u].fn,void 0,!0),f){case 1:l[u].fn.call(l[u].context);break;case 2:l[u].fn.call(l[u].context,t);break;case 3:l[u].fn.call(l[u].context,t,r);break;case 4:l[u].fn.call(l[u].context,t,r,i);break;default:if(!s)for(d=1,s=new Array(f-1);d<f;d++)s[d-1]=arguments[d];l[u].fn.apply(l[u].context,s)}}return!0},c.prototype.on=function(e,t,n){return o(this,e,t,n,!1)},c.prototype.once=function(e,t,n){return o(this,e,t,n,!0)},c.prototype.removeListener=function(e,t,r,i){var o=n?n+e:e;if(!this._events[o])return this;if(!t)return a(this,o),this;var c=this._events[o];if(c.fn)c.fn!==t||i&&!c.once||r&&c.context!==r||a(this,o);else{for(var s=0,u=[],l=c.length;s<l;s++)(c[s].fn!==t||i&&!c[s].once||r&&c[s].context!==r)&&u.push(c[s]);u.length?this._events[o]=1===u.length?u[0]:u:a(this,o)}return this},c.prototype.removeAllListeners=function(e){var t;return e?(t=n?n+e:e,this._events[t]&&a(this,t)):(this._events=new r,this._eventsCount=0),this},c.prototype.off=c.prototype.removeListener,c.prototype.addListener=c.prototype.on,c.prefixed=n,c.EventEmitter=c,e.exports=c},1640:function(e,t,n){e=n.nmd(e);var r=\"__lodash_hash_undefined__\",i=9007199254740991,o=\"[object Arguments]\",a=\"[object Boolean]\",c=\"[object Date]\",s=\"[object Function]\",u=\"[object GeneratorFunction]\",l=\"[object Map]\",f=\"[object Number]\",d=\"[object Object]\",p=\"[object Promise]\",v=\"[object RegExp]\",h=\"[object Set]\",g=\"[object String]\",m=\"[object Symbol]\",y=\"[object WeakMap]\",b=\"[object ArrayBuffer]\",w=\"[object DataView]\",O=\"[object Float32Array]\",j=\"[object Float64Array]\",S=\"[object Int8Array]\",x=\"[object Int16Array]\",E=\"[object Int32Array]\",k=\"[object Uint8Array]\",_=\"[object Uint8ClampedArray]\",A=\"[object Uint16Array]\",T=\"[object Uint32Array]\",P=/\\w*$/,C=/^\\[object .+?Constructor\\]$/,I=/^(?:0|[1-9]\\d*)$/,R={};R[o]=R[\"[object Array]\"]=R[b]=R[w]=R[a]=R[c]=R[O]=R[j]=R[S]=R[x]=R[E]=R[l]=R[f]=R[d]=R[v]=R[h]=R[g]=R[m]=R[k]=R[_]=R[A]=R[T]=!0,R[\"[object Error]\"]=R[s]=R[y]=!1;var L=\"object\"==typeof n.g&&n.g&&n.g.Object===Object&&n.g,N=\"object\"==typeof self&&self&&self.Object===Object&&self,D=L||N||Function(\"return this\")(),F=t&&!t.nodeType&&t,K=F&&e&&!e.nodeType&&e,M=K&&K.exports===F;function q(e,t){return e.set(t[0],t[1]),e}function z(e,t){return e.add(t),e}function H(e,t,n,r){var i=-1,o=e?e.length:0;for(r&&o&&(n=e[++i]);++i<o;)n=t(n,e[i],i,e);return n}function $(e){var t=!1;if(null!=e&&\"function\"!=typeof e.toString)try{t=!!(e+\"\")}catch(e){}return t}function U(e){var t=-1,n=Array(e.size);return e.forEach((function(e,r){n[++t]=[r,e]})),n}function V(e,t){return function(n){return e(t(n))}}function W(e){var t=-1,n=Array(e.size);return e.forEach((function(e){n[++t]=e})),n}var B,X=Array.prototype,G=Function.prototype,J=Object.prototype,Z=D[\"__core-js_shared__\"],Y=(B=/[^.]+$/.exec(Z&&Z.keys&&Z.keys.IE_PROTO||\"\"))?\"Symbol(src)_1.\"+B:\"\",Q=G.toString,ee=J.hasOwnProperty,te=J.toString,ne=RegExp(\"^\"+Q.call(ee).replace(/[\\\\^$.*+?()[\\]{}|]/g,\"\\\\$&\").replace(/hasOwnProperty|(function).*?(?=\\\\\\()| for .+?(?=\\\\\\])/g,\"$1.*?\")+\"$\"),re=M?D.Buffer:void 0,ie=D.Symbol,oe=D.Uint8Array,ae=V(Object.getPrototypeOf,Object),ce=Object.create,se=J.propertyIsEnumerable,ue=X.splice,le=Object.getOwnPropertySymbols,fe=re?re.isBuffer:void 0,de=V(Object.keys,Object),pe=Ke(D,\"DataView\"),ve=Ke(D,\"Map\"),he=Ke(D,\"Promise\"),ge=Ke(D,\"Set\"),me=Ke(D,\"WeakMap\"),ye=Ke(Object,\"create\"),be=$e(pe),we=$e(ve),Oe=$e(he),je=$e(ge),Se=$e(me),xe=ie?ie.prototype:void 0,Ee=xe?xe.valueOf:void 0;function ke(e){var t=-1,n=e?e.length:0;for(this.clear();++t<n;){var r=e[t];this.set(r[0],r[1])}}function _e(e){var t=-1,n=e?e.length:0;for(this.clear();++t<n;){var r=e[t];this.set(r[0],r[1])}}function Ae(e){var t=-1,n=e?e.length:0;for(this.clear();++t<n;){var r=e[t];this.set(r[0],r[1])}}function Te(e){this.__data__=new _e(e)}function Pe(e,t){var n=Ve(e)||function(e){return function(e){return function(e){return!!e&&\"object\"==typeof e}(e)&&We(e)}(e)&&ee.call(e,\"callee\")&&(!se.call(e,\"callee\")||te.call(e)==o)}(e)?function(e,t){for(var n=-1,r=Array(e);++n<e;)r[n]=t(n);return r}(e.length,String):[],r=n.length,i=!!r;for(var a in e)!t&&!ee.call(e,a)||i&&(\"length\"==a||ze(a,r))||n.push(a);return n}function Ce(e,t,n){var r=e[t];ee.call(e,t)&&Ue(r,n)&&(void 0!==n||t in e)||(e[t]=n)}function Ie(e,t){for(var n=e.length;n--;)if(Ue(e[n][0],t))return n;return-1}function Re(e,t,n,r,i,p,y){var C;if(r&&(C=p?r(e,i,p,y):r(e)),void 0!==C)return C;if(!Ge(e))return e;var I=Ve(e);if(I){if(C=function(e){var t=e.length,n=e.constructor(t);t&&\"string\"==typeof e[0]&&ee.call(e,\"index\")&&(n.index=e.index,n.input=e.input);return n}(e),!t)return function(e,t){var n=-1,r=e.length;t||(t=Array(r));for(;++n<r;)t[n]=e[n];return t}(e,C)}else{var L=qe(e),N=L==s||L==u;if(Be(e))return function(e,t){if(t)return e.slice();var n=new e.constructor(e.length);return e.copy(n),n}(e,t);if(L==d||L==o||N&&!p){if($(e))return p?e:{};if(C=function(e){return\"function\"!=typeof e.constructor||He(e)?{}:(t=ae(e),Ge(t)?ce(t):{});var t}(N?{}:e),!t)return function(e,t){return De(e,Me(e),t)}(e,function(e,t){return e&&De(t,Je(t),e)}(C,e))}else{if(!R[L])return p?e:{};C=function(e,t,n,r){var i=e.constructor;switch(t){case b:return Ne(e);case a:case c:return new i(+e);case w:return function(e,t){var n=t?Ne(e.buffer):e.buffer;return new e.constructor(n,e.byteOffset,e.byteLength)}(e,r);case O:case j:case S:case x:case E:case k:case _:case A:case T:return function(e,t){var n=t?Ne(e.buffer):e.buffer;return new e.constructor(n,e.byteOffset,e.length)}(e,r);case l:return function(e,t,n){var r=t?n(U(e),!0):U(e);return H(r,q,new e.constructor)}(e,r,n);case f:case g:return new i(e);case v:return function(e){var t=new e.constructor(e.source,P.exec(e));return t.lastIndex=e.lastIndex,t}(e);case h:return function(e,t,n){var r=t?n(W(e),!0):W(e);return H(r,z,new e.constructor)}(e,r,n);case m:return o=e,Ee?Object(Ee.call(o)):{}}var o}(e,L,Re,t)}}y||(y=new Te);var D=y.get(e);if(D)return D;if(y.set(e,C),!I)var F=n?function(e){return function(e,t,n){var r=t(e);return Ve(e)?r:function(e,t){for(var n=-1,r=t.length,i=e.length;++n<r;)e[i+n]=t[n];return e}(r,n(e))}(e,Je,Me)}(e):Je(e);return function(e,t){for(var n=-1,r=e?e.length:0;++n<r&&!1!==t(e[n],n,e););}(F||e,(function(i,o){F&&(i=e[o=i]),Ce(C,o,Re(i,t,n,r,o,e,y))})),C}function Le(e){return!(!Ge(e)||(t=e,Y&&Y in t))&&(Xe(e)||$(e)?ne:C).test($e(e));var t}function Ne(e){var t=new e.constructor(e.byteLength);return new oe(t).set(new oe(e)),t}function De(e,t,n,r){n||(n={});for(var i=-1,o=t.length;++i<o;){var a=t[i],c=r?r(n[a],e[a],a,n,e):void 0;Ce(n,a,void 0===c?e[a]:c)}return n}function Fe(e,t){var n,r,i=e.__data__;return(\"string\"==(r=typeof(n=t))||\"number\"==r||\"symbol\"==r||\"boolean\"==r?\"__proto__\"!==n:null===n)?i[\"string\"==typeof t?\"string\":\"hash\"]:i.map}function Ke(e,t){var n=function(e,t){return null==e?void 0:e[t]}(e,t);return Le(n)?n:void 0}ke.prototype.clear=function(){this.__data__=ye?ye(null):{}},ke.prototype.delete=function(e){return this.has(e)&&delete this.__data__[e]},ke.prototype.get=function(e){var t=this.__data__;if(ye){var n=t[e];return n===r?void 0:n}return ee.call(t,e)?t[e]:void 0},ke.prototype.has=function(e){var t=this.__data__;return ye?void 0!==t[e]:ee.call(t,e)},ke.prototype.set=function(e,t){return this.__data__[e]=ye&&void 0===t?r:t,this},_e.prototype.clear=function(){this.__data__=[]},_e.prototype.delete=function(e){var t=this.__data__,n=Ie(t,e);return!(n<0)&&(n==t.length-1?t.pop():ue.call(t,n,1),!0)},_e.prototype.get=function(e){var t=this.__data__,n=Ie(t,e);return n<0?void 0:t[n][1]},_e.prototype.has=function(e){return Ie(this.__data__,e)>-1},_e.prototype.set=function(e,t){var n=this.__data__,r=Ie(n,e);return r<0?n.push([e,t]):n[r][1]=t,this},Ae.prototype.clear=function(){this.__data__={hash:new ke,map:new(ve||_e),string:new ke}},Ae.prototype.delete=function(e){return Fe(this,e).delete(e)},Ae.prototype.get=function(e){return Fe(this,e).get(e)},Ae.prototype.has=function(e){return Fe(this,e).has(e)},Ae.prototype.set=function(e,t){return Fe(this,e).set(e,t),this},Te.prototype.clear=function(){this.__data__=new _e},Te.prototype.delete=function(e){return this.__data__.delete(e)},Te.prototype.get=function(e){return this.__data__.get(e)},Te.prototype.has=function(e){return this.__data__.has(e)},Te.prototype.set=function(e,t){var n=this.__data__;if(n instanceof _e){var r=n.__data__;if(!ve||r.length<199)return r.push([e,t]),this;n=this.__data__=new Ae(r)}return n.set(e,t),this};var Me=le?V(le,Object):function(){return[]},qe=function(e){return te.call(e)};function ze(e,t){return!!(t=null==t?i:t)&&(\"number\"==typeof e||I.test(e))&&e>-1&&e%1==0&&e<t}function He(e){var t=e&&e.constructor;return e===(\"function\"==typeof t&&t.prototype||J)}function $e(e){if(null!=e){try{return Q.call(e)}catch(e){}try{return e+\"\"}catch(e){}}return\"\"}function Ue(e,t){return e===t||e!=e&&t!=t}(pe&&qe(new pe(new ArrayBuffer(1)))!=w||ve&&qe(new ve)!=l||he&&qe(he.resolve())!=p||ge&&qe(new ge)!=h||me&&qe(new me)!=y)&&(qe=function(e){var t=te.call(e),n=t==d?e.constructor:void 0,r=n?$e(n):void 0;if(r)switch(r){case be:return w;case we:return l;case Oe:return p;case je:return h;case Se:return y}return t});var Ve=Array.isArray;function We(e){return null!=e&&function(e){return\"number\"==typeof e&&e>-1&&e%1==0&&e<=i}(e.length)&&!Xe(e)}var Be=fe||function(){return!1};function Xe(e){var t=Ge(e)?te.call(e):\"\";return t==s||t==u}function Ge(e){var t=typeof e;return!!e&&(\"object\"==t||\"function\"==t)}function Je(e){return We(e)?Pe(e):function(e){if(!He(e))return de(e);var t=[];for(var n in Object(e))ee.call(e,n)&&\"constructor\"!=n&&t.push(n);return t}(e)}e.exports=function(e){return Re(e,!0,!0)}},4486:function(e,t){var n,r,i;!function(o,a){\"use strict\";r=[],void 0===(i=\"function\"==typeof(n=function(){function e(e){return!isNaN(parseFloat(e))&&isFinite(e)}function t(e){return e.charAt(0).toUpperCase()+e.substring(1)}function n(e){return function(){return this[e]}}var r=[\"isConstructor\",\"isEval\",\"isNative\",\"isToplevel\"],i=[\"columnNumber\",\"lineNumber\"],o=[\"fileName\",\"functionName\",\"source\"],a=[\"args\"],c=[\"evalOrigin\"],s=r.concat(i,o,a,c);function u(e){if(e)for(var n=0;n<s.length;n++)void 0!==e[s[n]]&&this[\"set\"+t(s[n])](e[s[n]])}u.prototype={getArgs:function(){return this.args},setArgs:function(e){if(\"[object Array]\"!==Object.prototype.toString.call(e))throw new TypeError(\"Args must be an Array\");this.args=e},getEvalOrigin:function(){return this.evalOrigin},setEvalOrigin:function(e){if(e instanceof u)this.evalOrigin=e;else{if(!(e instanceof Object))throw new TypeError(\"Eval Origin must be an Object or StackFrame\");this.evalOrigin=new u(e)}},toString:function(){var e=this.getFileName()||\"\",t=this.getLineNumber()||\"\",n=this.getColumnNumber()||\"\",r=this.getFunctionName()||\"\";return this.getIsEval()?e?\"[eval] (\"+e+\":\"+t+\":\"+n+\")\":\"[eval]:\"+t+\":\"+n:r?r+\" (\"+e+\":\"+t+\":\"+n+\")\":e+\":\"+t+\":\"+n}},u.fromString=function(e){var t=e.indexOf(\"(\"),n=e.lastIndexOf(\")\"),r=e.substring(0,t),i=e.substring(t+1,n).split(\",\"),o=e.substring(n+1);if(0===o.indexOf(\"@\"))var a=/@(.+?)(?::(\\d+))?(?::(\\d+))?$/.exec(o,\"\"),c=a[1],s=a[2],l=a[3];return new u({functionName:r,args:i||void 0,fileName:c,lineNumber:s||void 0,columnNumber:l||void 0})};for(var l=0;l<r.length;l++)u.prototype[\"get\"+t(r[l])]=n(r[l]),u.prototype[\"set\"+t(r[l])]=function(e){return function(t){this[e]=Boolean(t)}}(r[l]);for(var f=0;f<i.length;f++)u.prototype[\"get\"+t(i[f])]=n(i[f]),u.prototype[\"set\"+t(i[f])]=function(t){return function(n){if(!e(n))throw new TypeError(t+\" must be a Number\");this[t]=Number(n)}}(i[f]);for(var d=0;d<o.length;d++)u.prototype[\"get\"+t(o[d])]=n(o[d]),u.prototype[\"set\"+t(o[d])]=function(e){return function(t){this[e]=String(t)}}(o[d]);return u})?n.apply(t,r):n)||(e.exports=i)}()},2476:function(){Element.prototype.matches||(Element.prototype.matches=Element.prototype.msMatchesSelector||Element.prototype.webkitMatchesSelector),Element.prototype.closest||(Element.prototype.closest=function(e){var t=this;do{if(Element.prototype.matches.call(t,e))return t;t=t.parentElement||t.parentNode}while(null!==t&&1===t.nodeType);return null})},903:function(e,t,n){\"use strict\";var r=n(3835),i=n.n(r),o=n(8645),a=n.n(o)()(i());a.push([e.id,\".r34K7X1zGgAi6DllVF3T{box-sizing:border-box;border:0;margin:0;padding:0;overflow:hidden;z-index:2147483647;pointer-events:none;visibility:hidden;opacity:0;transition:opacity 300ms linear;height:0;width:0;position:absolute;top:-9999px;left:-9999px}.r34K7X1zGgAi6DllVF3T.active{display:block;visibility:visible}.r34K7X1zGgAi6DllVF3T.active.show{opacity:1;pointer-events:inherit;position:inherit}.r34K7X1zGgAi6DllVF3T.active.show.in-situ{width:inherit;height:inherit}.r34K7X1zGgAi6DllVF3T.active.show.lightbox{position:fixed;width:100% !important;height:100% !important;top:0;right:0;bottom:0;left:0}.r34K7X1zGgAi6DllVF3T.active.show.inline{position:static;left:0;top:0}@-moz-document url-prefix(''){.r34K7X1zGgAi6DllVF3T{visibility:visible;display:block}}\\n\",\"\"]),a.locals={container:\"r34K7X1zGgAi6DllVF3T\"},t.Z=a},3379:function(e){\"use strict\";var t=[];function n(e){for(var n=-1,r=0;r<t.length;r++)if(t[r].identifier===e){n=r;break}return n}function r(e,r){for(var o={},a=[],c=0;c<e.length;c++){var s=e[c],u=r.base?s[0]+r.base:s[0],l=o[u]||0,f=\"\".concat(u,\" \").concat(l);o[u]=l+1;var d=n(f),p={css:s[1],media:s[2],sourceMap:s[3],supports:s[4],layer:s[5]};if(-1!==d)t[d].references++,t[d].updater(p);else{var v=i(p,r);r.byIndex=c,t.splice(c,0,{identifier:f,updater:v,references:1})}a.push(f)}return a}function i(e,t){var n=t.domAPI(t);n.update(e);return function(t){if(t){if(t.css===e.css&&t.media===e.media&&t.sourceMap===e.sourceMap&&t.supports===e.supports&&t.layer===e.layer)return;n.update(e=t)}else n.remove()}}e.exports=function(e,i){var o=r(e=e||[],i=i||{});return function(e){e=e||[];for(var a=0;a<o.length;a++){var c=n(o[a]);t[c].references--}for(var s=r(e,i),u=0;u<o.length;u++){var l=n(o[u]);0===t[l].references&&(t[l].updater(),t.splice(l,1))}o=s}}},569:function(e){\"use strict\";var t={};e.exports=function(e,n){var r=function(e){if(void 0===t[e]){var n=document.querySelector(e);if(window.HTMLIFrameElement&&n instanceof window.HTMLIFrameElement)try{n=n.contentDocument.head}catch(e){n=null}t[e]=n}return t[e]}(e);if(!r)throw new Error(\"Couldn't find a style target. This probably means that the value for the 'insert' parameter is invalid.\");r.appendChild(n)}},9216:function(e){\"use strict\";e.exports=function(e){var t=document.createElement(\"style\");return e.setAttributes(t,e.attributes),e.insert(t,e.options),t}},3565:function(e,t,n){\"use strict\";e.exports=function(e){var t=n.nc;t&&e.setAttribute(\"nonce\",t)}},7795:function(e){\"use strict\";e.exports=function(e){var t=e.insertStyleElement(e);return{update:function(n){!function(e,t,n){var r=\"\";n.supports&&(r+=\"@supports (\".concat(n.supports,\") {\")),n.media&&(r+=\"@media \".concat(n.media,\" {\"));var i=void 0!==n.layer;i&&(r+=\"@layer\".concat(n.layer.length>0?\" \".concat(n.layer):\"\",\" {\")),r+=n.css,i&&(r+=\"}\"),n.media&&(r+=\"}\"),n.supports&&(r+=\"}\");var o=n.sourceMap;o&&\"undefined\"!=typeof btoa&&(r+=\"\\n/*# sourceMappingURL=data:application/json;base64,\".concat(btoa(unescape(encodeURIComponent(JSON.stringify(o)))),\" */\")),t.styleTagTransform(r,e,t.options)}(t,e,n)},remove:function(){!function(e){if(null===e.parentNode)return!1;e.parentNode.removeChild(e)}(t)}}}},4589:function(e){\"use strict\";e.exports=function(e,t){if(t.styleSheet)t.styleSheet.cssText=e;else{for(;t.firstChild;)t.removeChild(t.firstChild);t.appendChild(document.createTextNode(e))}}}},t={};function n(r){var i=t[r];if(void 0!==i)return i.exports;var o=t[r]={id:r,loaded:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.loaded=!0,o.exports}n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,{a:t}),t},n.d=function(e,t){for(var r in t)n.o(t,r)&&!n.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:t[r]})},n.g=function(){if(\"object\"==typeof globalThis)return globalThis;try{return this||new Function(\"return this\")()}catch(e){if(\"object\"==typeof window)return window}}(),n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.r=function(e){\"undefined\"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:\"Module\"}),Object.defineProperty(e,\"__esModule\",{value:!0})},n.nmd=function(e){return e.paths=[],e.children||(e.children=[]),e},n.nc=void 0;var r={};!function(){\"use strict\";function e(t){return e=\"function\"==typeof Symbol&&\"symbol\"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&\"function\"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?\"symbol\":typeof e},e(t)}function t(t){var n=function(t,n){if(\"object\"!==e(t)||null===t)return t;var r=t[Symbol.toPrimitive];if(void 0!==r){var i=r.call(t,n||\"default\");if(\"object\"!==e(i))return i;throw new TypeError(\"@@toPrimitive must return a primitive value.\")}return(\"string\"===n?String:Number)(t)}(t,\"string\");return\"symbol\"===e(n)?n:String(n)}function i(e,n){for(var r=0;r<n.length;r++){var i=n[r];i.enumerable=i.enumerable||!1,i.configurable=!0,\"value\"in i&&(i.writable=!0),Object.defineProperty(e,t(i.key),i)}}function o(e,t,n){return t&&i(e.prototype,t),n&&i(e,n),Object.defineProperty(e,\"prototype\",{writable:!1}),e}function a(e,t){if(!(e instanceof t))throw new TypeError(\"Cannot call a class as a function\")}function c(e,n,r){return(n=t(n))in e?Object.defineProperty(e,n,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[n]=r,e}n.r(r);var s,u=n(1640),l=n.n(u),f=(n(2476),\"arkose\"),d=\"2.2.2\",p=\"inline\",v=\"Verification challenge\",h=(\"data-\".concat(f,\"-challenge-api-url\"),\"data-\".concat(f,\"-event-blocked\")),g=\"data-\".concat(f,\"-event-completed\"),m=\"data-\".concat(f,\"-event-hide\"),y=\"data-\".concat(f,\"-event-ready\"),b=\"data-\".concat(f,\"-event-ready-inline\"),w=\"data-\".concat(f,\"-event-reset\"),O=\"data-\".concat(f,\"-event-show\"),j=\"data-\".concat(f,\"-event-suppress\"),S=\"data-\".concat(f,\"-event-shown\"),x=\"data-\".concat(f,\"-event-error\"),E=\"data-\".concat(f,\"-event-warning\"),k=\"data-\".concat(f,\"-event-resize\"),_=\"data-\".concat(f,\"-event-data-request\"),A=\"enforcement resize\",T=\"enforcement loaded\",P=\"challenge shown\",C=\"config\",I=\"data_response\",R=\"settings loaded\",L=\"api\",N=\"enforcement\",D=\"CAPI_RELOAD_EC\",F=\"observability timer\",K=\"data collected\",M=\"update_frame_attributes\",q=\"js_ready\",z=\"default\",H=\"ark\",$=\"onAPILoad\",U=\"onReady\",V=\"onShown\",W=\"onComplete\",B=\"apiExecute\",X=\"enforcementLoad\",G=\"intersectionCheck\",J=\"eventEnforcementLoad\",Z=\"eventFPCollected\",Y=\"eventSettingsLoad\",Q=(c(s={},T,J),c(s,R,Y),c(s,K,Z),s),ee=n(913),te=n.n(ee),ne=function(e){return 4===(e.match(/-/g)||[]).length},re=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:\"api\",t=function(e){if(document.currentScript)return document.currentScript;var t=\"enforcement\"===e?'script[id=\"enforcementScript\"]':'script[src*=\"v2\"][src*=\"api.js\"][data-callback]',n=document.querySelectorAll(t);if(n&&1===n.length)return n[0];try{throw new Error}catch(e){try{var r=te().parse(e)[0].fileName;return document.querySelector('script[src=\"'.concat(r,'\"]'))}catch(e){return null}}}(e);if(!t)return null;var n=t.src,r={};try{r=function(e){if(!e)throw new Error(\"Empty URL\");var t=e.toLowerCase().split(\"/v2/\").filter((function(e){return\"\"!==e}));if(t.length<2)throw new Error(\"Invalid Client-API URL\");var n=t[0],r=t[1].split(\"/\").filter((function(e){return\"\"!==e}));return{host:n,key:ne(r[0])?r[0].toUpperCase():null,extHost:n}}(n)}catch(e){}if(e===N){var i=window.location.hash;if(i.length>0){var o=(\"#\"===i.charAt(0)?i.substring(1):i).split(\"&\"),a=o[0];r.key=ne(a)?a:r.key,r.id=o[1]}}return r}(),ie=function(e,t){for(var n,r=0;r<e.length;r+=1){var i=e[r],o=String(i.getAttribute(\"src\"));if((o.match(t)||o.match(\"v2/api.js\"))&&i.hasAttribute(\"data-callback\")){n=i;break}}return n}(document.querySelectorAll(\"script\"),re.key||null);if(ie){var oe=ie.nonce,ae=ie.getAttribute?ie.getAttribute(\"data-nonce\"):null,ce=oe||ae;ce&&(n.nc=ce)}var se=function(e){return\"function\"==typeof e},ue=function(e,t,n){try{var r=t.split(\".\"),i=e;return r.forEach((function(e){i=i[e]})),i||n}catch(e){return n}},le=function(t){var n=t,r=e(t);return(\"string\"!==r||\"string\"===r&&-1===t.indexOf(\"px\")&&-1===t.indexOf(\"vw\")&&-1===t.indexOf(\"vh\"))&&(n=\"\".concat(t,\"px\")),n},fe=function(e,t){if(e[H])e[H][t]||(e[H][t]={});else{var n=t?c({},t,{}):{};Object.defineProperty(e,H,{value:n,writable:!0})}},de=function(e,t,n,r){e[H]&&e[H][t]||fe(e,t),e[H][t][n]=r};function pe(e,t){if(null==e)return{};var n,r,i=function(e,t){if(null==e)return{};var n,r,i={},o=Object.keys(e);for(r=0;r<o.length;r++)n=o[r],t.indexOf(n)>=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r<o.length;r++)n=o[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var ve=function(){return window&&window.crypto&&\"function\"==typeof window.crypto.getRandomValues?([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g,(function(e){return(e^crypto.getRandomValues(new Uint8Array(1))[0]&15>>e/4).toString(16)})):\"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g,(function(e){var t=16*Math.random()|0;return(\"x\"==e?t:3&t|8).toString(16)}))},he=n(2265),ge=n.n(he),me=n(7983);function ye(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function be(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?ye(Object(n),!0).forEach((function(t){c(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):ye(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}var we=[\"settings\",\"styling\",\"token\"],Oe=function t(n){return\"object\"===e(n)&&null!==n?Object.keys(n).reduce((function(r,i){var o,a=n[i],s=e(a),u=a;return-1===we.indexOf(i)&&(\"string\"===s&&(u=\"\"===(o=a)?o:(0,me.N)(o)),\"object\"===s&&(u=Array.isArray(a)?a:t(a))),be(be({},r),{},c({},i,u))}),{}):n};function je(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function Se(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?je(Object(n),!0).forEach((function(t){c(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):je(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}var xe=function(){function e(){var t=this;a(this,e),this.config={context:null,target:\"*\",identifier:null,iframePosition:null},this.emitter=new(ge()),this.messageListener=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};try{var n=function(e){return JSON.parse(e)}(e.data),r=n||{},i=r.data,o=r.key,a=r.message,c=r.type,s=Oe(i);if(a&&o===t.config.identifier)return t.emitter.emit(a,s),\"broadcast\"===c&&t.postMessageToParent({data:s,key:o,message:a}),void(\"emit\"===c&&t.postMessageToChildren({data:s,key:o,message:a}));n&&\"FunCaptcha-action\"===n.msg&&t.postMessageToChildren({data:Se(Se({},n),n.payload||{})})}catch(n){if(e.data===q)return void t.emitter.emit(q,{});if(e.data===D)return void t.emitter.emit(D,{});if(e.data.msg===M)return void t.emitter.emit(M,{});\"string\"==typeof e.data&&-1!==e.data.indexOf(\"key_pressed_\")&&t.config.iframePosition===N&&window.parent&&\"function\"==typeof window.parent.postMessage&&window.parent.postMessage(e.data,\"*\")}}}return o(e,[{key:\"context\",set:function(e){this.config.context=e}},{key:\"identifier\",set:function(e){this.config.identifier=e}},{key:\"setup\",value:function(e,t){var n,r,i;this.config.identifier!==this.identifier&&(n=window,r=this.config.identifier,(i=n[H])&&i[r]&&(i[r].listener&&window.removeEventListener(\"message\",i[r].listener),i[r].error&&window.removeEventListener(\"error\",i[r].error),delete i[r])),this.config.identifier=e,this.config.iframePosition=t,fe(window,this.config.identifier);var o=window[H][this.config.identifier].listener;o&&window.removeEventListener(\"message\",o),de(window,this.config.identifier,\"listener\",this.messageListener),window.addEventListener(\"message\",window[H][this.config.identifier].listener)}},{key:\"postMessage\",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=arguments.length>1?arguments[1]:void 0,n=t.data,r=t.key,i=t.message,o=t.type;if(se(e.postMessage)){var a=Se(Se({},n),{},{data:n,key:r,message:i,type:o});e.postMessage(function(e){return JSON.stringify(e)}(a),this.config.target)}}},{key:\"postMessageToChildren\",value:function(e){for(var t=e.data,n=e.key,r=e.message,i=document.querySelectorAll(\"iframe\"),o=[],a=0;a<i.length;a+=1){var c=i[a].contentWindow;c&&o.push(c)}for(var s=0;s<o.length;s+=1){var u=o[s];this.postMessage(u,{data:t,key:n,message:r,type:\"emit\"},this.config.target)}}},{key:\"postMessageToParent\",value:function(e){var t=e.data,n=e.key,r=e.message;window.parent!==window&&this.postMessage(window.parent,{data:t,key:n,message:r,type:\"broadcast\"})}},{key:\"emit\",value:function(e,t){this.emitter.emit(e,t),this.postMessageToParent({message:e,data:t,key:this.config.identifier}),this.postMessageToChildren({message:e,data:t,key:this.config.identifier})}},{key:\"off\",value:function(){var e;(e=this.emitter).removeListener.apply(e,arguments)}},{key:\"on\",value:function(){var e;(e=this.emitter).on.apply(e,arguments)}},{key:\"once\",value:function(){var e;(e=this.emitter).once.apply(e,arguments)}}]),e}(),Ee=new xe,ke=[\"logged\"];function _e(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function Ae(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?_e(Object(n),!0).forEach((function(t){c(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):_e(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}var Te,Pe,Ce,Ie,Re=\"sampled\",Le=\"error\",Ne={onReady:3e4,onShown:6e4},De={enabled:{type:\"boolean\",default:!1},onReadyThreshold:{type:\"integer\",default:Ne.onReady},onShownThreshold:{type:\"integer\",default:Ne.onShown},windowErrorEnabled:{type:\"boolean\",default:!0},samplePercentage:{type:\"float\",default:1}},Fe=function(e,t,n,r){Ee.emit(F,{action:e,timerId:t,subTimerId:n||null,time:Date.now(),info:r})},Ke=function(e){var t=arguments.length>1&&void 0!==arguments[1]&&arguments[1],n=Date.now();Te||(Te=n,Pe=n);var r=n-Te,i=n-Pe;Ie&&(t?console.debug(\"%c\".concat(Ce).concat(e,\": \").concat(r,\" since last event - \").concat(i,\" total time - \").concat(Date.now()),\"color: \".concat(t,\";\")):console.debug(\"\".concat(Ce).concat(e,\": \").concat(r,\" since last event - \").concat(i,\" total time - \").concat(Date.now()))),Te=n},Me=n(3940),qe=n.n(Me),ze=We;!function(e,t){for(var n=119,r=134,i=122,o=118,a=133,c=131,s=137,u=107,l=113,f=We,d=e();;)try{if(379847===-parseInt(f(n))/1*(-parseInt(f(r))/2)+parseInt(f(i))/3+parseInt(f(o))/4+parseInt(f(a))/5+-parseInt(f(c))/6+parseInt(f(s))/7*(-parseInt(f(u))/8)+-parseInt(f(l))/9)break;d.push(d.shift())}catch(e){d.push(d.shift())}}(Je);var He,$e,Ue=(He=115,$e=!0,function(e,t){var n=$e?function(){if(t){var n=t[We(He)](e,arguments);return t=null,n}}:function(){};return $e=!1,n}),Ve=Ue(void 0,(function(){var e=117,t=121,n=132,r=109,i=We;return Ve[i(e)]()[i(t)](i(n)+i(r))[i(e)]().constructor(Ve)[i(t)](\"(((.+)+)+)+$\")}));function We(e,t){var n=Je();return We=function(e,t){return n[e-=102]},We(e,t)}Ve();var Be=[ze(135),ze(116)+ze(102)],Xe={};Xe[ze(130)]=!0;var Ge={};function Je(){var e=[\"operty\",\"98752jXTTXx\",\"hasOwnPr\",\"+)+$\",\"forEach\",\"enabled\",\"eOffset\",\"3115449jUsVhz\",\"call\",\"apply\",\"ECRespon\",\"toString\",\"1311240fFqRvl\",\"63617knDNJe\",\"prototyp\",\"search\",\"1622595aRpzHJ\",\"theme\",\"closeOnE\",\"eButton\",\"keys\",\"observab\",\"optional\",\"hideClos\",\"default\",\"4164720ByzkrJ\",\"(((.+)+)\",\"1499220eaMZBt\",\"18zEdzoa\",\"lightbox\",\"ility\",\"182OLSPTB\",\"sive\",\"length\",\"settings\",\"landscap\"];return(Je=function(){return e})()}Ge.default=!1;var Ze={};Ze[ze(124)+\"sc\"]=Xe,Ze[ze(129)+ze(125)]=Ge;var Ye={};Ye[ze(130)]=!0;var Qe={};Qe[ze(130)]=70;var et={};et[ze(111)]=Ye,et[ze(105)+ze(112)]=Qe;var tt={};tt[ze(130)]={};var nt={optional:!0},rt={};rt[ze(135)]=Ze,rt[ze(116)+ze(102)]=et,rt[ze(127)+ze(136)]=tt,rt.f=nt;var it=rt,ot=function(){var e=123,t=104,n=135,r=116,i=102,o=110,a=126,c=120,s=108,u=106,l=114,f=128,d=110,p=ze,v=arguments[p(103)]>0&&void 0!==arguments[0]?arguments[0]:{},h=v[p(e)],g=void 0===h?null:h,m=v[p(t)]||v,y={};y[p(n)]={},y[p(r)+p(i)]={};var b=y;[\"lightbox\",p(r)+p(i)][p(o)]((function(e){var t=120,n=106,r=114,i=p,o=m[e]||{},a=it[e];Object.keys(a)[i(d)]((function(c){var s=i;Object[s(t)+\"e\"][\"hasOwnPr\"+s(n)][s(r)](o,c)?b[e][c]=o[c]:b[e][c]=a[c].default}))})),g&&(b.theme=g);it[p(n)],it[p(r)+p(i)];var w=pe(it,Be);return Object[p(a)](w).forEach((function(e){var t=p;Object[t(c)+\"e\"][t(s)+t(u)][t(l)](m,e)?b[e]=m[e]:!0!==it[e][t(f)]&&(b[e]=it[e].default)})),b},at=n(3379),ct=n.n(at),st=n(7795),ut=n.n(st),lt=n(569),ft=n.n(lt),dt=n(3565),pt=n.n(dt),vt=n(9216),ht=n.n(vt),gt=n(4589),mt=n.n(gt),yt=n(903),bt={};bt.styleTagTransform=mt(),bt.setAttributes=pt(),bt.insert=ft().bind(null,\"head\"),bt.domAPI=ut(),bt.insertStyleElement=ht();ct()(yt.Z,bt);var wt=yt.Z&&yt.Z.locals?yt.Z.locals:void 0;function Ot(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}var jt={show:!1,isActive:void 0,element:void 0,frame:void 0,mode:void 0,ECResponsive:!0,enforcementUrl:null},St=function(e,t){e.setAttribute(\"class\",t)},xt=function(){return qe()(wt.container,function(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?Ot(Object(n),!0).forEach((function(t){c(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):Ot(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}({show:!!jt.show,active:!!jt.isActive},jt.mode?c({},jt.mode,!0):{}))};Ee.on(\"challenge iframe\",(function(e){var t=e.width,n=e.height,r=e.minWidth,i=e.minHeight,o=e.maxWidth,a=e.maxHeight;if(jt.frame){jt.show=!0;var c=xt();St(jt.frame,c);var s=n,u=t;if(jt.ECResponsive){var l=function(e){var t=e.width,n=e.height,r=e.minWidth,i=e.maxWidth,o=e.minHeight,a=e.maxHeight,c=e.landscapeOffset,s=t,u=n;if(!r||!i)return{height:u,width:s};if(window.screen&&window.screen.width&&window.screen.height){var l=window.screen.availHeight||window.screen.height,f=window.screen.availWidth||window.screen.width,d=l-(!window.orientation||90!==window.orientation&&-90!==window.orientation?0:c);s=f,u=o&&a?d:n,f>=parseInt(i,10)&&(s=i),f<=parseInt(r,10)&&(s=r),a&&d>=parseInt(a,10)&&(u=a),o&&d<=parseInt(o,10)&&(u=o)}return s=le(s),{height:u=le(u),width:s}}({width:t,height:n,minWidth:r,maxWidth:o,minHeight:i,maxHeight:a,landscapeOffset:jt.ECResponsive.landscapeOffset||0});u=l.width,s=l.height}var f=!1;t&&t!==jt.frame.style.width&&(jt.frame.style.width=t,f=!0),n&&n!==jt.frame.style.height&&(jt.frame.style.height=n,f=!0),jt.mode===p&&(r&&r!==jt.frame.style[\"min-width\"]&&(jt.frame.style[\"min-width\"]=r,f=!0),i&&i!==jt.frame.style[\"min-height\"]&&(jt.frame.style[\"min-height\"]=i,f=!0),o&&o!==jt.frame.style[\"max-width\"]&&(jt.frame.style[\"max-width\"]=o,f=!0),a&&a!==jt.frame.style[\"max-height\"]&&(jt.frame.style[\"max-height\"]=a,f=!0)),f&&Ee.emit(A,{width:u,height:s}),document.activeElement!==jt.element&&!1===jt.mode&&jt.frame.focus()}}));var Et=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t={},n=[\"publicKey\",\"data\",\"isSDK\",\"language\",\"mode\",\"onDataRequest\",\"onCompleted\",\"onHide\",\"onReady\",\"onReset\",\"onResize\",\"onShow\",\"onShown\",\"onSuppress\",\"onError\",\"onWarning\",\"onFailed\",\"onResize\",\"settings\",\"selector\",\"accessibilitySettings\",\"styleTheme\",\"uaTheme\",\"apiLoadTime\",\"enableDirectionalInput\",\"inlineRunOnTrigger\"];return Object.keys(e).filter((function(e){return-1!==n.indexOf(e)})).forEach((function(n){t[n]=e[n]})),t};!function(e,t){for(var n=190,r=191,i=203,o=201,a=197,c=208,s=198,u=202,l=193,f=207,d=192,p=204,v=Tt,h=e();;)try{if(134883===parseInt(v(n))/1*(parseInt(v(r))/2)+-parseInt(v(i))/3*(parseInt(v(o))/4)+-parseInt(v(a))/5+-parseInt(v(c))/6+-parseInt(v(s))/7*(-parseInt(v(u))/8)+-parseInt(v(l))/9*(-parseInt(v(f))/10)+-parseInt(v(d))/11*(parseInt(v(p))/12))break;h.push(h.shift())}catch(e){h.push(h.shift())}}(At);var kt=function(){var e=195,t=!0;return function(n,r){var i=t?function(){if(r){var t=r[Tt(e)](n,arguments);return r=null,t}}:function(){};return t=!1,i}}(),_t=kt(void 0,(function(){var e=205,t=194,n=196,r=200,i=189,o=199,a=Tt;return _t[a(200)]()[a(e)](a(t)+a(n))[a(r)]()[a(i)+a(o)](_t).search(a(t)+a(n))}));function At(){var e=[\"331140bObYZE\",\"3269dePuBo\",\"tor\",\"toString\",\"124700NFjzSD\",\"3256galLZq\",\"3gvmdVa\",\"594444sQfUHh\",\"search\",\"split\",\"38730GmOFGi\",\"1057680axFmxk\",\"construc\",\"3vjqrlw\",\"142958HOfWqr\",\"55qzyzgN\",\"585eyUPFl\",\"(((.+)+)\",\"apply\",\"+)+$\"];return(At=function(){return e})()}function Tt(e,t){var n=At();return Tt=function(e,t){return n[e-=189]},Tt(e,t)}_t();!function(e,t){for(var n=459,r=464,i=458,o=461,a=475,c=471,s=454,u=477,l=455,f=476,d=463,p=Rt,v=e();;)try{if(217126===parseInt(p(n))/1+-parseInt(p(r))/2+parseInt(p(i))/3*(parseInt(p(o))/4)+parseInt(p(a))/5*(parseInt(p(c))/6)+-parseInt(p(s))/7*(parseInt(p(u))/8)+-parseInt(p(l))/9+parseInt(p(f))/10*(parseInt(p(d))/11))break;v.push(v.shift())}catch(e){v.push(v.shift())}}(It);var Pt=function(){var e=479,t=!0;return function(n,r){var i=t?function(){if(r){var t=r[Rt(e)](n,arguments);return r=null,t}}:function(){};return t=!1,i}}(),Ct=Pt(void 0,(function(){var e=469,t=466,n=457,r=462,i=460,o=473,a=466,c=457,s=Rt;return Ct[s(462)]()[s(e)](s(t)+s(n))[s(r)]()[s(i)+s(o)](Ct)[s(e)](s(a)+s(c))}));function It(){var e=[\"724465bXqSUS\",\"322020jhTTBg\",\"118424nMYndJ\",\"nOnTrigg\",\"apply\",\"77wyYzHF\",\"1267956rJKgkn\",\"location\",\"+)+$\",\"9iclmJq\",\"198561xLEuCT\",\"construc\",\"339236wQBSpJ\",\"toString\",\"66YyrQIj\",\"540500wywSxE\",\"language\",\"(((.+)+)\",\"href\",\"__nightm\",\"search\",\"isSDK\",\"6TpKyDX\",\"inlineRu\",\"tor\",\"are\"];return(It=function(){return e})()}function Rt(e,t){var n=It();return Rt=function(e,t){return n[e-=454]},Rt(e,t)}Ct();var Lt,Nt,Dt=function(){var e=456,t=467,n=467,r=Rt;return window[r(e)][r(t)]?function(e){return e||\"string\"==typeof e?e[Tt(206)](\"?\")[0]:null}(window[r(e)][r(n)]):null},Ft=function(e){return\"boolean\"==typeof e?e:null},Kt=function(){var e=474,t=Rt;return!!window[t(468)+t(e)]};function Mt(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function qt(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?Mt(Object(n),!0).forEach((function(t){c(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):Mt(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}Ce=\"API: \",Ie=Nt,Ke(\"Starting app\");var zt=re.key,Ht=re.host,$t=re.extHost;Ke(\"Starting observer\");var Ut=function(e,t,n){var r=arguments.length>3&&void 0!==arguments[3]?arguments[3]:5e3,i=t,o=n,a=ve(),s=function(){var e={},t=window.navigator;if(e.platform=t.platform,e.language=t.language,t.connection)try{e.connection={effectiveType:t.connection.effectiveType,rtt:t.connection.rtt,downlink:t.connection.downlink}}catch(e){}return e}(),u={},l={},f=e,d=null,p={},v=null,h=null,g={timerCheckInterval:r},m=!1,y=!1,b=!1,w=!1,O=!1,j=function(){var e;if(w){for(var t=arguments.length,n=new Array(t),r=0;r<t;r++)n[r]=arguments[r];\"string\"==typeof n[0]&&(n[0]=\"Observability - \".concat(n[0])),(e=console).log.apply(e,n)}},S=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=e.timerId,n=e.type;if(!0===g.enabled){var r=t?c({},t,u[t]):u,d=Object.keys(r).reduce((function(e,t){r[t].logged=!0;var n=r[t],i=(n.logged,pe(n,ke));return Ae(Ae({},e),{},c({},t,i))}),{}),m={id:a,publicKey:f,capiVersion:o,mode:h,suppressed:O,device:s,error:p,windowError:l,sessionId:v,timers:d,sampled:n===Re};j(\"Logging Metrics:\",m);try{var y=new XMLHttpRequest;y.open(\"POST\",i),y.send(JSON.stringify(m))}catch(e){}}},x=function(e){return g&&Object.prototype.hasOwnProperty.call(g,\"\".concat(e,\"Threshold\"))?g[\"\".concat(e,\"Threshold\")]:Ne[e]},E=function e(){if(b)return!1;var t=!1;return m&&(Object.keys(u).forEach((function(e){var n=x(e),r=u[e],i=r.diff,o=r.logged,a=r.end;if(0!==n&&!0!==o&&(i&&i>n&&(t=!0,u[e].logged=!0),!i&&!a)){var c=u[e].start,s=Date.now(),l=s-c;l>n&&(u[e].diff=l,u[e].end=s,u[e].logged=!0,t=!0)}})),t&&S()),d=setTimeout(e,g.timerCheckInterval),!0},k=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return Ae(Ae({},{start:null,end:null,diff:null,threshold:null,logged:!1,metrics:{}}),e)},_=function(){return{id:a,publicKey:f,sessionId:v,mode:h,settings:g,device:s,error:p,windowError:l,timers:u,debugEnabled:w}},A=function(){clearTimeout(d)};d=setTimeout(E,g.timerCheckInterval);try{\"true\"===window.localStorage.getItem(\"capiDebug\")&&(w=!0,window.capiObserver={getValues:_})}catch(e){}return{getValues:_,timerStart:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:Date.now(),n=u[e]||{};if(!n.start){var r=x(e);j(\"\".concat(e,\" started:\"),t),u[e]=k(Ae(Ae({},n),{},{start:t,threshold:r}))}},timerEnd:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:Date.now(),n=u[e];n&&!n.end&&(n.end=t,n.diff=n.end-n.start,j(\"\".concat(e,\" ended:\"),t,n.diff),b&&S({timerId:e,type:Re}))},timerCheck:E,subTimerStart:function(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:Date.now(),r=arguments.length>3?arguments[3]:void 0,i=u[e];i||(i=k()),i.end||(i.metrics[t]=Ae({start:n,end:null,diff:null},r&&{info:r}),u[e]=i,j(\"\".concat(e,\".\").concat(t,\" started:\"),n))},subTimerEnd:function(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:Date.now(),r=u[e];if(r&&!r.end){var i=r.metrics[t];i&&(i.end=n,i.diff=i.end-i.start,j(\"\".concat(e,\".\").concat(t,\" ended:\"),n,i.diff))}},cancelIntervalTimer:A,setup:function(e,t){m=!0,g=Ae(Ae({},g),function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return Object.keys(De).reduce((function(t,n){var r=e[n],i=De[n];if(\"boolean\"===i.type)return Ae(Ae({},t),{},c({},n,\"boolean\"==typeof r?r:i.default));var o=\"float\"===i.type?parseFloat(r,0):parseInt(r,10);return Ae(Ae({},t),{},c({},n,isNaN(o)?i.default:o))}),{})}(e)),h=t,Object.keys(u).forEach((function(e){var t=x(e);u[e].threshold=t}));var n,r=g.samplePercentage;n=r,(b=Math.random()<=n/100)&&A(),j(\"Session sampled:\",b)},setSession:function(e){v=e},logError:function(e){y||(p=e,y=!0,S({type:Le}))},logWindowError:function(e,t,n,r){g&&!0!==g.windowErrorEnabled||(l[e]={message:t,filename:n,stack:r})},debugLog:j,setSuppressed:function(){O=!0},setPublicKey:function(e){f=e,y=!1,p={},[\"onShown\",\"onComplete\"].forEach((function(e){if(u[e]){var t=u[e].threshold||null;u[e]=k({threshold:t})}}))},observabilityTimer:Fe,apiLoadTimerSetup:function(e,t){u[e]=Ae(Ae({},t),{},{logged:!1}),b&&S({timerId:e,type:Re})}}}(zt,\"\".concat($t).concat(\"/metrics/ui\"),d,5e3);Ut.subTimerStart(U,B);var Vt=function(e){return\"arkose-\".concat(e,\"-wrapper\")},Wt={},Bt=\"onCompleted\",Xt=\"onHide\",Gt=\"onReady\",Jt=\"onReset\",Zt=\"onShow\",Yt=\"onShown\",Qt=\"onSuppress\",en=\"onFailed\",tn=\"onError\",nn=\"onWarning\",rn=\"onResize\",on=\"onDataRequest\",an=(c(Lt={},g,Bt),c(Lt,m,Xt),c(Lt,y,Gt),c(Lt,b,Gt),c(Lt,w,Jt),c(Lt,O,Zt),c(Lt,S,Yt),c(Lt,j,Qt),c(Lt,h,en),c(Lt,x,tn),c(Lt,E,nn),c(Lt,k,rn),c(Lt,_,on),Lt);Ke(\"Set all hooks\");var cn=o((function e(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=t.completed,r=t.token,i=t.suppressed,o=t.error,c=t.warning,s=t.width,u=t.height,l=t.requested;a(this,e),this.completed=!!n,this.token=r||null,this.suppressed=!!i,this.error=o||null,this.warning=c||null,this.width=s||0,this.height=u||0,this.requested=l||null}));Ke(\"Instantiated Ark Hook Class\");var sn=function(e){var t=document.createElement(\"div\");return t.setAttribute(\"aria-hidden\",!0),t.setAttribute(\"class\",Vt(e||zt)),t},un=function(){var e,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return qt(qt({element:sn(),inactiveElement:null,bodyElement:document.querySelector(\"body\"),savedActiveElement:null,modifiedSiblings:[],challengeLoadedEvents:[],container:null,elements:function(){return document.querySelectorAll(Wt.config.selector)},initialSetupCompleted:!1,enforcementLoaded:!1,enforcementReady:!1,getPublicKeyTimeout:null,isActive:!1,isHidden:!1,isReady:!1,isConfigured:!1,suppressed:!1,isResettingChallenge:!1,lastResetTimestamp:0,isCompleteReset:!1,fpData:null,onReadyEventCheck:[],width:0,height:0,token:null,externalRequested:!1},t),{},{config:qt(qt({},zt?{publicKey:zt}:{}),{},{selector:(e=zt,\"[data-\".concat(f,'-public-key=\"').concat(e,'\"]')),styleTheme:t.config&&t.config.styleTheme||z,siteData:{location:{...window.location,origin:\"https://chat.openai.com\"}},apiLoadTime:null,settings:{},accessibilitySettings:{lockFocusToModal:!0}},t.config),events:qt({},t.events)})},ln=function(e){var t=Wt.events[an[e]];if(se(t)){for(var n=arguments.length,r=new Array(n>1?n-1:0),i=1;i<n;i++)r[i-1]=arguments[i];t.apply(void 0,r)}},fn=function(){Ke(\"Rendering enforcement frame\",\"blue\"),function(e){var t=e.host,n=e.id,r=e.publicKey,i=e.element,o=e.config,a=e.isActive,c=e.isReady,s=e.capiObserver;Ke(\"Creating iframe\");var u=ue(o,\"mode\");jt.mode=u,jt.element=i,jt.isActive=a,jt.show=c,jt.ECResponsive=ue(ot(o.settings),\"ECResponsive\",{}),jt.accessibilitySettings=ue(o,\"accessibilitySettings\");var l=xt(),f=function(e){var t=e.host,n=e.publicKey,r=e.id,i=e.file;return\"development\"===e.environment?\"\".concat(i,\"#\").concat(n||\"\",\"&\").concat(r):\"\".concat(t,\"/v2/\").concat(i,\"#\").concat(n||\"\",\"&\").concat(r)}({host:t,publicKey:r,id:n,file:\"2.2.2/enforcement.7fe4ebdd37c791e59a12da2c9c38eec6.html\",environment:\"production\"});if(ue(jt.element,\"children\",[]).length<1){jt.enforcementUrl=f;var d=document.createElement(\"iframe\");d.setAttribute(\"src\",f),d.setAttribute(\"class\",l),d.setAttribute(\"title\",v),d.setAttribute(\"aria-label\",v),d.setAttribute(\"data-e2e\",\"enforcement-frame\"),d.style.width=\"0px\",d.style.height=\"0px\",d.addEventListener(\"load\",(function(){s.subTimerEnd(U,X)})),s.subTimerStart(U,X),jt.element.appendChild(d),jt.frame=d}else f!==jt.enforcementUrl&&(jt.frame.setAttribute(\"src\",f),jt.enforcementUrl=f),St(jt.frame,l),jt.isActive||(jt.frame.style.width=0,jt.frame.style.height=0)}({host:'https://tcr9i.chat.openai.com',id:Wt.id,publicKey:Wt.config.publicKey,element:Wt.element,config:Wt.config,isActive:Wt.isActive,isReady:Wt.isReady,capiObserver:Ut})},dn=function(){var e=arguments.length>0&&void 0!==arguments[0]&&arguments[0],t=Wt,n=t.element,r=t.bodyElement,i=t.container,o=t.events,a=t.lastResetTimestamp,c=t.config;if(c.publicKey){var s=Date.now();if(!(s-a<100)){Wt.lastResetTimestamp=s,Wt.isActive=!1,Wt.completed=!1,Wt.token=null,Wt.isReady=!1,Wt.onReadyEventCheck=[],fn(),r&&o&&(r.removeEventListener(\"click\",o.bodyClicked),window.removeEventListener(\"keyup\",o.escapePressed),Wt.events.bodyClicked=null,Wt.events.escapePressed=null);var u=n;Wt.inactiveElement=u,Wt.element=void 0,Wt.element=sn(c.publicKey),i&&u&&i.contains(u)&&(Ee.emit(\"enforcement detach\"),setTimeout((function(){try{i.removeChild(u)}catch(e){}}),5e3)),Wt=un(l()(Wt)),e||ln(w,new cn(Wt)),yn()}}},pn=function(e){Wt.element.setAttribute(\"aria-hidden\",e)},vn=function(){Ke(\"Showing enforcement\"),Wt.enforcementReady&&!Wt.isActive&&(Ee.emit(\"trigger show\"),Wt.isHidden&&(Wt.isHidden=!1,Wt.isReady&&Ee.emit(P,{token:Wt.token})))},hn=function(){var e=(arguments.length>0&&void 0!==arguments[0]?arguments[0]:{}).manual;Wt.isActive=!1,e&&(Wt.isHidden=!0),ln(m,new cn(Wt)),Wt.savedActiveElement&&(Wt.savedActiveElement.focus(),Wt.savedActiveElement=null),ue(Wt,\"config.mode\")!==p&&function(){for(var e=Wt.modifiedSiblings,t=0;t<e.length;t+=1){var n=e[t],r=n.elem,i=n.ariaHiddenState;r!==Wt.appEl&&(null===i?r.removeAttribute(\"aria-hidden\"):r.setAttribute(\"aria-hidden\",i))}}(),fn(),pn(!0)},gn=function(e){e.target.closest(Wt.config.selector)&&vn()},mn=function(e){return 27!==ue(e,\"keyCode\")?null:hn({manual:!0})},yn=function(){return ue(Wt,\"config.mode\")===p?(Ke(\"Setting up inline\"),Wt.container=document.querySelector(ue(Wt,\"config.selector\",\"\")),void(Wt.container&&(Wt.container.contains(Wt.element)||(Wt.container.appendChild(Wt.element),fn())))):(Ke(\"Setting up Modal\"),Wt.container=Wt.bodyElement,Wt.events.bodyClicked||(Wt.events.bodyClicked=gn,Wt.bodyElement.addEventListener(\"click\",Wt.events.bodyClicked)),Wt.events.escapePressed||(Wt.events.escapePressed=mn,window.addEventListener(\"keyup\",Wt.events.escapePressed)),void(Wt.container&&(Wt.container.contains(Wt.element)||(Wt.container.appendChild(Wt.element),fn()))))},bn=function(){var e=ve();Ut.subTimerEnd(U,B),Ke(\"API Execute done\"),fe(window,e),Ke(\"Set up Window\"),Ee.setup(e,L),Ke(\"Set up emitter\"),function(e){if(e){var t=window[H][e].error;t&&window.removeEventListener(\"error\",t)}de(window,e,\"error\",(function(e){var t=e.message,n=e.filename,r=e.error;if(n&&\"string\"==typeof n&&n.indexOf(\"api.js\")>=0&&n.indexOf(Wt.config.publicKey)>=0){var i=r.stack;Ut.logWindowError(\"integration\",t,n,i)}})),window.addEventListener(\"error\",window[H][e].error)}(e),Ke(\"Set up window error\"),Wt=un({id:e})},wn=function(){var e,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};Wt.initialSetupCompleted=!0;var n=function(e){return e===p?p:\"lightbox\"}(t.mode||ue(Wt,\"config.mode\")),r=t.styleTheme||z,i=Wt.isConfigured&&r!==Wt.config.styleTheme;Wt.isConfigured=!0;var o=zt||Wt.config.publicKey||null,a=!1;t.publicKey&&o!==t.publicKey&&(!function(e){Ke(\"Seting up key\"),de(window,Wt.id,\"publicKey\",e),Ut.setPublicKey(e),Wt.element&&Wt.element.getAttribute&&(Wt.element.getAttribute(\"class\").match(e)||Wt.element.setAttribute(\"class\",Vt(e))),Ke(\"Set up key\")}(t.publicKey),o=t.publicKey,Wt.config.publicKey&&Wt.config.publicKey!==t.publicKey&&(a=!0)),Wt.config=qt(qt(qt(qt({},Wt.config),t),{mode:n}),{},{styleTheme:r,publicKey:o,language:\"\"!==t.language?t.language||Wt.config.language:void 0}),Wt.events=qt(qt({},Wt.events),{},(c(e={},Bt,t[Bt]||Wt.events[Bt]),c(e,en,t[en]||Wt.events[en]),c(e,Xt,t[Xt]||Wt.events[Xt]),c(e,Gt,t[Gt]||Wt.events[Gt]),c(e,Jt,t[Jt]||Wt.events[Jt]),c(e,Zt,t[Zt]||Wt.events[Zt]),c(e,Yt,t[Yt]||Wt.events[Yt]),c(e,Qt,t[Qt]||Wt.events[Qt]),c(e,tn,t[tn]||Wt.events[tn]),c(e,nn,t[nn]||Wt.events[nn]),c(e,rn,t[rn]||Wt.events[rn]),c(e,on,t[on]||Wt.events[on]),e)),Wt.config.pageLevel=function(e){var t,n=465,r=470,i=472,o=478,a=Rt;return{chref:Dt(),clang:null!==(t=e[a(n)])&&void 0!==t?t:null,surl:null,sdk:Ft(e[a(r)])||!1,nm:Kt(),triggeredInline:e[a(i)+a(o)+\"er\"]||!1}}(Wt.config),Ke(\"Configured initial state\"),Ee.emit(C,Wt.config),Ke(\"Emitt Config event\"),i||a?(Ke(\"Resetting enforcement\"),dn(!0)):(Ke(\"Call setup mode\"),yn()),\"lightbox\"===n&&(Wt.element.setAttribute(\"aria-modal\",!0),Wt.element.setAttribute(\"role\",\"dialog\"))},On=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=e.event,n=e.observability;if(Wt.onReadyEventCheck.push(t),n){var r=n.timerId,i=n.subTimerId,o=n.time;Ut.subTimerEnd(r,i,o)}Q[t]&&Ut.subTimerEnd(U,Q[t]);var a=[T,K,R];Ut.subTimerStart(U,G);var c=function(e,t){var n,r,i=[],o=e.length,a=t.length;for(n=0;n<o;n+=1)for(r=0;r<a;r+=1)e[n]===t[r]&&i.push(e[n]);return i}(a,Wt.onReadyEventCheck);c.length===a.length&&(Wt.enforcementReady=!0,Wt.onReadyEventCheck=[],Ut.subTimerEnd(U,G),Wt.isCompleteReset||(Ut.timerEnd(U),Ke(\"onReady triggered\",\"orange\"),ln(y,new cn(Wt))),Wt.isCompleteReset=!1),Ke(\"onReady event: \".concat(t),\"green\")},jn=function(e){var t=e.token;if(t){Wt.token=t;var n=t.split(\"|\"),r=n.length?n[0]:null;Ut.setSession(r)}},Sn={setConfig:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};Ut.timerStart(U),[J,Y,Z].forEach((function(e){Ut.subTimerStart(U,e)})),wn(Et(e))},getConfig:function(){return l()(Wt.config)},dataResponse:function(e){if(Wt.requested){var t={message:I,data:e,key:Wt.config.publicKey,type:\"emit\"};Ee.emit(I,t),Wt.requested=null}},reset:function(){dn()},run:vn,version:d},xn=ie.getAttribute(\"data-callback\");Ke(\"Set up Every function\"),Ee.on(\"show enforcement\",(function(){Wt.isReady||(Ut.timerStart(V),Ut.timerStart(W)),Wt.isActive=!0,Wt.savedActiveElement=document.activeElement,ln(O,new cn(Wt)),ue(Wt,\"config.mode\")!==p&&function(){var e=Wt.bodyElement.children;Wt.modifiedSiblings=[];for(var t=0;t<e.length;t+=1){var n=e.item(t),r=n.getAttribute(\"aria-hidden\");n!==Wt.appEl&&\"true\"!==r&&(Wt.modifiedSiblings.push({elem:n,ariaHiddenState:r}),n.setAttribute(\"aria-hidden\",!0))}}(),fn(),pn(!1)})),Ee.on(P,(function(e){var t=e.token;Wt.isReady=!0,Wt.token=t,Wt.isHidden||(Wt.isActive=!0,fn(),Ut.timerEnd(V),ln(S,new cn(Wt)))})),Ee.on(\"challenge completed\",(function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};Wt.completed=!0,Wt.token=e.token,Ut.timerEnd(W),ln(g,new cn(Wt)),ue(Wt,\"config.mode\")!==p&&(Wt.isCompleteReset=!0,dn())})),Ee.on(\"hide enforcement\",hn),Ee.on(A,(function(e){var t=e.width,n=e.height;Wt.width=t,Wt.height=n,ln(k,new cn(Wt))})),Ee.on(T,(function(){Ke(\"Got enforcement loaded\",\"darkblue\"),Wt.enforcementLoaded=!0,On({event:T}),Wt.initialSetupCompleted&&Ee.emit(C,Wt.config)})),Ee.on(\"challenge suppressed\",(function(e){var t=e.token;Wt.isActive=!1,Wt.suppressed=!0,jn({token:t}),Ut.setSuppressed(),Ut.timerEnd(V),ln(j,new cn(Wt))})),Ee.on(\"data initial\",On),Ee.on(\"settings fp collected\",On),Ee.on(\"challenge token\",jn),Ee.on(\"challenge window error\",(function(e){var t=e.message,n=e.source,r=e.stack;Ut.logWindowError(\"challenge\",t,n,r)})),Ee.on(R,(function(e){var t=e.event,n=void 0===t?{}:t,r=e.settings,i=void 0===r?{}:r,o=e.observability;Wt.config.settings=i;var a=function(e){return ue(e,\"observability\",{})}(Wt.config.settings);Ut.setup(a,Wt.config.mode);var c=ue(Wt,\"config.apiLoadTime\");c&&Ut.apiLoadTimerSetup($,c),On({event:n,observability:o}),fn()})),Ee.on(\"challenge fail number limit reached\",(function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};Wt.isActive=!1,Wt.isHidden=!0,Wt.token=e.token,ln(h,new cn(Wt),e)})),Ee.on(\"error\",(function(e){var t=qt({source:null},e.error);Wt.error=t,Ut.logError(t),ln(x,new cn(Wt)),hn()})),Ee.on(\"warning\",(function(e){var t=qt({source:null},e.warning);Wt.warning=t,Ut.logError(t),ln(E,new cn(Wt))})),Ee.on(\"data_request\",(function(e){e.sdk&&(Wt.requested=e,ln(_,new cn(Wt)))})),Ee.on(K,On),Ee.on(F,(function(e){var t=e.action,n=e.timerId,r=e.subTimerId,i=e.time,o=e.info,a=\"\".concat(r?\"subTimer\":\"timer\").concat(\"end\"===t?\"End\":\"Start\"),c=r?[n,r,i,o]:[n,i];Ut[a].apply(Ut,c)})),Ee.on(\"force reset\",(function(){dn()})),Ee.on(\"redraw challenge\",(function(){Wt.element&&(Wt.element.querySelector(\"iframe\").style.display=\"inline\")})),Ke(\"Set up Every emitter\"),xn?(Ke(\"Attempting callback\"),function e(){if(!se(window[xn]))return setTimeout(e,1e3);var t=document.querySelectorAll(\".\".concat(Vt(zt)));return t&&t.length&&Array.prototype.slice.call(t).forEach((function(e){try{e.parentNode.removeChild(e)}catch(e){}})),Ke(\"Cleaned up iframes\"),bn(),window[xn](Sn)}()):(Ke(\"Start setup function\"),bn())}(),arkoseLabsClientApi2c145230=r}();"
  },
  {
    "path": "sidepanel.html",
    "content": "<!DOCTYPE html>\n<html translate=\"no\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <meta content=\"width=device-width,initial-scale=1.0\" name=\"viewport\" />\n    <title>ChatHub</title>\n    <script type=\"module\" src=\"./src/app/theme.ts\"></script>\n  </head>\n  <body>\n    <div id=\"app\"></div>\n    <script type=\"module\" src=\"./src/app/sidepanel.tsx\"></script>\n  </body>\n</html>\n"
  },
  {
    "path": "src/app/base.scss",
    "content": "@use 'inter-ui/default' as inter-ui with (\n  $inter-font-display: swap,\n  $inter-font-path: 'inter-ui/Inter (web)'\n);\n@use 'inter-ui/variable' as inter-ui-variable with (\n  $inter-font-display: swap,\n  $inter-font-path: 'inter-ui/Inter (web)'\n);\n@include inter-ui.weight-400-normal;\n@include inter-ui.weight-500-normal;\n@include inter-ui.weight-600-normal;\n@include inter-ui.weight-700-normal;\n@include inter-ui-variable.normal;\n\n@tailwind base;\n@tailwind components;\n@tailwind utilities;\n\nhtml,\nbody {\n  font-family: 'Inter', 'system-ui';\n}\n\n@supports (font-variation-settings: normal) {\n  html,\n  body {\n    font-family: 'Inter var', 'system-ui';\n  }\n}\n\nbody {\n  font-size: 100%;\n}\n\n:focus-visible {\n  outline: none;\n}\n\n@mixin light-theme {\n  color-scheme: light;\n  --color-primary-blue: 73 135 252; // #4987FC\n  --color-secondary: 242 242 242; // #F2F2F2\n  --color-primary-purple: 103 86 189; // #6756BD\n  --primary-background: 255 255 255; // #FFFFFF\n  --primary-text: 48 48 48; // #303030\n  --secondary-text: 128 128 128; // #808080\n  --light-text: 190 190 190; // #BEBEBE\n  --primary-border: 237 237 237; // #EDEDED\n}\n\n@mixin dark-theme {\n  color-scheme: dark;\n  --color-primary-blue: 50 104 206; // #3268CE\n  --color-secondary: 46 46 46; // #2E2E2E\n  --color-primary-purple: 57 41 141; // #39298D\n  --primary-background: 25 25 25; // #191919\n  --primary-text: 223 223 223; // #DFDFDF\n  --secondary-text: 127 127 127; // #7F7F7F\n  --light-text: 79 79 79; // #4F4F4F\n  --primary-border: 53 53 53; // #353535\n}\n\n@layer base {\n  :root {\n    opacity: 0.88;\n  }\n}\n\n:root.light {\n  @include light-theme;\n  @import 'highlight.js/scss/github.scss';\n}\n\n:root.dark {\n  @include dark-theme;\n  @import 'highlight.js/scss/github-dark.scss';\n}\n"
  },
  {
    "path": "src/app/bots/abstract-bot.ts",
    "content": "import { Sentry } from '~services/sentry'\nimport { ChatError, ErrorCode } from '~utils/errors'\nimport { streamAsyncIterable } from '~utils/stream-async-iterable'\n\nexport type AnwserPayload = {\n  text: string\n}\n\nexport type Event =\n  | {\n      type: 'UPDATE_ANSWER'\n      data: AnwserPayload\n    }\n  | {\n      type: 'DONE'\n    }\n  | {\n      type: 'ERROR'\n      error: ChatError\n    }\n\nexport interface MessageParams {\n  prompt: string\n  rawUserInput?: string\n  image?: File\n  signal?: AbortSignal\n}\n\nexport interface SendMessageParams extends MessageParams {\n  onEvent: (event: Event) => void\n}\n\nexport abstract class AbstractBot {\n  public async sendMessage(params: MessageParams) {\n    return this.doSendMessageGenerator(params)\n  }\n\n  protected async *doSendMessageGenerator(params: MessageParams) {\n    const wrapError = (err: unknown) => {\n      Sentry.captureException(err)\n      if (err instanceof ChatError) {\n        return err\n      }\n      if (!params.signal?.aborted) {\n        // ignore user abort exception\n        return new ChatError((err as Error).message, ErrorCode.UNKOWN_ERROR)\n      }\n    }\n    const stream = new ReadableStream<AnwserPayload>({\n      start: (controller) => {\n        this.doSendMessage({\n          prompt: params.prompt,\n          rawUserInput: params.rawUserInput,\n          image: params.image,\n          signal: params.signal,\n          onEvent(event) {\n            if (event.type === 'UPDATE_ANSWER') {\n              controller.enqueue(event.data)\n            } else if (event.type === 'DONE') {\n              controller.close()\n            } else if (event.type === 'ERROR') {\n              const error = wrapError(event.error)\n              if (error) {\n                controller.error(error)\n              }\n            }\n          },\n        }).catch((err) => {\n          const error = wrapError(err)\n          if (error) {\n            controller.error(error)\n          }\n        })\n      },\n    })\n    yield* streamAsyncIterable(stream)\n  }\n\n  get name(): string | undefined {\n    return undefined\n  }\n\n  get supportsImageInput() {\n    return false\n  }\n\n  abstract doSendMessage(params: SendMessageParams): Promise<void>\n  abstract resetConversation(): void\n}\n\nclass DummyBot extends AbstractBot {\n  async doSendMessage(_params: SendMessageParams) {\n    // dummy\n  }\n  resetConversation() {\n    // dummy\n  }\n  get name() {\n    return ''\n  }\n}\n\nexport abstract class AsyncAbstractBot extends AbstractBot {\n  #bot: AbstractBot\n  #initializeError?: Error\n\n  constructor() {\n    super()\n    this.#bot = new DummyBot()\n    this.initializeBot()\n      .then((bot) => {\n        this.#bot = bot\n      })\n      .catch((err) => {\n        this.#initializeError = err\n      })\n  }\n\n  abstract initializeBot(): Promise<AbstractBot>\n\n  doSendMessage(params: SendMessageParams) {\n    if (this.#bot instanceof DummyBot && this.#initializeError) {\n      throw this.#initializeError\n    }\n    return this.#bot.doSendMessage(params)\n  }\n\n  resetConversation() {\n    return this.#bot.resetConversation()\n  }\n\n  get name() {\n    return this.#bot.name\n  }\n\n  get supportsImageInput() {\n    return this.#bot.supportsImageInput\n  }\n}\n"
  },
  {
    "path": "src/app/bots/baichuan/api.ts",
    "content": "import { ofetch } from 'ofetch'\nimport { customAlphabet } from 'nanoid'\nimport { ChatError, ErrorCode } from '~utils/errors'\n\ninterface UserInfo {\n  id: number\n}\n\nexport async function getUserInfo(): Promise<UserInfo> {\n  const resp = await ofetch<{ data?: UserInfo; code: number; msg: string }>(\n    'https://www.baichuan-ai.com/api/user/user-info',\n    { method: 'POST' },\n  )\n  if (resp.code === 401) {\n    throw new ChatError('请先登录百川账号', ErrorCode.BAICHUAN_WEB_UNAUTHORIZED)\n  }\n  if (resp.code !== 200) {\n    throw new Error(`Error: ${resp.code} ${resp.msg}`)\n  }\n  return resp.data!\n}\n\nconst nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz0123456789')\n\nfunction randomString(length: number) {\n  return nanoid(length)\n}\n\nexport function generateSessionId() {\n  return 'p' + randomString(10)\n}\n\nexport function generateMessageId() {\n  return 'U' + randomString(14)\n}\n"
  },
  {
    "path": "src/app/bots/baichuan/index.ts",
    "content": "import { AbstractBot, SendMessageParams } from '../abstract-bot'\nimport { requestHostPermission } from '~app/utils/permissions'\nimport { ChatError, ErrorCode } from '~utils/errors'\nimport { uuid } from '~utils'\nimport { generateMessageId, generateSessionId, getUserInfo } from './api'\nimport { streamAsyncIterable } from '~utils/stream-async-iterable'\n\ninterface Message {\n  id: string\n  createdAt: number\n  data: string\n  from: 0 | 1 // human | bot\n}\n\ninterface ConversationContext {\n  conversationId: string\n  historyMessages: Message[]\n  userId: number\n  lastMessageId?: string\n}\n\nexport class BaichuanWebBot extends AbstractBot {\n  private conversationContext?: ConversationContext\n\n  async doSendMessage(params: SendMessageParams) {\n    if (!(await requestHostPermission('https://*.baichuan-ai.com/'))) {\n      throw new ChatError('Missing baichuan-ai.com permission', ErrorCode.MISSING_HOST_PERMISSION)\n    }\n\n    if (!this.conversationContext) {\n      const conversationId = generateSessionId()\n      const userInfo = await getUserInfo()\n      this.conversationContext = { conversationId, historyMessages: [], userId: userInfo.id }\n    }\n\n    const { conversationId, lastMessageId, historyMessages, userId } = this.conversationContext\n\n    const message: Message = {\n      id: generateMessageId(),\n      createdAt: Date.now(),\n      data: params.prompt,\n      from: 0,\n    }\n\n    const resp = await fetch('https://www.baichuan-ai.com/api/chat/v1/chat', {\n      method: 'POST',\n      signal: params.signal,\n      headers: {\n        'Content-Type': 'application/json',\n      },\n      body: JSON.stringify({\n        assistant: {},\n        assistant_info: {},\n        retry: 3,\n        type: \"input\",\n        stream: true,\n        request_id: uuid(),\n        app_info: { id: 10001, name: 'baichuan_web' },\n        user_info: { id: userId, status: 1 },\n        prompt: {\n          id: message.id,\n          data: message.data,\n          from: message.from,\n          parent_id: lastMessageId || 0,\n          created_at: message.createdAt,\n          attachments: []\n        },\n        session_info: { id: conversationId, name: '新的对话', created_at: Date.now() },\n        parameters: {\n          repetition_penalty: -1,\n          temperature: -1,\n          top_k: -1,\n          top_p: -1,\n          max_new_tokens: -1,\n          do_sample: -1,\n          regenerate: 0,\n          wse:true\n        },\n        history: historyMessages,\n      }),\n    })\n\n    const decoder = new TextDecoder()\n    let result = ''\n    let answerMessageId: string | undefined\n\n    for await (const uint8Array of streamAsyncIterable(resp.body!)) {\n      const str = decoder.decode(uint8Array)\n      console.debug('baichuan stream', str)\n      const lines = str.split('\\n')\n      for (const line of lines) {\n        if (!line) {\n          continue\n        }\n        const data = JSON.parse(line)\n        if (!data.answer) {\n          continue\n        }\n        answerMessageId = data.answer.id\n        const text = data.answer.data\n        if (text) {\n          result += text\n          params.onEvent({ type: 'UPDATE_ANSWER', data: { text: result } })\n        }\n      }\n    }\n\n    this.conversationContext.historyMessages.push(message)\n    if (answerMessageId) {\n      this.conversationContext.lastMessageId = answerMessageId\n      if (result) {\n        this.conversationContext.historyMessages.push({\n          id: answerMessageId,\n          data: result,\n          createdAt: Date.now(),\n          from: 1,\n        })\n      }\n    }\n\n    params.onEvent({ type: 'DONE' })\n  }\n\n  resetConversation() {\n    this.conversationContext = undefined\n  }\n\n  get name() {\n    return '百川大模型'\n  }\n}\n"
  },
  {
    "path": "src/app/bots/bard/api.ts",
    "content": "import { ofetch } from 'ofetch'\nimport { ChatError, ErrorCode } from '~utils/errors'\n\nfunction extractFromHTML(variableName: string, html: string) {\n  const regex = new RegExp(`\"${variableName}\":\"([^\"]+)\"`)\n  const match = regex.exec(html)\n  return match?.[1]\n}\n\nexport async function fetchRequestParams() {\n  const html = await ofetch('https://bard.google.com/', { responseType: 'text' })\n\n  const atValue = extractFromHTML('SNlM0e', html)\n  const blValue = extractFromHTML('cfb2h', html)\n\n  if (!atValue) {\n    throw new ChatError('There is no logged-in Google account in this browser', ErrorCode.BARD_UNAUTHORIZED)\n  }\n\n  return { atValue, blValue }\n}\n\nexport function parseBardResponse(resp: string) {\n  const data = JSON.parse(resp.split('\\n')[3])\n  const payload = JSON.parse(data[0][2])\n  if (!payload) {\n    throw new ChatError('Failed to load bard response', ErrorCode.BARD_EMPTY_RESPONSE)\n  }\n  console.debug('bard response payload', payload)\n\n  let text = payload[4][0][1][0] as string\n\n  const images = payload[4][0][4] || []\n  for (const image of images) {\n    const [media, source, placeholder] = image\n    text = text.replace(placeholder, `[![${media[4]}](${media[0][0]})](${source[0][0]})`)\n  }\n\n  return {\n    text,\n    ids: [...payload[1], payload[4][0][0]] as [string, string, string],\n  }\n}\n"
  },
  {
    "path": "src/app/bots/bard/index.ts",
    "content": "import { ofetch } from 'ofetch'\nimport { AbstractBot, SendMessageParams } from '../abstract-bot'\nimport { fetchRequestParams, parseBardResponse } from './api'\n\nfunction generateReqId() {\n  return Math.floor(Math.random() * 900000) + 100000\n}\n\ninterface ConversationContext {\n  requestParams: Awaited<ReturnType<typeof fetchRequestParams>>\n  contextIds: [string, string, string]\n}\n\nexport class BardBot extends AbstractBot {\n  private conversationContext?: ConversationContext\n\n  async doSendMessage(params: SendMessageParams) {\n    if (!this.conversationContext) {\n      this.conversationContext = {\n        requestParams: await fetchRequestParams(),\n        contextIds: ['', '', ''],\n      }\n    }\n    const { requestParams, contextIds } = this.conversationContext\n\n    let imageUrl: string | undefined\n    if (params.image) {\n      imageUrl = await this.uploadImage(params.image)\n    }\n\n    const payload = [\n      null,\n      JSON.stringify([\n        [params.prompt, 0, null, imageUrl ? [[[imageUrl, 1], params.image!.name]] : []],\n        null,\n        contextIds,\n      ]),\n    ]\n\n    const resp = await ofetch(\n      'https://bard.google.com/_/BardChatUi/data/assistant.lamda.BardFrontendService/StreamGenerate',\n      {\n        method: 'POST',\n        signal: params.signal,\n        query: {\n          bl: requestParams.blValue,\n          _reqid: generateReqId(),\n          rt: 'c',\n        },\n        body: new URLSearchParams({\n          at: requestParams.atValue!,\n          'f.req': JSON.stringify(payload),\n        }),\n        parseResponse: (txt) => txt,\n      },\n    )\n    const { text, ids } = parseBardResponse(resp)\n    this.conversationContext.contextIds = ids\n    params.onEvent({\n      type: 'UPDATE_ANSWER',\n      data: { text },\n    })\n    params.onEvent({ type: 'DONE' })\n  }\n\n  resetConversation() {\n    this.conversationContext = undefined\n  }\n\n  get supportsImageInput() {\n    return true\n  }\n\n  private async uploadImage(image: File) {\n    const headers = {\n      'content-type': 'application/x-www-form-urlencoded;charset=UTF-8',\n      'push-id': 'feeds/mcudyrk2a4khkz',\n      'x-goog-upload-header-content-length': image.size.toString(),\n      'x-goog-upload-protocol': 'resumable',\n      'x-tenant-id': 'bard-storage',\n    }\n    const resp = await ofetch.raw('https://content-push.googleapis.com/upload/', {\n      method: 'POST',\n      headers: {\n        ...headers,\n        'x-goog-upload-command': 'start',\n      },\n      body: new URLSearchParams({ [`File name: ${image.name}`]: '' }),\n    })\n    const uploadUrl = resp.headers.get('x-goog-upload-url')\n    console.debug('Bard upload url', uploadUrl)\n    if (!uploadUrl) {\n      throw new Error('Failed to upload image')\n    }\n    const uploadResult = await ofetch(uploadUrl, {\n      method: 'POST',\n      headers: {\n        ...headers,\n        'x-goog-upload-command': 'upload, finalize',\n        'x-goog-upload-offset': '0',\n      },\n      body: image,\n    })\n    return uploadResult as string\n  }\n}\n"
  },
  {
    "path": "src/app/bots/bing/api.ts",
    "content": "import { random } from 'lodash-es'\nimport { FetchError, FetchResponse, ofetch } from 'ofetch'\nimport { uuid } from '~utils'\nimport { ChatError, ErrorCode } from '~utils/errors'\nimport { ConversationResponse } from './types'\n\n// https://github.com/acheong08/EdgeGPT/blob/master/src/EdgeGPT.py#L32\nfunction randomIP() {\n  return `13.${random(104, 107)}.${random(0, 255)}.${random(0, 255)}`\n}\n\nconst API_ENDPOINT = 'https://www.bing.com/turing/conversation/create'\n\nexport async function createConversation(): Promise<ConversationResponse> {\n  const headers = {\n    'x-ms-client-request-id': uuid(),\n    'x-ms-useragent': 'azsdk-js-api-client-factory/1.0.0-beta.1 core-rest-pipeline/1.10.3 OS/macOS',\n  }\n\n  let rawResponse: FetchResponse<ConversationResponse>\n  try {\n    rawResponse = await ofetch.raw<ConversationResponse>(API_ENDPOINT, { headers, redirect: 'error' })\n    if (!rawResponse._data?.result) {\n      throw new Error('Invalid response')\n    }\n  } catch (err) {\n    console.error('retry bing create', err)\n    rawResponse = await ofetch.raw<ConversationResponse>(API_ENDPOINT, {\n      headers: { ...headers, 'x-forwarded-for': randomIP() },\n      redirect: 'error',\n    })\n    if (!rawResponse._data) {\n      throw new FetchError(`Failed to fetch (${API_ENDPOINT})`)\n    }\n  }\n\n  const data = rawResponse._data\n\n  if (data.result.value !== 'Success') {\n    const message = `${data.result.value}: ${data.result.message}`\n    if (data.result.value === 'UnauthorizedRequest') {\n      throw new ChatError(message, ErrorCode.BING_UNAUTHORIZED)\n    }\n    throw new Error(message)\n  }\n\n  const conversationSignature = rawResponse.headers.get('x-sydney-conversationsignature')!\n  const encryptedConversationSignature = rawResponse.headers.get('x-sydney-encryptedconversationsignature') || undefined\n\n  data.conversationSignature = data.conversationSignature || conversationSignature\n  data.encryptedConversationSignature = encryptedConversationSignature\n\n  return data\n}\n"
  },
  {
    "path": "src/app/bots/bing/index.ts",
    "content": "import { ofetch } from 'ofetch'\nimport WebSocketAsPromised from 'websocket-as-promised'\nimport { requestHostPermission } from '~app/utils/permissions'\nimport { BingConversationStyle, getUserConfig } from '~services/user-config'\nimport { uuid } from '~utils'\nimport { ChatError, ErrorCode } from '~utils/errors'\nimport { AbstractBot, SendMessageParams } from '../abstract-bot'\nimport { createConversation } from './api'\nimport { ChatResponseMessage, ConversationInfo, InvocationEventType } from './types'\nimport { convertMessageToMarkdown, file2base64, websocketUtils } from './utils'\n\nconst OPTIONS_SETS = [\n  'nlu_direct_response_filter',\n  'deepleo',\n  'disable_emoji_spoken_text',\n  'responsible_ai_policy_235',\n  'enablemm',\n  'dv3sugg',\n  'autosave',\n  'glfluxv15',\n  'clgalileo',\n  'clgalileonsr',\n  'mtreasoncls3',\n  'sahararespv2',\n  'gptvprvc',\n  'fluxprod',\n  'revimglnk',\n  'revimgsrc1',\n]\n\nconst SLICE_IDS = [\n  '0712newass0',\n  '0212boptpsc',\n  'plgbd2c',\n  '1113gldcl1s1',\n  '1201reason',\n  '124multi2ts0',\n  'cacdupereccf',\n  'cacmuidarb',\n  'cacfrwebt2cf',\n  'sswebtop2cf',\n]\n\nexport class BingWebBot extends AbstractBot {\n  private conversationContext?: ConversationInfo\n\n  private buildChatRequest(conversation: ConversationInfo, message: string, imageUrl?: string) {\n    const requestId = uuid()\n\n    const optionsSets = [...OPTIONS_SETS]\n    let tone = 'Balanced'\n    if (conversation.conversationStyle === BingConversationStyle.Precise) {\n      optionsSets.push('h3precise')\n      tone = 'Precise'\n    } else if (conversation.conversationStyle === BingConversationStyle.Creative) {\n      optionsSets.push('h3imaginative')\n      tone = 'Creative'\n    }\n\n    return {\n      arguments: [\n        {\n          source: 'cib',\n          optionsSets,\n          allowedMessageTypes: [\n            'Chat',\n            'InternalSearchQuery',\n            'Disengaged',\n            'InternalLoaderMessage',\n            'SemanticSerp',\n            'GenerateContentQuery',\n            'SearchQuery',\n          ],\n          sliceIds: SLICE_IDS,\n          verbosity: 'verbose',\n          scenario: 'SERP',\n          plugins: [],\n          conversationHistoryOptionsSets: ['autosave', 'savemem', 'uprofupd', 'uprofgen'],\n          isStartOfSession: conversation.invocationId === 0,\n          message: {\n            timestamp: new Date().toISOString(),\n            author: 'user',\n            inputMethod: 'Keyboard',\n            text: message,\n            imageUrl,\n            messageType: 'Chat',\n            requestId,\n            messageId: requestId,\n          },\n          requestId,\n          conversationId: conversation.conversationId,\n          conversationSignature: conversation.conversationSignature,\n          participant: { id: conversation.clientId },\n          tone,\n        },\n      ],\n      invocationId: conversation.invocationId.toString(),\n      target: 'chat',\n      type: InvocationEventType.StreamInvocation,\n    }\n  }\n\n  async doSendMessage(params: SendMessageParams) {\n    if (!(await requestHostPermission('wss://*.bing.com/'))) {\n      throw new ChatError('Missing bing.com permission', ErrorCode.MISSING_HOST_PERMISSION)\n    }\n    if (!this.conversationContext) {\n      const [conversation, { bingConversationStyle }] = await Promise.all([createConversation(), getUserConfig()])\n      this.conversationContext = {\n        conversationId: conversation.conversationId,\n        conversationSignature: conversation.conversationSignature,\n        encryptedConversationSignature: conversation.encryptedConversationSignature,\n        clientId: conversation.clientId,\n        invocationId: 0,\n        conversationStyle: bingConversationStyle,\n      }\n    }\n\n    const conversation = this.conversationContext!\n\n    let imageUrl: string | undefined\n    if (params.image) {\n      imageUrl = await this.uploadImage(params.image)\n    }\n\n    const wsp = new WebSocketAsPromised(this.buildWssUrl(conversation.encryptedConversationSignature), {\n      packMessage: websocketUtils.packMessage,\n      unpackMessage: websocketUtils.unpackMessage,\n    })\n\n    let receivedAnswer = false\n\n    wsp.onUnpackedMessage.addListener((events) => {\n      for (const event of events) {\n        console.debug('bing ws event', event)\n        if (JSON.stringify(event) === '{}') {\n          wsp.sendPacked({ type: 6 })\n          wsp.sendPacked(this.buildChatRequest(conversation, params.prompt, imageUrl))\n          conversation.invocationId += 1\n        } else if (event.type === 6) {\n          wsp.sendPacked({ type: 6 })\n        } else if (event.type === 3) {\n          params.onEvent({ type: 'DONE' })\n          wsp.removeAllListeners()\n          wsp.close()\n        } else if (event.type === 1) {\n          const messages = event.arguments[0].messages\n          if (messages) {\n            receivedAnswer = true\n            const text = convertMessageToMarkdown(messages[0])\n            params.onEvent({ type: 'UPDATE_ANSWER', data: { text } })\n          }\n        } else if (event.type === 2) {\n          const messages = event.item.messages as ChatResponseMessage[] | undefined\n          if (!messages) {\n            if (event.item.result.value === 'UnauthorizedRequest') {\n              this.conversationContext = undefined\n              params.onEvent({\n                type: 'ERROR',\n                error: new ChatError('UnauthorizedRequest', ErrorCode.BING_UNAUTHORIZED),\n              })\n              return\n            }\n            const captcha = event.item.result.value === 'CaptchaChallenge'\n            if (captcha) {\n              this.conversationContext = undefined\n            }\n            params.onEvent({\n              type: 'ERROR',\n              error: new ChatError(\n                event.item.result.error || 'Unknown error',\n                captcha ? ErrorCode.BING_CAPTCHA : ErrorCode.UNKOWN_ERROR,\n              ),\n            })\n            return\n          }\n          const limited = messages.some((message) => message.contentOrigin === 'TurnLimiter')\n          if (limited) {\n            params.onEvent({\n              type: 'ERROR',\n              error: new ChatError(\n                'Sorry, you have reached chat turns limit in this conversation.',\n                ErrorCode.CONVERSATION_LIMIT,\n              ),\n            })\n            return\n          }\n          if (!receivedAnswer) {\n            const message = event.item.messages[event.item.firstNewMessageIndex] as ChatResponseMessage\n            if (message) {\n              receivedAnswer = true\n              const text = convertMessageToMarkdown(message)\n              params.onEvent({\n                type: 'UPDATE_ANSWER',\n                data: { text },\n              })\n            }\n          }\n        }\n      }\n    })\n\n    wsp.onClose.addListener(() => {\n      params.onEvent({ type: 'DONE' })\n    })\n\n    params.signal?.addEventListener('abort', () => {\n      wsp.removeAllListeners()\n      wsp.close()\n    })\n\n    try {\n      await wsp.open()\n    } catch (err) {\n      wsp.removeAllListeners()\n      throw new ChatError((err as Error).message, ErrorCode.NETWORK_ERROR)\n    }\n\n    wsp.sendPacked({ protocol: 'json', version: 1 })\n  }\n\n  resetConversation() {\n    this.conversationContext = undefined\n  }\n\n  get supportsImageInput() {\n    return true\n  }\n\n  private async uploadImage(image: File) {\n    const formData = new FormData()\n    formData.append(\n      'knowledgeRequest',\n      JSON.stringify({\n        imageInfo: {},\n        knowledgeRequest: {\n          invokedSkills: ['ImageById'],\n          subscriptionId: 'Bing.Chat.Multimodal',\n          invokedSkillsRequestData: { enableFaceBlur: false },\n          convoData: { convoid: '', convotone: 'Balanced' },\n        },\n      }),\n    )\n    formData.append('imageBase64', await file2base64(image))\n    const resp = await ofetch<{ blobId: string }>('https://www.bing.com/images/kblob', {\n      method: 'POST',\n      body: formData,\n    })\n    if (!resp.blobId) {\n      console.debug('kblob response: ', resp)\n      throw new Error('Failed to upload image')\n    }\n    return `https://www.bing.com/images/blob?bcid=${resp.blobId}`\n  }\n\n  private buildWssUrl(encryptedConversationSignature: string | undefined) {\n    if (!encryptedConversationSignature) {\n      return 'wss://sydney.bing.com/sydney/ChatHub'\n    }\n    return `wss://sydney.bing.com/sydney/ChatHub?sec_access_token=${encodeURIComponent(encryptedConversationSignature)}`\n  }\n}\n"
  },
  {
    "path": "src/app/bots/bing/types.ts",
    "content": "import { BingConversationStyle } from '~services/user-config'\n\nexport interface ConversationResponse {\n  conversationId: string\n  clientId: string\n  conversationSignature: string\n  encryptedConversationSignature?: string\n  result: {\n    value: string\n    message: null\n  }\n}\n\nexport enum InvocationEventType {\n  Invocation = 1,\n  StreamItem = 2,\n  Completion = 3,\n  StreamInvocation = 4,\n  CancelInvocation = 5,\n  Ping = 6,\n  Close = 7,\n}\n\n// https://github.com/bytemate/bingchat-api/blob/main/src/lib.ts\n\nexport interface ConversationInfo {\n  conversationId: string\n  clientId: string\n  conversationSignature: string\n  invocationId: number\n  conversationStyle: BingConversationStyle\n  encryptedConversationSignature?: string\n}\n\nexport interface BingChatResponse {\n  conversationSignature: string\n  conversationId: string\n  clientId: string\n  invocationId: number\n  conversationExpiryTime: Date\n  response: string\n  details: ChatResponseMessage\n}\n\nexport interface ChatResponseMessage {\n  text: string\n  author: string\n  createdAt: Date\n  timestamp: Date\n  messageId: string\n  messageType?: string\n  requestId: string\n  offense: string\n  adaptiveCards: AdaptiveCard[]\n  sourceAttributions: SourceAttribution[]\n  feedback: Feedback\n  contentOrigin: string\n  privacy: null\n  suggestedResponses: SuggestedResponse[]\n}\n\nexport interface AdaptiveCard {\n  type: string\n  version: string\n  body: Body[]\n}\n\nexport interface Body {\n  type: string\n  text: string\n  wrap: boolean\n  size?: string\n}\n\nexport interface Feedback {\n  tag: null\n  updatedOn: null\n  type: string\n}\n\nexport interface SourceAttribution {\n  providerDisplayName: string\n  seeMoreUrl: string\n  searchQuery: string\n}\n\nexport interface SuggestedResponse {\n  text: string\n  author: string\n  createdAt: Date\n  timestamp: Date\n  messageId: string\n  messageType: string\n  offense: string\n  feedback: Feedback\n  contentOrigin: string\n  privacy: null\n}\n\nexport async function generateMarkdown(response: BingChatResponse) {\n  // change `[^Number^]` to markdown link\n  const regex = /\\[\\^(\\d+)\\^\\]/g\n  const markdown = response.details.text.replace(regex, (match, p1) => {\n    const sourceAttribution = response.details.sourceAttributions[Number(p1) - 1]\n    return `[${sourceAttribution.providerDisplayName}](${sourceAttribution.seeMoreUrl})`\n  })\n  return markdown\n}\n"
  },
  {
    "path": "src/app/bots/bing/utils.ts",
    "content": "import { ChatResponseMessage } from './types'\n\nexport function convertMessageToMarkdown(message: ChatResponseMessage): string {\n  if (message.messageType === 'InternalSearchQuery') {\n    return message.text\n  }\n  if (message.messageType === 'InternalLoaderMessage') {\n    return `_${message.text}_`\n  }\n  for (const card of message.adaptiveCards) {\n    for (const block of card.body) {\n      if (block.type === 'TextBlock') {\n        return block.text\n      }\n    }\n  }\n  return ''\n}\n\nconst RecordSeparator = String.fromCharCode(30)\n\nexport const websocketUtils = {\n  packMessage(data: unknown) {\n    return `${JSON.stringify(data)}${RecordSeparator}`\n  },\n  unpackMessage(data: string | ArrayBuffer | Blob) {\n    return data\n      .toString()\n      .split(RecordSeparator)\n      .filter(Boolean)\n      .map((s) => JSON.parse(s))\n  },\n}\n\nexport async function file2base64(file: File, keepHeader = false): Promise<string> {\n  return new Promise((resolve, reject) => {\n    const reader = new FileReader()\n    reader.onload = () => {\n      if (keepHeader) {\n        resolve(reader.result as string)\n      } else {\n        const base64String = (reader.result as string).replace('data:', '').replace(/^.+,/, '')\n        resolve(base64String)\n      }\n    }\n    reader.onerror = reject\n    reader.readAsDataURL(file)\n  })\n}\n"
  },
  {
    "path": "src/app/bots/chatgpt/index.ts",
    "content": "import { ChatGPTMode, getUserConfig } from '~/services/user-config'\nimport * as agent from '~services/agent'\nimport { ChatError, ErrorCode } from '~utils/errors'\nimport { AsyncAbstractBot, MessageParams } from '../abstract-bot'\nimport { ChatGPTApiBot } from '../chatgpt-api'\nimport { ChatGPTAzureApiBot } from '../chatgpt-azure'\nimport { ChatGPTWebBot } from '../chatgpt-webapp'\nimport { PoeWebBot } from '../poe'\nimport { OpenRouterBot } from '../openrouter'\n\nexport class ChatGPTBot extends AsyncAbstractBot {\n  async initializeBot() {\n    const { chatgptMode, ...config } = await getUserConfig()\n    if (chatgptMode === ChatGPTMode.API) {\n      if (!config.openaiApiKey) {\n        throw new ChatError('OpenAI API key not set', ErrorCode.API_KEY_NOT_SET)\n      }\n      return new ChatGPTApiBot({\n        openaiApiKey: config.openaiApiKey,\n        openaiApiHost: config.openaiApiHost,\n        chatgptApiModel: config.chatgptApiModel,\n        chatgptApiTemperature: config.chatgptApiTemperature,\n        chatgptApiSystemMessage: config.chatgptApiSystemMessage,\n      })\n    }\n    if (chatgptMode === ChatGPTMode.Azure) {\n      if (!config.azureOpenAIApiInstanceName || !config.azureOpenAIApiDeploymentName || !config.azureOpenAIApiKey) {\n        throw new Error('Please check your Azure OpenAI API configuration')\n      }\n      return new ChatGPTAzureApiBot({\n        azureOpenAIApiKey: config.azureOpenAIApiKey,\n        azureOpenAIApiDeploymentName: config.azureOpenAIApiDeploymentName,\n        azureOpenAIApiInstanceName: config.azureOpenAIApiInstanceName,\n      })\n    }\n    if (chatgptMode === ChatGPTMode.Poe) {\n      return new PoeWebBot(config.chatgptPoeModelName)\n    }\n    if (chatgptMode === ChatGPTMode.OpenRouter) {\n      if (!config.openrouterApiKey) {\n        throw new ChatError('OpenRouter API key not set', ErrorCode.API_KEY_NOT_SET)\n      }\n      const model = `openai/${config.openrouterOpenAIModel}`\n      return new OpenRouterBot({ apiKey: config.openrouterApiKey, model })\n    }\n    return new ChatGPTWebBot(config.chatgptWebappModelName)\n  }\n\n  async sendMessage(params: MessageParams) {\n    const { chatgptWebAccess } = await getUserConfig()\n    if (chatgptWebAccess) {\n      return agent.execute(params.prompt, (prompt) => this.doSendMessageGenerator({ ...params, prompt }), params.signal)\n    }\n    return this.doSendMessageGenerator(params)\n  }\n}\n"
  },
  {
    "path": "src/app/bots/chatgpt-api/index.ts",
    "content": "import { isArray } from 'lodash-es'\nimport { DEFAULT_CHATGPT_SYSTEM_MESSAGE } from '~app/consts'\nimport { UserConfig } from '~services/user-config'\nimport { ChatError, ErrorCode } from '~utils/errors'\nimport { parseSSEResponse } from '~utils/sse'\nimport { AbstractBot, SendMessageParams } from '../abstract-bot'\nimport { file2base64 } from '../bing/utils'\nimport { ChatMessage } from './types'\n\ninterface ConversationContext {\n  messages: ChatMessage[]\n}\n\nconst CONTEXT_SIZE = 9\n\nexport abstract class AbstractChatGPTApiBot extends AbstractBot {\n  private conversationContext?: ConversationContext\n\n  private buildUserMessage(prompt: string, imageUrl?: string): ChatMessage {\n    if (!imageUrl) {\n      return { role: 'user', content: prompt }\n    }\n    return {\n      role: 'user',\n      content: [\n        { type: 'text', text: prompt },\n        { type: 'image_url', image_url: { url: imageUrl, detail: 'low' } },\n      ],\n    }\n  }\n\n  private buildMessages(prompt: string, imageUrl?: string): ChatMessage[] {\n    const currentDate = new Date().toISOString().split('T')[0]\n    const systemMessage = this.getSystemMessage().replace('{current_date}', currentDate)\n    return [\n      { role: 'system', content: systemMessage },\n      ...this.conversationContext!.messages.slice(-(CONTEXT_SIZE + 1)),\n      this.buildUserMessage(prompt, imageUrl),\n    ]\n  }\n\n  getSystemMessage() {\n    return DEFAULT_CHATGPT_SYSTEM_MESSAGE\n  }\n\n  async doSendMessage(params: SendMessageParams) {\n    if (!this.conversationContext) {\n      this.conversationContext = { messages: [] }\n    }\n\n    let imageUrl: string | undefined\n    if (params.image) {\n      imageUrl = await file2base64(params.image, true)\n    }\n\n    const resp = await this.fetchCompletionApi(this.buildMessages(params.prompt, imageUrl), params.signal)\n\n    // add user message to context only after fetch success\n    this.conversationContext.messages.push(this.buildUserMessage(params.rawUserInput || params.prompt, imageUrl))\n\n    let done = false\n    const result: ChatMessage = { role: 'assistant', content: '' }\n\n    const finish = () => {\n      done = true\n      params.onEvent({ type: 'DONE' })\n      const messages = this.conversationContext!.messages\n      messages.push(result)\n    }\n\n    await parseSSEResponse(resp, (message) => {\n      console.debug('chatgpt sse message', message)\n      if (message === '[DONE]') {\n        finish()\n        return\n      }\n      let data\n      try {\n        data = JSON.parse(message)\n      } catch (err) {\n        console.error(err)\n        return\n      }\n      if (data?.choices?.length) {\n        const delta = data.choices[0].delta\n        if (delta?.content) {\n          result.content += delta.content\n          params.onEvent({\n            type: 'UPDATE_ANSWER',\n            data: { text: result.content },\n          })\n        }\n      }\n    })\n\n    if (!done) {\n      finish()\n    }\n  }\n\n  resetConversation() {\n    this.conversationContext = undefined\n  }\n\n  abstract fetchCompletionApi(messages: ChatMessage[], signal?: AbortSignal): Promise<Response>\n}\n\nexport class ChatGPTApiBot extends AbstractChatGPTApiBot {\n  constructor(\n    private config: Pick<\n      UserConfig,\n      'openaiApiKey' | 'openaiApiHost' | 'chatgptApiModel' | 'chatgptApiTemperature' | 'chatgptApiSystemMessage'\n    >,\n  ) {\n    super()\n  }\n\n  getSystemMessage() {\n    return this.config.chatgptApiSystemMessage || DEFAULT_CHATGPT_SYSTEM_MESSAGE\n  }\n\n  async fetchCompletionApi(messages: ChatMessage[], signal?: AbortSignal) {\n    const { openaiApiKey, openaiApiHost } = this.config\n    const hasImageInput = messages.some(\n      (message) => isArray(message.content) && message.content.some((part) => part.type === 'image_url'),\n    )\n    const model = hasImageInput ? 'gpt-4-vision-preview' : this.getModelName()\n    const resp = await fetch(`${openaiApiHost}/v1/chat/completions`, {\n      method: 'POST',\n      signal,\n      headers: {\n        'Content-Type': 'application/json',\n        Authorization: `Bearer ${openaiApiKey}`,\n      },\n      body: JSON.stringify({\n        model,\n        messages,\n        max_tokens: hasImageInput ? 500 : undefined,\n        stream: true,\n      }),\n    })\n    if (!resp.ok) {\n      const error = await resp.text()\n      if (error.includes('insufficient_quota')) {\n        throw new ChatError('Insufficient ChatGPT API usage quota', ErrorCode.CHATGPT_INSUFFICIENT_QUOTA)\n      }\n    }\n    return resp\n  }\n\n  private getModelName() {\n    const { chatgptApiModel } = this.config\n    if (chatgptApiModel === 'gpt-4-turbo') {\n      return 'gpt-4-1106-preview'\n    }\n    if (chatgptApiModel === 'gpt-3.5-turbo') {\n      return 'gpt-3.5-turbo-1106'\n    }\n    return chatgptApiModel\n  }\n\n  get name() {\n    return `ChatGPT (API/${this.config.chatgptApiModel})`\n  }\n\n  get supportsImageInput() {\n    return true\n  }\n}\n"
  },
  {
    "path": "src/app/bots/chatgpt-api/types.ts",
    "content": "export type ContentPart =\n  | { type: 'text'; text: string }\n  | { type: 'image_url'; image_url: { url: string; detail?: 'low' | 'high' } }\n\nexport type ChatMessage =\n  | {\n      role: 'system' | 'assistant'\n      content: string\n    }\n  | {\n      role: 'user'\n      content: string | ContentPart[]\n    }\n"
  },
  {
    "path": "src/app/bots/chatgpt-azure/index.ts",
    "content": "import { UserConfig } from '~services/user-config'\nimport { AbstractChatGPTApiBot } from '../chatgpt-api'\nimport { ChatMessage } from '../chatgpt-api/types'\n\nexport class ChatGPTAzureApiBot extends AbstractChatGPTApiBot {\n  constructor(\n    private config: Pick<\n      UserConfig,\n      'azureOpenAIApiKey' | 'azureOpenAIApiDeploymentName' | 'azureOpenAIApiInstanceName'\n    >,\n  ) {\n    super()\n  }\n\n  async fetchCompletionApi(messages: ChatMessage[], signal?: AbortSignal) {\n    const endpoint = `https://${this.config.azureOpenAIApiInstanceName}.openai.azure.com/openai/deployments/${this.config.azureOpenAIApiDeploymentName}/chat/completions?api-version=2025-01-01-preview`\n    return fetch(endpoint, {\n      method: 'POST',\n      signal,\n      headers: {\n        'Content-Type': 'application/json',\n        'api-key': this.config.azureOpenAIApiKey,\n      },\n      body: JSON.stringify({\n        messages,\n        stream: true,\n      }),\n    })\n  }\n\n  get name() {\n    return `ChatGPT (azure/gpt-3.5)`\n  }\n}\n"
  },
  {
    "path": "src/app/bots/chatgpt-webapp/arkose/generator.js",
    "content": "import Browser from 'webextension-polyfill'\n\nclass ArkoseTokenGenerator {\n  constructor() {\n    this.enforcement = undefined\n    this.pendingPromises = []\n    window.useArkoseSetupEnforcement = this.useArkoseSetupEnforcement.bind(this)\n    this.injectScript()\n  }\n\n  useArkoseSetupEnforcement(enforcement) {\n    this.enforcement = enforcement\n    enforcement.setConfig({\n      onCompleted: (r) => {\n        console.debug('enforcement.onCompleted', r)\n        this.pendingPromises.forEach((promise) => {\n          promise.resolve(r.token)\n        })\n        this.pendingPromises = []\n      },\n      onReady: () => {\n        console.debug('enforcement.onReady')\n      },\n      onError: (r) => {\n        console.debug('enforcement.onError', r)\n        this.pendingPromises.forEach((promise) => {\n          promise.reject(new Error('Error generating arkose token'))\n        })\n      },\n      onFailed: (r) => {\n        console.debug('enforcement.onFailed', r)\n        this.pendingPromises.forEach((promise) => {\n          promise.reject(new Error('Failed to generate arkose token'))\n        })\n      },\n    })\n  }\n\n  injectScript() {\n    const script = document.createElement('script')\n    script.src = Browser.runtime.getURL('/js/v2/35536E1E-65B4-4D96-9D97-6ADB7EFF8147/api.js')\n    script.async = true\n    script.defer = true\n    script.setAttribute('data-callback', 'useArkoseSetupEnforcement')\n    document.body.appendChild(script)\n  }\n\n  async generate() {\n    if (!this.enforcement) {\n      return\n    }\n    return new Promise((resolve, reject) => {\n      this.pendingPromises = [{ resolve, reject }] // store only one promise for now.\n      this.enforcement.run()\n    })\n  }\n}\n\nexport const arkoseTokenGenerator = new ArkoseTokenGenerator()\n"
  },
  {
    "path": "src/app/bots/chatgpt-webapp/arkose/index.ts",
    "content": "import { arkoseTokenGenerator } from './generator'\nimport { fetchArkoseToken } from './server'\n\nexport async function getArkoseToken() {\n  const token = await arkoseTokenGenerator.generate()\n  if (token) {\n    return token\n  }\n  return fetchArkoseToken()\n}\n"
  },
  {
    "path": "src/app/bots/chatgpt-webapp/arkose/server.ts",
    "content": "import { ofetch } from 'ofetch'\n\nexport async function fetchArkoseToken(): Promise<string | undefined> {\n  try {\n    const resp = await ofetch('https://chathub.gg/api/arkose')\n    return resp.token\n  } catch (err) {\n    console.error(err)\n    return undefined\n  }\n}\n"
  },
  {
    "path": "src/app/bots/chatgpt-webapp/client.ts",
    "content": "import { ofetch } from 'ofetch'\nimport { RequestInitSubset } from '~types/messaging'\nimport { ChatError, ErrorCode } from '~utils/errors'\nimport { Requester, globalFetchRequester, proxyFetchRequester } from './requesters'\n\nclass ChatGPTClient {\n  requester: Requester\n\n  constructor() {\n    this.requester = globalFetchRequester\n    proxyFetchRequester.findExistingProxyTab().then((tab) => {\n      if (tab) {\n        this.switchRequester(proxyFetchRequester)\n      }\n    })\n  }\n\n  switchRequester(newRequester: Requester) {\n    console.debug('client switchRequester', newRequester)\n    this.requester = newRequester\n  }\n\n  async fetch(url: string, options?: RequestInitSubset): Promise<Response> {\n    return this.requester.fetch(url, options)\n  }\n\n  async getAccessToken(): Promise<string> {\n    const resp = await this.fetch('https://chat.openai.com/api/auth/session')\n    if (resp.status === 403) {\n      throw new ChatError('Please pass Cloudflare check', ErrorCode.CHATGPT_CLOUDFLARE)\n    }\n    const data = await resp.json().catch(() => ({}))\n    if (!data.accessToken) {\n      throw new ChatError('There is no logged-in ChatGPT account in this browser.', ErrorCode.CHATGPT_UNAUTHORIZED)\n    }\n    return data.accessToken\n  }\n\n  private async requestBackendAPIWithToken(token: string, method: 'GET' | 'POST', path: string, data?: unknown) {\n    return this.fetch(`https://chat.openai.com/backend-api${path}`, {\n      method,\n      headers: {\n        'Content-Type': 'application/json',\n        Authorization: `Bearer ${token}`,\n      },\n      body: data === undefined ? undefined : JSON.stringify(data),\n    })\n  }\n\n  async getModels(token: string): Promise<{ slug: string; title: string; description: string; max_tokens: number }[]> {\n    const resp = await this.requestBackendAPIWithToken(token, 'GET', '/models').then((r) => r.json())\n    return resp.models\n  }\n\n  async generateChatTitle(token: string, conversationId: string, messageId: string) {\n    await this.requestBackendAPIWithToken(token, 'POST', `/conversation/gen_title/${conversationId}`, {\n      message_id: messageId,\n    })\n  }\n\n  async createFileUpload(token: string, file: File): Promise<{ fileId: string; uploadUrl: string }> {\n    const resp = await this.requestBackendAPIWithToken(token, 'POST', '/files', {\n      file_name: file.name,\n      file_size: file.size,\n      use_case: 'multimodal',\n    })\n    const data = await resp.json()\n    if (data.status !== 'success') {\n      throw new Error('Failed to init ChatGPT file upload')\n    }\n    return {\n      fileId: data.file_id,\n      uploadUrl: data.upload_url,\n    }\n  }\n\n  async completeFileUpload(token: string, fileId: string) {\n    await this.requestBackendAPIWithToken(token, 'POST', `/files/${fileId}/uploaded`, {})\n  }\n\n  async uploadFile(token: string, file: File) {\n    const { fileId, uploadUrl } = await this.createFileUpload(token, file)\n    await ofetch(uploadUrl, {\n      method: 'PUT',\n      body: file,\n      headers: {\n        'x-ms-blob-type': 'BlockBlob',\n        'x-ms-version': '2020-04-08',\n        'Content-Type': file.type,\n      },\n    })\n    await this.completeFileUpload(token, fileId)\n    return fileId\n  }\n\n  // Switch to proxy mode, or refresh the proxy tab\n  async fixAuthState() {\n    if (this.requester === proxyFetchRequester) {\n      await proxyFetchRequester.refreshProxyTab()\n    } else {\n      await proxyFetchRequester.getProxyTab()\n      this.switchRequester(proxyFetchRequester)\n    }\n  }\n}\n\nexport const chatGPTClient = new ChatGPTClient()\n"
  },
  {
    "path": "src/app/bots/chatgpt-webapp/index.ts",
    "content": "import { get as getPath } from 'lodash-es'\nimport { v4 as uuidv4 } from 'uuid'\nimport { getImageSize } from '~app/utils/image-size'\nimport { ChatGPTWebModel } from '~services/user-config'\nimport { ChatError, ErrorCode } from '~utils/errors'\nimport { parseSSEResponse } from '~utils/sse'\nimport { AbstractBot, SendMessageParams } from '../abstract-bot'\nimport { getArkoseToken } from './arkose'\nimport { chatGPTClient } from './client'\nimport { ImageContent, ResponseContent, ResponsePayload } from './types'\n\nfunction removeCitations(text: string) {\n  return text.replaceAll(/\\u3010\\d+\\u2020source\\u3011/g, '')\n}\n\nfunction parseResponseContent(content: ResponseContent): { text?: string; image?: ImageContent } {\n  if (content.content_type === 'text') {\n    return { text: removeCitations(content.parts[0]) }\n  }\n  if (content.content_type === 'code') {\n    return { text: '_' + content.text + '_' }\n  }\n  if (content.content_type === 'multimodal_text') {\n    for (const part of content.parts) {\n      if (part.content_type === 'image_asset_pointer') {\n        return { image: part }\n      }\n    }\n  }\n  return {}\n}\n\ninterface ConversationContext {\n  conversationId: string\n  lastMessageId: string\n}\n\nexport class ChatGPTWebBot extends AbstractBot {\n  private accessToken?: string\n  private conversationContext?: ConversationContext\n\n  constructor(public model: ChatGPTWebModel) {\n    super()\n  }\n\n  private async getModelName(): Promise<string> {\n    if (this.model === ChatGPTWebModel['GPT-4']) {\n      return 'gpt-4'\n    }\n    return 'text-davinci-002-render-sha'\n  }\n\n  private async uploadImage(image: File): Promise<ImageContent> {\n    const fileId = await chatGPTClient.uploadFile(this.accessToken!, image)\n    const size = await getImageSize(image)\n    return {\n      asset_pointer: `file-service://${fileId}`,\n      width: size.width,\n      height: size.height,\n      size_bytes: image.size,\n    }\n  }\n\n  private buildMessage(prompt: string, image?: ImageContent) {\n    return {\n      id: uuidv4(),\n      author: { role: 'user' },\n      content: image\n        ? { content_type: 'multimodal_text', parts: [image, prompt] }\n        : { content_type: 'text', parts: [prompt] },\n    }\n  }\n\n  async doSendMessage(params: SendMessageParams) {\n    if (!this.accessToken) {\n      this.accessToken = await chatGPTClient.getAccessToken()\n    }\n\n    const modelName = await this.getModelName()\n    console.debug('Using model:', modelName)\n\n    const arkoseToken = await getArkoseToken()\n\n    let image: ImageContent | undefined = undefined\n    if (params.image) {\n      image = await this.uploadImage(params.image)\n    }\n\n    const resp = await chatGPTClient.fetch('https://chat.openai.com/backend-api/conversation', {\n      method: 'POST',\n      signal: params.signal,\n      headers: {\n        'Content-Type': 'application/json',\n        Authorization: `Bearer ${this.accessToken}`,\n      },\n      body: JSON.stringify({\n        action: 'next',\n        messages: [this.buildMessage(params.prompt, image)],\n        model: modelName,\n        conversation_id: this.conversationContext?.conversationId || undefined,\n        parent_message_id: this.conversationContext?.lastMessageId || uuidv4(),\n        arkose_token: arkoseToken,\n        conversation_mode: { kind: 'primary_assistant' },\n      }),\n    })\n\n    const isFirstMessage = !this.conversationContext\n\n    await parseSSEResponse(resp, (message) => {\n      console.debug('chatgpt sse message', message)\n      if (message === '[DONE]') {\n        params.onEvent({ type: 'DONE' })\n        return\n      }\n      let parsed: ResponsePayload | { message: null; error: string }\n      try {\n        parsed = JSON.parse(message)\n      } catch (err) {\n        console.error(err)\n        return\n      }\n      if (!parsed.message && parsed.error) {\n        params.onEvent({\n          type: 'ERROR',\n          error: new ChatError(parsed.error, ErrorCode.UNKOWN_ERROR),\n        })\n        return\n      }\n\n      const payload = parsed as ResponsePayload\n\n      const role = getPath(payload, 'message.author.role')\n      if (role !== 'assistant' && role !== 'tool') {\n        return\n      }\n\n      const content = payload.message?.content as ResponseContent | undefined\n      if (!content) {\n        return\n      }\n\n      const { text } = parseResponseContent(content)\n      if (text) {\n        this.conversationContext = { conversationId: payload.conversation_id, lastMessageId: payload.message.id }\n        params.onEvent({ type: 'UPDATE_ANSWER', data: { text } })\n      }\n    }).catch((err: Error) => {\n      if (err.message.includes('token_expired')) {\n        throw new ChatError(err.message, ErrorCode.CHATGPT_AUTH)\n      }\n      throw err\n    })\n\n    // auto generate title on first response\n    if (isFirstMessage && this.conversationContext) {\n      const c = this.conversationContext\n      chatGPTClient.generateChatTitle(this.accessToken, c.conversationId, c.lastMessageId)\n    }\n  }\n\n  resetConversation() {\n    this.conversationContext = undefined\n  }\n\n  get name() {\n    return `ChatGPT (webapp/${this.model})`\n  }\n\n  get supportsImageInput() {\n    return true\n  }\n}\n"
  },
  {
    "path": "src/app/bots/chatgpt-webapp/requesters.ts",
    "content": "import Browser, { Runtime } from 'webextension-polyfill'\nimport { CHATGPT_HOME_URL } from '~app/consts'\nimport { proxyFetch } from '~services/proxy-fetch'\nimport { RequestInitSubset } from '~types/messaging'\n\nexport interface Requester {\n  fetch(url: string, options?: RequestInitSubset): Promise<Response>\n}\n\nclass GlobalFetchRequester implements Requester {\n  fetch(url: string, options?: RequestInitSubset) {\n    return fetch(url, options)\n  }\n}\n\nclass ProxyFetchRequester implements Requester {\n  async findExistingProxyTab() {\n    const tabs = await Browser.tabs.query({ pinned: true })\n    const results: (string | undefined)[] = await Promise.all(\n      tabs.map(async (tab) => {\n        if (tab.url) {\n          return tab.url\n        }\n        return Browser.tabs.sendMessage(tab.id!, 'url').catch(() => undefined)\n      }),\n    )\n    for (let i = 0; i < results.length; i++) {\n      if (results[i]?.startsWith('https://chat.openai.com')) {\n        return tabs[i]\n      }\n    }\n  }\n\n  waitForProxyTabReady(): Promise<Browser.Tabs.Tab> {\n    return new Promise((resolve, reject) => {\n      const listener = async function (message: any, sender: Runtime.MessageSender) {\n        if (message.event === 'PROXY_TAB_READY') {\n          console.debug('new proxy tab ready')\n          Browser.runtime.onMessage.removeListener(listener)\n          clearTimeout(timer)\n          resolve(sender.tab!)\n          return true\n        }\n      }\n      const timer = setTimeout(() => {\n        Browser.runtime.onMessage.removeListener(listener)\n        reject(new Error('Timeout waiting for ChatGPT tab'))\n      }, 10 * 1000)\n\n      Browser.runtime.onMessage.addListener(listener)\n    })\n  }\n\n  async createProxyTab() {\n    const readyPromise = this.waitForProxyTabReady()\n    Browser.tabs.create({ url: CHATGPT_HOME_URL, pinned: true })\n    return readyPromise\n  }\n\n  async getProxyTab() {\n    let tab = await this.findExistingProxyTab()\n    if (!tab) {\n      tab = await this.createProxyTab()\n    }\n    return tab\n  }\n\n  async refreshProxyTab() {\n    const tab = await this.findExistingProxyTab()\n    if (!tab) {\n      await this.createProxyTab()\n      return\n    }\n    const readyPromise = this.waitForProxyTabReady()\n    Browser.tabs.reload(tab.id!)\n    return readyPromise\n  }\n\n  async fetch(url: string, options?: RequestInitSubset) {\n    const tab = await this.getProxyTab()\n    const resp = await proxyFetch(tab.id!, url, options)\n    if (resp.status === 403) {\n      await this.refreshProxyTab()\n      return proxyFetch(tab.id!, url, options)\n    }\n    return resp\n  }\n}\n\nexport const globalFetchRequester = new GlobalFetchRequester()\nexport const proxyFetchRequester = new ProxyFetchRequester()\n"
  },
  {
    "path": "src/app/bots/chatgpt-webapp/types.ts",
    "content": "export type ResponsePayload = {\n  conversation_id: string\n  message: {\n    id: string\n    author: { role: 'assistant' | 'tool' | 'user' }\n    content: ResponseContent\n    recipient: 'all' | string\n  }\n  error: null\n}\n\nexport type ResponseContent =\n  | {\n      content_type: 'text'\n      parts: string[]\n    }\n  | {\n      content_type: 'code'\n      text: string\n    }\n  | {\n      content_type: 'tether_browsing_display'\n      result: string\n    }\n  | {\n      content_type: 'multimodal_text'\n      parts: ({ content_type: 'image_asset_pointer' } & ImageContent)[]\n    }\n\nexport type ResponseCitation = {\n  start_ix: number\n  end_ix: number\n  metadata: {\n    title: string\n    url: string\n    text: string\n  }\n}\n\nexport interface ImageContent {\n  asset_pointer: string // file-service://file-5JUtfsLd8O0GEZzjtFmWvZr8\n  size_bytes: number\n  width: number\n  height: number\n}\n"
  },
  {
    "path": "src/app/bots/claude/index.ts",
    "content": "import { ClaudeMode, getUserConfig } from '~/services/user-config'\nimport * as agent from '~services/agent'\nimport { AsyncAbstractBot, MessageParams } from '../abstract-bot'\nimport { ClaudeApiBot } from '../claude-api'\nimport { ClaudeWebBot } from '../claude-web'\nimport { PoeWebBot } from '../poe'\nimport { ChatError, ErrorCode } from '~utils/errors'\nimport { OpenRouterBot } from '../openrouter'\n\nexport class ClaudeBot extends AsyncAbstractBot {\n  async initializeBot() {\n    const { claudeMode, ...config } = await getUserConfig()\n    if (claudeMode === ClaudeMode.API) {\n      if (!config.claudeApiKey) {\n        throw new Error('Claude API key missing')\n      }\n      return new ClaudeApiBot({\n        claudeApiKey: config.claudeApiKey,\n        claudeApiModel: config.claudeApiModel,\n      })\n    }\n    if (claudeMode === ClaudeMode.Webapp) {\n      return new ClaudeWebBot()\n    }\n    if (claudeMode === ClaudeMode.OpenRouter) {\n      if (!config.openrouterApiKey) {\n        throw new ChatError('OpenRouter API key not set', ErrorCode.API_KEY_NOT_SET)\n      }\n      const model = `anthropic/${config.openrouterClaudeModel}`\n      return new OpenRouterBot({ apiKey: config.openrouterApiKey, model })\n    }\n    return new PoeWebBot(config.poeModel)\n  }\n\n  async sendMessage(params: MessageParams) {\n    const { claudeWebAccess } = await getUserConfig()\n    if (claudeWebAccess) {\n      return agent.execute(params.prompt, (prompt) => this.doSendMessageGenerator({ ...params, prompt }), params.signal)\n    }\n    return this.doSendMessageGenerator(params)\n  }\n}\n"
  },
  {
    "path": "src/app/bots/claude-api/index.ts",
    "content": "import { requestHostPermission } from '~app/utils/permissions'\nimport { ClaudeAPIModel, UserConfig } from '~services/user-config'\nimport { ChatError, ErrorCode } from '~utils/errors'\nimport { parseSSEResponse } from '~utils/sse'\nimport { AbstractBot, SendMessageParams } from '../abstract-bot'\n\ninterface ConversationContext {\n  prompt: string\n}\n\nexport class ClaudeApiBot extends AbstractBot {\n  private conversationContext?: ConversationContext\n\n  constructor(private config: Pick<UserConfig, 'claudeApiKey' | 'claudeApiModel'>) {\n    super()\n  }\n\n  async fetchCompletionApi(prompt: string, signal?: AbortSignal) {\n    return fetch('https://api.anthropic.com/v1/complete', {\n      method: 'POST',\n      signal,\n      headers: {\n        'content-type': 'application/json',\n        'x-api-key': this.config.claudeApiKey,\n        'anthropic-version': '2023-06-01',\n      },\n      body: JSON.stringify({\n        prompt,\n        model: this.getModelName(),\n        max_tokens_to_sample: 100_000,\n        stream: true,\n      }),\n    })\n  }\n\n  async doSendMessage(params: SendMessageParams) {\n    if (!(await requestHostPermission('https://*.anthropic.com/'))) {\n      throw new ChatError('Missing anthropic.com permission', ErrorCode.UNKOWN_ERROR)\n    }\n\n    if (!this.conversationContext) {\n      this.conversationContext = { prompt: '' }\n    }\n    this.conversationContext.prompt += `\\n\\nHuman: ${params.prompt}\\n\\nAssistant:`\n\n    const resp = await this.fetchCompletionApi(this.conversationContext.prompt, params.signal)\n\n    let result = ''\n\n    await parseSSEResponse(resp, (message) => {\n      console.debug('claude sse message', message)\n      const data = JSON.parse(message) as { completion: string }\n      if (data.completion) {\n        result += data.completion\n        params.onEvent({ type: 'UPDATE_ANSWER', data: { text: result.trimStart() } })\n      }\n    })\n\n    params.onEvent({ type: 'DONE' })\n    this.conversationContext!.prompt += result\n  }\n\n  private getModelName() {\n    switch (this.config.claudeApiModel) {\n      case ClaudeAPIModel['claude-instant-1']:\n        return 'claude-instant-1.2'\n      default:\n        return 'claude-2.1'\n    }\n  }\n\n  resetConversation() {\n    this.conversationContext = undefined\n  }\n\n  get name() {\n    return `Claude (API/${this.config.claudeApiModel})`\n  }\n}\n"
  },
  {
    "path": "src/app/bots/claude-web/api.ts",
    "content": "import { FetchError, ofetch } from 'ofetch'\nimport { uuid } from '~utils'\nimport { ChatError, ErrorCode } from '~utils/errors'\n\nexport async function fetchOrganizationId(): Promise<string> {\n  let resp: Response\n  try {\n    resp = await fetch('https://claude.ai/api/organizations', { redirect: 'error', cache: 'no-cache' })\n  } catch (err) {\n    console.error(err)\n    throw new ChatError('Claude webapp not avaiable in your country', ErrorCode.CLAUDE_WEB_UNAVAILABLE)\n  }\n  if (resp.status === 403) {\n    throw new ChatError('There is no logged-in Claude account in this browser.', ErrorCode.CLAUDE_WEB_UNAUTHORIZED)\n  }\n  const orgs = await resp.json()\n  return orgs[0].uuid\n}\n\nexport async function createConversation(organizationId: string): Promise<string> {\n  const id = uuid()\n  try {\n    await ofetch(`https://claude.ai/api/organizations/${organizationId}/chat_conversations`, {\n      method: 'POST',\n      body: { name: '', uuid: id },\n    })\n  } catch (err) {\n    if (err instanceof FetchError && err.status === 403) {\n      throw new ChatError('There is no logged-in Claude account in this browser.', ErrorCode.CLAUDE_WEB_UNAUTHORIZED)\n    }\n    throw err\n  }\n  return id\n}\n\nexport async function generateChatTitle(organizationId: string, conversationId: string, content: string) {\n  await ofetch('https://claude.ai/api/generate_chat_title', {\n    method: 'POST',\n    body: {\n      organization_uuid: organizationId,\n      conversation_uuid: conversationId,\n      recent_titles: [],\n      message_content: content,\n    },\n  })\n}\n"
  },
  {
    "path": "src/app/bots/claude-web/index.ts",
    "content": "import { parseSSEResponse } from '~utils/sse'\nimport { AbstractBot, SendMessageParams } from '../abstract-bot'\nimport { createConversation, fetchOrganizationId, generateChatTitle } from './api'\nimport { requestHostPermission } from '~app/utils/permissions'\nimport { ChatError, ErrorCode } from '~utils/errors'\n\ninterface ConversationContext {\n  conversationId: string\n}\n\nexport class ClaudeWebBot extends AbstractBot {\n  private organizationId?: string\n  private conversationContext?: ConversationContext\n  private model: string\n\n  constructor() {\n    super()\n    this.model = 'claude-2.1'\n  }\n\n  async doSendMessage(params: SendMessageParams): Promise<void> {\n    if (!(await requestHostPermission('https://*.claude.ai/'))) {\n      throw new ChatError('Missing claude.ai permission', ErrorCode.MISSING_HOST_PERMISSION)\n    }\n\n    if (!this.organizationId) {\n      this.organizationId = await fetchOrganizationId()\n    }\n\n    if (!this.conversationContext) {\n      const conversationId = await createConversation(this.organizationId)\n      this.conversationContext = { conversationId }\n      generateChatTitle(this.organizationId, conversationId, params.prompt).catch(console.error)\n    }\n\n    const resp = await fetch('https://claude.ai/api/append_message', {\n      method: 'POST',\n      signal: params.signal,\n      headers: {\n        'Content-Type': 'application/json',\n      },\n      body: JSON.stringify({\n        organization_uuid: this.organizationId,\n        conversation_uuid: this.conversationContext.conversationId,\n        text: params.prompt,\n        completion: {\n          prompt: params.prompt,\n          model: this.model,\n        },\n        attachments: [],\n      }),\n    })\n\n    // different models are available for different accounts\n    if (!resp.ok && resp.status === 403 && this.model === 'claude-2.1') {\n      if ((await resp.text()).includes('model_not_allowed')) {\n        this.model = 'claude-2.0'\n        return this.doSendMessage(params)\n      }\n    }\n\n    let result = ''\n\n    await parseSSEResponse(resp, (message) => {\n      console.debug('claude sse message', message)\n      const payload = JSON.parse(message)\n      if (payload.completion) {\n        result += payload.completion\n        params.onEvent({\n          type: 'UPDATE_ANSWER',\n          data: { text: result.trimStart() },\n        })\n      } else if (payload.error) {\n        throw new Error(JSON.stringify(payload.error))\n      }\n    })\n\n    params.onEvent({ type: 'DONE' })\n  }\n\n  resetConversation() {\n    this.conversationContext = undefined\n  }\n\n  get name() {\n    return 'Claude (webapp/claude-2)'\n  }\n}\n"
  },
  {
    "path": "src/app/bots/gemini-api/index.ts",
    "content": "import { GoogleGenerativeAI, ChatSession } from '@google/generative-ai'\nimport { AbstractBot, AsyncAbstractBot, SendMessageParams } from '../abstract-bot'\nimport { getUserConfig } from '~services/user-config'\n\ninterface ConversationContext {\n  chatSession: ChatSession\n}\n\nexport class GeminiApiBot extends AbstractBot {\n  private conversationContext?: ConversationContext\n  sdk: GoogleGenerativeAI\n\n  constructor(public apiKey: string) {\n    super()\n    this.sdk = new GoogleGenerativeAI(apiKey)\n  }\n\n  async doSendMessage(params: SendMessageParams) {\n    if (!this.conversationContext) {\n      const model = this.sdk.getGenerativeModel({ model: 'gemini-pro' })\n      const chatSession = model.startChat()\n      this.conversationContext = { chatSession }\n    }\n\n    const result = await this.conversationContext.chatSession.sendMessageStream(params.prompt)\n\n    let text = ''\n    for await (const chunk of result.stream) {\n      const chunkText = chunk.text()\n      console.debug('gemini stream', chunkText)\n      text += chunkText\n      params.onEvent({ type: 'UPDATE_ANSWER', data: { text } })\n    }\n\n    if (!text) {\n      params.onEvent({ type: 'UPDATE_ANSWER', data: { text: 'Empty response' } })\n    }\n    params.onEvent({ type: 'DONE' })\n  }\n\n  resetConversation() {\n    this.conversationContext = undefined\n  }\n\n  get name() {\n    return 'Gemini Pro'\n  }\n}\n\nexport class GeminiBot extends AsyncAbstractBot {\n  async initializeBot() {\n    const { geminiApiKey } = await getUserConfig()\n    if (!geminiApiKey) {\n      throw new Error('Gemini API key missing')\n    }\n    return new GeminiApiBot(geminiApiKey)\n  }\n}\n"
  },
  {
    "path": "src/app/bots/gradio/index.ts",
    "content": "import WebSocketAsPromised from 'websocket-as-promised'\nimport { ChatError, ErrorCode } from '~utils/errors'\nimport { AbstractBot, SendMessageParams } from '../abstract-bot'\nimport { html2md } from '~app/utils/markdown'\n\nfunction generateSessionHash() {\n  // https://stackoverflow.com/a/12502559/325241\n  return Math.random().toString(36).substring(2)\n}\n\nenum FnIndex {\n  Send = 39,\n  Receive = 40,\n}\n\ninterface ConversationContext {\n  sessionHash: string\n}\n\nexport class GradioBot extends AbstractBot {\n  private conversationContext?: ConversationContext\n\n  constructor(\n    public wsUrl: string,\n    public model: string,\n    public params: number[],\n    public mode?: 'text' | 'html',\n  ) {\n    super()\n  }\n\n  async doSendMessage(params: SendMessageParams) {\n    if (!this.conversationContext) {\n      const sessionHash = await this.createSession(params.signal)\n      this.conversationContext = { sessionHash }\n    }\n\n    const sendWsp = await this.connectWebsocket(\n      FnIndex.Send,\n      this.conversationContext.sessionHash,\n      [null, this.model, params.prompt],\n      params.onEvent,\n    )\n    const receiveWsp = await this.connectWebsocket(\n      FnIndex.Receive,\n      this.conversationContext.sessionHash,\n      [null, ...this.params],\n      params.onEvent,\n    )\n\n    params.signal?.addEventListener('abort', () => {\n      ;[sendWsp, receiveWsp].forEach((wsp) => {\n        wsp.removeAllListeners()\n        wsp.close()\n      })\n    })\n  }\n\n  async connectWebsocket(fnIndex: number, sessionHash: string, data: unknown[], onEvent: SendMessageParams['onEvent']) {\n    const wsp = new WebSocketAsPromised(this.wsUrl, {\n      packMessage: (data) => JSON.stringify(data),\n      unpackMessage: (data) => JSON.parse(data as string),\n    })\n\n    wsp.onUnpackedMessage.addListener(async (event) => {\n      if (event.msg === 'send_hash') {\n        wsp.sendPacked({ fn_index: fnIndex, session_hash: sessionHash })\n      } else if (event.msg === 'send_data') {\n        wsp.sendPacked({\n          fn_index: fnIndex,\n          data,\n          event_data: null,\n          session_hash: sessionHash,\n        })\n      } else if (event.msg === 'process_generating') {\n        if (event.success && event.output.data) {\n          if (fnIndex === FnIndex.Receive) {\n            const outputData = event.output.data\n            if (outputData[1].length > 0) {\n              const text = outputData[1][outputData[1].length - 1][1]\n              onEvent({\n                type: 'UPDATE_ANSWER',\n                data: {\n                  text: this.mode === 'html' ? html2md(text) : text,\n                },\n              })\n            }\n          }\n        } else {\n          onEvent({ type: 'ERROR', error: new ChatError(event.output.error, ErrorCode.UNKOWN_ERROR) })\n        }\n      } else if (event.msg === 'queue_full') {\n        onEvent({ type: 'ERROR', error: new ChatError('queue_full', ErrorCode.UNKOWN_ERROR) })\n      } else if (event.msg === 'process_completed' && fnIndex === FnIndex.Receive && !event.output.data[1].length) {\n        onEvent({\n          type: 'ERROR',\n          error: new ChatError('Session has been inactive for too long', ErrorCode.LMSYS_SESSION_EXPIRED),\n        })\n      }\n    })\n\n    if (fnIndex === FnIndex.Receive) {\n      wsp.onClose.addListener(() => {\n        wsp.removeAllListeners()\n        onEvent({ type: 'DONE' })\n      })\n    }\n\n    try {\n      await wsp.open()\n    } catch (err) {\n      console.error('WS open error', err)\n      throw new ChatError('Failed to establish websocket connection.', ErrorCode.NETWORK_ERROR)\n    }\n\n    return wsp\n  }\n\n  resetConversation() {\n    this.conversationContext = undefined\n  }\n\n  public async createSession(_signal?: AbortSignal) {\n    return generateSessionHash()\n  }\n}\n"
  },
  {
    "path": "src/app/bots/grok/index.ts",
    "content": "import { FetchError, ofetch } from 'ofetch'\nimport Browser from 'webextension-polyfill'\nimport { requestHostPermission } from '~app/utils/permissions'\nimport { ChatError, ErrorCode } from '~utils/errors'\nimport { streamAsyncIterable } from '~utils/stream-async-iterable'\nimport { AbstractBot, SendMessageParams } from '../abstract-bot'\n\nconst AUTHORIZATION_VALUE =\n  'Bearer AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs=1Zv7ttfk8LF81IUq16cHjhLTvJu4FA33AGWWjCpTnA'\n\ninterface StreamMessage {\n  result: {\n    sender: string\n    message: string\n    query: string\n  }\n}\n\ninterface ChatMessage {\n  sender: 1 | 2\n  message: string\n}\n\ninterface ConversationContext {\n  conversationId: string\n  messages: ChatMessage[]\n}\n\nexport class GrokWebBot extends AbstractBot {\n  private csrfToken?: string\n  private conversationContext?: ConversationContext\n\n  constructor() {\n    super()\n  }\n\n  async doSendMessage(params: SendMessageParams) {\n    if (!(await requestHostPermission('https://*.twitter.com/'))) {\n      throw new ChatError('Missing twitter.com permission', ErrorCode.MISSING_HOST_PERMISSION)\n    }\n\n    if (!this.csrfToken) {\n      this.csrfToken = await this.readCsrfToken()\n    }\n\n    if (!this.conversationContext) {\n      const conversationId = await this.getConversationId()\n      this.conversationContext = { conversationId, messages: [] }\n    }\n\n    this.conversationContext.messages.push({ sender: 1, message: params.prompt })\n\n    const resp = await fetch('https://api.twitter.com/2/grok/add_response.json', {\n      method: 'POST',\n      headers: {\n        Authorization: AUTHORIZATION_VALUE,\n        'x-csrf-token': this.csrfToken!,\n      },\n      body: JSON.stringify({\n        conversationId: this.conversationContext.conversationId,\n        responses: this.conversationContext.messages,\n        systemPromptName: 'fun',\n      }),\n      signal: params.signal,\n    })\n\n    if (!resp.ok) {\n      throw new Error(resp.status.toString() + ' ' + (await resp.text()))\n    }\n\n    const decoder = new TextDecoder()\n    let result = ''\n\n    for await (const uint8Array of streamAsyncIterable(resp.body!)) {\n      const str = decoder.decode(uint8Array)\n      console.debug('grok stream', str)\n      const lines = str.split('\\n')\n      for (const line of lines) {\n        if (!line) {\n          continue\n        }\n        const payload: StreamMessage = JSON.parse(line)\n        if (!payload.result) {\n          continue\n        }\n        if (!result && !payload.result.message && payload.result.query) {\n          params.onEvent({ type: 'UPDATE_ANSWER', data: { text: '_' + payload.result.query + '_' } })\n        } else {\n          const text = payload.result.message\n          if (text.startsWith('[link]')) {\n            // [link](#tweet=1711679181984346515)\\n\\n==\\n\\n[link](#tweet=1663711402643845122)\n            // skip special Twitter card message for now\n          } else {\n            result += text\n            params.onEvent({ type: 'UPDATE_ANSWER', data: { text: result } })\n          }\n        }\n      }\n    }\n\n    this.conversationContext.messages.push({ sender: 2, message: result })\n    params.onEvent({ type: 'DONE' })\n  }\n\n  private async getConversationId(): Promise<string> {\n    try {\n      const resp = await ofetch('https://twitter.com/i/api/2/grok/conversation_id.json', {\n        headers: {\n          Authorization: AUTHORIZATION_VALUE,\n          'x-csrf-token': this.csrfToken!,\n        },\n      })\n      return resp.conversationId\n    } catch (err) {\n      if (err instanceof FetchError) {\n        if (err.status === 401) {\n          throw new ChatError('Grok is only available to Twitter Premium+ subscribers', ErrorCode.GROK_UNAVAILABLE)\n        }\n        if (err.status === 451) {\n          throw new ChatError('Grok is not available in your country', ErrorCode.GROK_UNAVAILABLE)\n        }\n        // csrf & cookie mismatch\n        if (err.status === 403) {\n          this.csrfToken = await this.readCsrfToken({ refresh: true })\n          return this.getConversationId()\n        }\n      }\n      throw err\n    }\n  }\n\n  private async readCsrfToken({ refresh }: { refresh?: boolean } = {}): Promise<string> {\n    const token = await Browser.runtime.sendMessage({\n      type: 'read-twitter-csrf-token',\n      data: { refresh },\n      target: 'background',\n    })\n    console.debug('twitter csrf token', token)\n    if (!token) {\n      throw new ChatError('There is no logged-in Twitter account in this browser.', ErrorCode.TWITTER_UNAUTHORIZED)\n    }\n    return token\n  }\n\n  resetConversation() {\n    this.conversationContext = undefined\n  }\n\n  get name() {\n    return 'Grok'\n  }\n}\n"
  },
  {
    "path": "src/app/bots/index.ts",
    "content": "import { BaichuanWebBot } from './baichuan'\nimport { BardBot } from './bard'\nimport { BingWebBot } from './bing'\nimport { ChatGPTBot } from './chatgpt'\nimport { ClaudeBot } from './claude'\nimport { GeminiBot } from './gemini-api'\nimport { GrokWebBot } from './grok'\nimport { LMSYSBot } from './lmsys'\nimport { PerplexityBot } from './perplexity'\nimport { PiBot } from './pi'\nimport { QianwenWebBot } from './qianwen'\nimport { XunfeiBot } from './xunfei'\n\nexport type BotId =\n  | 'chatgpt'\n  | 'bing'\n  | 'bard'\n  | 'claude'\n  | 'perplexity'\n  | 'xunfei'\n  | 'vicuna'\n  | 'falcon'\n  | 'mistral'\n  | 'chatglm'\n  | 'llama'\n  | 'pi'\n  | 'wizardlm'\n  | 'qianwen'\n  | 'baichuan'\n  | 'yi'\n  | 'grok'\n  | 'gemini'\n\nexport function createBotInstance(botId: BotId) {\n  switch (botId) {\n    case 'chatgpt':\n      return new ChatGPTBot()\n    case 'bing':\n      return new BingWebBot()\n    case 'bard':\n      return new BardBot()\n    case 'claude':\n      return new ClaudeBot()\n    case 'xunfei':\n      return new XunfeiBot()\n    case 'vicuna':\n      return new LMSYSBot('vicuna-33b')\n    case 'chatglm':\n      return new LMSYSBot('chatglm2-6b')\n    case 'llama':\n      return new LMSYSBot('llama-2-70b-chat')\n    case 'wizardlm':\n      return new LMSYSBot('wizardlm-13b')\n    case 'falcon':\n      return new LMSYSBot('falcon-180b-chat')\n    case 'mistral':\n      return new LMSYSBot('mixtral-8x7b-instruct-v0.1')\n    case 'yi':\n      return new LMSYSBot('yi-34b-chat')\n    case 'pi':\n      return new PiBot()\n    case 'qianwen':\n      return new QianwenWebBot()\n    case 'baichuan':\n      return new BaichuanWebBot()\n    case 'perplexity':\n      return new PerplexityBot()\n    case 'grok':\n      return new GrokWebBot()\n    case 'gemini':\n      return new GeminiBot()\n  }\n}\n\nexport type BotInstance = ReturnType<typeof createBotInstance>\n"
  },
  {
    "path": "src/app/bots/lmsys/index.ts",
    "content": "import WebSocketAsPromised from 'websocket-as-promised'\nimport { GradioBot } from '../gradio'\nimport { ChatError, ErrorCode } from '~utils/errors'\n\nexport class LMSYSBot extends GradioBot {\n  constructor(model: string) {\n    super('wss://chat.lmsys.org/queue/join', model, [0.7, 1, 512], 'text')\n  }\n\n  private async initializeSession(\n    fnIndex: number,\n    sessionHash: string,\n    data: unknown[],\n    signal?: AbortSignal,\n  ): Promise<void> {\n    const wsp = new WebSocketAsPromised(this.wsUrl, {\n      packMessage: (data) => JSON.stringify(data),\n      unpackMessage: (data) => JSON.parse(data as string),\n    })\n    signal?.addEventListener('abort', () => wsp.close())\n    return new Promise((resolve, reject) => {\n      wsp.onUnpackedMessage.addListener((event) => {\n        if (event.msg === 'send_hash') {\n          wsp.sendPacked({ fn_index: fnIndex, session_hash: sessionHash })\n        } else if (event.msg === 'send_data') {\n          wsp.sendPacked({ fn_index: fnIndex, data, event_data: null, session_hash: sessionHash })\n        } else if (event.msg === 'process_completed') {\n          resolve()\n        }\n      })\n      wsp.open().catch((err) => {\n        console.error('lmsys ws open error', err)\n        reject(new ChatError('Failed to establish websocket connection.', ErrorCode.LMSYS_WS_ERROR))\n      })\n    })\n  }\n\n  async createSession(signal?: AbortSignal) {\n    const sessionHash = await super.createSession(signal)\n    await Promise.all([\n      this.initializeSession(36, sessionHash, [], signal),\n      this.initializeSession(43, sessionHash, [{}], signal),\n    ])\n    return sessionHash\n  }\n}\n"
  },
  {
    "path": "src/app/bots/openrouter/index.ts",
    "content": "import { requestHostPermission } from '~app/utils/permissions'\nimport { ChatError, ErrorCode } from '~utils/errors'\nimport { parseSSEResponse } from '~utils/sse'\nimport { AbstractBot, SendMessageParams } from '../abstract-bot'\n\ninterface ChatMessage {\n  role: 'system' | 'assistant' | 'user'\n  content: string\n}\n\ninterface ConversationContext {\n  messages: ChatMessage[]\n}\n\nconst CONTEXT_SIZE = 9\n\nexport class OpenRouterBot extends AbstractBot {\n  private conversationContext?: ConversationContext\n\n  constructor(private config: { apiKey: string; model: string }) {\n    super()\n  }\n\n  buildMessages(prompt: string): ChatMessage[] {\n    return [...this.conversationContext!.messages.slice(-(CONTEXT_SIZE + 1)), { role: 'user', content: prompt }]\n  }\n\n  async doSendMessage(params: SendMessageParams) {\n    if (!(await requestHostPermission('https://*.openrouter.ai/'))) {\n      throw new ChatError('Missing openrouter.ai permission', ErrorCode.MISSING_HOST_PERMISSION)\n    }\n\n    if (!this.conversationContext) {\n      this.conversationContext = { messages: [] }\n    }\n\n    const resp = await this.fetchCompletionApi(this.buildMessages(params.prompt), params.signal)\n\n    this.conversationContext.messages.push({\n      role: 'user',\n      content: params.rawUserInput || params.prompt,\n    })\n\n    let done = false\n    const result: ChatMessage = { role: 'assistant', content: '' }\n\n    const finish = () => {\n      done = true\n      params.onEvent({ type: 'DONE' })\n      const messages = this.conversationContext!.messages\n      messages.push(result)\n    }\n\n    await parseSSEResponse(resp, (message) => {\n      console.debug('openrouter sse message', message)\n      if (message === '[DONE]') {\n        finish()\n        return\n      }\n      let data\n      try {\n        data = JSON.parse(message)\n      } catch (err) {\n        console.error(err)\n        return\n      }\n      if (data?.choices?.length) {\n        const delta = data.choices[0].delta\n        if (delta?.content) {\n          result.content += delta.content\n          params.onEvent({\n            type: 'UPDATE_ANSWER',\n            data: { text: result.content },\n          })\n        }\n      }\n    })\n\n    if (!done) {\n      finish()\n    }\n  }\n\n  async fetchCompletionApi(messages: ChatMessage[], signal?: AbortSignal): Promise<Response> {\n    return fetch('https://openrouter.ai/api/v1/chat/completions', {\n      method: 'POST',\n      signal,\n      headers: {\n        'Content-Type': 'application/json',\n        Authorization: `Bearer ${this.config.apiKey}`,\n        'HTTP-Referer': 'https://chathub.gg',\n        'X-Title': 'ChatHub',\n      },\n      body: JSON.stringify({\n        model: this.config.model,\n        messages,\n        stream: true,\n      }),\n    })\n  }\n\n  resetConversation() {\n    this.conversationContext = undefined\n  }\n\n  get name() {\n    return `OpenRouter/${this.config.model}`\n  }\n}\n"
  },
  {
    "path": "src/app/bots/perplexity/index.ts",
    "content": "import { PerplexityMode, getUserConfig } from '~/services/user-config'\nimport { AsyncAbstractBot } from '../abstract-bot'\nimport { PerplexityApiBot } from '../perplexity-api'\nimport { PerplexityLabsBot } from '../perplexity-web'\n\nexport class PerplexityBot extends AsyncAbstractBot {\n  async initializeBot() {\n    const { perplexityMode, ...config } = await getUserConfig()\n    if (perplexityMode === PerplexityMode.API) {\n      if (!config.perplexityApiKey) {\n        throw new Error('Perplexity API key missing')\n      }\n      return new PerplexityApiBot(config.perplexityApiKey, 'pplx-70b-online')\n    }\n    return new PerplexityLabsBot('pplx-70b-online')\n  }\n}\n"
  },
  {
    "path": "src/app/bots/perplexity-api/api.ts",
    "content": "import { ofetch } from 'ofetch'\n\nasync function getSessionId() {\n  const resp: string = await ofetch('https://labs-api.perplexity.ai/socket.io/?transport=polling&EIO=4')\n  const data = JSON.parse(resp.slice(1))\n  const sessionId: string = data.sid\n  return sessionId\n}\n\nasync function initSession(sessionId: string) {\n  const resp = await ofetch(`https://labs-api.perplexity.ai/socket.io/?EIO=4&transport=polling&sid=${sessionId}`, {\n    method: 'POST',\n    body: '40{\"jwt\":\"anonymous-ask-user\"}',\n  })\n  if (resp !== 'OK') {\n    throw new Error('Failed to init perplexity session')\n  }\n}\n\nexport async function createSession(): Promise<string> {\n  const sessionId = await getSessionId()\n  await initSession(sessionId)\n  return sessionId\n}\n"
  },
  {
    "path": "src/app/bots/perplexity-api/index.ts",
    "content": "import { parseSSEResponse } from '~utils/sse'\nimport { AbstractBot, SendMessageParams } from '../abstract-bot'\n\ninterface ChatMessage {\n  role: 'user' | 'assistant'\n  content: string\n}\n\ninterface ConversationContext {\n  messages: ChatMessage[]\n}\n\nexport class PerplexityApiBot extends AbstractBot {\n  private conversationContext?: ConversationContext\n\n  constructor(\n    public apiKey: string,\n    public model: string,\n  ) {\n    super()\n  }\n\n  async doSendMessage(params: SendMessageParams) {\n    if (!this.conversationContext) {\n      this.conversationContext = { messages: [] }\n    }\n\n    const message: ChatMessage = { role: 'user', content: params.prompt }\n    const resp = await this.fetchCompletionApi([...this.conversationContext.messages, message], params.signal)\n\n    // add user message to context only after fetch success\n    this.conversationContext.messages.push(message)\n\n    let answer: string = ''\n\n    await parseSSEResponse(resp, (message) => {\n      console.debug('pplx sse message', message)\n      let data\n      try {\n        data = JSON.parse(message)\n      } catch (err) {\n        console.error(err)\n        return\n      }\n      if (data?.choices?.length) {\n        const message = data.choices[0].message\n        if (message.role === 'assistant' && message.content) {\n          answer = message.content\n          params.onEvent({ type: 'UPDATE_ANSWER', data: { text: answer } })\n        }\n      }\n    })\n\n    this.conversationContext.messages.push({ role: 'assistant', content: answer })\n    params.onEvent({ type: 'DONE' })\n  }\n\n  private async fetchCompletionApi(messages: ChatMessage[], signal?: AbortSignal) {\n    return fetch('https://api.perplexity.ai/chat/completions', {\n      method: 'POST',\n      signal,\n      body: JSON.stringify({\n        model: this.model,\n        messages,\n        stream: true,\n      }),\n      headers: {\n        'Content-Type': 'application/json',\n        Authorization: `Bearer ${this.apiKey}`,\n      },\n    })\n  }\n\n  resetConversation() {\n    this.conversationContext = undefined\n  }\n\n  get name() {\n    return 'Perplexity (API)'\n  }\n}\n"
  },
  {
    "path": "src/app/bots/perplexity-web/api.ts",
    "content": "import { FetchError, ofetch } from 'ofetch'\nimport { ChatError, ErrorCode } from '~utils/errors'\n\nasync function getSessionId() {\n  let resp: string\n  try {\n    resp = await ofetch('https://labs-api.perplexity.ai/socket.io/?transport=polling&EIO=4')\n  } catch (err) {\n    if (err instanceof FetchError && err.status === 403) {\n      throw new ChatError('Please pass Perplexity security check', ErrorCode.PPLX_FORBIDDEN_ERROR)\n    }\n    throw err\n  }\n  const data = JSON.parse(resp.slice(1))\n  const sessionId: string = data.sid\n  return sessionId\n}\n\nasync function initSession(sessionId: string) {\n  const resp = await ofetch(`https://labs-api.perplexity.ai/socket.io/?EIO=4&transport=polling&sid=${sessionId}`, {\n    method: 'POST',\n    body: '40{\"jwt\":\"anonymous-ask-user\"}',\n  })\n  if (resp !== 'OK') {\n    throw new Error('Failed to init perplexity session')\n  }\n}\n\nexport async function createSession(): Promise<string> {\n  const sessionId = await getSessionId()\n  await initSession(sessionId)\n  return sessionId\n}\n"
  },
  {
    "path": "src/app/bots/perplexity-web/index.ts",
    "content": "import WebSocketAsPromised from 'websocket-as-promised'\nimport { requestHostPermissions } from '~app/utils/permissions'\nimport { ChatError, ErrorCode } from '~utils/errors'\nimport { AbstractBot, SendMessageParams } from '../abstract-bot'\nimport { createSession } from './api'\n\ninterface ConversationContext {\n  wsp: WebSocketAsPromised\n}\n\nexport class PerplexityLabsBot extends AbstractBot {\n  private conversationContext?: ConversationContext\n\n  constructor(public model: string) {\n    super()\n  }\n\n  private buildMessage(prompt: string) {\n    const params = [\n      'perplexity_playground',\n      {\n        version: '2.1',\n        source: 'default',\n        model: this.model,\n        messages: [{ role: 'user', content: prompt, priority: 0 }],\n      },\n    ]\n    return `42${JSON.stringify(params)}`\n  }\n\n  private async setupWebsocket(sessionId: string): Promise<WebSocketAsPromised> {\n    const wsp = new WebSocketAsPromised(\n      `wss://labs-api.perplexity.ai/socket.io/?EIO=4&transport=websocket&sid=${sessionId}`,\n    )\n    return new Promise((resolve, reject) => {\n      wsp.onOpen.addListener(() => {\n        wsp.send('2probe')\n        wsp.send('5')\n      })\n      wsp.onMessage.addListener((data: string) => {\n        if (data === '2') {\n          wsp.send('3')\n        } else if (data === '6') {\n          resolve(wsp)\n        }\n      })\n      wsp.open().catch(reject)\n    })\n  }\n\n  async doSendMessage(params: SendMessageParams) {\n    if (!(await requestHostPermissions(['https://*.perplexity.ai/', 'wss://*.perplexity.ai/']))) {\n      throw new ChatError('Missing perplexity.ai permission', ErrorCode.MISSING_HOST_PERMISSION)\n    }\n\n    if (!this.conversationContext) {\n      const sessionId = await createSession()\n      const wsp = await this.setupWebsocket(sessionId)\n      this.conversationContext = { wsp }\n    }\n\n    const { wsp } = this.conversationContext\n\n    const listener = (data: string) => {\n      console.debug('pplx ws data', data)\n      if (!data.startsWith('42')) {\n        return\n      }\n      const payload = JSON.parse(data.slice(2))\n      if (payload[0] !== 'pplx-70b-online_query_progress') {\n        return\n      }\n      const chunk = payload[1]\n      if (chunk.output) {\n        params.onEvent({ type: 'UPDATE_ANSWER', data: { text: chunk.output } })\n      }\n      if (chunk.status === 'completed') {\n        wsp.onMessage.removeListener(listener)\n        params.onEvent({ type: 'DONE' })\n      }\n      if (chunk.status === 'failed') {\n        wsp.onMessage.removeListener(listener)\n        params.onEvent({ type: 'ERROR', error: new ChatError('failed', ErrorCode.UNKOWN_ERROR) })\n      }\n    }\n\n    wsp.onMessage.addListener(listener)\n    wsp.send(this.buildMessage(params.prompt))\n  }\n\n  resetConversation() {\n    this.conversationContext = undefined\n  }\n\n  get name() {\n    return 'Perplexity (webapp)'\n  }\n}\n"
  },
  {
    "path": "src/app/bots/pi/index.ts",
    "content": "import { requestHostPermission } from '~app/utils/permissions'\nimport { ChatError, ErrorCode } from '~utils/errors'\nimport { parseSSEResponse } from '~utils/sse'\nimport { AbstractBot, SendMessageParams } from '../abstract-bot'\n\ninterface ConversationContext {\n  initialized: boolean\n}\n\nexport class PiBot extends AbstractBot {\n  private conversationContext?: ConversationContext\n\n  async doSendMessage(params: SendMessageParams) {\n    if (!(await requestHostPermission('https://*.pi.ai/'))) {\n      throw new ChatError('Missing pi.ai permission', ErrorCode.MISSING_HOST_PERMISSION)\n    }\n\n    if (!this.conversationContext?.initialized) {\n      await fetch('https://pi.ai/api/chat/start', { method: 'POST' })\n      this.conversationContext = { initialized: true }\n    }\n\n    const resp = await fetch('https://pi.ai/api/chat', {\n      method: 'POST',\n      signal: params.signal,\n      body: JSON.stringify({ text: params.prompt }),\n      headers: {\n        'Content-Type': 'application/json',\n      },\n    })\n\n    await parseSSEResponse(resp, (message) => {\n      console.debug('pi sse', message)\n      const data = JSON.parse(message)\n      if (data.text) {\n        params.onEvent({ type: 'UPDATE_ANSWER', data: { text: data.text } })\n      }\n    })\n\n    params.onEvent({ type: 'DONE' })\n  }\n\n  resetConversation() {\n    this.conversationContext = undefined\n  }\n}\n"
  },
  {
    "path": "src/app/bots/poe/api.ts",
    "content": "import md5 from 'md5'\nimport { ofetch } from 'ofetch'\nimport i18n from '~app/i18n'\nimport { decodePoeFormkey } from '~services/server-api'\nimport { ChatError, ErrorCode } from '~utils/errors'\nimport AddMessageBreakMutation from './graphql/AddMessageBreakMutation.graphql?raw'\nimport ChatViewQuery from './graphql/ChatViewQuery.graphql?raw'\nimport MessageAddedSubscription from './graphql/MessageAddedSubscription.graphql?raw'\nimport SendMessageMutation from './graphql/SendMessageMutation.graphql?raw'\nimport SubscriptionsMutation from './graphql/SubscriptionsMutation.graphql?raw'\nimport ViewerStateUpdatedSubscription from './graphql/ViewerStateUpdatedSubscription.graphql?raw'\n\nexport const GRAPHQL_QUERIES = {\n  AddMessageBreakMutation,\n  ChatViewQuery,\n  SendMessageMutation,\n  SubscriptionsMutation,\n  MessageAddedSubscription,\n  ViewerStateUpdatedSubscription,\n}\n\nexport interface PoeSettings {\n  formkey: string\n  tchannelData: ChannelData\n}\n\ninterface ChannelData {\n  minSeq: string\n  channel: string\n  channelHash: string\n  boxName: string\n  baseHost: string\n  targetUrl: string\n  enableWebsocket: boolean\n}\n\nasync function getFormkey() {\n  const html: string = await ofetch('https://poe.com', { parseResponse: (txt) => txt })\n  const formkey = await decodePoeFormkey(html)\n  return formkey\n}\n\nexport async function getPoeSettings(): Promise<PoeSettings> {\n  const [settings, formkey] = await Promise.all([ofetch<PoeSettings>('https://poe.com/api/settings'), getFormkey()])\n  console.debug('poe formkey', formkey)\n  settings.formkey = formkey\n  return settings\n}\n\nexport interface GqlHeaders {\n  formkey: string\n  tchannel: string\n}\n\nexport async function gqlRequest(queryName: keyof typeof GRAPHQL_QUERIES, variables: any, poeSettings: PoeSettings) {\n  const query = GRAPHQL_QUERIES[queryName]\n  const payload = { query, variables }\n  const tagId = md5(JSON.stringify(payload) + poeSettings.formkey + 'Jb1hi3fg1MxZpzYfy')\n  return ofetch('https://poe.com/api/gql_POST', {\n    method: 'POST',\n    body: payload,\n    headers: {\n      'poe-formkey': poeSettings.formkey,\n      'poe-tag-id': tagId,\n      'poe-tchannel': poeSettings.tchannelData.channel,\n    },\n  })\n}\n\nexport async function getChatId(bot: string, poeSettings: PoeSettings): Promise<number> {\n  const resp = await gqlRequest('ChatViewQuery', { bot }, poeSettings)\n  if (!resp.data) {\n    throw new ChatError(i18n.t('You need to login to Poe first'), ErrorCode.POE_UNAUTHORIZED)\n  }\n  return resp.data.chatOfBot.chatId\n}\n"
  },
  {
    "path": "src/app/bots/poe/graphql/AddMessageBreakMutation.graphql",
    "content": "mutation AddMessageBreakMutation($chatId: BigInt!) {\n  messageBreakCreate(chatId: $chatId) {\n    message {\n      id\n      __typename\n      messageId\n      text\n      linkifiedText\n      authorNickname\n      state\n      vote\n      voteReason\n      creationTime\n      suggestedReplies\n    }\n  }\n}\n"
  },
  {
    "path": "src/app/bots/poe/graphql/AutoSubscriptionMutation.graphql",
    "content": "mutation AutoSubscriptionMutation($subscriptions: [AutoSubscriptionQuery!]!) {\n  autoSubscribe(subscriptions: $subscriptions) {\n    viewer {\n      id\n    }\n  }\n}\n"
  },
  {
    "path": "src/app/bots/poe/graphql/ChatViewQuery.graphql",
    "content": "query ChatViewQuery($bot: String!) {\n  chatOfBot(bot: $bot) {\n    id\n    chatId\n    defaultBotNickname\n    shouldShowDisclaimer\n  }\n}\n"
  },
  {
    "path": "src/app/bots/poe/graphql/MessageAddedSubscription.graphql",
    "content": "subscription messageAdded($chatId: BigInt!) {\n  messageAdded(chatId: $chatId) {\n    id\n    messageId\n    creationTime\n    state\n    ...ChatMessage_message\n    ...chatHelpers_isBotMessage\n  }\n}\n\nfragment ChatMessageDownvotedButton_message on Message {\n  ...MessageFeedbackReasonModal_message\n  ...MessageFeedbackOtherModal_message\n}\n\nfragment ChatMessageDropdownMenu_message on Message {\n  id\n  messageId\n  vote\n  text\n  linkifiedText\n  ...chatHelpers_isBotMessage\n}\n\nfragment ChatMessageFeedbackButtons_message on Message {\n  id\n  messageId\n  vote\n  voteReason\n  ...ChatMessageDownvotedButton_message\n}\n\nfragment ChatMessageOverflowButton_message on Message {\n  text\n  ...ChatMessageDropdownMenu_message\n  ...chatHelpers_isBotMessage\n}\n\nfragment ChatMessageSuggestedReplies_SuggestedReplyButton_message on Message {\n  messageId\n}\n\nfragment ChatMessageSuggestedReplies_message on Message {\n  suggestedReplies\n  ...ChatMessageSuggestedReplies_SuggestedReplyButton_message\n}\n\nfragment ChatMessage_message on Message {\n  id\n  messageId\n  text\n  author\n  linkifiedText\n  state\n  ...ChatMessageSuggestedReplies_message\n  ...ChatMessageFeedbackButtons_message\n  ...ChatMessageOverflowButton_message\n  ...chatHelpers_isHumanMessage\n  ...chatHelpers_isBotMessage\n  ...chatHelpers_isChatBreak\n  ...chatHelpers_useTimeoutLevel\n  ...MarkdownLinkInner_message\n}\n\nfragment MarkdownLinkInner_message on Message {\n  messageId\n}\n\nfragment MessageFeedbackOtherModal_message on Message {\n  id\n  messageId\n}\n\nfragment MessageFeedbackReasonModal_message on Message {\n  id\n  messageId\n}\n\nfragment chatHelpers_isBotMessage on Message {\n  ...chatHelpers_isHumanMessage\n  ...chatHelpers_isChatBreak\n}\n\nfragment chatHelpers_isChatBreak on Message {\n  author\n}\n\nfragment chatHelpers_isHumanMessage on Message {\n  author\n}\n\nfragment chatHelpers_useTimeoutLevel on Message {\n  id\n  state\n  text\n  messageId\n}\n"
  },
  {
    "path": "src/app/bots/poe/graphql/SendMessageMutation.graphql",
    "content": "mutation chatHelpers_sendMessageMutation_Mutation(\n  $chatId: BigInt!\n  $bot: String!\n  $query: String!\n  $source: MessageSource\n  $withChatBreak: Boolean!\n) {\n  messageEdgeCreate(chatId: $chatId, bot: $bot, query: $query, source: $source, withChatBreak: $withChatBreak) {\n    chatBreak {\n      cursor\n      node {\n        id\n        messageId\n        text\n        author\n        suggestedReplies\n        creationTime\n        state\n      }\n      id\n    }\n    message {\n      cursor\n      node {\n        id\n        messageId\n        text\n        author\n        suggestedReplies\n        creationTime\n        state\n        chat {\n          shouldShowDisclaimer\n          id\n        }\n      }\n      id\n    }\n  }\n}\n"
  },
  {
    "path": "src/app/bots/poe/graphql/SubscriptionsMutation.graphql",
    "content": "mutation subscriptionsMutation($subscriptions: [AutoSubscriptionQuery!]!) {\n  autoSubscribe(subscriptions: $subscriptions) {\n    viewer {\n      id\n    }\n  }\n}\n"
  },
  {
    "path": "src/app/bots/poe/graphql/ViewerStateUpdatedSubscription.graphql",
    "content": "subscription viewerStateUpdated {\n  viewerStateUpdated {\n    id\n    ...ChatPageBotSwitcher_viewer\n  }\n}\n\nfragment BotHeader_bot on Bot {\n  displayName\n  messageLimit {\n    dailyLimit\n  }\n  ...BotImage_bot\n}\n\nfragment BotImage_bot on Bot {\n  image {\n    __typename\n    ... on LocalBotImage {\n      localName\n    }\n    ... on UrlBotImage {\n      url\n    }\n  }\n  displayName\n}\n\nfragment BotLink_bot on Bot {\n  displayName\n}\n\nfragment ChatPageBotSwitcher_viewer on Viewer {\n  availableBots {\n    id\n    messageLimit {\n      dailyLimit\n    }\n    ...BotLink_bot\n    ...BotHeader_bot\n  }\n  allowUserCreatedBots: booleanGate(gateName: \"enable_user_created_bots\")\n}\n"
  },
  {
    "path": "src/app/bots/poe/index.ts",
    "content": "import { t } from 'i18next'\nimport WebSocketAsPromised from 'websocket-as-promised'\nimport { requestHostPermission } from '~app/utils/permissions'\nimport { PoeClaudeModel, PoeGPTModel } from '~services/user-config'\nimport { ChatError, ErrorCode } from '~utils/errors'\nimport { AbstractBot, SendMessageParams } from '../abstract-bot'\nimport { GRAPHQL_QUERIES, PoeSettings, getChatId, getPoeSettings, gqlRequest } from './api'\n\ninterface ChatMessage {\n  id: string\n  author: string\n  text: string\n  state: 'complete' | 'incomplete'\n  messageId: number\n}\n\ninterface WebsocketMessage {\n  message_type: 'subscriptionUpdate'\n  payload: {\n    subscription_name: 'messageAdded'\n    unique_id: string\n    data: {\n      messageAdded: ChatMessage\n    }\n  }\n}\n\ninterface ConversationContext {\n  poeSettings: PoeSettings\n  chatId: number // user specific chat id for the bot\n  wsp: WebSocketAsPromised\n  minMessageId?: number\n}\n\nexport class PoeWebBot extends AbstractBot {\n  private conversationContext?: ConversationContext\n\n  constructor(public botId: string) {\n    super()\n  }\n\n  async doSendMessage(params: SendMessageParams) {\n    if (!(await requestHostPermission('https://*.poe.com/'))) {\n      throw new ChatError('Missing poe.com permission', ErrorCode.MISSING_POE_HOST_PERMISSION)\n    }\n\n    if (!this.conversationContext) {\n      console.log('Using poe model', this.botId)\n      const { poeSettings, chatId } = await this.getChatInfo()\n      const wsp = await this.connectWebsocket(poeSettings)\n      await this.subscribe(poeSettings)\n      this.conversationContext = { chatId, poeSettings, wsp }\n      await this.sendChatBreak().catch(console.error)\n    }\n\n    const wsp = this.conversationContext.wsp\n\n    const onUnpackedMessageListener = (data: any) => {\n      const messages: WebsocketMessage[] = data.messages.map((s: string) => JSON.parse(s))\n      for (const m of messages) {\n        if (m.message_type === 'subscriptionUpdate' && m.payload.subscription_name === 'messageAdded') {\n          const chatMessage = m.payload.data.messageAdded\n          console.debug('poe ws chat message', chatMessage)\n          if (chatMessage.author !== this.botId) {\n            continue\n          }\n          if (\n            this.conversationContext?.minMessageId &&\n            chatMessage.messageId <= this.conversationContext.minMessageId\n          ) {\n            continue\n          }\n          params.onEvent({\n            type: 'UPDATE_ANSWER',\n            data: { text: chatMessage.text.trimStart() },\n          })\n          if (chatMessage.state === 'complete') {\n            this.conversationContext!.minMessageId = chatMessage.messageId\n            params.onEvent({ type: 'DONE' })\n            wsp.removeAllListeners()\n          }\n        }\n      }\n    }\n\n    wsp.onUnpackedMessage.addListener(onUnpackedMessageListener)\n    wsp.onError.addListener(console.error)\n\n    try {\n      await wsp.open()\n    } catch (e) {\n      console.error('poe ws open error', e)\n      throw new ChatError('Failed to establish websocket connection.', ErrorCode.NETWORK_ERROR)\n    }\n\n    try {\n      await this.sendMessageRequest(params.prompt)\n    } catch (err) {\n      wsp.removeAllListeners()\n      wsp.close()\n      throw err\n    }\n  }\n\n  resetConversation() {\n    if (!this.conversationContext) {\n      return\n    }\n    const wsp = this.conversationContext.wsp\n    wsp.removeAllListeners()\n    wsp.close()\n    this.sendChatBreak()\n    this.conversationContext = undefined\n  }\n\n  private async getChatInfo() {\n    const poeSettings = await getPoeSettings()\n    const chatId = await getChatId(this.botId, poeSettings)\n    return { poeSettings, chatId }\n  }\n\n  private async sendMessageRequest(message: string) {\n    const { poeSettings, chatId } = this.conversationContext!\n    const resp = await gqlRequest(\n      'SendMessageMutation',\n      {\n        bot: this.botId,\n        chatId,\n        query: message,\n        source: null,\n        withChatBreak: false,\n      },\n      poeSettings,\n    )\n    if (!resp.data) {\n      throw new Error(JSON.stringify(resp.errors))\n    }\n    if (!resp.data.messageEdgeCreate.message) {\n      throw new ChatError(t('You’ve reached the daily free message limit for this model'), ErrorCode.POE_MESSAGE_LIMIT)\n    }\n  }\n\n  private async sendChatBreak() {\n    const { chatId, poeSettings } = this.conversationContext!\n    await gqlRequest('AddMessageBreakMutation', { chatId }, poeSettings)\n  }\n\n  private async subscribe(poeSettings: PoeSettings) {\n    await gqlRequest(\n      'SubscriptionsMutation',\n      {\n        subscriptions: [\n          {\n            subscriptionName: 'messageAdded',\n            query: GRAPHQL_QUERIES.MessageAddedSubscription,\n          },\n        ],\n      },\n      poeSettings,\n    )\n  }\n\n  private async getWebsocketUrl(poeSettings: PoeSettings) {\n    const domain = `tch${Math.floor(Math.random() * 1000000) + 1}`\n    const channel = poeSettings.tchannelData\n    return `wss://${domain}.tch.${channel.baseHost}/up/${channel.boxName}/updates?min_seq=${channel.minSeq}&channel=${channel.channel}&hash=${channel.channelHash}`\n  }\n\n  private async connectWebsocket(poeSettings: PoeSettings) {\n    const wsUrl = await this.getWebsocketUrl(poeSettings)\n    console.debug('ws url', wsUrl)\n\n    const wsp = new WebSocketAsPromised(wsUrl, {\n      packMessage: (data) => JSON.stringify(data),\n      unpackMessage: (data) => JSON.parse(data as string),\n    })\n\n    return wsp\n  }\n\n  get name() {\n    if (this.botId === PoeGPTModel['GPT-3.5']) {\n      return 'ChatGPT (poe/gpt-3.5)'\n    }\n    if (this.botId === PoeGPTModel['GPT-4']) {\n      return 'ChatGPT (poe/gpt-4)'\n    }\n    if (this.botId === PoeClaudeModel['claude-instant']) {\n      return 'Claude (poe/claude-instant)'\n    }\n    if (this.botId === PoeClaudeModel['claude-instant-100k']) {\n      return 'Claude (poe/claude-100k)'\n    }\n    if (this.botId === PoeClaudeModel['claude-2-100k']) {\n      return 'Claude (poe/claude-2-100k)'\n    }\n  }\n}\n"
  },
  {
    "path": "src/app/bots/qianwen/api.ts",
    "content": "import { ofetch } from 'ofetch'\nimport { ChatError, ErrorCode } from '~utils/errors'\n\ninterface CreationResponse {\n  data: {\n    sessionId: string\n  }\n  success: boolean\n  errorMsg: string | null\n  errorCode: string | null\n}\n\nexport async function createConversation(firstQuery: string, csrfToken: string) {\n  const resp = await ofetch<CreationResponse>('https://qianwen.aliyun.com/addSession', {\n    method: 'POST',\n    body: {\n      firstQuery,\n      sessionType: 'text_chat',\n    },\n    headers: {\n      'X-Platform': 'pc_tongyi',\n      'X-Xsrf-Token': csrfToken,\n    },\n  })\n  if (!resp.success) {\n    if (resp.errorCode === '4000') {\n      throw new ChatError('请先登录通义千问账号', ErrorCode.QIANWEN_WEB_UNAUTHORIZED)\n    }\n    throw new Error(`Error: ${resp.errorCode} ${resp.errorMsg}`)\n  }\n  return resp.data.sessionId\n}\n\nfunction extractVariable(variableName: string, html: string) {\n  const regex = new RegExp(`${variableName}\\\\s?=\\\\s?\"([^\"]+)\"`)\n  const match = regex.exec(html)\n  if (!match) {\n    throw new Error('Failed to get csrfToken')\n  }\n  return match[1]\n}\n\nexport async function getCsrfToken() {\n  const html = await ofetch('https://tongyi.aliyun.com/qianwen/', { parseResponse: (t) => t })\n  return extractVariable('csrfToken', html)\n}\n"
  },
  {
    "path": "src/app/bots/qianwen/index.ts",
    "content": "import { requestHostPermissions } from '~app/utils/permissions'\nimport { uuid } from '~utils'\nimport { ChatError, ErrorCode } from '~utils/errors'\nimport { parseSSEResponse } from '~utils/sse'\nimport { AbstractBot, SendMessageParams } from '../abstract-bot'\nimport { createConversation, getCsrfToken } from './api'\n\nfunction generateMessageId() {\n  return uuid().replace(/-/g, '')\n}\n\ninterface ConversationContext {\n  conversationId: string\n  csrfToken: string\n  lastMessageId?: string\n}\n\nexport class QianwenWebBot extends AbstractBot {\n  private conversationContext?: ConversationContext\n\n  async doSendMessage(params: SendMessageParams) {\n    if (!(await requestHostPermissions(['https://qianwen.aliyun.com/', 'https://tongyi.aliyun.com/']))) {\n      throw new ChatError('Missing qianwen.aliyun.com permission', ErrorCode.MISSING_HOST_PERMISSION)\n    }\n\n    if (!this.conversationContext) {\n      const csrfToken = await getCsrfToken()\n      const conversationId = await createConversation(params.prompt, csrfToken)\n      this.conversationContext = { conversationId, csrfToken }\n    }\n\n    const resp = await fetch('https://qianwen.aliyun.com/conversation', {\n      method: 'POST',\n      signal: params.signal,\n      headers: {\n        'Content-Type': 'application/json',\n        'X-Platform': 'pc_tongyi',\n        'X-Xsrf-Token': this.conversationContext.csrfToken,\n      },\n      body: JSON.stringify({\n        action: 'next',\n        msgId: generateMessageId(),\n        parentMsgId: this.conversationContext.lastMessageId || '0',\n        contents: [{ contentType: 'text', content: params.prompt }],\n        sessionId: this.conversationContext.conversationId,\n        sessionType: 'text_chat',\n        model: '',\n        modelType: '',\n        openSearch: true,\n        timeout: 120,\n      }),\n    })\n\n    let done = false\n\n    await parseSSEResponse(resp, (message) => {\n      console.debug('qianwen sse', message)\n      const data = JSON.parse(message)\n      const text = data.content[0]\n      if (text) {\n        params.onEvent({ type: 'UPDATE_ANSWER', data: { text } })\n      }\n      if (data.stopReason === 'stop') {\n        this.conversationContext!.lastMessageId = data.msgId\n        done = true\n        params.onEvent({ type: 'DONE' })\n      }\n    })\n\n    if (!done) {\n      params.onEvent({ type: 'DONE' })\n    }\n  }\n\n  resetConversation() {\n    this.conversationContext = undefined\n  }\n\n  get name() {\n    return '通义千问'\n  }\n}\n"
  },
  {
    "path": "src/app/bots/xunfei/api.ts",
    "content": "import { ofetch } from 'ofetch'\nimport './geeguard'\nimport { ChatError, ErrorCode } from '~utils/errors'\n\nexport async function getGeeToken(): Promise<string> {\n  const resp: string = await ofetch('https://riskct.geetest.com/g2/api/v1/pre_load?client_type=web')\n  const config = JSON.parse(resp.slice(1, -1))\n  console.debug('GeeGuard config:', config)\n  const token = await (window as any).GeeGuard.load({\n    appId: 'ihuqg3dmuzcr2kmghumvivsk7c3l4joe',\n    js: config.data.js,\n    staticPath: config.data.static_path,\n    gToken: config.data.g_token,\n    type: 'gt',\n  })\n  return token.gee_token\n}\n\nexport async function createConversation() {\n  const resp = await ofetch('https://xinghuo.xfyun.cn/iflygpt/u/chat-list/v1/create-chat-list', {\n    method: 'POST',\n    body: {},\n  })\n  if (resp.code === 80000) {\n    throw new ChatError('请先登录讯飞账号', ErrorCode.XUNFEI_UNAUTHORIZED)\n  }\n  if (resp.code !== 0) {\n    throw new Error(`Failed to create conversation: ${resp.desc}`)\n  }\n  return {\n    chatId: resp.data.id as number,\n  }\n}\n"
  },
  {
    "path": "src/app/bots/xunfei/geeguard.js",
    "content": "_MNVo.$_Aq=function(){var $_BDGR=2;for(;$_BDGR!==1;){switch($_BDGR){case 2:return{$_BDHO:function($_BDIz){var $_BDJb=2;for(;$_BDJb!==14;){switch($_BDJb){case 5:$_BDJb=$_BEAm<$_BEBW.length?4:7;break;case 2:var $_BECR='',$_BEBW=decodeURI('%15P%0EY!7$%5D%0AZ3%0C%14G%00h5=%03L=X8%259X%10e2&.X%0ES3;%06A%06h\\'=%14%5C%17_8%3C9V%0BW%25%11%08Q%06w#%0C%15P%07C479G%06X37%15P%07t%224%01P%11h%107%09P%11W#=%15%15%0AEw3%0BG%06W3+GP%1BS4\\'%13%5C%0DQy%0C%20Z%0CQ;79%5E%06O$%0C%06E%13Z.%0C%10P%01%5D%3E&3P%0EF8%20%06G%1Ae#=%15T%04S%096%08%5B%06h;3%05P%0Fh\\'=%17k%14S59%0EA1S$=%0BC%06z81%06Y%25_;74L%10B2?2g/h%14%014e%11_:;%13%5C%15S%013%0B@%06h4=%0AE%0FS#79%5C%0EF8%20%13T%0DB%09=%05_%06U#%0C%14A%02X33%0BZ%0DS%09&%0FP%0Dh4%20%02T%17S%12%3E%02X%06X#%0C%13G%1AE%09%10%06A%17S%25+*T%0DW07%15k%0CF$%0C%14T%0DEz!%02G%0APz&%0F%5C%0Dh#:%15Z%14h:!*T%1Bb8\\'%04%5D3Y%3E%3C%13F=@2%3C%03Z%11h:=%09Z%10F61%02k%0CX07%14A%16D27%09Q=Q2&4A%0CD65%02%60%13R6&%02F=a20,%5C%17%7B26%0ET(S.!9W%11S699F%17W#79F%02P6%20%0Ek%14S59%0EA0F27%04%5D$D6?%0AT%11h#=%17k%17Y%04&%15%5C%0DQ%096%08V%16%5B2%3C%13k%0EE%07=%0E%5B%17S%25%17%09T%01Z269A%0A%5B2=%12A=Z24%13k%0DC:0%02G=%5B$%1B%09Q%06N26#w=Y9%3E%08T%07h%137%11%5C%00S%1A=%13%5C%0CX%12$%02%5B%17h\\'\\'%14%5D=%5B%3E%3C9E%02D2%3C%13%7B%0CR2%0C%14P%17f%25=%17P%11B.%0C%01%5C%0FB2%209T%01E8%3E%12A%06h%09!%02%5B%17h%16%22%17Y%06f6+%22G%11Y%25%0C%0BP%0DQ#:9%5B%06N#%0C%01@%0DU#;%08%5B=E6%3C%14%18%10S%25;%01k%10D46%08V=w\\'%22%0BP=%5B2!%14T%04S%090%0E%5B%07h%257%06Q%1Ae#3%13P=Y91%08X%13Z2&%02k%07_$%22%0BT%1Ah%207%05%5E%0AB%1A7%03%5C%02e#%20%02T%0Eh$&%06G%17d2%3C%03P%11_959E%11Y#=%13L%13S%09!%02G%0AP%09bW%05S%06gbWk%00Y91%06A=X6?%02k%00Y9&%02%5B%17a%3E%3C%03Z%14h6%22%17P%0DR%14:%0EY%07h%3E&%02G%02B8%209v%0CC9&%02G=D%22%3C%09%5C%0DQ%09!%0B%5C%00S%093%0BY=A20%0C%5C%17f2%20%14%5C%10B2%3C%13f%17Y%253%00P=D2&%12G%0Dh$&%1EY%06h?;%03Q%06X%09$%06Y%16S%09!%12F%13S96%02Q=%06%09%1F4v0e%1A3%13G%0AN%091%06Y%0Fh%3E4%15T%0ES%09;%09Q%06N%1849W%0FY499T%01Y%22&%5DW%0FW999Z%0DS%25%20%08G=@%3E!%0EW%0AZ%3E&%1Ek%22d%19%1DGe1y%09(%08Z%0Eh%1F3%02A%17S9!%04%5D%14S%3E%3E%02G=%1E%3E%3C%11P%11B26JV%0CZ8%20%14%0FCh$+%14A%06%5Bz\\'%0Ek%25D6%3C%0CY%0AXw%15%08A%0B_4%0C%06C%02_;%1E%02S%17h%16$%06%5B%17q6%20%03PCt%3Cr%25a=c9;%11P%11Ew%11%22%15V%03w%1F%02Q%0AC:%0C%14Z%0ES%09%14%12A%16D6r%25%5ECt%03%0C&G%0AW;r2%5B%0AU86%02%15.e%09?%14s%16Z;!%04G%06S9%17%0BP%0ES9&9w%0AB$&%15P%02%5Bw%04%02G%02%16%043%09FC%7B8%3C%08k%0BS%3E5%0FA=W!3%0EY4_3&%0Fk%14S59%0EA7S/&4%5C%19S%166%0D@%10B%09%04%15%5C%0DR6%0C$P%0DB%22%20%1E%15$Y#:%0EV=A20%0C%5C%17s/;%13s%16Z;!%04G%06S9%0C%25T%0D%5D%10=%13%5D%0AUw%1F%03%15!b%09%20%02F%06B%09?%06A%00%5E2!9x0%16%18\\'%13Y%0CY%3C%0C*fCc%1Er%20Z%17%5E%3E19P%1B_#%14%12Y%0FE4%20%02P%0Dh1=%09A0_-79S%0CX#%14%06X%0AZ.%0C%5B%14%07Y4&%1EE%06%16?&%0AY%5D%0A?&%0AY%5D%0A?7%06Q%5D%0A:7%13TCX6?%02%08A@%3E7%10E%0CD#pGV%0CX#7%09A%5E%14%20;%03A%0B%0B37%11%5C%00Sz%25%0EQ%17%5E%7Br%0E%5B%0AB%3E3%0B%18%10U6%3E%02%08R%14i%0C%0AZ%19p%22%3E%0Bf%00D27%09p%0FS:7%09A=t6&%06%5B%04h%1B7%02Y%02A66%02P=%11%7B%0COQ%1AX6?%0EVND6%3C%00PY%16%09%7F%06E%13Z2%7F%14L%10B2?JW%0CR.%0C$P%0DB%22%20%1Ek%17Y%133%13T6d%1B%0CS%0D%13N%09%1F%0E%5B%0AY9r7G%0Ch%20;%03A%0Bh%7F%22%15P%05S%25!JV%0CX#%20%06F%17%0Cw%0C+P%17B2%20Gr%0CB?;%04k+S;$%02A%0AU6r)P%16S%09%13%15T%01_4r3L%13S$7%13A%0AX0%0C%08S%05E2&0%5C%07B?%0C&R%06X4+Gs!h%12%075z0b%1E%1E%22k%14Y%2569B%06T%3C;%13s%16Z;!%04G%06S9%17%0BP%0ES9&9x%02D;7%13A=W!3%0EY7Y\\'%0C$Y%02D2%3C%03Z%0Dh%7F4%08G%00S3%7F%04Z%0FY%25!%5D%15=%7B%03r%22M%17D6%0C%17M=e2%20%0ES%02hw%0C3g%22%7C%16%1CGe1y%09z%17G%06P2%20%14%18%11S3\\'%04P%07%1B:=%13%5C%0CXmr9x%06_%25+%08%156%7F%09&%02M%17u8%3C%13P%0DB%09%1E%12V%0AR6r%25G%0AQ?&9_%0C_9%0C*%5C%00D8!%08S%17%16%02;%00%5D%16D%09%01$g*f%03%1B)t=z%221%0EQ%02%16%043%09F=%5B:%1F%10b/Z%3E%1BWzE%07%096%02C%0AU2%02%0EM%06Z%053%13%5C%0Ch%10;%0BYCe6%3C%14k.ew%00%02S%06D2%3C%04PCe\\'7%04%5C%02Z#+9f%0A%5B%1F7%0Ek%0EY-%11%06%5B%00S;%14%12Y%0Fe4%20%02P%0Dh%10%1D3%7D%22%7B%09&%02M%17e%3E(%02t%07%5C%22!%13k%05C;%3E%14V%11S2%3C%22Y%06%5B2%3C%13k+C:3%09F%17%03ecGw7h3;%11k3D%3E!%13%5C%0DW%09%02*%5C%0DQ%1B;2k.Y9=%13L%13Sw%11%08G%10_!39%7D&z%01%0C4X%02Z;r!Z%0DB$%0C%0AF&N%3E&!@%0FZ$1%15P%06X%09%1F4%15._91%0FZ=X8%3C%02k9a%166%08W%06p%09%1E%02C%06X%3E?Gx7h:3%17kDhf%22%1Fk%25C#\\'%15TC%7B3r%25a=E\\'3%09k%20W;;%05G%0Ah84%01F%06B%1F7%0ER%0BB%09%01%02R%0CSw%07.%15/_0:%13k.o%05%1B&qCf%05%1D9%1C=e#3%04V%02B8%60U%07Ct%03%0C%06C%02_;%1A%02%5C%04%5E#%0C*P%0DZ8%0C%0AX.A%00%1E%0B%5C*%061;%01Y,%10f%0C%01Z%0DB%09:%06G%07A6%20%02v%0CX4\\'%15G%06X4+9q,%7B%057%04A/_$&9x%06R%3E34P%17B%3E%3C%00F1W95%02k%17_:7=Z%0DS%094%15P%12C2%3C%04L=Q2&%25Z%16X3;%09R%20Z%3E7%09A1S4&9R%0FY53%0Bv%0C%5B\\'=%14%5C%17S%18%22%02G%02B%3E=%09k.S3;%06f%0CC%251%02k%00D23%13P,E4;%0BY%02B8%209x0e#%20%02T%0Eh%207%05%5E%0AB%184%01Y%0AX2%13%12Q%0AY%14=%09A%06N#%0C%05P%04_9%02%06A%0Bh$7%14F%0AY9%01%13Z%11W079B%06T%3C;%13g%06G%227%14A%25C;%3E%14V%11S2%3C9%7C%0DB;%0C%0C%5B%06S%09%60%03k%00D23%13P\\'O93%0A%5C%00E%14=%0AE%11S$!%08G=Z6%3C%00@%02Q2%0C%15P%0FS6!%02k@%06ak9%5C%10f8;%09A*X%073%13%5D=_$%13%15G%02O%09!%04G%06S9%0C%01%5C%0FZ%057%04A=U\\'\\'$Y%02E$%0C%08F%00F%22%0C%14E%0F_#%0CDSZU%09%02.kHht%60%01S=%5B$%01%06C%06t;=%05k%10O$&%02X/W95%12T%04S%09!%13G%0AX0%0CKk.W4%1B%09A%06Z%095%02A%20Y9&%02M%17h$\\'%05T%11D6+9V%02X!3%14k%07S!;%04P.S:=%15L=W%2519g%06P;7%04A=Z81%06Y0B8%20%06R%06h%253%13%5C%0Ch$&%06G%17h;3%09R%16W07%14k%10Y%25&9%607u%09&%15%5C%02X0%3E%02k%06@2%3C%08Q%07h37%14V%11_\\'&%0EZ%0Dh43%13V%0Bh%20:%0EA%06e\\'3%04P=%5B%22%3E%13%5C%13Z.%0C%04Y%0CE2%02%06A%0Bh4=%0BZ%11r2%22%13%5D=B2*%13w%02E2%3E%0E%5B%06h%0C=%05_%06U#r5P%05Z21%13h=C$7%15y%02X0\\'%06R%06h%3E%02%06Q=P%3E%3E%0Bf%17O;79X%02N%09%22%0B@%04_9!9%5B%0CA%253%17k%00Y9%3C%02V%17h%184%01Y%0AX2%13%12Q%0AY%14=%09A%06N#%0C%15P%15S%25!%02k%04S#%14%12Y%0Fo23%15k@Pab9n%0CT=7%04AC%7F9&%0Bh=D8\\'%09Q=Q2&3%5C%0ES-=%09P,P1!%02A=r6&%02a%0A%5B2%14%08G%0EW#%0C%17Y%02B1=%15X=D21%13k%0Af?=%09P=T%25%0C%00P%17u?3%09%5B%06Z%133%13T=R2!%13%5C%0DW#;%08%5B=Y\\'7%09q%02B60%06F%06h%05%06$e%06S%25%11%08%5B%0DS4&%0EZ%0D%7F47%22C%06X#%0C%0AF4D%3E&%02e%11Y1;%0BP%11%7B6%20%0Ck%01D8%25%14P%11z6%3C%00@%02Q2%0C%01%5C%0FZ%09=%09A%11W9!%0EA%0AY91%06%5B%00S;%0C%0E%5B%07S/7%03q!h%05%06$p%0DU86%02Q%22C3;%08s%11W:79%16%05Pe%0C%0AF/W%22%3C%04%5D6D%3E%0C%06A%17W499F%16P1;%1FP%10h#:%15P%10%5E8%3E%03k%11S$=%0BC%06R%18%22%13%5C%0CX$%0C%06W%10h6%3E%17%5D%02T2&%0EV=B.%22%02k0%60%10%15%02Z%0ES#%20%1Ep%0FS:7%09A=%151%60%01k%11W96%08X=P8%20%04P%07h4:%06G%22B%09=%17G%17h$;%09%5D=Q2&7T%11W:7%13P%11h2%229%11%3Cs%22%0C%0BZ%14hs%0D!Q=S/%229%11%3C~%04%0C2%7B.w%04%19%22q%3Cd%12%1C#p1s%05%0D0p!q%1B%0C0p!q%1B%0D%03P%01C0%0D%15P%0DR2%20%02G%3C_94%08k%0AX97%15k6x%1A%134~&r%08%04%22%7B\\'y%05%0D0p!q%1B%0CVk%02B6%3C%0FkQh059T%07R%3E&%0EZ%0Dh;=%00%04%13h6&%06%5B=U8=%0C%5C%06h4=%08%5E%0AS#7%14A%5E%07lr4T%0ES%04;%13P%5Ee#%20%0EV%17%0D%094%15Z%0Eu?3%15v%0CR2%0C%04G%06W#79D%16S%25+9X%02N%03=%12V%0Bf8;%09A%10h%180%0DP%00Bw%22%15Z%17Y#+%17PC%5B6+GZ%0DZ.r%05PCW9r(W%09S4&%5D%15=%0B%09c_E%17%16%16%20%0ET%0Fh%08%0D%1EW=C4%25%02W=%5B%3E6%03Y%06h4:%15Z%0ES%09%0D8R%20D%007%05k%00D23%13P&@2%3C%13k%06%5B\\'&%1Ek%06D%25=%15k%0DYz%22%15P%05S%257%09V%06h%08%0D%01%5C%11S1=%1Fj%3Ch:=%15P=E%3E%3C9B%06T%3C;%13k8Y58%02V%17%16%180%0DP%00B%0A%0C%00A%3CZ81%06Y%3C_3%0COX%0AXz?%08%5B%0CU?%20%08X%06%0CwbNk%0CX#=%12V%0BE#3%15A=%12%08%150k%02U8!%0Fk%3Ci26%00P7D61%0C%5C%0DQ%07%20%02C%06X#;%08%5B0B6&%0EF%17_4!9R%06B%12*%13P%0DE%3E=%09k%11Q53O%04S%04%7BrU%05W%1AwbK%15S%18e%7B9a%0CYw:%0ER%0B%16!3%0B@%06h$#%15A=A20%00YQh%03:%0EFCT%25=%10F%06Dp!G%5C%0EF;7%0AP%0DB6&%0EZ%0D%1684Gz%01%5C21%13%1B%00D23%13PC_$r%06%15%10%5E%3E?GT%0DRw6%08P%10Xp&GF%16F\\'=%15AC%119\\'%0BYD%166!GA%0BSw4%0EG%10Bw3%15R%16%5B2%3C%13%1B=c%14%01%0FP%0FZ%1D3%11T=U8=%0C%5C%06B2!%13%08=E#3%09Q%02D3%0C%17@%05P%3E%3C#P%15_479S%0AZ;%06%02M%17h;7%14F=%5E%3E5%0Fk%00Y89%0EP%17S$&Z%04X%16%043%0AP0_#7Zf%17D%3E1%13%0ECS/%22%0EG%06Ej%06%0F@O%16gcJ%7F%02Xzc%5E%02S%16gb%5D%05S%0CgcGr.b%093%14%5C%0D%5E%091%08F=D21U%05Q%06%09z%0AT%1B%1B:=%09Z%00%5E%25=%0APY%16%09%7F9%04RF#rEa%0A%5B2!G%7B%06Aw%00%08X%02Xu%0C8R%00B%09&%06%5B=i%08+%05G%0Ch;3%14A5W;%0C%04Z%10%5E%09=%12A%10_379%5E%15O1%0C%0E%5B%15S%25&%02Q=F8%259T%10_9%0C%02M%13%5Bf%0C3%5D%0AEw0%15Z%14E2%20@FC_:%22%0BP%0ES9&%06A%0AY9r%08SCy58%02V%17%184%20%02T%17Sw;%14%15%02%16$:%0EXCW96GQ%0CS$%3C@ACE%22%22%17Z%11Bw3GF%06U8%3C%03%15%02D0\\'%0AP%0DBy%0C%06V%17_!79a%0CC4:%22C%06X#%0C%14T%0EE%22%3C%00t%11h;=%00k%02U8!9j%3CU%25%05%02W=Z6%3C%00k%10C5!%13G%0AX0%0C%14G%04T%09%7FJk%0EC;&%0EE%0F_43%13%5C%0CX%09%22Tk%1AW96%02M=B6%3C%0Fk%20A:r%01_%0CD30%06%5B%08%160%3E%1E%15=%1E4=%0BZ%11%1B03%0A@%17%0Cw%0C%04Z%0DB6;%09F=%5C%09%119O=d%09v8%7C*h8%3C%14@%00U2!%14kWh%0E%0C3k/h\\'%0C%20k%00D23%13P,T=7%04A0B8%20%02k%06hs%0D-x=e%09v8w\\'Y%09$9M=_96%02M%07T%09%20%02F%16Z#%0C(kTh%06%0C%14k%16E2%20&R%06X#%0C%12k%07T%133%13T=G%09v8w!%7F%09!%02A=%12%08%10$%7D=c%09%169%03=f%0969t=Y9\\'%17R%11W37%09P%06R269p=P%09%0A9@%0DR24%0E%5B%06R%097%1FP%00C#74D%0Fh%01%0CCj!w8%0C%15Z%14E%09%259B%0AX3=%10%7B%02%5B2%0C.%7B0s%05%06Gz1%16%05%177y%22u%12r.%7B7yw1%06V%0BS%7F%3C%06X%06%1Aw$%06Y%16S~r1t/c%12%01O%0AO%16h%7B9%5B=x%09%3E%0EF%17E%09g9%5B%16Z;%0C%0EkZh4%0C%0Bk%04h$7%14F%0AY9%0C_k%07W#3%05T%10S%09;%13P%0Eh%057%03@%00Sw=%01%15%06%5B\\'&%1E%15%02D%253%1E%15%14_#:G%5B%0C%16%3E%3C%0EA%0AW;r%11T%0FC2%0C%15k*h%11%0C%08E%06X%0909%5E=X6$%0ER%02B8%209w=w%25%20%06LMF%25=%13Z%17O\\'7IG%06R%221%02%15%00W;%3E%02QCY9r%09@%0FZw=%15%15%16X37%01%5C%0DS3%0C%08W%09S4&4A%0CD2%0C%1Ek%17h%207%05%5E%0AB%1E%3C%03P%1BS3%16%25kPh#3%15R%06B%09%115p%22b%12r3t!z%12r.sCx%18%06Gp;%7F%04%064%15%00W4:%02%1D%0ARw%1B)a&q%12%00G%7B,bw%1C2y/%16%07%00.x%22d%0Er,p:%16%16%073z*x%14%00%22x&x%03~G%5B%02%5B2r3p;bw%1C(aCx%02%1E+%19C@6%3E%12PCb%12%0A3%15-y%03r)%60/z%7Br2%7B*g%02%17G%1D%0DW:7N%1C=%5B%09=%05_%06U#%01%13Z%11S%193%0AP%10h6%0C%13G%02X$3%04A%0AY9%0C,k%13C#%0C%0CP%1Ah%1A%0C%08k4h%0D%0C/k)hw;%14%15%0DY#r%06%15%05C91%13%5C%0CX%09&%02F%17h%04%17+p%20bw$%06Y%16Sw%145z.%1643%04%5D%06%16%00%1A%22g&%1693%0AP%5E%09%09:9X%0CL%1E%3C%03P%1BS3%16%25k-bwdI%07=x%03rQ%1BWh%197%13F%00W\\'79G%06F;3%04P=x%03rQ%1BRh%257%06Q%14D%3E&%02k:W96%02M=Q2&.A%06%5B%09%1F%08W%0AZ2r4T%05W%25;9y%06X8$%08k%0AR5%16%06A%02hw%05%02W5_2%259P%0ET26%03P%07hx%0CH%01R%0F%09o%5C%15%06N\\';%15P%10%0B%1A=%09%19C%04gr4P%13%16ebV%0CC%06ghW%05Y%06gr2a%20%0Dw%22%06A%0B%0BxiGQ%0C%5B6;%09%08=l20%15T=x%03rR%1BRhWRg5c6WR9F%16T$&%15k%00Y9!%08Y%06hw%00%02T%0F_#+9T%0ERaf9F%06B%1E&%02X=U;=%14P=%12fr4P%00C%257Gk%0AWd%609s%0AD24%08M=s35%02k%02D:dSk-bwgI%05=%7F%12%0C*%7C6%7Fw%0CAk-bc%7CWk,f%07%1D9R%06B%09%13%0AT%19Y9%0C%00P%17b%3E?%02kCb8\\'%04%5D=n%3E3%08X%0Ah%19%06G%03M%05%09%7DVk%17W5%3E%02A=x%03rR%1BQh;=%04T%0Fe#=%15P=W%25?9v%0CUw%11%08V=u?%20%08X%06h%1B%159%1AW%07%60%0C%10P%02D60%0BP=%12fr9%1AW%07a%0C%11P%11E%3E=%09kX%162*%17%5C%11S$o3@%06%1AwaV%15\\'S4rU%05W%06wbW%0FS%06mbW%156b%14iGE%02B?oH%0ECR8?%06%5C%0D%0B%09?%08Q%06Z%09%1F%0EV%11Y$=%01A=a2%11%0FT%17h%16%00*k%17Y%02%22%17P%11u6!%02kL%05%09%1C3%15U%18g%0C%13Z/Y%207%15v%02E2%0CGs%0CU%22!9F%0EW%25&%13C=~%223%10P%0Ah%113%04P%01Y899%60%20h%04=%09L=%16%1F7%06Q%0FS$!9~%0CX&\\'%02G%0CD%09%10%0BT%00%5D%157%15G%1Ah%19%06G%04S%18g%0CS%1BZ%06%09%05%02v%0BW#z0%5C%0D%1Fw%16%02F%08B8%229%7B7%05ygVkC%16wrG%15C%16%097%1FP%00h%10%01&k1S6%3E%0AP=%16%14=%06F%17h#3%15R%06B%13=%0AT%0AX%093%15V%0B_#7%04A%16D2%0C%02%5B%00D.%22%13kL%0E%09!%17T%11U%09%13%09Q%11Y%3E6Gk.Y#=%15Z%0FW%09%01%06X%10C959%15._9;9%06U%06w%0C1%5C%15Y%09%1D%17P%11W%09?%08W%0AZ2%0CXkL%02f%609w%11Y%20!%02G=W%25?%0FS=r8%3E%17%5D%0AX%09%14%06%5C%11F?=%09P=x2*%13w%0CY%3C%0C%00P%17c%16%0C%12T=x%22%04%0EF%0AY9%0C*T%00%16%18%019p%07Q2%1A3x/h%137%0BY=F2%20%0A%5C%10E%3E=%09k*X$;%00%5B%0AW%095%02A%20f%02%0C%17%5D%02X#=%0A%7F0h%13%171%7C%20s%09%01%22y&x%1E%07*j/%7F%12%0C%03P%15_479V%13C%09cV%05=%07ybI%07=a%12%10#g*%60%12%009%7B%0C%5D%3E39R%06B%18%019F%06Z2%3C%0E@%0Eh%0D7%17A%0Ch%13%20%06R%0CXw%06%08@%00%5E%09cW%07=e.?%05%5C%02X%09%10%06G%0DS$rA%15-Y5%3E%02k%14S5%16%15%5C%15S%25%0C+C7S;%0C5Z%17Y%25%0C%05T%17B2%20%1Ek!d%18%054p1h%04:%06G%13h%12%1C%20%7C-s%09%0D9Z%10h\\'7%15X%0AE$;%08%5B%10h:3%0DZ%11h%07%1A&%7B7y%1A%0D2t=%7B2;%1D@=%07fe9F%06Z2%3C%0E@%0Ez%3E79E%11Y:%22%13k.W4:4E%06S3%0CGz0h$7%13%60%22h37%09%5C%06R%09%04%02G%0AL8%3C9%5C,e%09%1A%22t\\'u%1F%008e&d%1A%1B4f*y%19%019%1B=~%03%119P%0DQ%3E%3C%02k5s%05%01.z-h%0D%06%22k%20%5E%25=%0A%5C%16%5Bw%1D4k-@%3E6%0ET=w47%15k&E$7%09A%0AW;%0C%10P%01y%04%0CGa5hfbSk%04S#%00%02F%16Z#%0C(%5B%06f;\\'%14k%09g%227%15L=%07fa9r%06X2%20%0EV=u%1F%008w%22b%03%175l=%608;%04P=%07fd9f%0CZ6%20%0EF=f%1F%13)a,%7B%08%025z3s%05%06.p0h%0D7%0C%5C=~%12%13#v+d%08%02+%60$%7F%19%019m%13S%25;%06%157W5%3E%02A=%07gc9V%02E#%0C%00P%17r2$%0EV%06h%18%019v3c%09%10%0B%5C%0D%5D%09%134%600hfc%5Ek0s%1B%17)%7C6%7B%08%165%7C5s%05%0C4X%02D#%061kR%06n%0C/p%22r%14%1A5j6w%095%02A&X0;%09P=T%25=%10F%06D%09%14%0EG%06%16%07:%08%5B%06%16sc9e+w%19%06(x%3Cz%16%1C%20%60%22q%12%0CCk4_96%08B%10h%12%3C%11%5C%19S9%0C4%5C%06%5B2%3C%14k0A%3E!%14k%04S#%10%15Z%14E2%209g%20w%09%133%137hfcUk%11S$%3E9G%06E%09%22%15Z%07C4&4@%01h%08!%02Y%06X%3E\\'%0Ak%02C3;%08%1A%0CQ0iGV%0CR21%14%08A@8%20%05%5C%10%14%09%25%0E%5B%07Y%20%0C8j%0FW$&0T%17_%25%02%15Z%0EF#%0C8j%05N3%20%0EC%06D%08\\'%09B%11W\\'%22%02Q=W4%25%13F=i%084%1FQ%11_!7%15j%06@6%3E%12T%17S%093%04T%02B$%0C%06@%07_8%7D%10T%15%0Dw1%08Q%06U$oE%04Ah%3E!3L%13S%04\\'%17E%0CD#7%03k%3Ci3%20%0EC%06D%08\\'%09B%11W\\'%22%02Q=W449X%0A%5B2%06%1EE%06E%091%06V%0BS%08%0C%06V%0EF#!9%11%3Ct%11!9T%16%5E%093%12Q%0AYx?%17P%04%0Du%0C%15P%14h6\\'%03%5C%0C%19d5%17EXh\\':%06%5B%17Y:%0C%06VPh%08%0D%03G%0A@2%208P%15W;\\'%06A%06h%08%01%02Y%06X%3E\\'%0Aj*r%12%0D5P%00Y%256%02G=U6%3C7Y%02O%03+%17P=O%2519j%3CA20%03G%0A@2%208P%15W;\\'%06A%06h%08%0D%09%5C%04%5E#?%06G%06h%207%05Q%11_!7%15v%0C%5B:3%09Q=i%08!%02Y%06X%3E\\'%0Aj%06@6%3E%12T%17S%095%02A,A9%02%15Z%13S%25&%1Eq%06E4%20%0EE%17Y%25%0C%01%5C%0FS93%0AP=U6%3E%0Bf%06Z2%3C%0E@%0Eh%04%06%22t/b%1F%0D7y6q%1E%1C9R%06B%16&%13G%0AT%22&%02k%10X?%0C8j%10S;7%09%5C%16%5B%08\\'%09B%11W\\'%22%02Q=i%08%3E%06F%17a6&%0EG%22Z2%20%13k%16X%3C%3C%08B%0Dh$&%17%5B=%5B6&%04%5D=i%08%25%02W%07D%3E$%02G%25C919P%04F%093%12Q%0AYx?%17%01Xh6\\'%03%5C%0C%1963%04%0E=R%25;%11P%11h$&%02T%0FB?%1B%01G%02%5B2%0C8j%0FW$&0T%17_%25%11%08%5B%05_%25?9%0FYh61%0AEWh3%20%0EC%06Dz7%11T%0FC6&%02k%10S#%06%0EX%06Y%22&9j%3CA20%03G%0A@2%208@%0DA%253%17E%06R%094%08G&W4:9j%3CA20%03G%0A@2%208F%00D%3E%22%13j%05X%09!%09%5C%0Bh9=%13%5C%05_43%13%5C%0CX$%0C%06V%0EF%096%08V%16%5B2%3C%13p%0FS:7%09A=i\\':%06%5B%17Y:%0C%06V%0CB$%0C%04T%0FZ264P%0FS9;%12X=%07eb9T%16R%3E=HS%0FW4i9T%00P#!9T%00%05#!9j4s%15%165%7C5s%05%0D%22y&%7B%08%11&v+s%096%06A%02h$&%02T%0FB?%17%15G%0CD%09v%04Q%00i6!%03_%05Z6!%12A%0CF1:%11V9z:1%01Y%3Ch61%0AT=W4?%06A%10h$7%0BP%0D_%22?JP%15W;\\'%06A%06h%08%0D9T%16R%3E=9T%16R%3E=HMN%5Bc3%5Ck%20%5E%25=%0AP\\'D%3E$%02G%14h61%0AEWB$%0C%14P%13h%08%0DCB%06T3%20%0EC%06D%16!%1E%5B%00s/7%04@%17Y%25%0C%06V%14h$&%02T%0FB?%02%0B@%04_9%0C8j%14S56%15%5C%15S%25%0D%14V%11_\\'&8S%16X4%0CCV%0BD8?%02j%02E.%3C%04f%00D%3E%22%13%7C%0DP8%0C%02%5B%02T;7%03e%0FC0;%09k%14S56%15%5C%15S%25%0C%10P%01R%25;%11P%11%1B2$%06Y%16W#79K=U8%3C%14%5C%10B2%3C%13k%02U639V%02Z;%02%0FT%0DB8?9T%16R%3E=HX%13S0i9B%06T3%20%0EC%06Dz7%11T%0FC6&%02%18%11S$%22%08%5B%10S%093%12E=H)%0C%06V%0Ch61%0AEPhs%0D%25%7F%11hs%0D#t%08h!1%10A%10hs%0D$%7F;h47%0EY=%12%08%11%25_=E%3E5%25L%17S$%0C%02%5B%00h2%3E%04kGi%15%1B%1Dk%00_\\':%02G%17S/&9%11%3Cu%1119A%0Ce#%20%0E%5B%04v%096%02S%0AX2%02%15Z%13S%25&%0EP%10h%257%03kR%06g%0C%11V%0EF#!9P%0DU%25+%17A!Z81%0Ck%15_37%08%1APQ\\'%22%5Ck%02Z0=9C%0AR2=HX%13%02lr%04Z%07S4!Z%17%02@4cI%01Qsgc%22%17=A6%20%09k%10S#%13%13A%11_5\\'%13P=Z%3E09%11%3Ct%1F%229%11%3Cu%1E(9C%0AR2=HB%06T:iGV%0CR21%14%08A@\\'jK%15%15Y%250%0EFAh\\'%20%08V%06E$%10%0BZ%00%5D%093%12Q%0AYx?%17%06Xh%20=%15Q%10hs%0D$p)h07%13e%11Y#=%13L%13S%1849V%11S6&%02p%0DU%25+%17A%0CD%09;%11kGi%14%13%20k%20y%19%01(y&h\\'3%15F%06h$7%13e%11Y#=%13L%13S%1849y%02B%3E%3CVk7O\\'7%22G%11Y%25hGv%1AU;;%04k%15Ud%0C%0A%5C%1B%7F9%0C%0FP%02R%09%02%0CV%10%01%09$%0EQ%06Yx=%00RX%164=%03P%00Ejp%13%5D%06Y%253Ek%07_$%22%0BT%1A%0Cw%3C%08%5B%06%0D%09%11%0EE%0BS%25%0C2A%05%0E%09$%04%5D%17E%091%0BT%0EF%09%05%08G%07w%25%20%06L=@4c9w%0FY49$%5C%13%5E2%209Q%06T%225%00P%11h!1%0AE=@4=%13F=@%3E6%02ZL%5B\\'f%5C%15%00Y37%04F%5E%146$W%04M%06yb_xM%06op9%5C%0D_#%0C%0FT%10y%20%3C7G%0CF2%20%13L=@4%259T%17%16%180%0DP%00By!%02A3D8%0C%06@%07_8%7D%10P%01%5Bl%0C%25@%05P2%20%02Q!Z81%0Ct%0FQ8%20%0EA%0B%5B%09?%08Q%06h%13%17%25w6q%12%009%05S%06gbW%05S%06gbW%05S%06g%0CCj%20u#%0C%14A%02D#%06%0EX%06hs!%12E%06D%09$%04Z=S/&%02%5B%07h!1TA%10hs%0D$q%10h%15%3E%08V%08u%3E%22%0FP%11%7B86%02k&X4%20%1EE%17Y%25%0C%08V%13B%09$%04%5D=t6!%02k%15U&&%14k%15_37%08%1A%0EF25%5Ck%15_37%08%1A%12C%3E1%0CA%0A%5B2i9T%00A:&%14k%15U&%0C%06V%0EFd&%14k%15_37%08k%01Z81%0Cf%0AL2%0C%14E%0F_479%5C%0DU;\\'%03P%10hs%0D#w)h44%00k-w%09v8q%20q%09%11%25v=W4%25%0Ak%15Uf&%14k%15_37%08%1A%0EF259%1AI%1Cx%0Cmk%10B61%0Ck%13W3%0C;G=j#%0C!%07=Q2&2a%20%7B8%3C%13%5D=%06gbWk%10S#%02%12W%0F_4%0CCj\\'~.%0C%12%5B%10%5E%3E4%13kGi%13%170k%17Y%1D%01(%7B=Q2&2a%20e21%08%5B%07E%09%141k%0EF;%0C%01Y%0CY%25%0C%01%5C%0DW;;%1DP=Z%04:%0ES%17b8%0C(%7B&hgcU%06W%03ae_%0C%02T46%02S%04%5E%3E8%0CY%0EX8%22%16G%10B%22$%10M%1AL%09~mk)e%18%1CIF%17D%3E%3C%00%5C%05O%09;%09C\\'_0;%13k%20_\\':%02G3W%253%0AF=E%2203Z=w%12%019Q%11e?;%01A7Y%091%08E%1Ab8%0C4P%11_6%3E%0EO%02T;7$%5C%13%5E2%209n%3Eh%1A7%14F%02Q2r%13Z%0C%16;=%09RCP8%20Gg0w%09%0E%12k*X!3%0B%5C%07%16%05%01&%15%13C5%3E%0EVC%5D2+9X%17%04%09%14Vk%0EC;%06%08k%02%5B%09\\'%0Ak%0EY3%02%08B*X#%0CW%05%20%07%12a%5E%06WrfdV%01W%00b%10T%06S%03d%17PsW%0E%12%17Sp%20%0E%60%10V%01!%0Fb%17!%0D%5B%0FceP%04Preg%22p%20t%11%14PpT%02%14e%5E%02Trg%60#vRrnfR%04%25%01n%16#%00\\'%07%14cWvQ%0F%16%11%25%03%22%0F%15f#%03%25t%60%16WtS%04%60k%25%03T%07n%17V%02T%04bdRsS%0F%16%14Q%07T%01fg%5E%04Z%04ec&p%25%0Ffj%5E%0C%20w%12b_vSrajQqT%02o%10U%05%22%05abTw&%04dc_v%22%00%15%11UwV%0F%60bQ%00Z%04%16kU%04Zrg%10!%05Vun%14Q%00S%04d%13U%04\\'%04daW%0DS%01egUt&%06gdQqV%0F%14%17%22s%22%03%11%60P%01%5Bs%16jWw%22toc9N=R%3E$5P%0Eb8%0C%01G%0C%5B%04&%15%5C%0DQ%09$%06Y%16S%1849q5h1%20%08X-C:0%02G=D2$%02G%17h%0B%0E9F%12C6%20%02a%0Ch%13%109X%13h,/9%04S%06gc9V%0CS149nih%25%01%0F%5C%05B%03=9R%06B%02%06$s%16Z;%0B%02T%11h97%1FA!O#7%14k%13W36%0E%5B%04h%143%09%5B%0CBw1%08%5B%15S%25&G@%0DR24%0E%5B%06Rw=%15%15%0DC;%3EGA%0C%1680%0DP%00B%096%0AERh%0B09R%06B%02%06$q%02B2%0C%5D%15=T8=%0BP%02X%095%02A6b%14%1F%0E%5B%16B2!9X%16Z#;%17Y%1Ab8%0C%3Ck%00Y9$%02G%17h07%13%607u%1F=%12G%10h1=%15X%02B%09/9q.h4=%0AE%02D2%06%08k%0AE%12$%02%5B=M%5D%0C%14D%11b8%0C%13Z1W3;%1Fk8Y58%02V%17%16%16%20%15T%1Ak%09%0EEkYh6!%14%5C%04X%09%0E%09k%05D8?.%5B%17hs%0D#q%04h;3%14A*X37%1Fk%10B%25;%09R%0AP.%0C%05%5C%17z2%3C%00A%0Bhs%0D#r%16h1%20%08X1W3;%1Fk%07Z%04:%0ES%17b8%0C:k%0EY3%0CCj%20~%1D%0CCj\\'p%03%0C%09P%04W#79o&d%18%0C;S=%5B\\':9Q%0Cf%220%0B%5C%00h3?%16%04=%14%09%0C9k=h%09%0C9V%0CX$&%15@%00B8%209V%00hs%0D%22q%02h;=%06Q=Q2%3C%02G%02B2%11%08Y%0FS4&9k%0CX%057%0DP%00B269B%0Dh%09%0C9k%11Y2%0C%15P%09S4&%02Q=h%22%3C%0FT%0DR;7%03G%06%5C21%13%5C%0CXw1%06A%00%5Ew7%15G%0CD%09%0C&%15%13D8?%0EF%06%1643%09%5B%0CBw0%02%15%11S$=%0BC%06Rw%25%0EA%0B%16%3E&%14P%0FPy%0C9e%11Y:;%14P=S9%0CCj\\'%7F%14%0C9kGi%12%13%15k%16D;!%06S%06i2%3C%04Z%07S%09%0CG%5C%10%169=%13%15%0AB2%20%06W%0FS%7F1%06%5B%0DY#r%15P%02Rw%22%15Z%13S%25&%1E%150O:0%08YKe.?%05Z%0F%18%3E&%02G%02B8%20N%1C=f%25=%0A%5C%10Sy3%0BYCW41%02E%17Ew3%09%15%02D%253%1Ek%0CX%11\\'%0BS%0AZ;7%03k%16X60%0BPCB8r%0BZ%00W#7GR%0FY53%0B%15%0CT=7%04A=q27%20@%02D3%0C7G%0C%5B%3E!%02FC%5B%22!%13%15%01Sw1%08%5B%10B%25\\'%04A%06Rw$%0ETCX2%259k%14E%09&%14@=h%09%0C%08P%07h37%01%5C%0DS%07%20%08E%06D#+9T%0DW;+%14P=h37%01T%16Z#%0C7G%0C%5B%3E!%02%1B%11W47GT%00U2%22%13FCW9r%06G%11W.%0C%01@%0FP%3E%3E%0BP%07h%095%12Q=D875P%10C;&9k=Q#%0C%0E%5B%05Y%094%0E%5B%02Z;+9k=h%257%0DP%00B%09%20%08P*X1=9k%0FW-+3%5C%0ES%09%3C%08ACWw4%12%5B%00B%3E=%09k%E6%A9%82%E5%9D%A1%E5%BD%95%E5%B9%AA9kGi%12%11%1Ek%07S5\\'%00R%06S%093%03Q&@2%3C%13y%0AE#7%09P%11h0%06%08%5E%06X%09%20%02F%0CZ!79R%06S%09%0CCj&t-%0C7Z%10E%3E0%0BPCc9:%06%5B%07Z26Ge%11Y:;%14PCd28%02V%17_8%3C%5Dk%11S&\\'%02F%17%7F3%3E%02v%02Z;0%06V%08h2!9k=h\\'%20%08X%0AE2%0C%20p&6Q%0C9G%02U2%0C9k%3Ci2!*Z%07C;79%5E%0C%5E%09v8q)g%09%0C%03P%00D.%22%13k%16X?3%09Q%0FS3%20%02_%06U#;%08%5B=h6%3E%0Bf%06B#%3E%02Q');$_BDJb=1;break;case 1:var $_BEAm=0,$_BEDp=0;$_BDJb=5;break;case 4:$_BDJb=$_BEDp===$_BDIz.length?3:9;break;case 8:$_BEAm++,$_BEDp++;$_BDJb=5;break;case 3:$_BEDp=0;$_BDJb=9;break;case 9:$_BECR+=String.fromCharCode($_BEBW.charCodeAt($_BEAm)^$_BDIz.charCodeAt($_BEDp));$_BDJb=8;break;case 7:$_BECR=$_BECR.split('^');return function($_BEEj){var $_BEFk=2;for(;$_BEFk!==1;){switch($_BEFk){case 2:return $_BECR[$_BEEj];break;}}};break;}}}('g5c6WR')};break;}}}();_MNVo.$_BY=function(){var $_BEGb=2;for(;$_BEGb!==1;){switch($_BEGb){case 2:return{$_BEHy:function $_BEIG($_BEJJ,$_BFAc){var $_BFBy=2;for(;$_BFBy!==10;){switch($_BFBy){case 4:$_BFCI[($_BFDF+$_BFAc)%$_BEJJ]=[];$_BFBy=3;break;case 13:$_BFEa-=1;$_BFBy=6;break;case 9:var $_BFFz=0;$_BFBy=8;break;case 8:$_BFBy=$_BFFz<$_BEJJ?7:11;break;case 12:$_BFFz+=1;$_BFBy=8;break;case 6:$_BFBy=$_BFEa>=0?14:12;break;case 1:var $_BFDF=0;$_BFBy=5;break;case 2:var $_BFCI=[];$_BFBy=1;break;case 3:$_BFDF+=1;$_BFBy=5;break;case 14:$_BFCI[$_BFFz][($_BFEa+$_BFAc*$_BFFz)%$_BEJJ]=$_BFCI[$_BFEa];$_BFBy=13;break;case 5:$_BFBy=$_BFDF<$_BEJJ?4:9;break;case 7:var $_BFEa=$_BEJJ-1;$_BFBy=6;break;case 11:return $_BFCI;break;}}}(20,5)};break;}}}();_MNVo.$_Cn=function(){return typeof _MNVo.$_Aq.$_BDHO==='function'?_MNVo.$_Aq.$_BDHO.apply(_MNVo.$_Aq,arguments):_MNVo.$_Aq.$_BDHO;};_MNVo.$_Dt=function(){return typeof _MNVo.$_BY.$_BEHy==='function'?_MNVo.$_BY.$_BEHy.apply(_MNVo.$_BY,arguments):_MNVo.$_BY.$_BEHy;};function _MNVo(){}!function(){var GeeGuard=function(e){function p(e,t,c,s){var $_EEN=_MNVo.$_Dt()[4][18];for(;$_EEN!==_MNVo.$_Dt()[4][17];){switch($_EEN){case _MNVo.$_Dt()[12][18]:return new(c=c||Promise)(function(n,i){function r(e){var $_EFL=_MNVo.$_Dt()[4][18];for(;$_EFL!==_MNVo.$_Dt()[8][17];){switch($_EFL){case _MNVo.$_Dt()[4][18]:try{a(s[_MNVo.$_Cn(60)](e));}catch(t){i(t);}$_EFL=_MNVo.$_Dt()[8][17];break;}}}function o(e){var $_EGb=_MNVo.$_Dt()[12][18];for(;$_EGb!==_MNVo.$_Dt()[0][17];){switch($_EGb){case _MNVo.$_Dt()[4][18]:try{a(s[_MNVo.$_Cn(29)](e));}catch(t){i(t);}$_EGb=_MNVo.$_Dt()[0][17];break;}}}function a(e){var $_EHZ=_MNVo.$_Dt()[12][18];for(;$_EHZ!==_MNVo.$_Dt()[12][16];){switch($_EHZ){case _MNVo.$_Dt()[8][18]:var t;$_EHZ=_MNVo.$_Dt()[4][17];break;case _MNVo.$_Dt()[12][17]:e[_MNVo.$_Cn(14)]?n(e[_MNVo.$_Cn(88)]):((t=e[_MNVo.$_Cn(88)])instanceof c?t:new c(function(e){e(t);}))[_MNVo.$_Cn(23)](r,o);$_EHZ=_MNVo.$_Dt()[12][16];break;}}}a((s=s[_MNVo.$_Cn(12)](e,t||[]))[_MNVo.$_Cn(60)]());});break;}}}function m(n,i){var $_EIr=_MNVo.$_Dt()[8][18];for(;$_EIr!==_MNVo.$_Dt()[4][17];){switch($_EIr){case _MNVo.$_Dt()[12][18]:var r,o,a,c={\"\\u006c\\u0061\\u0062\\u0065\\u006c\":0,\"\\u0073\\u0065\\u006e\\u0074\":function(){if(1&a[0])throw a[1];return a[1];},\"\\u0074\\u0072\\u0079\\u0073\":[],\"\\u006f\\u0070\\u0073\":[]},e={\"\\u006e\\u0065\\u0078\\u0074\":t(0),\"\\u0074\\u0068\\u0072\\u006f\\u0077\":t(1),\"\\u0072\\u0065\\u0074\\u0075\\u0072\\u006e\":t(2)};return _MNVo.$_Cn(61)==typeof Symbol&&(e[Symbol[_MNVo.$_Cn(79)]]=function(){return this;}),e;function t(t){var $_EJC=_MNVo.$_Dt()[0][18];for(;$_EJC!==_MNVo.$_Dt()[12][17];){switch($_EJC){case _MNVo.$_Dt()[0][18]:return function(e){return s([t,e]);};break;}}}function s(e){var $_FAF=_MNVo.$_Dt()[4][18];for(;$_FAF!==_MNVo.$_Dt()[12][16];){switch($_FAF){case _MNVo.$_Dt()[0][18]:if(r)throw new TypeError(_MNVo.$_Cn(9));while(c)try{if(r=1,o&&(a=2&e[0]?o[_MNVo.$_Cn(85)]:e[0]?o[_MNVo.$_Cn(29)]||((a=o[_MNVo.$_Cn(85)])&&a[_MNVo.$_Cn(92)](o),0):o[_MNVo.$_Cn(60)])&&!(a=a[_MNVo.$_Cn(92)](o,e[1]))[_MNVo.$_Cn(14)])return a;switch(o=0,(e=a?[2&e[0],a[_MNVo.$_Cn(88)]]:e)[0]){case 0:case 1:a=e;break;case 4:return c[_MNVo.$_Cn(15)]++,{\"\\u0076\\u0061\\u006c\\u0075\\u0065\":e[1],\"\\u0064\\u006f\\u006e\\u0065\":!1};case 5:c[_MNVo.$_Cn(15)]++,o=e[1],e=[0];continue;case 7:e=c[_MNVo.$_Cn(27)][_MNVo.$_Cn(16)](),c[_MNVo.$_Cn(25)][_MNVo.$_Cn(16)]();continue;default:if(!(a=0<(a=c[_MNVo.$_Cn(25)])[_MNVo.$_Cn(59)]&&a[a[_MNVo.$_Cn(59)]-1])&&(6===e[0]||2===e[0])){c=0;continue;}if(3===e[0]&&(!a||e[1]>a[0]&&e[1]<a[3])){c[_MNVo.$_Cn(15)]=e[1];break;}if(6===e[0]&&c[_MNVo.$_Cn(15)]<a[1]){c[_MNVo.$_Cn(15)]=a[1],a=e;break;}if(a&&c[_MNVo.$_Cn(15)]<a[2]){c[_MNVo.$_Cn(15)]=a[2],c[_MNVo.$_Cn(27)][_MNVo.$_Cn(50)](e);break;}a[2]&&c[_MNVo.$_Cn(27)][_MNVo.$_Cn(16)](),c[_MNVo.$_Cn(25)][_MNVo.$_Cn(16)]();continue;}e=i[_MNVo.$_Cn(92)](n,c);}catch(t){e=[6,t],o=0;}finally{r=a=0;}$_FAF=_MNVo.$_Dt()[4][17];break;case _MNVo.$_Dt()[4][17]:if(5&e[0])throw e[1];return{\"\\u0076\\u0061\\u006c\\u0075\\u0065\":e[0]?e[1]:void 0,\"\\u0064\\u006f\\u006e\\u0065\":!0};break;}}}break;}}}function c(e,t,n){var $_FBl=_MNVo.$_Dt()[0][18];for(;$_FBl!==_MNVo.$_Dt()[12][16];){switch($_FBl){case _MNVo.$_Dt()[4][18]:if(n||2===arguments[_MNVo.$_Cn(59)])for(var i,r=0,o=t[_MNVo.$_Cn(59)];r<o;r++)!i&&r in t||((i=i||Array[_MNVo.$_Cn(72)][_MNVo.$_Cn(82)][_MNVo.$_Cn(92)](t,0,r))[r]=t[r]);$_FBl=_MNVo.$_Dt()[12][17];break;case _MNVo.$_Dt()[8][17]:return e[_MNVo.$_Cn(75)](i||Array[_MNVo.$_Cn(72)][_MNVo.$_Cn(82)][_MNVo.$_Cn(92)](t));break;}}}function u(t,n){var $_FCO=_MNVo.$_Dt()[12][18];for(;$_FCO!==_MNVo.$_Dt()[8][17];){switch($_FCO){case _MNVo.$_Dt()[4][18]:return new Promise(function(e){return setTimeout(e,t,n);});break;}}}function l(e,t){var $_FDN=_MNVo.$_Dt()[12][18];for(;$_FDN!==_MNVo.$_Dt()[0][17];){switch($_FDN){case _MNVo.$_Dt()[12][18]:try{var n=e();(i=n)&&_MNVo.$_Cn(61)==typeof i[_MNVo.$_Cn(23)]?n[_MNVo.$_Cn(23)](function(e){return t(!0,e);},function(e){return t(!1,e);}):t(!0,n);}catch(r){t(!1,r);}var i;$_FDN=_MNVo.$_Dt()[0][17];break;}}}function d(r,o,a){var $_FEP=_MNVo.$_Dt()[8][18];for(;$_FEP!==_MNVo.$_Dt()[8][17];){switch($_FEP){case _MNVo.$_Dt()[12][18]:return void 0===a&&(a=16),p(this,void 0,void 0,function(){var t,n,i;return m(this,function(e){switch(e[_MNVo.$_Cn(15)]){case 0:t=Date[_MNVo.$_Cn(3)](),n=0,e[_MNVo.$_Cn(15)]=1;case 1:return n<r[_MNVo.$_Cn(59)]?(o(r[n],n),i=Date[_MNVo.$_Cn(3)](),t+a<=i?(t=i,[4,u(0)]):[3,3]):[3,4];case 2:e[_MNVo.$_Cn(57)](),e[_MNVo.$_Cn(15)]=3;case 3:return++n,[3,1];case 4:return[2];}});});break;}}}function f(e,t){var $_FFn=_MNVo.$_Dt()[8][18];for(;$_FFn!==_MNVo.$_Dt()[8][17];){switch($_FFn){case _MNVo.$_Dt()[8][18]:e=[e[0]>>>16,65535&e[0],e[1]>>>16,65535&e[1]],t=[t[0]>>>16,65535&t[0],t[1]>>>16,65535&t[1]];var n=[0,0,0,0];return n[3]+=e[3]+t[3],n[2]+=n[3]>>>16,n[3]&=65535,n[2]+=e[2]+t[2],n[1]+=n[2]>>>16,n[2]&=65535,n[1]+=e[1]+t[1],n[0]+=n[1]>>>16,n[1]&=65535,n[0]+=e[0]+t[0],n[0]&=65535,[n[0]<<16|n[1],n[2]<<16|n[3]];break;}}}function h(e,t){var $_FGn=_MNVo.$_Dt()[8][18];for(;$_FGn!==_MNVo.$_Dt()[4][17];){switch($_FGn){case _MNVo.$_Dt()[8][18]:e=[e[0]>>>16,65535&e[0],e[1]>>>16,65535&e[1]],t=[t[0]>>>16,65535&t[0],t[1]>>>16,65535&t[1]];var n=[0,0,0,0];return n[3]+=e[3]*t[3],n[2]+=n[3]>>>16,n[3]&=65535,n[2]+=e[2]*t[3],n[1]+=n[2]>>>16,n[2]&=65535,n[2]+=e[3]*t[2],n[1]+=n[2]>>>16,n[2]&=65535,n[1]+=e[1]*t[3],n[0]+=n[1]>>>16,n[1]&=65535,n[1]+=e[2]*t[2],n[0]+=n[1]>>>16,n[1]&=65535,n[1]+=e[3]*t[1],n[0]+=n[1]>>>16,n[1]&=65535,n[0]+=e[0]*t[3]+e[1]*t[2]+e[2]*t[1]+e[3]*t[0],n[0]&=65535,[n[0]<<16|n[1],n[2]<<16|n[3]];break;}}}function v(e,t){var $_FHE=_MNVo.$_Dt()[8][18];for(;$_FHE!==_MNVo.$_Dt()[4][17];){switch($_FHE){case _MNVo.$_Dt()[0][18]:return 32===(t%=64)?[e[1],e[0]]:t<32?[e[0]<<t|e[1]>>>32-t,e[1]<<t|e[0]>>>32-t]:[e[1]<<(t-=32)|e[0]>>>32-t,e[0]<<t|e[1]>>>32-t];break;}}}function w(e,t){var $_FIr=_MNVo.$_Dt()[0][18];for(;$_FIr!==_MNVo.$_Dt()[4][17];){switch($_FIr){case _MNVo.$_Dt()[4][18]:return 0===(t%=64)?e:t<32?[e[0]<<t|e[1]>>>32-t,e[1]<<t]:[e[1]<<t-32,0];break;}}}function g(e,t){var $_FJn=_MNVo.$_Dt()[12][18];for(;$_FJn!==_MNVo.$_Dt()[0][17];){switch($_FJn){case _MNVo.$_Dt()[12][18]:return[e[0]^t[0],e[1]^t[1]];break;}}}function b(e){var $_GAe=_MNVo.$_Dt()[0][18];for(;$_GAe!==_MNVo.$_Dt()[4][17];){switch($_GAe){case _MNVo.$_Dt()[12][18]:return e=g(e,[0,e[0]>>>1]),e=g(e=h(e,[4283543511,3981806797]),[0,e[0]>>>1]),e=g(e=h(e,[3301882366,444984403]),[0,e[0]>>>1]);break;}}}function r(e,t){var $_GBn=_MNVo.$_Dt()[12][18];for(;$_GBn!==_MNVo.$_Dt()[12][16];){switch($_GBn){case _MNVo.$_Dt()[12][18]:for(var n=(e=e||_MNVo.$_Cn(56))[_MNVo.$_Cn(59)]%16,i=e[_MNVo.$_Cn(59)]-n,r=[0,t=t||0],o=[0,t],a=[0,0],c=[0,0],s=[2277735313,289559509],u=[1291169091,658871167],l=0;l<i;l+=16)a=[255&e[_MNVo.$_Cn(6)](l+4)|(255&e[_MNVo.$_Cn(6)](l+5))<<8|(255&e[_MNVo.$_Cn(6)](l+6))<<16|(255&e[_MNVo.$_Cn(6)](l+7))<<24,255&e[_MNVo.$_Cn(6)](l)|(255&e[_MNVo.$_Cn(6)](l+1))<<8|(255&e[_MNVo.$_Cn(6)](l+2))<<16|(255&e[_MNVo.$_Cn(6)](l+3))<<24],c=[255&e[_MNVo.$_Cn(6)](l+12)|(255&e[_MNVo.$_Cn(6)](l+13))<<8|(255&e[_MNVo.$_Cn(6)](l+14))<<16|(255&e[_MNVo.$_Cn(6)](l+15))<<24,255&e[_MNVo.$_Cn(6)](l+8)|(255&e[_MNVo.$_Cn(6)](l+9))<<8|(255&e[_MNVo.$_Cn(6)](l+10))<<16|(255&e[_MNVo.$_Cn(6)](l+11))<<24],a=v(a=h(a,s),31),r=f(r=v(r=g(r,a=h(a,u)),27),o),r=f(h(r,[0,5]),[0,1390208809]),c=v(c=h(c,u),33),o=f(o=v(o=g(o,c=h(c,s)),31),r),o=f(h(o,[0,5]),[0,944331445]);switch(a=[0,0],c=[0,0],n){case 15:c=g(c,w([0,e[_MNVo.$_Cn(6)](l+14)],48));case 14:c=g(c,w([0,e[_MNVo.$_Cn(6)](l+13)],40));case 13:c=g(c,w([0,e[_MNVo.$_Cn(6)](l+12)],32));case 12:c=g(c,w([0,e[_MNVo.$_Cn(6)](l+11)],24));case 11:c=g(c,w([0,e[_MNVo.$_Cn(6)](l+10)],16));case 10:c=g(c,w([0,e[_MNVo.$_Cn(6)](l+9)],8));case 9:c=h(c=g(c,[0,e[_MNVo.$_Cn(6)](l+8)]),u),o=g(o,c=h(c=v(c,33),s));case 8:a=g(a,w([0,e[_MNVo.$_Cn(6)](l+7)],56));case 7:a=g(a,w([0,e[_MNVo.$_Cn(6)](l+6)],48));case 6:a=g(a,w([0,e[_MNVo.$_Cn(6)](l+5)],40));case 5:a=g(a,w([0,e[_MNVo.$_Cn(6)](l+4)],32));case 4:a=g(a,w([0,e[_MNVo.$_Cn(6)](l+3)],24));case 3:a=g(a,w([0,e[_MNVo.$_Cn(6)](l+2)],16));case 2:a=g(a,w([0,e[_MNVo.$_Cn(6)](l+1)],8));case 1:a=h(a=g(a,[0,e[_MNVo.$_Cn(6)](l)]),s),r=g(r,a=h(a=v(a,31),u));}$_GBn=_MNVo.$_Dt()[0][17];break;case _MNVo.$_Dt()[12][17]:return r=f(r=g(r,[0,e[_MNVo.$_Cn(59)]]),o=g(o,[0,e[_MNVo.$_Cn(59)]])),o=f(o,r),r=f(r=b(r),o=b(o)),o=f(o,r),(_MNVo.$_Cn(74)+(r[0]>>>0)[_MNVo.$_Cn(41)](16))[_MNVo.$_Cn(82)](-8)+(_MNVo.$_Cn(74)+(r[1]>>>0)[_MNVo.$_Cn(41)](16))[_MNVo.$_Cn(82)](-8)+(_MNVo.$_Cn(74)+(o[0]>>>0)[_MNVo.$_Cn(41)](16))[_MNVo.$_Cn(82)](-8)+(_MNVo.$_Cn(74)+(o[1]>>>0)[_MNVo.$_Cn(41)](16))[_MNVo.$_Cn(82)](-8);break;}}}function n(e,t){var $_GCs=_MNVo.$_Dt()[4][18];for(;$_GCs!==_MNVo.$_Dt()[8][17];){switch($_GCs){case _MNVo.$_Dt()[0][18]:return!function(e,t){for(var n=0,i=e[_MNVo.$_Cn(59)];n<i;++n)if(e[n]===t)return 1;}(e,t);break;}}}function o(e){var $_GDB=_MNVo.$_Dt()[12][18];for(;$_GDB!==_MNVo.$_Dt()[8][17];){switch($_GDB){case _MNVo.$_Dt()[0][18]:return parseInt(e);break;}}}function i(e){var $_GEK=_MNVo.$_Dt()[4][18];for(;$_GEK!==_MNVo.$_Dt()[8][17];){switch($_GEK){case _MNVo.$_Dt()[12][18]:return parseFloat(e);break;}}}function a(e,t){var $_GFq=_MNVo.$_Dt()[12][18];for(;$_GFq!==_MNVo.$_Dt()[4][17];){switch($_GFq){case _MNVo.$_Dt()[4][18]:return _MNVo.$_Cn(46)==typeof e&&isNaN(e)?t:e;break;}}}function s(e){var $_GGO=_MNVo.$_Dt()[12][18];for(;$_GGO!==_MNVo.$_Dt()[12][17];){switch($_GGO){case _MNVo.$_Dt()[12][18]:return e[_MNVo.$_Cn(7)](function(e,t){return e+(t?1:0);},0);break;}}}function y(e){var $_GHb=_MNVo.$_Dt()[4][18];for(;$_GHb!==_MNVo.$_Dt()[4][17];){switch($_GHb){case _MNVo.$_Dt()[4][18]:return e&&_MNVo.$_Cn(21)==typeof e&&_MNVo.$_Cn(65)in e?e:{\"\\u006d\\u0065\\u0073\\u0073\\u0061\\u0067\\u0065\":e};break;}}}function _(o,a,t){var $_GIQ=_MNVo.$_Dt()[0][18];for(;$_GIQ!==_MNVo.$_Dt()[12][17];){switch($_GIQ){case _MNVo.$_Dt()[8][18]:var c=Object[_MNVo.$_Cn(11)](o)[_MNVo.$_Cn(54)](function(e){return n(t,e);}),s=Array(c[_MNVo.$_Cn(59)]);return d(c,function(e,t){var n,i,r;s[t]=(n=o[e],i=a,r=new Promise(function(r){var o=Date[_MNVo.$_Cn(3)]();l(n[_MNVo.$_Cn(66)](null,i),function(){for(var e=[],t=0;t<arguments[_MNVo.$_Cn(59)];t++)e[t]=arguments[t];var n=Date[_MNVo.$_Cn(3)]()-o;if(!e[0])return r(function(){return{\"\\u0065\\u0072\\u0072\\u006f\\u0072\":y(e[1]),\"\\u0064\\u0075\\u0072\\u0061\\u0074\\u0069\\u006f\\u006e\":n};});var i=e[1];if(_MNVo.$_Cn(61)!=typeof i)return r(function(){return{\"\\u0064\\u0061\\u0074\\u0061\":i};});r(function(){return new Promise(function(n){l(i,function(){for(var e=[],t=0;t<arguments[_MNVo.$_Cn(59)];t++)e[t]=arguments[t];if(!e[0])return n({\"\\u0065\\u0072\\u0072\\u006f\\u0072\":y(e[1])});n({\"\\u0064\\u0061\\u0074\\u0061\":e[1]});});});});});}),function(){return r[_MNVo.$_Cn(23)](function(e){return e();});});}),function(){return p(this,void 0,void 0,function(){var i,t,n,r,o,a;return m(this,function(e){switch(e[_MNVo.$_Cn(15)]){case 0:for(i={},t=0,n=c;t<n[_MNVo.$_Cn(59)];t++)r=n[t],i[r]=undefined;o=Array(c[_MNVo.$_Cn(59)]),a=function(){var n;return m(this,function(e){switch(e[_MNVo.$_Cn(15)]){case 0:return n=!0,[4,d(c,function(t,e){o[e]||(s[e]?o[e]=s[e]()[_MNVo.$_Cn(23)](function(e){return i[t]=e;}):n=!1);})];case 1:return e[_MNVo.$_Cn(57)](),n?[2,_MNVo.$_Cn(36)]:[4,u(1)];case 2:return e[_MNVo.$_Cn(57)](),[2];}});},e[_MNVo.$_Cn(15)]=1;case 1:return[5,a()];case 2:if(_MNVo.$_Cn(36)===e[_MNVo.$_Cn(57)]())return[3,4];e[_MNVo.$_Cn(15)]=3;case 3:return[3,1];case 4:return[4,Promise[_MNVo.$_Cn(83)](o)];case 5:return e[_MNVo.$_Cn(57)](),[2,i];}});});};break;}}}function S(){var $_GJw=_MNVo.$_Dt()[8][18];for(;$_GJw!==_MNVo.$_Dt()[8][16];){switch($_GJw){case _MNVo.$_Dt()[0][18]:var e=window,t=navigator;$_GJw=_MNVo.$_Dt()[0][17];break;case _MNVo.$_Dt()[0][17]:return 4<=s([_MNVo.$_Cn(91)in e,_MNVo.$_Cn(4)in e,_MNVo.$_Cn(47)in e,_MNVo.$_Cn(30)in t,_MNVo.$_Cn(43)in t]);break;}}}function A(){var $_HAT=_MNVo.$_Dt()[0][18];for(;$_HAT!==_MNVo.$_Dt()[8][17];){switch($_HAT){case _MNVo.$_Dt()[4][18]:var e=window,t=navigator;return 5<=s([_MNVo.$_Cn(84)in t,_MNVo.$_Cn(13)in t,0===t[_MNVo.$_Cn(31)][_MNVo.$_Cn(94)](_MNVo.$_Cn(10)),_MNVo.$_Cn(17)in e,_MNVo.$_Cn(26)in e,_MNVo.$_Cn(70)in e,_MNVo.$_Cn(39)in e]);break;}}}function C(){var $_HBa=_MNVo.$_Dt()[8][18];for(;$_HBa!==_MNVo.$_Dt()[4][16];){switch($_HBa){case _MNVo.$_Dt()[8][18]:var e=window,t=navigator;$_HBa=_MNVo.$_Dt()[8][17];break;case _MNVo.$_Dt()[4][17]:return 4<=s([_MNVo.$_Cn(58)in e,_MNVo.$_Cn(18)in e,_MNVo.$_Cn(80)in e,0===t[_MNVo.$_Cn(31)][_MNVo.$_Cn(94)](_MNVo.$_Cn(64)),_MNVo.$_Cn(34)in t,_MNVo.$_Cn(35)in e]);break;}}}function T(){var $_HCm=_MNVo.$_Dt()[8][18];for(;$_HCm!==_MNVo.$_Dt()[8][16];){switch($_HCm){case _MNVo.$_Dt()[12][18]:var e=window;$_HCm=_MNVo.$_Dt()[0][17];break;case _MNVo.$_Dt()[0][17]:return 3<=s([_MNVo.$_Cn(38)in e,!(_MNVo.$_Cn(49)in e),!(_MNVo.$_Cn(33)in e),!(_MNVo.$_Cn(22)in navigator)]);break;}}}function E(s){var $_HDd=_MNVo.$_Dt()[12][18];for(;$_HDd!==_MNVo.$_Dt()[4][17];){switch($_HDd){case _MNVo.$_Dt()[8][18]:var e=function(){return undefined;};return[new Promise(function(t,n){var i=!1,r=0,o=0;s[_MNVo.$_Cn(68)]=function(e){return t(e[_MNVo.$_Cn(8)]);};var a=function(){setTimeout(function(){return n(x(_MNVo.$_Cn(44)));},Math[_MNVo.$_Cn(51)](500,o+5e3-Date[_MNVo.$_Cn(3)]()));},c=function(){try{switch(s[_MNVo.$_Cn(71)](),s[_MNVo.$_Cn(37)]){case _MNVo.$_Cn(81):o=Date[_MNVo.$_Cn(3)](),i&&a();break;case _MNVo.$_Cn(89):document[_MNVo.$_Cn(87)]||r++,i&&3<=r?n(x(_MNVo.$_Cn(89))):setTimeout(c,500);}}catch(e){n(e);}};c(),e=function(){i||(i=!0,0<o&&a());};}),e];break;}}}function x(e){var $_HEI=_MNVo.$_Dt()[8][18];for(;$_HEI!==_MNVo.$_Dt()[8][17];){switch($_HEI){case _MNVo.$_Dt()[4][18]:var t=new Error(e);return t[_MNVo.$_Cn(76)]=e,t;break;}}}function t(t,s,n){var $_HFd=_MNVo.$_Dt()[8][18];for(;$_HFd!==_MNVo.$_Dt()[8][16];){switch($_HFd){case _MNVo.$_Dt()[8][18]:var i;$_HFd=_MNVo.$_Dt()[0][17];break;case _MNVo.$_Dt()[8][17]:return void 0===n&&(n=50),p(this,void 0,void 0,function(){var a,c;return m(this,function(e){switch(e[_MNVo.$_Cn(15)]){case 0:a=document,e[_MNVo.$_Cn(15)]=1;case 1:return a[_MNVo.$_Cn(2)]?[3,3]:[4,u(n)];case 2:return e[_MNVo.$_Cn(57)](),[3,1];case 3:c=a[_MNVo.$_Cn(24)](_MNVo.$_Cn(93)),e[_MNVo.$_Cn(15)]=4;case 4:return e[_MNVo.$_Cn(25)][_MNVo.$_Cn(50)]([4,,10,11]),[4,new Promise(function(e,t){var n=!1,i=function(){n=!0,e();};c[_MNVo.$_Cn(48)]=i,c[_MNVo.$_Cn(97)]=function(e){n=!0,t(e);};var r=c[_MNVo.$_Cn(86)];r[_MNVo.$_Cn(53)](_MNVo.$_Cn(69),_MNVo.$_Cn(95),_MNVo.$_Cn(20)),r[_MNVo.$_Cn(5)]=_MNVo.$_Cn(55),r[_MNVo.$_Cn(40)]=_MNVo.$_Cn(90),r[_MNVo.$_Cn(45)]=_MNVo.$_Cn(90),r[_MNVo.$_Cn(98)]=_MNVo.$_Cn(87),s&&_MNVo.$_Cn(63)in c?c[_MNVo.$_Cn(63)]=s:c[_MNVo.$_Cn(1)]=_MNVo.$_Cn(96),a[_MNVo.$_Cn(2)][_MNVo.$_Cn(78)](c);var o=function(){var e;n||(_MNVo.$_Cn(19)===(null===(e=null===(e=c[_MNVo.$_Cn(77)])||void 0===e?void 0:e[_MNVo.$_Cn(42)])||void 0===e?void 0:e[_MNVo.$_Cn(67)])?i():setTimeout(o,10));};o();})];case 5:e[_MNVo.$_Cn(57)](),e[_MNVo.$_Cn(15)]=6;case 6:return null!==(i=null===(i=c[_MNVo.$_Cn(77)])||void 0===i?void 0:i[_MNVo.$_Cn(42)])&&void 0!==i&&i[_MNVo.$_Cn(2)]?[3,8]:[4,u(n)];case 7:return e[_MNVo.$_Cn(57)](),[3,6];case 8:return[4,t(c,c[_MNVo.$_Cn(77)])];case 9:return[2,e[_MNVo.$_Cn(57)]()];case 10:return null!==(i=c[_MNVo.$_Cn(52)])&&void 0!==i&&i[_MNVo.$_Cn(0)](c),[7];case 11:return[2];}});});break;}}}var k=[_MNVo.$_Cn(32),_MNVo.$_Cn(62),_MNVo.$_Cn(73)],P=[_MNVo.$_Cn(28),_MNVo.$_Cn(99),_MNVo.$_Cn(144),_MNVo.$_Cn(142),_MNVo.$_Cn(110),_MNVo.$_Cn(106),_MNVo.$_Cn(119),_MNVo.$_Cn(129),_MNVo.$_Cn(112),_MNVo.$_Cn(191),_MNVo.$_Cn(134),_MNVo.$_Cn(117),_MNVo.$_Cn(150),_MNVo.$_Cn(145),_MNVo.$_Cn(104),_MNVo.$_Cn(109),_MNVo.$_Cn(189),_MNVo.$_Cn(171),_MNVo.$_Cn(167),_MNVo.$_Cn(179),_MNVo.$_Cn(101),_MNVo.$_Cn(141),_MNVo.$_Cn(174),_MNVo.$_Cn(130),_MNVo.$_Cn(140),_MNVo.$_Cn(185),_MNVo.$_Cn(160),_MNVo.$_Cn(164),_MNVo.$_Cn(198),_MNVo.$_Cn(182),_MNVo.$_Cn(122),_MNVo.$_Cn(168),_MNVo.$_Cn(123),_MNVo.$_Cn(152),_MNVo.$_Cn(194),_MNVo.$_Cn(148),_MNVo.$_Cn(158),_MNVo.$_Cn(162),_MNVo.$_Cn(137),_MNVo.$_Cn(178),_MNVo.$_Cn(177),_MNVo.$_Cn(176),_MNVo.$_Cn(163),_MNVo.$_Cn(193),_MNVo.$_Cn(154),_MNVo.$_Cn(169),_MNVo.$_Cn(180),_MNVo.$_Cn(196),_MNVo.$_Cn(156),_MNVo.$_Cn(107),_MNVo.$_Cn(116),_MNVo.$_Cn(184)];function O(e){var $_HGm=_MNVo.$_Dt()[4][18];for(;$_HGm!==_MNVo.$_Dt()[4][17];){switch($_HGm){case _MNVo.$_Dt()[4][18]:return e[_MNVo.$_Cn(135)]();break;}}}var D,M,N=2500;function B(){var $_HHg=_MNVo.$_Dt()[12][18];for(;$_HHg!==_MNVo.$_Dt()[0][16];){switch($_HHg){case _MNVo.$_Dt()[4][18]:var t,e=this;$_HHg=_MNVo.$_Dt()[4][17];break;case _MNVo.$_Dt()[12][17]:return M===undefined&&(t=function(){var e=R();M=j(e)?setTimeout(t,N):(D=e,undefined);})(),function(){return p(e,void 0,void 0,function(){var n;return m(this,function(e){switch(e[_MNVo.$_Cn(15)]){case 0:return j(n=R())?D?[2,c([],D,!0)]:(t=document)[_MNVo.$_Cn(173)]||t[_MNVo.$_Cn(111)]||t[_MNVo.$_Cn(128)]||t[_MNVo.$_Cn(147)]?[4,((t=document)[_MNVo.$_Cn(124)]||t[_MNVo.$_Cn(181)]||t[_MNVo.$_Cn(170)]||t[_MNVo.$_Cn(118)])[_MNVo.$_Cn(92)](t)]:[3,2]:[3,2];case 1:e[_MNVo.$_Cn(57)](),n=R(),e[_MNVo.$_Cn(15)]=2;case 2:return j(n)||(D=n),[2,n];}var t;});});};break;}}}function R(){var $_HIN=_MNVo.$_Dt()[4][18];for(;$_HIN!==_MNVo.$_Dt()[8][17];){switch($_HIN){case _MNVo.$_Dt()[12][18]:var e=screen;return[a(i(e[_MNVo.$_Cn(149)]),null),a(i(e[_MNVo.$_Cn(138)])-i(e[_MNVo.$_Cn(114)])-a(i(e[_MNVo.$_Cn(105)]),0),null),a(i(e[_MNVo.$_Cn(113)])-i(e[_MNVo.$_Cn(197)])-a(i(e[_MNVo.$_Cn(149)]),0),null),a(i(e[_MNVo.$_Cn(105)]),null)];break;}}}function j(e){var $_HJx=_MNVo.$_Dt()[4][18];for(;$_HJx!==_MNVo.$_Dt()[0][16];){switch($_HJx){case _MNVo.$_Dt()[12][18]:for(var t=0;t<4;++t)if(e[t])return;$_HJx=_MNVo.$_Dt()[8][17];break;case _MNVo.$_Dt()[0][17]:return 1;break;}}}function I(e){var $_IAO=_MNVo.$_Dt()[0][18];for(;$_IAO!==_MNVo.$_Dt()[8][17];){switch($_IAO){case _MNVo.$_Dt()[12][18]:return matchMedia(_MNVo.$_Cn(102)[_MNVo.$_Cn(75)](e,_MNVo.$_Cn(195)))[_MNVo.$_Cn(121)];break;}}}function F(e){var $_IBm=_MNVo.$_Dt()[12][18];for(;$_IBm!==_MNVo.$_Dt()[4][17];){switch($_IBm){case _MNVo.$_Dt()[8][18]:return matchMedia(_MNVo.$_Cn(151)[_MNVo.$_Cn(75)](e,_MNVo.$_Cn(195)))[_MNVo.$_Cn(121)];break;}}}function U(e){var $_ICi=_MNVo.$_Dt()[12][18];for(;$_ICi!==_MNVo.$_Dt()[0][17];){switch($_ICi){case _MNVo.$_Dt()[12][18]:return matchMedia(_MNVo.$_Cn(139)[_MNVo.$_Cn(75)](e,_MNVo.$_Cn(195)))[_MNVo.$_Cn(121)];break;}}}function L(e){var $_IDl=_MNVo.$_Dt()[0][18];for(;$_IDl!==_MNVo.$_Dt()[8][17];){switch($_IDl){case _MNVo.$_Dt()[12][18]:return matchMedia(_MNVo.$_Cn(157)[_MNVo.$_Cn(75)](e,_MNVo.$_Cn(195)))[_MNVo.$_Cn(121)];break;}}}function z(e){var $_IEX=_MNVo.$_Dt()[4][18];for(;$_IEX!==_MNVo.$_Dt()[8][17];){switch($_IEX){case _MNVo.$_Dt()[12][18]:return matchMedia(_MNVo.$_Cn(132)[_MNVo.$_Cn(75)](e,_MNVo.$_Cn(195)))[_MNVo.$_Cn(121)];break;}}}var q=Math,G=function(){return 0;};var H={\"\\u0064\\u0065\\u0066\\u0061\\u0075\\u006c\\u0074\":[],\"\\u0061\\u0070\\u0070\\u006c\\u0065\":[{\"\\u0066\\u006f\\u006e\\u0074\":_MNVo.$_Cn(133)}],\"\\u0073\\u0065\\u0072\\u0069\\u0066\":[{\"\\u0066\\u006f\\u006e\\u0074\\u0046\\u0061\\u006d\\u0069\\u006c\\u0079\":_MNVo.$_Cn(73)}],\"\\u0073\\u0061\\u006e\\u0073\":[{\"\\u0066\\u006f\\u006e\\u0074\\u0046\\u0061\\u006d\\u0069\\u006c\\u0079\":_MNVo.$_Cn(62)}],\"\\u006d\\u006f\\u006e\\u006f\":[{\"\\u0066\\u006f\\u006e\\u0074\\u0046\\u0061\\u006d\\u0069\\u006c\\u0079\":_MNVo.$_Cn(32)}],\"\\u006d\\u0069\\u006e\":[{\"\\u0066\\u006f\\u006e\\u0074\\u0053\\u0069\\u007a\\u0065\":_MNVo.$_Cn(188)}],\"\\u0073\\u0079\\u0073\\u0074\\u0065\\u006d\":[{\"\\u0066\\u006f\\u006e\\u0074\\u0046\\u0061\\u006d\\u0069\\u006c\\u0079\":_MNVo.$_Cn(103)}]};var V={\"\\u0073\\u006f\\u0066\":function(){return t(function(e,t){var i=t[_MNVo.$_Cn(42)],t=i[_MNVo.$_Cn(2)];t[_MNVo.$_Cn(86)][_MNVo.$_Cn(125)]=_MNVo.$_Cn(136);var r=i[_MNVo.$_Cn(24)](_MNVo.$_Cn(175)),o={},a={},n=function(e){var t=i[_MNVo.$_Cn(24)](_MNVo.$_Cn(190)),n=t[_MNVo.$_Cn(86)];return n[_MNVo.$_Cn(5)]=_MNVo.$_Cn(55),n[_MNVo.$_Cn(40)]=_MNVo.$_Cn(90),n[_MNVo.$_Cn(45)]=_MNVo.$_Cn(90),n[_MNVo.$_Cn(126)]=e,t[_MNVo.$_Cn(159)]=_MNVo.$_Cn(165),r[_MNVo.$_Cn(78)](t),t;},c=function(e,t){return n(_MNVo.$_Cn(187)[_MNVo.$_Cn(75)](e,_MNVo.$_Cn(131))[_MNVo.$_Cn(75)](t));},s=k[_MNVo.$_Cn(186)](n),u=function(){for(var e={},t=0,n=P;t<n[_MNVo.$_Cn(59)];t++)!function(t){e[t]=k[_MNVo.$_Cn(186)](function(e){return c(t,e);});}(n[t]);return e;}();t[_MNVo.$_Cn(78)](r);for(var l=0;l<k[_MNVo.$_Cn(59)];l++)o[k[l]]=s[l][_MNVo.$_Cn(143)],a[k[l]]=s[l][_MNVo.$_Cn(192)];return P[_MNVo.$_Cn(54)](function(e){return n=u[e],k[_MNVo.$_Cn(108)](function(e,t){return n[t][_MNVo.$_Cn(143)]!==o[e]||n[t][_MNVo.$_Cn(192)]!==a[e];});var n;});});},\"\\u0073\\u0065\\u006f\\u0066\":function(){return function(o,a){void 0===a&&(a=4e3);return t(function(e,t){var n=t[_MNVo.$_Cn(42)],i=n[_MNVo.$_Cn(2)],r=i[_MNVo.$_Cn(86)];r[_MNVo.$_Cn(138)]=_MNVo.$_Cn(56)[_MNVo.$_Cn(75)](a,_MNVo.$_Cn(153)),r[_MNVo.$_Cn(115)]=r[_MNVo.$_Cn(172)]=_MNVo.$_Cn(183),A()?i[_MNVo.$_Cn(86)][_MNVo.$_Cn(100)]=_MNVo.$_Cn(56)[_MNVo.$_Cn(75)](1/t[_MNVo.$_Cn(166)]):C()&&(i[_MNVo.$_Cn(86)][_MNVo.$_Cn(100)]=_MNVo.$_Cn(120));t=n[_MNVo.$_Cn(24)](_MNVo.$_Cn(175));return t[_MNVo.$_Cn(159)]=c([],Array(a/20<<0),!0)[_MNVo.$_Cn(186)](function(){return _MNVo.$_Cn(146);})[_MNVo.$_Cn(161)](_MNVo.$_Cn(155)),i[_MNVo.$_Cn(78)](t),o(n,i);},_MNVo.$_Cn(127));}(function(e,t){for(var n={},i={},r=0,o=Object[_MNVo.$_Cn(11)](H);r<o[_MNVo.$_Cn(59)];r++){var a=o[r],c=H[a],s=c[0],u=void 0===s?{}:s,c=c[1],c=void 0===c?_MNVo.$_Cn(199):c,l=e[_MNVo.$_Cn(24)](_MNVo.$_Cn(190));l[_MNVo.$_Cn(159)]=c,l[_MNVo.$_Cn(86)][_MNVo.$_Cn(254)]=_MNVo.$_Cn(265);for(var d=0,f=Object[_MNVo.$_Cn(11)](u);d<f[_MNVo.$_Cn(59)];d++){var h=f[d],p=u[h];p!==undefined&&(l[_MNVo.$_Cn(86)][h]=p);}n[a]=l,t[_MNVo.$_Cn(78)](e[_MNVo.$_Cn(24)](_MNVo.$_Cn(278))),t[_MNVo.$_Cn(78)](l);}for(var m=0,v=Object[_MNVo.$_Cn(11)](H);m<v[_MNVo.$_Cn(59)];m++)i[a=v[m]]=n[a][_MNVo.$_Cn(206)]()[_MNVo.$_Cn(138)];return i;});},\"\\u006f\\u0075\\u0061\":function(){var e=window,t=e[_MNVo.$_Cn(267)]||e[_MNVo.$_Cn(211)];if(!t)return-2;if(C()&&!T()&&!function(){var e=window;return 3<=s([_MNVo.$_Cn(202)in e,_MNVo.$_Cn(282)in e,_MNVo.$_Cn(298)in e,_MNVo.$_Cn(286)in e]);}())return-1;var n=new t(1,5e3,44100);(e=n[_MNVo.$_Cn(209)]())[_MNVo.$_Cn(297)]=_MNVo.$_Cn(250),e[_MNVo.$_Cn(205)][_MNVo.$_Cn(88)]=1e4,(t=n[_MNVo.$_Cn(218)]())[_MNVo.$_Cn(293)][_MNVo.$_Cn(88)]=-50,t[_MNVo.$_Cn(216)][_MNVo.$_Cn(88)]=40,t[_MNVo.$_Cn(245)][_MNVo.$_Cn(88)]=12,t[_MNVo.$_Cn(291)][_MNVo.$_Cn(88)]=0,t[_MNVo.$_Cn(220)][_MNVo.$_Cn(88)]=.25,e[_MNVo.$_Cn(266)](t),t[_MNVo.$_Cn(266)](n[_MNVo.$_Cn(280)]),e[_MNVo.$_Cn(246)](0);var n=(e=E(n))[0],i=e[1],r=n[_MNVo.$_Cn(23)](function(e){return function(e){for(var t=0,n=0;n<e[_MNVo.$_Cn(59)];++n)t+=Math[_MNVo.$_Cn(295)](e[n]);return t;}(e[_MNVo.$_Cn(279)](0)[_MNVo.$_Cn(239)](4500));},function(e){if(_MNVo.$_Cn(44)===e[_MNVo.$_Cn(76)]||_MNVo.$_Cn(89)===e[_MNVo.$_Cn(76)])return-3;throw e;});return r[_MNVo.$_Cn(253)](function(){return undefined;}),function(){return i(),r;};},\"\\u0065\\u0063\\u0073\":function(){var e=this,i=B();return function(){return p(e,void 0,void 0,function(){var t,n;return m(this,function(e){switch(e[_MNVo.$_Cn(15)]){case 0:return[4,i()];case 1:return t=e[_MNVo.$_Cn(57)](),[2,[(n=function(e){return null===e?null:(t=e,void 0===(e=10)&&(e=1),1<=Math[_MNVo.$_Cn(295)](e)?Math[_MNVo.$_Cn(272)](t/e)*e:(e=1/e,Math[_MNVo.$_Cn(272)](t*e)/e));var t;})(t[0]),n(t[1]),n(t[2]),n(t[3])]];}});});};},\"\\u0075\\u0073\\u006f\":function(){return navigator[_MNVo.$_Cn(227)];},\"\\u0073\\u0061\\u006c\":function(){var e=navigator,t=[],n=e[_MNVo.$_Cn(219)]||e[_MNVo.$_Cn(260)]||e[_MNVo.$_Cn(284)]||e[_MNVo.$_Cn(234)];return n!==undefined&&t[_MNVo.$_Cn(50)]([n]),Array[_MNVo.$_Cn(223)](e[_MNVo.$_Cn(247)])?A()&&3<=s([!(_MNVo.$_Cn(203)in(n=window)),_MNVo.$_Cn(288)in n,_MNVo.$_Cn(56)+n[_MNVo.$_Cn(215)]==_MNVo.$_Cn(271),_MNVo.$_Cn(56)+n[_MNVo.$_Cn(243)]==_MNVo.$_Cn(259)])||t[_MNVo.$_Cn(50)](e[_MNVo.$_Cn(247)]):_MNVo.$_Cn(235)!=typeof e[_MNVo.$_Cn(247)]||(e=e[_MNVo.$_Cn(247)])&&t[_MNVo.$_Cn(50)](e[_MNVo.$_Cn(228)](_MNVo.$_Cn(236))),t;},\"\\u0068\\u006f\\u0063\":function(){return window[_MNVo.$_Cn(224)][_MNVo.$_Cn(257)];},\"\\u0079\\u0065\\u0064\":function(){return a(i(navigator[_MNVo.$_Cn(241)]),undefined);},\"\\u006e\\u0063\\u0073\":function(){var e=screen,t=function(e){return a(o(e),null);};return(t=[t(e[_MNVo.$_Cn(138)]),t(e[_MNVo.$_Cn(113)])])[_MNVo.$_Cn(248)]()[_MNVo.$_Cn(268)](),t;},\"\\u0079\\u0061\\u0068\":function(){return a(o(navigator[_MNVo.$_Cn(201)]),undefined);},\"\\u0065\\u0069\\u0074\":function(){var e=null===(e=window[_MNVo.$_Cn(215)])||void 0===e?void 0:e[_MNVo.$_Cn(274)];if(e){var t=new e()[_MNVo.$_Cn(294)]()[_MNVo.$_Cn(204)];if(t)return t;}return t=new Date()[_MNVo.$_Cn(269)](),t=-Math[_MNVo.$_Cn(263)](i(new Date(t,0,1)[_MNVo.$_Cn(273)]()),i(new Date(t,6,1)[_MNVo.$_Cn(273)]())),_MNVo.$_Cn(249)[_MNVo.$_Cn(75)](0<=t?_MNVo.$_Cn(231):_MNVo.$_Cn(56))[_MNVo.$_Cn(75)](Math[_MNVo.$_Cn(295)](t));},\"\\u0065\\u0065\\u0073\":function(){try{return!!window[_MNVo.$_Cn(213)];}catch(e){return!0;}},\"\\u0065\\u006f\\u006c\":function(){try{return!!window[_MNVo.$_Cn(244)];}catch(e){return!0;}},\"\\u0062\\u006e\\u0069\":function(){if(S()||(e=window,t=navigator,3<=s([_MNVo.$_Cn(283)in e,_MNVo.$_Cn(210)in e,_MNVo.$_Cn(290)in t,_MNVo.$_Cn(233)in t])&&!S()))return undefined;var e,t;try{return!!window[_MNVo.$_Cn(287)];}catch(n){return!0;}},\"\\u0065\\u0070\\u006f\":function(){return!!window[_MNVo.$_Cn(281)];},\"\\u0073\\u0070\\u0063\":function(){return navigator[_MNVo.$_Cn(226)];},\"\\u006d\\u006c\\u0070\":function(){var e=navigator[_MNVo.$_Cn(275)];return _MNVo.$_Cn(237)===e&&C()&&!T()?function(){if(_MNVo.$_Cn(261)===navigator[_MNVo.$_Cn(275)])return 1;var e=(e=screen)[_MNVo.$_Cn(138)]/e[_MNVo.$_Cn(113)];return 2<=s([_MNVo.$_Cn(208)in window,!!Element[_MNVo.$_Cn(72)][_MNVo.$_Cn(214)],.65<e&&e<1.53]);}()?_MNVo.$_Cn(261):_MNVo.$_Cn(277):e;},\"\\u0073\\u006c\\u0070\":function(){var e=navigator[_MNVo.$_Cn(264)];if(!e)return undefined;for(var t=[],n=0;n<e[_MNVo.$_Cn(59)];++n){var i=e[n];if(i){for(var r=[],o=0;o<i[_MNVo.$_Cn(59)];++o){var a=i[o];r[_MNVo.$_Cn(50)]({\"\\u0074\\u0079\\u0070\\u0065\":a[_MNVo.$_Cn(297)],\"\\u0073\\u0075\\u0066\\u0066\\u0069\\u0078\\u0065\\u0073\":a[_MNVo.$_Cn(292)]});}t[_MNVo.$_Cn(50)]({\"\\u006e\\u0061\\u006d\\u0065\":i[_MNVo.$_Cn(76)],\"\\u0064\\u0065\\u0073\\u0063\\u0072\\u0069\\u0070\\u0074\\u0069\\u006f\\u006e\":i[_MNVo.$_Cn(252)],\"\\u006d\\u0069\\u006d\\u0065\\u0054\\u0079\\u0070\\u0065\\u0073\":r});}}return t;},\"\\u0073\\u0061\\u0063\":function(){var e,t=(e=((n=document[_MNVo.$_Cn(24)](_MNVo.$_Cn(240)))[_MNVo.$_Cn(138)]=1,n[_MNVo.$_Cn(113)]=1,[n,n[_MNVo.$_Cn(238)](_MNVo.$_Cn(217))]))[0],n=e[1];return e=t,n&&e[_MNVo.$_Cn(135)]?{\"\\u0077\\u0069\\u006e\\u0064\\u0069\\u006e\\u0067\":((e=n)[_MNVo.$_Cn(276)](0,0,10,10),e[_MNVo.$_Cn(276)](2,2,6,6),!e[_MNVo.$_Cn(222)](5,5,_MNVo.$_Cn(251))),\"\\u0067\\u0065\\u006f\\u006d\\u0065\\u0074\\u0072\\u0079\":r(function(e,t){e[_MNVo.$_Cn(138)]=122,e[_MNVo.$_Cn(113)]=110,t[_MNVo.$_Cn(207)]=_MNVo.$_Cn(255);for(var n=0,i=[[_MNVo.$_Cn(299),40,40],[_MNVo.$_Cn(232),80,40],[_MNVo.$_Cn(289),60,80]];n<i[_MNVo.$_Cn(59)];n++){var r=i[n],o=r[0],a=r[1],r=r[2];t[_MNVo.$_Cn(262)]=o,t[_MNVo.$_Cn(212)](),t[_MNVo.$_Cn(242)](a,r,40,0,2*Math[_MNVo.$_Cn(230)],!0),t[_MNVo.$_Cn(256)](),t[_MNVo.$_Cn(285)]();}return t[_MNVo.$_Cn(262)]=_MNVo.$_Cn(229),t[_MNVo.$_Cn(242)](60,60,60,0,2*Math[_MNVo.$_Cn(230)],!0),t[_MNVo.$_Cn(242)](60,60,20,0,2*Math[_MNVo.$_Cn(230)],!0),t[_MNVo.$_Cn(285)](_MNVo.$_Cn(251)),O(e);}(t,n)),\"\\u0074\\u0065\\u0078\\u0074\":r(function(e,t){e[_MNVo.$_Cn(138)]=240,e[_MNVo.$_Cn(113)]=60,t[_MNVo.$_Cn(258)]=_MNVo.$_Cn(296),t[_MNVo.$_Cn(262)]=_MNVo.$_Cn(270),t[_MNVo.$_Cn(225)](100,1,62,20),t[_MNVo.$_Cn(262)]=_MNVo.$_Cn(221),t[_MNVo.$_Cn(200)]=_MNVo.$_Cn(371);var n=_MNVo.$_Cn(398)[_MNVo.$_Cn(75)](String[_MNVo.$_Cn(325)](55357,56835));return t[_MNVo.$_Cn(362)](n,2,15),t[_MNVo.$_Cn(262)]=_MNVo.$_Cn(353),t[_MNVo.$_Cn(200)]=_MNVo.$_Cn(331),t[_MNVo.$_Cn(362)](n,4,45),O(e);}(t,n))}:{\"\\u0077\\u0069\\u006e\\u0064\\u0069\\u006e\\u0067\":!1,\"\\u0067\\u0065\\u006f\\u006d\\u0065\\u0074\\u0072\\u0079\":_MNVo.$_Cn(56),\"\\u0074\\u0065\\u0078\\u0074\":_MNVo.$_Cn(56)};},\"\\u0074\\u006f\\u0074\":function(){var e,t=navigator,n=0;t[_MNVo.$_Cn(328)]!==undefined?n=o(t[_MNVo.$_Cn(328)]):t[_MNVo.$_Cn(30)]!==undefined&&(n=t[_MNVo.$_Cn(30)]);try{document[_MNVo.$_Cn(337)](_MNVo.$_Cn(385)),e=!0;}catch(i){e=!1;}return{\"\\u006d\\u0061\\u0078\\u0054\\u006f\\u0075\\u0063\\u0068\\u0050\\u006f\\u0069\\u006e\\u0074\\u0073\":n,\"\\u0074\\u006f\\u0075\\u0063\\u0068\\u0045\\u0076\\u0065\\u006e\\u0074\":e,\"\\u0074\\u006f\\u0075\\u0063\\u0068\\u0053\\u0074\\u0061\\u0072\\u0074\":_MNVo.$_Cn(348)in window};},\"\\u0072\\u0065\\u0076\":function(){return navigator[_MNVo.$_Cn(31)]||_MNVo.$_Cn(56);},\"\\u0073\\u0065\\u0076\":function(){for(var e=[],t=0,n=[_MNVo.$_Cn(335),_MNVo.$_Cn(38),_MNVo.$_Cn(389),_MNVo.$_Cn(336),_MNVo.$_Cn(396),_MNVo.$_Cn(332),_MNVo.$_Cn(374),_MNVo.$_Cn(341),_MNVo.$_Cn(351),_MNVo.$_Cn(344),_MNVo.$_Cn(303),_MNVo.$_Cn(386),_MNVo.$_Cn(333),_MNVo.$_Cn(358),_MNVo.$_Cn(361)];t<n[_MNVo.$_Cn(59)];t++){var i=n[t],r=window[i];r&&_MNVo.$_Cn(21)==typeof r&&e[_MNVo.$_Cn(50)](i);}return e[_MNVo.$_Cn(248)]();},\"\\u0064\\u006f\\u0063\":function(){var e=document;try{e[_MNVo.$_Cn(323)]=_MNVo.$_Cn(324);var t=-1!==e[_MNVo.$_Cn(323)][_MNVo.$_Cn(94)](_MNVo.$_Cn(359));return e[_MNVo.$_Cn(323)]=_MNVo.$_Cn(365),t;}catch(n){return!1;}},\"\\u0063\\u006f\\u006c\\u006f\\u0072\\u0047\\u0061\\u006d\\u0075\\u0074\":function(){for(var e=0,t=[_MNVo.$_Cn(368),_MNVo.$_Cn(395),_MNVo.$_Cn(392)];e<t[_MNVo.$_Cn(59)];e++){var n=t[e];if(matchMedia(_MNVo.$_Cn(399)[_MNVo.$_Cn(75)](n,_MNVo.$_Cn(195)))[_MNVo.$_Cn(121)])return n;}return undefined;},\"\\u0069\\u006e\\u0076\\u0065\\u0072\\u0074\\u0065\\u0064\\u0043\\u006f\\u006c\\u006f\\u0072\\u0073\":function(){return!!I(_MNVo.$_Cn(379))||!I(_MNVo.$_Cn(183))&&undefined;},\"\\u0066\\u006f\\u0072\\u0063\\u0065\\u0064\\u0043\\u006f\\u006c\\u006f\\u0072\\u0073\":function(){return!!F(_MNVo.$_Cn(384))||!F(_MNVo.$_Cn(183))&&undefined;},\"\\u006d\\u006f\\u006e\\u006f\\u0063\\u0068\\u0072\\u006f\\u006d\\u0065\":function(){if(!matchMedia(_MNVo.$_Cn(347))[_MNVo.$_Cn(121)])return undefined;for(var e=0;e<=100;++e)if(matchMedia(_MNVo.$_Cn(369)[_MNVo.$_Cn(75)](e,_MNVo.$_Cn(195)))[_MNVo.$_Cn(121)])return e;throw new Error(_MNVo.$_Cn(354));},\"\\u0063\\u006f\\u006e\\u0074\\u0072\\u0061\\u0073\\u0074\":function(){return U(_MNVo.$_Cn(340))?0:U(_MNVo.$_Cn(364))||U(_MNVo.$_Cn(342))?1:U(_MNVo.$_Cn(308))||U(_MNVo.$_Cn(363))?-1:U(_MNVo.$_Cn(301))?10:undefined;},\"\\u0072\\u0065\\u0064\\u0075\\u0063\\u0065\\u0064\\u004d\\u006f\\u0074\\u0069\\u006f\\u006e\":function(){return!!L(_MNVo.$_Cn(7))||!L(_MNVo.$_Cn(340))&&undefined;},\"\\u0064\\u0072\\u0068\":function(){return!!z(_MNVo.$_Cn(364))||!z(_MNVo.$_Cn(360))&&undefined;},\"\\u006d\\u0061\\u0074\\u0068\":function(){var e=q[_MNVo.$_Cn(388)]||G,t=q[_MNVo.$_Cn(350)]||G,n=q[_MNVo.$_Cn(381)]||G,i=q[_MNVo.$_Cn(366)]||G,r=q[_MNVo.$_Cn(317)]||G,o=q[_MNVo.$_Cn(322)]||G,a=q[_MNVo.$_Cn(343)]||G,c=q[_MNVo.$_Cn(304)]||G,s=q[_MNVo.$_Cn(367)]||G,u=q[_MNVo.$_Cn(376)]||G,l=q[_MNVo.$_Cn(373)]||G,d=q[_MNVo.$_Cn(397)]||G,f=q[_MNVo.$_Cn(310)]||G,h=q[_MNVo.$_Cn(382)]||G,p=q[_MNVo.$_Cn(321)]||G;return{\"\\u0061\\u0063\\u006f\\u0073\":e(.12312423423423424),\"\\u0061\\u0063\\u006f\\u0073\\u0068\":t(1e308),\"\\u0061\\u0063\\u006f\\u0073\\u0068\\u0050\\u0066\":(t=1e154,q[_MNVo.$_Cn(387)](t+q[_MNVo.$_Cn(355)](t*t-1))),\"\\u0061\\u0073\\u0069\\u006e\":n(.12312423423423424),\"\\u0061\\u0073\\u0069\\u006e\\u0068\":i(1),\"\\u0061\\u0073\\u0069\\u006e\\u0068\\u0050\\u0066\":(i=1,q[_MNVo.$_Cn(387)](i+q[_MNVo.$_Cn(355)](i*i+1))),\"\\u0061\\u0074\\u0061\\u006e\\u0068\":r(.5),\"\\u0061\\u0074\\u0061\\u006e\\u0068\\u0050\\u0066\":(r=.5,q[_MNVo.$_Cn(387)]((1+r)/(1-r))/2),\"\\u0061\\u0074\\u0061\\u006e\":o(.5),\"\\u0073\\u0069\\u006e\":a(-1e300),\"\\u0073\\u0069\\u006e\\u0068\":c(1),\"\\u0073\\u0069\\u006e\\u0068\\u0050\\u0066\":(c=1,q[_MNVo.$_Cn(310)](c)-1/q[_MNVo.$_Cn(310)](c)/2),\"\\u0063\\u006f\\u0073\":s(10.000000000123),\"\\u0063\\u006f\\u0073\\u0068\":u(1),\"\\u0063\\u006f\\u0073\\u0068\\u0050\\u0066\":(u=1,(q[_MNVo.$_Cn(310)](u)+1/q[_MNVo.$_Cn(310)](u))/2),\"\\u0074\\u0061\\u006e\":l(-1e300),\"\\u0074\\u0061\\u006e\\u0068\":d(1),\"\\u0074\\u0061\\u006e\\u0068\\u0050\\u0066\":(d=1,(q[_MNVo.$_Cn(310)](2*d)-1)/(q[_MNVo.$_Cn(310)](2*d)+1)),\"\\u0065\\u0078\\u0070\":f(1),\"\\u0065\\u0078\\u0070\\u006d\\u0031\":h(1),\"\\u0065\\u0078\\u0070\\u006d\\u0031\\u0050\\u0066\":q[_MNVo.$_Cn(310)](1)-1,\"\\u006c\\u006f\\u0067\\u0031\\u0070\":p(10),\"\\u006c\\u006f\\u0067\\u0031\\u0070\\u0050\\u0066\":q[_MNVo.$_Cn(387)](11),\"\\u0070\\u006f\\u0077\\u0050\\u0049\":q[_MNVo.$_Cn(380)](q[_MNVo.$_Cn(230)],-100)};},\"\\u006c\\u0065\\u0077\":function(){try{return function(e){var t=e[_MNVo.$_Cn(352)](_MNVo.$_Cn(313));if(!t)return _MNVo.$_Cn(338);var n=e[_MNVo.$_Cn(305)](t[_MNVo.$_Cn(315)]),e=e[_MNVo.$_Cn(305)](t[_MNVo.$_Cn(312)]);return n+e;}(document[_MNVo.$_Cn(24)](_MNVo.$_Cn(240))[_MNVo.$_Cn(238)](_MNVo.$_Cn(356)));}catch(e){return _MNVo.$_Cn(338);}}};function W(t){var $_IFK=_MNVo.$_Dt()[12][18];for(;$_IFK!==_MNVo.$_Dt()[4][17];){switch($_IFK){case _MNVo.$_Dt()[4][18]:return{\"\\u0063\\u0063\":function(){try{t[_MNVo.$_Cn(300)][_MNVo.$_Cn(59)]&&t[_MNVo.$_Cn(307)]({\"\\u0070\\u006f\\u0073\\u0069\\u0074\\u0069\\u006f\\u006e\":1,\"\\u0069\\u006e\\u006e\\u0065\\u0072\":_MNVo.$_Cn(370),\"\\u006d\\u0069\\u0064\\u0064\\u006c\\u0065\":_MNVo.$_Cn(370),\"\\u006f\\u0075\\u0074\\u0073\\u0069\\u0064\\u0065\":_MNVo.$_Cn(370)});}catch(e){}}};break;}}}function Z(t){var $_IGX=_MNVo.$_Dt()[0][18];for(;$_IGX!==_MNVo.$_Dt()[12][17];){switch($_IGX){case _MNVo.$_Dt()[4][18]:return{\"\\u0063\\u0063\":function(){try{t[_MNVo.$_Cn(300)][_MNVo.$_Cn(59)]&&t[_MNVo.$_Cn(307)]({\"\\u0070\\u006f\\u0073\\u0069\\u0074\\u0069\\u006f\\u006e\":5,\"\\u0069\\u006e\\u006e\\u0065\\u0072\":_MNVo.$_Cn(393),\"\\u006d\\u0069\\u0064\\u0064\\u006c\\u0065\":_MNVo.$_Cn(393),\"\\u006f\\u0075\\u0074\\u0073\\u0069\\u0064\\u0065\":_MNVo.$_Cn(393)});}catch(e){}}};break;}}}function J(t){var $_IHz=_MNVo.$_Dt()[8][18];for(;$_IHz!==_MNVo.$_Dt()[8][17];){switch($_IHz){case _MNVo.$_Dt()[12][18]:return{\"\\u0063\\u0063\":function(){try{t[_MNVo.$_Cn(300)][_MNVo.$_Cn(59)]&&t[_MNVo.$_Cn(307)]({\"\\u0070\\u006f\\u0073\\u0069\\u0074\\u0069\\u006f\\u006e\":4,\"\\u0069\\u006e\\u006e\\u0065\\u0072\":_MNVo.$_Cn(370),\"\\u006d\\u0069\\u0064\\u0064\\u006c\\u0065\":_MNVo.$_Cn(393),\"\\u006f\\u0075\\u0074\\u0073\\u0069\\u0064\\u0065\":_MNVo.$_Cn(393)});}catch(e){}}};break;}}}function X(t){var $_IIS=_MNVo.$_Dt()[12][18];for(;$_IIS!==_MNVo.$_Dt()[0][17];){switch($_IIS){case _MNVo.$_Dt()[4][18]:return{\"\\u0063\\u0063\":function(){try{t[_MNVo.$_Cn(300)][_MNVo.$_Cn(59)]&&t[_MNVo.$_Cn(307)]({\"\\u0070\\u006f\\u0073\\u0069\\u0074\\u0069\\u006f\\u006e\":8,\"\\u0069\\u006e\\u006e\\u0065\\u0072\":_MNVo.$_Cn(393),\"\\u006d\\u0069\\u0064\\u0064\\u006c\\u0065\":_MNVo.$_Cn(370),\"\\u006f\\u0075\\u0074\\u0073\\u0069\\u0064\\u0065\":_MNVo.$_Cn(370)});}catch(e){}}};break;}}}function K(t){var $_IJy=_MNVo.$_Dt()[8][18];for(;$_IJy!==_MNVo.$_Dt()[8][17];){switch($_IJy){case _MNVo.$_Dt()[12][18]:return{\"\\u0063\\u0063\":function(){try{t[_MNVo.$_Cn(300)][_MNVo.$_Cn(59)]&&t[_MNVo.$_Cn(307)]({\"\\u0070\\u006f\\u0073\\u0069\\u0074\\u0069\\u006f\\u006e\":7,\"\\u0069\\u006e\\u006e\\u0065\\u0072\":_MNVo.$_Cn(393),\"\\u006d\\u0069\\u0064\\u0064\\u006c\\u0065\":_MNVo.$_Cn(370),\"\\u006f\\u0075\\u0074\\u0073\\u0069\\u0064\\u0065\":_MNVo.$_Cn(393)});}catch(e){}}};break;}}}function $(t){var $_JAU=_MNVo.$_Dt()[0][18];for(;$_JAU!==_MNVo.$_Dt()[12][17];){switch($_JAU){case _MNVo.$_Dt()[12][18]:return{\"\\u0063\\u0063\":function(){try{t[_MNVo.$_Cn(300)][_MNVo.$_Cn(59)]&&t[_MNVo.$_Cn(307)]({\"\\u0070\\u006f\\u0073\\u0069\\u0074\\u0069\\u006f\\u006e\":3,\"\\u0069\\u006e\\u006e\\u0065\\u0072\":_MNVo.$_Cn(370),\"\\u006d\\u0069\\u0064\\u0064\\u006c\\u0065\":_MNVo.$_Cn(393),\"\\u006f\\u0075\\u0074\\u0073\\u0069\\u0064\\u0065\":_MNVo.$_Cn(370)});}catch(e){}}};break;}}}function Y(t){var $_JBn=_MNVo.$_Dt()[12][18];for(;$_JBn!==_MNVo.$_Dt()[4][17];){switch($_JBn){case _MNVo.$_Dt()[8][18]:return{\"\\u0063\\u0063\":function(){try{t[_MNVo.$_Cn(300)][_MNVo.$_Cn(59)]&&t[_MNVo.$_Cn(307)]({\"\\u0070\\u006f\\u0073\\u0069\\u0074\\u0069\\u006f\\u006e\":6,\"\\u0069\\u006e\\u006e\\u0065\\u0072\":_MNVo.$_Cn(393),\"\\u006d\\u0069\\u0064\\u0064\\u006c\\u0065\":_MNVo.$_Cn(393),\"\\u006f\\u0075\\u0074\\u0073\\u0069\\u0064\\u0065\":_MNVo.$_Cn(370)});}catch(e){}}};break;}}}function Q(t){var $_JCY=_MNVo.$_Dt()[8][18];for(;$_JCY!==_MNVo.$_Dt()[12][17];){switch($_JCY){case _MNVo.$_Dt()[12][18]:return{\"\\u0063\\u0063\":function(){try{t[_MNVo.$_Cn(300)][_MNVo.$_Cn(59)]&&t[_MNVo.$_Cn(307)]({\"\\u0070\\u006f\\u0073\\u0069\\u0074\\u0069\\u006f\\u006e\":2,\"\\u0069\\u006e\\u006e\\u0065\\u0072\":_MNVo.$_Cn(370),\"\\u006d\\u0069\\u0064\\u0064\\u006c\\u0065\":_MNVo.$_Cn(370),\"\\u006f\\u0075\\u0074\\u0073\\u0069\\u0064\\u0065\":_MNVo.$_Cn(393)});}catch(e){}}};break;}}}function ee(e,t){var $_JDE=_MNVo.$_Dt()[8][18];for(;$_JDE!==_MNVo.$_Dt()[8][17];){switch($_JDE){case _MNVo.$_Dt()[8][18]:try{this[_MNVo.$_Cn(327)]=Object[_MNVo.$_Cn(326)](e),this[_MNVo.$_Cn(339)]=[],this[_MNVo.$_Cn(300)]=this[_MNVo.$_Cn(327)][t]?this[_MNVo.$_Cn(327)][t][_MNVo.$_Cn(41)]()[_MNVo.$_Cn(228)](_MNVo.$_Cn(56)):_MNVo.$_Cn(56),this[_MNVo.$_Cn(320)]=_MNVo.$_Cn(370),this[_MNVo.$_Cn(394)]=_MNVo.$_Cn(393);}catch(n){}$_JDE=_MNVo.$_Dt()[8][17];break;}}}_MNVo.$_Cn(61)!=typeof Object[_MNVo.$_Cn(326)]&&(Object[_MNVo.$_Cn(326)]=function(e,t){if(_MNVo.$_Cn(21)!=typeof e&&_MNVo.$_Cn(61)!=typeof e)throw new TypeError(_MNVo.$_Cn(329)+e);if(null===e)throw new Error(_MNVo.$_Cn(357));if(void 0!==t)throw new Error(_MNVo.$_Cn(383));function n(){var $_JEE=_MNVo.$_Dt()[12][18];for(;$_JEE!==_MNVo.$_Dt()[12][18];){switch($_JEE){}}}return n[_MNVo.$_Cn(72)]=e,new n();}),ee[_MNVo.$_Cn(72)]={\"\\u0024\\u005f\\u0045\\u0075\":function(n){var t=this;new Promise(function(e,t){e({\"\\u0070\\u006f\\u0073\\u0069\\u0074\\u0069\\u006f\\u006e\":n[_MNVo.$_Cn(5)]});})[_MNVo.$_Cn(309)](function(e){return e[_MNVo.$_Cn(314)]=n[_MNVo.$_Cn(314)],e;})[_MNVo.$_Cn(309)](function(e){return e[_MNVo.$_Cn(334)]=n[_MNVo.$_Cn(334)],e;})[_MNVo.$_Cn(309)](function(e){return e[_MNVo.$_Cn(377)]=n[_MNVo.$_Cn(377)],e;})[_MNVo.$_Cn(309)](function(e){return e[_MNVo.$_Cn(375)]=+t[_MNVo.$_Cn(300)][t[_MNVo.$_Cn(300)][_MNVo.$_Cn(59)]-1],e;})[_MNVo.$_Cn(309)](function(e){t[_MNVo.$_Cn(300)][e[_MNVo.$_Cn(5)]]&&(e[_MNVo.$_Cn(314)]===t[_MNVo.$_Cn(320)]?t[_MNVo.$_Cn(349)](e[_MNVo.$_Cn(5)],e[_MNVo.$_Cn(375)]):t[_MNVo.$_Cn(311)](e[_MNVo.$_Cn(5)],e[_MNVo.$_Cn(375)]),e[_MNVo.$_Cn(334)]===t[_MNVo.$_Cn(320)]?t[_MNVo.$_Cn(349)](e[_MNVo.$_Cn(5)],e[_MNVo.$_Cn(375)]):t[_MNVo.$_Cn(311)](e[_MNVo.$_Cn(5)],e[_MNVo.$_Cn(375)]),e[_MNVo.$_Cn(377)]===t[_MNVo.$_Cn(320)]?t[_MNVo.$_Cn(349)](e[_MNVo.$_Cn(5)],e[_MNVo.$_Cn(375)]):t[_MNVo.$_Cn(311)](resposition,e[_MNVo.$_Cn(375)]));});},\"\\u0024\\u005f\\u0047\\u0057\":function(t,n){var i=this;new Promise(function(e){i[_MNVo.$_Cn(300)][t]=(+i[_MNVo.$_Cn(300)][t]+n)[_MNVo.$_Cn(41)](),e();});},\"\\u0024\\u005f\\u0048\\u0053\":function(t,n){var i=this;new Promise(function(e){i[_MNVo.$_Cn(300)][t]=(+i[_MNVo.$_Cn(300)][t]*n)[_MNVo.$_Cn(41)](),e();});}};var te=function(e){return e&&_MNVo.$_Cn(345)===Object[_MNVo.$_Cn(72)][_MNVo.$_Cn(41)][_MNVo.$_Cn(92)](e)?ie(e):ne(ne[_MNVo.$_Cn(41)]());};function ne(e){var $_JFQ=_MNVo.$_Dt()[12][18];for(;$_JFQ!==_MNVo.$_Dt()[8][17];){switch($_JFQ){case _MNVo.$_Dt()[4][18]:var t=5381,n=e[_MNVo.$_Cn(59)],i=0;while(n--)t=(t<<5)+t+e[_MNVo.$_Cn(6)](i++);return t&=~(1<<31);break;}}}function ie(e){var $_JGQ=_MNVo.$_Dt()[4][18];for(;$_JGQ!==_MNVo.$_Dt()[4][17];){switch($_JGQ){case _MNVo.$_Dt()[4][18]:function t(){var $_JHd=_MNVo.$_Dt()[12][18];for(;$_JHd!==_MNVo.$_Dt()[12][17];){switch($_JHd){case _MNVo.$_Dt()[12][18]:this[_MNVo.$_Cn(390)]=e[_MNVo.$_Cn(390)],this[_MNVo.$_Cn(306)]=e[_MNVo.$_Cn(306)];$_JHd=_MNVo.$_Dt()[4][17];break;}}}function n(){var $_JIa=_MNVo.$_Dt()[0][18];for(;$_JIa!==_MNVo.$_Dt()[0][18];){switch($_JIa){}}}return e[_MNVo.$_Cn(390)]&&e[_MNVo.$_Cn(306)]&&(e[_MNVo.$_Cn(378)]=ne(ie[_MNVo.$_Cn(41)]()+ne(ne[_MNVo.$_Cn(41)]()))+_MNVo.$_Cn(56)),t[_MNVo.$_Cn(72)]=new n(),n[_MNVo.$_Cn(72)][_MNVo.$_Cn(319)]={\"\\u006e\":Z,\"\\u0073\":W,\"\\u0065\":$,\"\\u0065\\u0073\":Q,\"\\u0065\\u006e\":J,\"\\u0077\":K,\"\\u0077\\u006e\":Y,\"\\u0077\\u0073\":X,\"\\u0066\":ee},new t();break;}}}window[_MNVo.$_Cn(372)]=te;var re={\"\\u006b\\u0065\\u0079\":_MNVo.$_Cn(346),\"\\u0074\\u0061\\u0072\\u0067\\u0065\\u0074\\u0044\\u006f\\u006d\\u0061\\u0069\\u006e\":_MNVo.$_Cn(56),\"\\u0062\\u0061\\u0073\\u0065\\u0075\\u0072\\u006c\":_MNVo.$_Cn(56),\"\\u0073\\u0065\\u0072\\u0076\\u0065\\u0072\\u0075\\u0072\\u006c\":_MNVo.$_Cn(56),\"\\u0073\\u0065\\u0074\\u0054\\u0069\\u006d\\u0065\\u006f\\u0075\\u0074\":2e3,\"\\u0069\\u006e\\u0064\\u0065\\u0078\\u0064\\u0062\":!0,\"\\u0064\\u0061\\u0074\\u0061\\u0062\\u0061\\u0073\\u0065\":!0,\"\\u0073\\u0065\\u0073\\u0073\\u0069\\u006f\\u006e\":!0,\"\\u0063\\u006f\\u006f\\u006b\\u0069\\u0065\":!0,\"\\u006c\\u006f\\u0063\\u0061\\u006c\\u0053\\u0074\\u006f\\u0072\\u0061\\u0067\\u0065\":!0,\"\\u0077\\u0069\\u006e\\u0064\\u006f\\u0077\\u004e\\u0061\\u006d\\u0065\":!0};function oe(e,t){var $_JJr=_MNVo.$_Dt()[0][18];for(;$_JJr!==_MNVo.$_Dt()[4][17];){switch($_JJr){case _MNVo.$_Dt()[0][18]:if(_MNVo.$_Cn(235)==typeof t)for(var n,i=_MNVo.$_Cn(56)[_MNVo.$_Cn(75)](e,_MNVo.$_Cn(330)),r=t[_MNVo.$_Cn(228)](/[;&]/),o=0;o<r[_MNVo.$_Cn(59)];o++){n=r[o];while(_MNVo.$_Cn(155)===n[_MNVo.$_Cn(302)](0))n=n[_MNVo.$_Cn(391)](1,n[_MNVo.$_Cn(59)]);if(0===n[_MNVo.$_Cn(94)](i))return n[_MNVo.$_Cn(391)](i[_MNVo.$_Cn(59)],n[_MNVo.$_Cn(59)]);}$_JJr=_MNVo.$_Dt()[12][17];break;}}}function ae(e){var $_BAAO=_MNVo.$_Dt()[0][18];for(;$_BAAO!==_MNVo.$_Dt()[0][17];){switch($_BAAO){case _MNVo.$_Dt()[8][18]:if(_MNVo.$_Cn(46)!=typeof e)return!1;if(0<e){for(var t=[_MNVo.$_Cn(90),_MNVo.$_Cn(316),_MNVo.$_Cn(318),_MNVo.$_Cn(479),_MNVo.$_Cn(407),_MNVo.$_Cn(454),_MNVo.$_Cn(435),_MNVo.$_Cn(423),_MNVo.$_Cn(462),_MNVo.$_Cn(457),_MNVo.$_Cn(438),_MNVo.$_Cn(473),_MNVo.$_Cn(402),_MNVo.$_Cn(434),_MNVo.$_Cn(440),_MNVo.$_Cn(468),_MNVo.$_Cn(412),_MNVo.$_Cn(493),_MNVo.$_Cn(467),_MNVo.$_Cn(494),_MNVo.$_Cn(486),_MNVo.$_Cn(410),_MNVo.$_Cn(489),_MNVo.$_Cn(452),_MNVo.$_Cn(422),_MNVo.$_Cn(436),_MNVo.$_Cn(424),_MNVo.$_Cn(404),_MNVo.$_Cn(416),_MNVo.$_Cn(409),_MNVo.$_Cn(433),_MNVo.$_Cn(445),_MNVo.$_Cn(491),_MNVo.$_Cn(442),_MNVo.$_Cn(408),_MNVo.$_Cn(492),_MNVo.$_Cn(484),_MNVo.$_Cn(470),_MNVo.$_Cn(458),_MNVo.$_Cn(437),_MNVo.$_Cn(414),_MNVo.$_Cn(441),_MNVo.$_Cn(460),_MNVo.$_Cn(498),_MNVo.$_Cn(456),_MNVo.$_Cn(401),_MNVo.$_Cn(471),_MNVo.$_Cn(459),_MNVo.$_Cn(482),_MNVo.$_Cn(451),_MNVo.$_Cn(490),_MNVo.$_Cn(411),_MNVo.$_Cn(429),_MNVo.$_Cn(466),_MNVo.$_Cn(425),_MNVo.$_Cn(477),_MNVo.$_Cn(427),_MNVo.$_Cn(418),_MNVo.$_Cn(448),_MNVo.$_Cn(419),_MNVo.$_Cn(476),_MNVo.$_Cn(403)],n=_MNVo.$_Cn(56),i=0;i<e;i++)n+=t[parseInt(String(61*Math[_MNVo.$_Cn(300)]()),10)];return n;}return!1;break;}}}function ce(e){var $_BABc=_MNVo.$_Dt()[4][18];for(;$_BABc!==_MNVo.$_Dt()[8][15];){switch($_BABc){case _MNVo.$_Dt()[0][18]:if(null===this)throw new TypeError(_MNVo.$_Cn(474));if(_MNVo.$_Cn(61)!=typeof e)throw new TypeError(_MNVo.$_Cn(56)[_MNVo.$_Cn(75)](e,_MNVo.$_Cn(495)));$_BABc=_MNVo.$_Dt()[8][17];break;case _MNVo.$_Dt()[12][17]:var t,n=Object(this),i=n[_MNVo.$_Cn(59)]>>>0,r=0;if(2<=arguments[_MNVo.$_Cn(59)])t=arguments[1];else{while(r<i&&!(r in n))r++;if(i<=r)throw new TypeError(_MNVo.$_Cn(465));t=n[r++];}$_BABc=_MNVo.$_Dt()[12][16];break;case _MNVo.$_Dt()[4][16]:while(r<i)r in n&&(t=e(t,n[r],r,n)),r++;return t;break;}}}var se=(Qe=window[_MNVo.$_Cn(42)][_MNVo.$_Cn(24)](_MNVo.$_Cn(240)),Ye=Qe[_MNVo.$_Cn(238)]&&Qe[_MNVo.$_Cn(238)](_MNVo.$_Cn(217)),Qe=/msie/i[_MNVo.$_Cn(496)](window[_MNVo.$_Cn(472)][_MNVo.$_Cn(426)]),!Ye&&Qe);function ue(){var $_BACy=_MNVo.$_Dt()[8][18];for(;$_BACy!==_MNVo.$_Dt()[12][17];){switch($_BACy){case _MNVo.$_Dt()[0][18]:se&&(re[_MNVo.$_Cn(405)]=!1,re[_MNVo.$_Cn(415)]=!1),this[_MNVo.$_Cn(446)]={},this[_MNVo.$_Cn(430)]=0,this[_MNVo.$_Cn(76)]=re[_MNVo.$_Cn(488)],this[_MNVo.$_Cn(453)]=[_MNVo.$_Cn(463),_MNVo.$_Cn(420),_MNVo.$_Cn(461),_MNVo.$_Cn(323),_MNVo.$_Cn(244),_MNVo.$_Cn(449)];$_BACy=_MNVo.$_Dt()[0][17];break;}}}ue[_MNVo.$_Cn(72)]={\"\\u0067\\u0065\\u0074\":function(e,t,n){this[_MNVo.$_Cn(432)](e,t,n,!0);},\"\\u0073\\u0065\\u0074\":function(e,t,n){this[_MNVo.$_Cn(432)](e,t,n);},\"\\u0024\\u005f\\u0042\\u0043\\u0048\":function(i,r,e,t){for(var o=this,a=o[_MNVo.$_Cn(453)],c=[],n=0;n<a[_MNVo.$_Cn(59)];n++)!function(n){re&&re[a[n]]&&c[_MNVo.$_Cn(50)](new Promise(function(e,t){o[a[n]](i,r,e,t);}));}(n);Promise[_MNVo.$_Cn(83)](c)[_MNVo.$_Cn(23)](function(){o[_MNVo.$_Cn(417)](i,t,e);});},\"\\u0024\\u005f\\u0042\\u0044\\u006f\":function(e,t,n){var i=this[_MNVo.$_Cn(446)],r=[],o=0,a=0;for(c in i)i[c]&&_MNVo.$_Cn(455)!==i[c]&&_MNVo.$_Cn(443)!==i[c]&&r[_MNVo.$_Cn(50)](i[c]);if(r[0]!==undefined){_MNVo.$_Cn(61)!=typeof Array[_MNVo.$_Cn(72)][_MNVo.$_Cn(7)]&&(Array[_MNVo.$_Cn(72)][_MNVo.$_Cn(7)]=ce);var c,s=r[_MNVo.$_Cn(7)](function(e,t){return t in e?e[t]++:e[t]=1,e;},{});for(c in s)s[c]>o&&(o=s[c],a=c);}t&&0!==a?this[_MNVo.$_Cn(431)](e,a,n):n(this[_MNVo.$_Cn(430)]=a);},\"\\u0064\\u0061\\u0074\\u0061\\u0062\\u0061\\u0073\\u0065\":function(t,n,i){try{var e,r=this;window[_MNVo.$_Cn(281)]?(e=window[_MNVo.$_Cn(281)](r[_MNVo.$_Cn(76)],_MNVo.$_Cn(56),r[_MNVo.$_Cn(76)],1048576),n!==undefined?e[_MNVo.$_Cn(485)](function(e){e[_MNVo.$_Cn(444)](_MNVo.$_Cn(481),[],function(){},function(){}),e[_MNVo.$_Cn(444)](_MNVo.$_Cn(450),[t,n],function(){i();},function(){i();});}):e[_MNVo.$_Cn(485)](function(e){e[_MNVo.$_Cn(444)](_MNVo.$_Cn(497),[t],function(e,t){1<=t[_MNVo.$_Cn(447)][_MNVo.$_Cn(59)]?r[_MNVo.$_Cn(446)][_MNVo.$_Cn(428)]=t[_MNVo.$_Cn(447)][_MNVo.$_Cn(464)](0)[_MNVo.$_Cn(88)]:r[_MNVo.$_Cn(446)][_MNVo.$_Cn(428)]=_MNVo.$_Cn(56),i();},function(){i();});})):i();}catch(o){i();}},\"\\u0069\\u006e\\u0064\\u0065\\u0078\\u0064\\u0062\":function(n,t,i){try{var e,r=this;_MNVo.$_Cn(287)in window||(indexedDB=window[_MNVo.$_Cn(287)]||window[_MNVo.$_Cn(499)]||window[_MNVo.$_Cn(478)]||window[_MNVo.$_Cn(47)]),indexedDB?((e=indexedDB[_MNVo.$_Cn(469)](r[_MNVo.$_Cn(76)],1))[_MNVo.$_Cn(97)]=function(){i();},e[_MNVo.$_Cn(439)]=function(e){(e[_MNVo.$_Cn(480)]&&e[_MNVo.$_Cn(480)][_MNVo.$_Cn(421)])[_MNVo.$_Cn(413)](r[_MNVo.$_Cn(76)],{\"\\u006b\\u0065\\u0079\\u0050\\u0061\\u0074\\u0068\":_MNVo.$_Cn(76),\"\\u0075\\u006e\\u0069\\u0071\\u0075\\u0065\":!1}),i();},t!==undefined?e[_MNVo.$_Cn(406)]=function(e){e=e[_MNVo.$_Cn(480)][_MNVo.$_Cn(421)];e[_MNVo.$_Cn(483)][_MNVo.$_Cn(400)](r[_MNVo.$_Cn(76)])&&e[_MNVo.$_Cn(485)]([r[_MNVo.$_Cn(76)]],_MNVo.$_Cn(505))[_MNVo.$_Cn(475)](r[_MNVo.$_Cn(76)])[_MNVo.$_Cn(487)]({\"\\u006e\\u0061\\u006d\\u0065\":n,\"\\u0076\\u0061\\u006c\\u0075\\u0065\":t}),i(),e[_MNVo.$_Cn(524)]();}:e[_MNVo.$_Cn(406)]=function(e){var t,e=e[_MNVo.$_Cn(480)]&&e[_MNVo.$_Cn(480)][_MNVo.$_Cn(421)];e[_MNVo.$_Cn(483)][_MNVo.$_Cn(400)](r[_MNVo.$_Cn(76)])?(t=e[_MNVo.$_Cn(485)]([r[_MNVo.$_Cn(76)]])[_MNVo.$_Cn(475)](r[_MNVo.$_Cn(76)])[_MNVo.$_Cn(536)](n))[_MNVo.$_Cn(406)]=function(){t[_MNVo.$_Cn(421)]===undefined?r[_MNVo.$_Cn(446)][_MNVo.$_Cn(510)]=undefined:r[_MNVo.$_Cn(446)][_MNVo.$_Cn(510)]=t[_MNVo.$_Cn(421)][_MNVo.$_Cn(88)];}:r[_MNVo.$_Cn(446)][_MNVo.$_Cn(510)]=undefined,i(),e[_MNVo.$_Cn(524)]();}):i();}catch(o){i();}},\"\\u0073\\u0065\\u0073\\u0073\\u0069\\u006f\\u006e\":function(e,t,n){try{var i=window[_MNVo.$_Cn(213)];i&&(t!==undefined?i[_MNVo.$_Cn(523)](e,t):this[_MNVo.$_Cn(446)][_MNVo.$_Cn(461)]=i[_MNVo.$_Cn(507)](e)),n();}catch(r){n();}},\"\\u0063\\u006f\\u006f\\u006b\\u0069\\u0065\":function(e,t,n){t!==undefined?(document[_MNVo.$_Cn(323)]=_MNVo.$_Cn(56)[_MNVo.$_Cn(75)](e,_MNVo.$_Cn(515))[_MNVo.$_Cn(75)](re[_MNVo.$_Cn(582)]),document[_MNVo.$_Cn(323)]=_MNVo.$_Cn(56)[_MNVo.$_Cn(75)](e,_MNVo.$_Cn(330))[_MNVo.$_Cn(75)](t,_MNVo.$_Cn(555))[_MNVo.$_Cn(75)](re[_MNVo.$_Cn(582)])):this[_MNVo.$_Cn(446)][_MNVo.$_Cn(323)]=oe(e,document[_MNVo.$_Cn(323)]),n();},\"\\u006c\\u006f\\u0063\\u0061\\u006c\\u0053\\u0074\\u006f\\u0072\\u0061\\u0067\\u0065\":function(e,t,n){try{var i=window[_MNVo.$_Cn(244)];i&&(t!==undefined?i[_MNVo.$_Cn(523)](e,t):this[_MNVo.$_Cn(446)][_MNVo.$_Cn(545)]=i[_MNVo.$_Cn(507)](e)),n();}catch(r){n();}},\"\\u0077\\u0069\\u006e\\u0064\\u006f\\u0077\\u004e\\u0061\\u006d\\u0065\":function(e,t,n){t!==undefined?window[_MNVo.$_Cn(76)]=function(e,t,n){if(-1<e[_MNVo.$_Cn(94)](_MNVo.$_Cn(533)[_MNVo.$_Cn(75)](t,_MNVo.$_Cn(330)))||0===e[_MNVo.$_Cn(94)](_MNVo.$_Cn(56)[_MNVo.$_Cn(75)](t,_MNVo.$_Cn(330)))){var i=e[_MNVo.$_Cn(94)](_MNVo.$_Cn(533)[_MNVo.$_Cn(75)](t,_MNVo.$_Cn(330)));-1===i&&(i=e[_MNVo.$_Cn(94)](_MNVo.$_Cn(56)[_MNVo.$_Cn(75)](t,_MNVo.$_Cn(330))));var r=e[_MNVo.$_Cn(94)](_MNVo.$_Cn(533),i+1);return _MNVo.$_Cn(56)[_MNVo.$_Cn(75)](-1!==r?e[_MNVo.$_Cn(519)](0,i)+e[_MNVo.$_Cn(519)](r+(i?0:1)):e[_MNVo.$_Cn(519)](0,i),_MNVo.$_Cn(533))[_MNVo.$_Cn(75)](t,_MNVo.$_Cn(330))[_MNVo.$_Cn(75)](n);}return _MNVo.$_Cn(56)[_MNVo.$_Cn(75)](e,_MNVo.$_Cn(533))[_MNVo.$_Cn(75)](t,_MNVo.$_Cn(330))[_MNVo.$_Cn(75)](n);}(window[_MNVo.$_Cn(76)],e,t):this[_MNVo.$_Cn(446)][_MNVo.$_Cn(449)]=oe(e,window[_MNVo.$_Cn(76)]),n();}};var le=function(e){if((e=(e=(e=_MNVo.$_Cn(56)[_MNVo.$_Cn(75)](e))[_MNVo.$_Cn(503)](/[ \\t\\n\\f\\r]/g,_MNVo.$_Cn(56)))[_MNVo.$_Cn(59)]%4==0?e[_MNVo.$_Cn(503)](/==?$/,_MNVo.$_Cn(56)):e)[_MNVo.$_Cn(59)]%4==1||/[^+/0-9A-Za-z]/[_MNVo.$_Cn(496)](e))return null;for(var t,n=_MNVo.$_Cn(56),i=0,r=0,o=0;o<e[_MNVo.$_Cn(59)];o++)i<<=6,i|=(t=e[o],/[A-Z]/[_MNVo.$_Cn(496)](t)?t[_MNVo.$_Cn(6)](0)-_MNVo.$_Cn(438)[_MNVo.$_Cn(6)](0):/[a-z]/[_MNVo.$_Cn(496)](t)?t[_MNVo.$_Cn(6)](0)-_MNVo.$_Cn(484)[_MNVo.$_Cn(6)](0)+26:/[0-9]/[_MNVo.$_Cn(496)](t)?t[_MNVo.$_Cn(6)](0)-_MNVo.$_Cn(90)[_MNVo.$_Cn(6)](0)+52:_MNVo.$_Cn(231)===t?62:_MNVo.$_Cn(513)===t?63:void 0),24===(r+=6)&&(n+=String[_MNVo.$_Cn(325)]((16711680&i)>>16),n+=String[_MNVo.$_Cn(325)]((65280&i)>>8),n+=String[_MNVo.$_Cn(325)](255&i),i=r=0);return 12===r?(i>>=4,n+=String[_MNVo.$_Cn(325)](i)):18===r&&(i>>=2,n+=String[_MNVo.$_Cn(325)]((65280&i)>>8),n+=String[_MNVo.$_Cn(325)](255&i)),n;};var de=function(e){for(e=_MNVo.$_Cn(56)[_MNVo.$_Cn(75)](e),i=0;i<e[_MNVo.$_Cn(59)];i++)if(255<e[_MNVo.$_Cn(6)](i))return null;for(var t,n=_MNVo.$_Cn(56),i=0;i<e[_MNVo.$_Cn(59)];i+=3){var r=[void 0,void 0,void 0,void 0];r[0]=e[_MNVo.$_Cn(6)](i)>>2,r[1]=(3&e[_MNVo.$_Cn(6)](i))<<4,e[_MNVo.$_Cn(59)]>i+1&&(r[1]|=e[_MNVo.$_Cn(6)](i+1)>>4,r[2]=(15&e[_MNVo.$_Cn(6)](i+1))<<2),e[_MNVo.$_Cn(59)]>i+2&&(r[2]|=e[_MNVo.$_Cn(6)](i+2)>>6,r[3]=63&e[_MNVo.$_Cn(6)](i+2));for(var o=0;o<r[_MNVo.$_Cn(59)];o++)_MNVo.$_Cn(443)==typeof r[o]?n+=_MNVo.$_Cn(330):n+=(t=r[o])<26?String[_MNVo.$_Cn(325)](t+_MNVo.$_Cn(438)[_MNVo.$_Cn(6)](0)):t<52?String[_MNVo.$_Cn(325)](t-26+_MNVo.$_Cn(484)[_MNVo.$_Cn(6)](0)):t<62?String[_MNVo.$_Cn(325)](t-52+_MNVo.$_Cn(90)[_MNVo.$_Cn(6)](0)):62===t?_MNVo.$_Cn(231):63===t?_MNVo.$_Cn(513):void 0;}return n;},fe=function(e,t,n,i,r,o){n&&(t=unescape(encodeURIComponent(t)));var a,c,s,u,l,d,f,h,p,m,v,w,g,b=new Array(16843776,0,65536,16843780,16842756,66564,4,65536,1024,16843776,16843780,1024,16778244,16842756,16777216,4,1028,16778240,16778240,66560,66560,16842752,16842752,16778244,65540,16777220,16777220,65540,0,1028,66564,16777216,65536,16843780,4,16842752,16843776,16777216,16777216,1024,16842756,65536,66560,16777220,1024,4,16778244,66564,16843780,65540,16842752,16778244,16777220,1028,66564,16843776,1028,16778240,16778240,0,65540,66560,0,16842756),y=new Array(-2146402272,-2147450880,32768,1081376,1048576,32,-2146435040,-2147450848,-2147483616,-2146402272,-2146402304,-2147483648,-2147450880,1048576,32,-2146435040,1081344,1048608,-2147450848,0,-2147483648,32768,1081376,-2146435072,1048608,-2147483616,0,1081344,32800,-2146402304,-2146435072,32800,0,1081376,-2146435040,1048576,-2147450848,-2146435072,-2146402304,32768,-2146435072,-2147450880,32,-2146402272,1081376,32,32768,-2147483648,32800,-2146402304,1048576,-2147483616,1048608,-2147450848,-2147483616,1048608,1081344,0,-2147450880,32800,-2147483648,-2146435040,-2146402272,1081344),_=new Array(520,134349312,0,134348808,134218240,0,131592,134218240,131080,134217736,134217736,131072,134349320,131080,134348800,520,134217728,8,134349312,512,131584,134348800,134348808,131592,134218248,131584,131072,134218248,8,134349320,512,134217728,134349312,134217728,131080,520,131072,134349312,134218240,0,512,131080,134349320,134218240,134217736,512,0,134348808,134218248,131072,134217728,134349320,8,131592,131584,134217736,134348800,134218248,520,134348800,131592,8,134348808,131584),S=new Array(8396801,8321,8321,128,8396928,8388737,8388609,8193,0,8396800,8396800,8396929,129,0,8388736,8388609,1,8192,8388608,8396801,128,8388608,8193,8320,8388737,1,8320,8388736,8192,8396928,8396929,129,8388736,8388609,8396800,8396929,129,0,0,8396800,8320,8388736,8388737,1,8396801,8321,8321,128,8396929,129,1,8192,8388609,8193,8396928,8388737,8193,8320,8388608,8396801,128,8388608,8192,8396928),A=new Array(256,34078976,34078720,1107296512,524288,256,1073741824,34078720,1074266368,524288,33554688,1074266368,1107296512,1107820544,524544,1073741824,33554432,1074266112,1074266112,0,1073742080,1107820800,1107820800,33554688,1107820544,1073742080,0,1107296256,34078976,33554432,1107296256,524544,524288,1107296512,256,33554432,1073741824,34078720,1107296512,1074266368,33554688,1073741824,1107820544,34078976,1074266368,256,33554432,1107820544,1107820800,524544,1107296256,1107820800,34078720,0,1074266112,1107296256,524544,33554688,1073742080,524288,0,1074266112,34078976,1073742080),C=new Array(536870928,541065216,16384,541081616,541065216,16,541081616,4194304,536887296,4210704,4194304,536870928,4194320,536887296,536870912,16400,0,4194320,536887312,16384,4210688,536887312,16,541065232,541065232,0,4210704,541081600,16400,4210688,541081600,536870912,536887296,16,541065232,4210688,541081616,4194304,16400,536870928,4194304,536887296,536870912,16400,536870928,541081616,4210688,541065216,4210704,541081600,0,541065232,16,16384,541065216,4210704,16384,4194320,536887312,0,541081600,536870912,4194320,536887312),T=new Array(2097152,69206018,67110914,0,2048,67110914,2099202,69208064,69208066,2097152,0,67108866,2,67108864,69206018,2050,67110912,2099202,2097154,67110912,67108866,69206016,69208064,2097154,69206016,2048,2050,69208066,2099200,2,67108864,2099200,67108864,2099200,2097152,67110914,67110914,69206018,69206018,2,2097154,67108864,67110912,2097152,69208064,2050,2099202,69208064,2050,67108866,69208066,69206016,2099200,0,2,69208066,0,2099202,69206016,2048,67108866,67110912,2048,2097154),E=new Array(268439616,4096,262144,268701760,268435456,268439616,64,268435456,262208,268697600,268701760,266240,268701696,266304,4096,64,268697600,268435520,268439552,4160,266240,262208,268697664,268701696,4160,0,0,268697664,268435520,268439552,266304,262144,266304,262144,268701696,4096,64,268697664,4096,266304,268439552,64,268435520,268697600,268697664,268435456,262144,268439616,0,268701760,262208,268435520,268697600,268439552,268439616,0,268701760,266240,266240,4160,4160,262208,268435456,268701696),x=function(e){for(var t,n,i,r=new Array(0,4,536870912,536870916,65536,65540,536936448,536936452,512,516,536871424,536871428,66048,66052,536936960,536936964),o=new Array(0,1,1048576,1048577,67108864,67108865,68157440,68157441,256,257,1048832,1048833,67109120,67109121,68157696,68157697),a=new Array(0,8,2048,2056,16777216,16777224,16779264,16779272,0,8,2048,2056,16777216,16777224,16779264,16779272),c=new Array(0,2097152,134217728,136314880,8192,2105344,134225920,136323072,131072,2228224,134348800,136445952,139264,2236416,134356992,136454144),s=new Array(0,262144,16,262160,0,262144,16,262160,4096,266240,4112,266256,4096,266240,4112,266256),u=new Array(0,1024,32,1056,0,1024,32,1056,33554432,33555456,33554464,33555488,33554432,33555456,33554464,33555488),l=new Array(0,268435456,524288,268959744,2,268435458,524290,268959746,0,268435456,524288,268959744,2,268435458,524290,268959746),d=new Array(0,65536,2048,67584,536870912,536936448,536872960,536938496,131072,196608,133120,198656,537001984,537067520,537004032,537069568),f=new Array(0,262144,0,262144,2,262146,2,262146,33554432,33816576,33554432,33816576,33554434,33816578,33554434,33816578),h=new Array(0,268435456,8,268435464,0,268435456,8,268435464,1024,268436480,1032,268436488,1024,268436480,1032,268436488),p=new Array(0,32,0,32,1048576,1048608,1048576,1048608,8192,8224,8192,8224,1056768,1056800,1056768,1056800),m=new Array(0,16777216,512,16777728,2097152,18874368,2097664,18874880,67108864,83886080,67109376,83886592,69206016,85983232,69206528,85983744),v=new Array(0,4096,134217728,134221824,524288,528384,134742016,134746112,16,4112,134217744,134221840,524304,528400,134742032,134746128),w=new Array(0,4,256,260,0,4,256,260,1,5,257,261,1,5,257,261),g=e[_MNVo.$_Cn(59)]>8?3:1,b=new Array(32*g),y=new Array(0,0,1,1,1,1,1,1,0,1,1,1,1,1,1,0),_=0,S=0,A=0;A<g;A++){var C=e[_MNVo.$_Cn(6)](_++)<<24|e[_MNVo.$_Cn(6)](_++)<<16|e[_MNVo.$_Cn(6)](_++)<<8|e[_MNVo.$_Cn(6)](_++),T=e[_MNVo.$_Cn(6)](_++)<<24|e[_MNVo.$_Cn(6)](_++)<<16|e[_MNVo.$_Cn(6)](_++)<<8|e[_MNVo.$_Cn(6)](_++);i=252645135&(C>>>4^T),T^=i,C^=i<<4,i=65535&(T>>>-16^C),C^=i,T^=i<<-16,i=858993459&(C>>>2^T),T^=i,C^=i<<2,i=65535&(T>>>-16^C),C^=i,T^=i<<-16,i=1431655765&(C>>>1^T),T^=i,C^=i<<1,i=16711935&(T>>>8^C),C^=i,T^=i<<8,i=1431655765&(C>>>1^T),T^=i,C^=i<<1,i=C<<8|T>>>20&240,C=T<<24|T<<8&16711680|T>>>8&65280|T>>>24&240,T=i;for(var E=0;E<y[_MNVo.$_Cn(59)];E++)y[E]?(C=C<<2|C>>>26,T=T<<2|T>>>26):(C=C<<1|C>>>27,T=T<<1|T>>>27),C&=-15,T&=-15,t=r[C>>>28]|o[C>>>24&15]|a[C>>>20&15]|c[C>>>16&15]|s[C>>>12&15]|u[C>>>8&15]|l[C>>>4&15],n=d[T>>>28]|f[T>>>24&15]|h[T>>>20&15]|p[T>>>16&15]|m[T>>>12&15]|v[T>>>8&15]|w[T>>>4&15],i=65535&(n>>>16^t),b[S++]=t^i,b[S++]=n^i<<16;}return b;}(e),k=0,P=t[_MNVo.$_Cn(59)],O=0,D=32==x[_MNVo.$_Cn(59)]?3:9,M=3==D?n?new Array(0,32,2):new Array(30,-2,-2):n?new Array(0,32,2,62,30,-2,64,96,2):new Array(94,62,-2,32,64,2,30,-2,-2);2==o?t+=_MNVo.$_Cn(577):1==o?n&&(s=8-P%8,t+=String[_MNVo.$_Cn(325)](s,s,s,s,s,s,s,s),8===s&&(P+=8)):o||(t+=_MNVo.$_Cn(518));var N=_MNVo.$_Cn(56),B=_MNVo.$_Cn(56);1==i&&(h=r[_MNVo.$_Cn(6)](k++)<<24|r[_MNVo.$_Cn(6)](k++)<<16|r[_MNVo.$_Cn(6)](k++)<<8|r[_MNVo.$_Cn(6)](k++),m=r[_MNVo.$_Cn(6)](k++)<<24|r[_MNVo.$_Cn(6)](k++)<<16|r[_MNVo.$_Cn(6)](k++)<<8|r[_MNVo.$_Cn(6)](k++),k=0);while(k<P){for(d=t[_MNVo.$_Cn(6)](k++)<<24|t[_MNVo.$_Cn(6)](k++)<<16|t[_MNVo.$_Cn(6)](k++)<<8|t[_MNVo.$_Cn(6)](k++),f=t[_MNVo.$_Cn(6)](k++)<<24|t[_MNVo.$_Cn(6)](k++)<<16|t[_MNVo.$_Cn(6)](k++)<<8|t[_MNVo.$_Cn(6)](k++),1==i&&(n?(d^=h,f^=m):(p=h,v=m,h=d,m=f)),d^=(s=252645135&(d>>>4^f))<<4,d^=(s=65535&(d>>>16^(f^=s)))<<16,d^=s=858993459&((f^=s)>>>2^d),d^=s=16711935&((f^=s<<2)>>>8^d),d=(d^=(s=1431655765&(d>>>1^(f^=s<<8)))<<1)<<1|d>>>31,f=(f^=s)<<1|f>>>31,c=0;c<D;c+=3){for(w=M[c+1],g=M[c+2],a=M[c];a!=w;a+=g)u=f^x[a],l=(f>>>4|f<<28)^x[a+1],s=d,d=f,f=s^(y[u>>>24&63]|S[u>>>16&63]|C[u>>>8&63]|E[63&u]|b[l>>>24&63]|_[l>>>16&63]|A[l>>>8&63]|T[63&l]);s=d,d=f,f=s;}f=f>>>1|f<<31,f^=s=1431655765&((d=d>>>1|d<<31)>>>1^f),f^=(s=16711935&(f>>>8^(d^=s<<1)))<<8,f^=(s=858993459&(f>>>2^(d^=s)))<<2,f^=s=65535&((d^=s)>>>16^f),f^=s=252645135&((d^=s<<16)>>>4^f),d^=s<<4,1==i&&(n?(h=d,m=f):(d^=p,f^=v)),B+=String[_MNVo.$_Cn(325)](d>>>24,d>>>16&255,d>>>8&255,255&d,f>>>24,f>>>16&255,f>>>8&255,255&f),512==(O+=8)&&(N+=B,B=_MNVo.$_Cn(56),O=0);}return N+=B,n||(1===o&&(r=0,(r=(o=N[_MNVo.$_Cn(59)])?N[_MNVo.$_Cn(6)](o-1):r)<=8&&(N=N[_MNVo.$_Cn(391)](0,o-r))),N=decodeURIComponent(escape(N))),N;},he=function(e,t,n){return{\"\\u006b\\u0065\\u0079\":function(e){for(var t=e[_MNVo.$_Cn(59)];t<24;t++)e+=_MNVo.$_Cn(90);return e;}(e[_MNVo.$_Cn(82)](t,n)),\"\\u0076\\u0065\\u0063\\u0074\\u006f\\u0072\":1};},pe={\"\\u0065\\u006e\\u0063\\u0072\\u0079\\u0070\\u0074\":function(e,t){e=he(e,0,24);return de(fe(e[_MNVo.$_Cn(488)],t,1,0,0,1));},\"\\u0064\\u0065\\u0063\\u0072\\u0079\\u0070\\u0074\":function(e,t){e=he(e,0,24);return fe(e[_MNVo.$_Cn(488)],le(t),0,0,0,1);}};function me(e,t){var $_BADu=_MNVo.$_Dt()[8][18];for(;$_BADu!==_MNVo.$_Dt()[0][17];){switch($_BADu){case _MNVo.$_Dt()[12][18]:var n=r(ae(32)+String(new Date()[_MNVo.$_Cn(538)]())),i=pe[_MNVo.$_Cn(584)](re[_MNVo.$_Cn(488)],n);t[_MNVo.$_Cn(431)](re[_MNVo.$_Cn(488)],i,function(){window[_MNVo.$_Cn(346)]=i,e(n);});$_BADu=_MNVo.$_Dt()[4][17];break;}}}var ve=_MNVo.$_Cn(56),we=_MNVo.$_Cn(61),ge=_MNVo.$_Cn(443),be=_MNVo.$_Cn(21),ye=_MNVo.$_Cn(235),$_BEK=_MNVo.$_Cn(556),Se=_MNVo.$_Cn(76),Ae=_MNVo.$_Cn(297),Ce=_MNVo.$_Cn(31),Te=_MNVo.$_Cn(554),Ee=_MNVo.$_Cn(583),xe=_MNVo.$_Cn(520),ke=_MNVo.$_Cn(594),Pe=_MNVo.$_Cn(543),Oe=_MNVo.$_Cn(565),De=_MNVo.$_Cn(551),Me=_MNVo.$_Cn(512),Ne=_MNVo.$_Cn(537),Be=_MNVo.$_Cn(64),Re=_MNVo.$_Cn(572),je=_MNVo.$_Cn(597),Ie=_MNVo.$_Cn(548),Fe=_MNVo.$_Cn(527),Ue=_MNVo.$_Cn(10),Le=_MNVo.$_Cn(557),ze=_MNVo.$_Cn(588),qe=_MNVo.$_Cn(593),Ge=_MNVo.$_Cn(589),He=_MNVo.$_Cn(569),Ve=_MNVo.$_Cn(516),We=_MNVo.$_Cn(567),Ze=function(e){for(var t={},n=0;n<e[_MNVo.$_Cn(59)];n++)t[e[n][_MNVo.$_Cn(560)]()]=e[n];return t;},Je=function(e,t){return typeof e===ye&&-1!==Xe(t)[_MNVo.$_Cn(94)](Xe(e));},Xe=function(e){return e[_MNVo.$_Cn(563)]();},Ke=function(e,t){if(typeof e===ye)return e=e[_MNVo.$_Cn(503)](/^\\s\\s*/,ve)[_MNVo.$_Cn(503)](/\\s\\s*$/,ve),typeof t==ge?e:e[_MNVo.$_Cn(391)](0,255);},$e=function(e,t){var n,i,r,o,a,c=0;while(c<t[_MNVo.$_Cn(59)]&&!o){var s=t[c],u=t[c+1],l=n=0;while(l<s[_MNVo.$_Cn(59)]&&!o)if(o=s[l++][_MNVo.$_Cn(578)](e))for(i=0;i<u[_MNVo.$_Cn(59)];i++)a=o[++n],typeof(r=u[i])===be&&0<r[_MNVo.$_Cn(59)]?2===r[_MNVo.$_Cn(59)]?typeof r[1]==we?this[r[0]]=r[1][_MNVo.$_Cn(92)](this,a):this[r[0]]=r[1]:3===r[_MNVo.$_Cn(59)]?typeof r[1]!==we||r[1][_MNVo.$_Cn(578)]&&r[1][_MNVo.$_Cn(496)]?this[r[0]]=a?a[_MNVo.$_Cn(503)](r[1],r[2]):undefined:this[r[0]]=a?r[1][_MNVo.$_Cn(92)](this,a,r[2]):undefined:4===r[_MNVo.$_Cn(59)]&&(this[r[0]]=a?r[3][_MNVo.$_Cn(92)](this,a[_MNVo.$_Cn(503)](r[1],r[2])):undefined):this[r]=a||undefined;c+=2;}},Ye=function(e,t){for(var n in t)if(typeof t[n]===be&&0<t[n][_MNVo.$_Cn(59)]){for(var i=0;i<t[n][_MNVo.$_Cn(59)];i++)if(Je(t[n][i],e))return _MNVo.$_Cn(595)===n?undefined:n;}else if(Je(t[n],e))return _MNVo.$_Cn(595)===n?undefined:n;return e;},Qe={\"\\u004d\\u0045\":_MNVo.$_Cn(574),\"\\u004e\\u0054\\u0020\\u0033\\u002e\\u0031\\u0031\":_MNVo.$_Cn(576),\"\\u004e\\u0054\\u0020\\u0034\\u002e\\u0030\":_MNVo.$_Cn(534),\"\\u0032\\u0030\\u0030\\u0030\":_MNVo.$_Cn(530),\"\\u0058\\u0050\":[_MNVo.$_Cn(517),_MNVo.$_Cn(544)],\"\\u0056\\u0069\\u0073\\u0074\\u0061\":_MNVo.$_Cn(562),\"\\u0037\":_MNVo.$_Cn(504),\"\\u0038\":_MNVo.$_Cn(500),\"\\u0038\\u002e\\u0031\":_MNVo.$_Cn(541),\"\\u0031\\u0030\":[_MNVo.$_Cn(501),_MNVo.$_Cn(573)],\"\\u0052\\u0054\":_MNVo.$_Cn(559)},et={\"\\u0062\\u0072\\u006f\\u0077\\u0073\\u0065\\u0072\":[[/\\b(?:crmo|crios)\\/([\\w\\.]+)/i],[Te,[Se,_MNVo.$_Cn(548)]],[/edg(?:e|ios|a)?\\/([\\w\\.]+)/i],[Te,[Se,_MNVo.$_Cn(528)]],[/(opera mini)\\/([-\\w\\.]+)/i,/(opera [mobiletab]{3,6})\\b.+version\\/([-\\w\\.]+)/i,/(opera)(?:.+version\\/|[\\/ ]+)([\\w\\.]+)/i],[Se,Te],[/opios[\\/ ]+([\\w\\.]+)/i],[Te,[Se,qe+_MNVo.$_Cn(590)]],[/\\bopr\\/([\\w\\.]+)/i],[Te,[Se,qe]],[/(kindle)\\/([\\w\\.]+)/i,/(lunascape|maxthon|netfront|jasmine|blazer)[\\/ ]?([\\w\\.]*)/i,/(avant |iemobile|slim)(?:browser)?[\\/ ]?([\\w\\.]*)/i,/(ba?idubrowser)[\\/ ]?([\\w\\.]+)/i,/(?:ms|\\()(ie) ([\\w\\.]+)/i,/(flock|rockmelt|midori|epiphany|silk|skyfire|ovibrowser|bolt|iron|vivaldi|iridium|phantomjs|bowser|quark|qupzilla|falkon|rekonq|puffin|brave|whale|qqbrowserlite|qq)\\/([-\\w\\.]+)/i,/(weibo)__([\\d\\.]+)/i],[Se,Te],[/(?:\\buc? ?browser|(?:juc.+)ucweb)[\\/ ]?([\\w\\.]+)/i],[Te,[Se,_MNVo.$_Cn(568)+je]],[/\\bqbcore\\/([\\w\\.]+)/i],[Te,[Se,_MNVo.$_Cn(575)]],[/micromessenger\\/([\\w\\.]+)/i],[Te,[Se,_MNVo.$_Cn(558)]],[/konqueror\\/([\\w\\.]+)/i],[Te,[Se,_MNVo.$_Cn(571)]],[/trident.+rv[: ]([\\w\\.]{1,9})\\b.+like gecko/i],[Te,[Se,_MNVo.$_Cn(531)]],[/yabrowser\\/([\\w\\.]+)/i],[Te,[Se,_MNVo.$_Cn(506)]],[/(avast|avg)\\/([\\w\\.]+)/i],[[Se,/(.+)/,_MNVo.$_Cn(525)+je],Te],[/\\bfocus\\/([\\w\\.]+)/i],[Te,[Se,Fe+_MNVo.$_Cn(564)]],[/\\bopt\\/([\\w\\.]+)/i],[Te,[Se,qe+_MNVo.$_Cn(539)]],[/coc_coc\\w+\\/([\\w\\.]+)/i],[Te,[Se,_MNVo.$_Cn(547)]],[/dolfin\\/([\\w\\.]+)/i],[Te,[Se,_MNVo.$_Cn(599)]],[/coast\\/([\\w\\.]+)/i],[Te,[Se,qe+_MNVo.$_Cn(581)]],[/miuibrowser\\/([\\w\\.]+)/i],[Te,[Se,_MNVo.$_Cn(532)+je]],[/fxios\\/([-\\w\\.]+)/i],[Te,[Se,Fe]],[/\\bqihu|(qi?ho?o?|360)browser/i],[[Se,_MNVo.$_Cn(591)+je]],[/(oculus|samsung|sailfish)browser\\/([\\w\\.]+)/i],[[Se,/(.+)/,_MNVo.$_Cn(552)+je],Te],[/(comodo_dragon)\\/([\\w\\.]+)/i],[[Se,/_/g,_MNVo.$_Cn(155)],Te],[/(electron)\\/([\\w\\.]+) safari/i,/(tesla)(?: qtcarbrowser|\\/(20\\d\\d\\.[-\\w\\.]+))/i,/m?(qqbrowser|baiduboxapp|2345Explorer)[\\/ ]?([\\w\\.]+)/i],[Se,Te],[/(metasr)[\\/ ]?([\\w\\.]+)/i,/(lbbrowser)/i],[Se],[/((?:fban\\/fbios|fb_iab\\/fb4a)(?!.+fbav)|;fbav\\/([\\w\\.]+);)/i],[[Se,We],Te],[/safari (line)\\/([\\w\\.]+)/i,/\\b(line)\\/([\\w\\.]+)\\/iab/i,/(chromium|instagram)[\\/ ]([-\\w\\.]+)/i],[Se,Te],[/\\bgsa\\/([\\w\\.]+) .*safari\\//i],[Te,[Se,_MNVo.$_Cn(579)]],[/headlesschrome(?:\\/([\\w\\.]+)| )/i],[Te,[Se,Ie+_MNVo.$_Cn(570)]],[/ wv\\).+(chrome)\\/([\\w\\.]+)/i],[[Se,Ie+_MNVo.$_Cn(511)],Te],[/droid.+ version\\/([\\w\\.]+)\\b.+(?:mobile safari|safari)/i],[Te,[Se,_MNVo.$_Cn(587)+je]],[/(chrome|omniweb|arora|[tizenoka]{5} ?browser)\\/v?([\\w\\.]+)/i],[Se,Te],[/version\\/([\\w\\.]+) .*mobile\\/\\w+ (safari)/i],[Te,[Se,_MNVo.$_Cn(508)]],[/version\\/([\\w\\.]+) .*(mobile ?safari|safari)/i],[Te,Se],[/webkit.+?(mobile ?safari|safari)(\\/[\\w\\.]+)/i],[Se,[Te,Ye,{\"\\u0031\\u002e\\u0030\":_MNVo.$_Cn(585),\"\\u0031\\u002e\\u0032\":_MNVo.$_Cn(542),\"\\u0031\\u002e\\u0033\":_MNVo.$_Cn(561),\"\\u0032\\u002e\\u0030\":_MNVo.$_Cn(596),\"\\u0032\\u002e\\u0030\\u002e\\u0032\":_MNVo.$_Cn(553),\"\\u0032\\u002e\\u0030\\u002e\\u0033\":_MNVo.$_Cn(550),\"\\u0032\\u002e\\u0030\\u002e\\u0034\":_MNVo.$_Cn(514),\"\\u003f\":_MNVo.$_Cn(513)}]],[/(webkit|khtml)\\/([\\w\\.]+)/i],[Se,Te],[/(navigator|netscape\\d?)\\/([-\\w\\.]+)/i],[[Se,_MNVo.$_Cn(502)],Te],[/mobile vr; rv:([\\w\\.]+)\\).+firefox/i],[Te,[Se,Fe+_MNVo.$_Cn(521)]],[/ekiohf.+(flow)\\/([\\w\\.]+)/i,/(swiftfox)/i,/(icedragon|iceweasel|camino|chimera|fennec|maemo browser|minimo|conkeror|klar)[\\/ ]?([\\w\\.\\+]+)/i,/(seamonkey|k-meleon|icecat|iceape|firebird|phoenix|palemoon|basilisk|waterfox)\\/([-\\w\\.]+)$/i,/(firefox)\\/([\\w\\.]+)/i,/(mozilla)\\/([\\w\\.]+) .+rv\\:.+gecko\\/\\d+/i,/(polaris|lynx|dillo|icab|doris|amaya|w3m|netsurf|sleipnir|obigo|mosaic|(?:go|ice|up)[\\. ]?browser)[-\\/ ]?v?([\\w\\.]+)/i,/(links) \\(([\\w\\.]+)/i],[Se,Te]],\"\\u0063\\u0070\\u0075\":[[/(?:(amd|x(?:(?:86|64)[-_])?|wow|win)64)[;\\)]/i],[[Ee,_MNVo.$_Cn(522)]],[/(ia32(?=;))/i],[[Ee,Xe]],[/((?:i[346]|x)86)[;\\)]/i],[[Ee,_MNVo.$_Cn(526)]],[/\\b(aarch64|arm(v?8e?l?|_?64))\\b/i],[[Ee,_MNVo.$_Cn(529)]],[/\\b(arm(?:v[67])?ht?n?[fl]p?)\\b/i],[[Ee,_MNVo.$_Cn(598)]],[/windows (ce|mobile); ppc;/i],[[Ee,_MNVo.$_Cn(546)]],[/((?:ppc|powerpc)(?:64)?)(?: mac|;|\\))/i],[[Ee,/ower/,ve,Xe]],[/(sun4\\w)[;\\)]/i],[[Ee,_MNVo.$_Cn(586)]],[/((?:avr32|ia64(?=;))|68k(?=\\))|\\barm(?=v(?:[1-7]|[5-7]1)l?|;|eabi)|(?=atmel )avr|(?:irix|mips|sparc)(?:64)?\\b|pa-risc)/i],[[Ee,Xe]]],\"\\u0064\\u0065\\u0076\\u0069\\u0063\\u0065\":[[/\\b(sch-i[89]0\\d|shw-m380s|sm-[pt]\\w{2,4}|gt-[pn]\\d{2,4}|sgh-t8[56]9|nexus 10)/i],[$_BEK,[Ce,Ge],[Ae,Pe]],[/\\b((?:s[cgp]h|gt|sm)-\\w+|galaxy nexus)/i,/samsung[- ]([-\\w]+)/i,/sec-(sgh\\w+)/i],[$_BEK,[Ce,Ge],[Ae,ke]],[/\\((ip(?:hone|od)[\\w ]*);/i],[$_BEK,[Ce,Be],[Ae,ke]],[/\\((ipad);[-\\w\\),; ]+apple/i,/applecoremedia\\/[\\w\\.]+ \\((ipad)/i,/\\b(ipad)\\d\\d?,\\d\\d?[;\\]].+ios/i],[$_BEK,[Ce,Be],[Ae,Pe]],[/\\b((?:ag[rs][23]?|bah2?|sht?|btv)-a?[lw]\\d{2})\\b(?!.+d\\/s)/i],[$_BEK,[Ce,_MNVo.$_Cn(566)],[Ae,Pe]],[/(?:huawei|honor)([-\\w ]+)[;\\)]/i,/\\b(nexus 6p|\\w{2,4}-[atu]?[ln][01259x][012359][an]?)\\b(?!.+d\\/s)/i],[$_BEK,[Ce,_MNVo.$_Cn(566)],[Ae,ke]],[/\\b(poco[\\w ]+)(?: bui|\\))/i,/\\b; (\\w+) build\\/hm\\1/i,/\\b(hm[-_ ]?note?[_ ]?(?:\\d\\w)?) bui/i,/\\b(redmi[\\-_ ]?(?:note|k)?[\\w_ ]+)(?: bui|\\))/i,/\\b(mi[-_ ]?(?:a\\d|one|one[_ ]plus|note lte|max)?[_ ]?(?:\\d?\\w?)[_ ]?(?:plus|se|lite)?)(?: bui|\\))/i],[[$_BEK,/_/g,_MNVo.$_Cn(155)],[Ce,_MNVo.$_Cn(540)],[Ae,ke]],[/\\b(mi[-_ ]?(?:pad)(?:[\\w_ ]+))(?: bui|\\))/i],[[$_BEK,/_/g,_MNVo.$_Cn(155)],[Ce,_MNVo.$_Cn(540)],[Ae,Pe]],[/; (\\w+) bui.+ oppo/i,/\\b(cph[12]\\d{3}|p(?:af|c[al]|d\\w|e[ar])[mt]\\d0|x9007|a101op)\\b/i],[$_BEK,[Ce,_MNVo.$_Cn(535)],[Ae,ke]],[/vivo (\\w+)(?: bui|\\))/i,/\\b(v[12]\\d{3}\\w?[at])(?: bui|;)/i],[$_BEK,[Ce,_MNVo.$_Cn(592)],[Ae,ke]],[/\\b(rmx[12]\\d{3})(?: bui|;|\\))/i],[$_BEK,[Ce,_MNVo.$_Cn(580)],[Ae,ke]],[/\\b(milestone|droid(?:[2-4x]| (?:bionic|x2|pro|razr))?:?( 4g)?)\\b[\\w ]+build\\//i,/\\bmot(?:orola)?[- ](\\w*)/i,/((?:moto[\\w\\(\\) ]+|xt\\d{3,4}|nexus 6)(?= bui|\\)))/i],[$_BEK,[Ce,ze],[Ae,ke]],[/\\b(mz60\\d|xoom[2 ]{0,2}) build\\//i],[$_BEK,[Ce,ze],[Ae,Pe]],[/((?=lg)?[vl]k\\-?\\d{3}) bui| 3\\.[-\\w; ]{10}lg?-([06cv9]{3,4})/i],[$_BEK,[Ce,_MNVo.$_Cn(549)],[Ae,Pe]],[/(lm(?:-?f100[nv]?|-[\\w\\.]+)(?= bui|\\))|nexus [45])/i,/\\blg[-e;\\/ ]+((?!browser|netcast|android tv)\\w+)/i,/\\blg-?([\\d\\w]+) bui/i],[$_BEK,[Ce,_MNVo.$_Cn(549)],[Ae,ke]],[/(ideatab[-\\w ]+)/i,/lenovo ?(s[56]000[-\\w]+|tab(?:[\\w ]+)|yt[-\\d\\w]{6}|tb[-\\d\\w]{6})/i],[$_BEK,[Ce,_MNVo.$_Cn(509)],[Ae,Pe]],[/(?:maemo|nokia).*(n900|lumia \\d+)/i,/nokia[-_ ]?([-\\w\\.]*)/i],[[$_BEK,/_/g,_MNVo.$_Cn(155)],[Ce,_MNVo.$_Cn(619)],[Ae,ke]],[/(pixel c)\\b/i],[$_BEK,[Ce,Ue],[Ae,Pe]],[/droid.+; (pixel[\\daxl ]{0,6})(?: bui|\\))/i],[$_BEK,[Ce,Ue],[Ae,ke]],[/droid.+ ([c-g]\\d{4}|so[-gl]\\w+|xq-a\\w[4-7][12])(?= bui|\\).+chrome\\/(?![1-6]{0,1}\\d\\.))/i],[$_BEK,[Ce,He],[Ae,ke]],[/sony tablet [ps]/i,/\\b(?:sony)?sgp\\w+(?: bui|\\))/i],[[$_BEK,_MNVo.$_Cn(674)],[Ce,He],[Ae,Pe]],[/ (kb2005|in20[12]5|be20[12][59])\\b/i,/(?:one)?(?:plus)? (a\\d0\\d\\d)(?: b|\\))/i],[$_BEK,[Ce,_MNVo.$_Cn(663)],[Ae,ke]],[/(alexa)webm/i,/(kf[a-z]{2}wi)( bui|\\))/i,/(kf[a-z]+)( bui|\\)).+silk\\//i],[$_BEK,[Ce,Ne],[Ae,Pe]],[/((?:sd|kf)[0349hijorstuw]+)( bui|\\)).+silk\\//i],[[$_BEK,/(.+)/g,_MNVo.$_Cn(689)],[Ce,Ne],[Ae,ke]],[/(playbook);[-\\w\\),; ]+(rim)/i],[$_BEK,Ce,[Ae,Pe]],[/\\b((?:bb[a-f]|st[hv])100-\\d)/i,/\\(bb10; (\\w+)/i],[$_BEK,[Ce,Re],[Ae,ke]],[/(?:\\b|asus_)(transfo[prime ]{4,10} \\w+|eeepc|slider \\w+|nexus 7|padfone|p00[cj])/i],[$_BEK,[Ce,_MNVo.$_Cn(681)],[Ae,Pe]],[/ (z[bes]6[027][012][km][ls]|zenfone \\d\\w?)\\b/i],[$_BEK,[Ce,_MNVo.$_Cn(681)],[Ae,ke]],[/(nexus 9)/i],[$_BEK,[Ce,_MNVo.$_Cn(651)],[Ae,Pe]],[/(htc)[-;_ ]{1,2}([\\w ]+(?=\\)| bui)|\\w+)/i,/(zte)[- ]([\\w ]+?)(?: bui|\\/|\\))/i,/(alcatel|geeksphone|nexian|panasonic|sony)[-_ ]?([-\\w]*)/i],[Ce,[$_BEK,/_/g,_MNVo.$_Cn(155)],[Ae,ke]],[/droid.+; ([ab][1-7]-?[0178a]\\d\\d?)/i],[$_BEK,[Ce,_MNVo.$_Cn(657)],[Ae,Pe]],[/droid.+; (m[1-5] note) bui/i,/\\bmz-([-\\w]{2,})/i],[$_BEK,[Ce,_MNVo.$_Cn(639)],[Ae,ke]],[/\\b(sh-?[altvz]?\\d\\d[a-ekm]?)/i],[$_BEK,[Ce,_MNVo.$_Cn(632)],[Ae,ke]],[/(blackberry|benq|palm(?=\\-)|sonyericsson|acer|asus|dell|meizu|motorola|polytron)[-_ ]?([-\\w]*)/i,/(hp) ([\\w ]+\\w)/i,/(asus)-?(\\w+)/i,/(microsoft); (lumia[\\w ]+)/i,/(lenovo)[-_ ]?([-\\w]+)/i,/(jolla)/i,/(oppo) ?([\\w ]+) bui/i],[Ce,$_BEK,[Ae,ke]],[/(archos) (gamepad2?)/i,/(hp).+(touchpad(?!.+tablet)|tablet)/i,/(kindle)\\/([\\w\\.]+)/i,/(nook)[\\w ]+build\\/(\\w+)/i,/(dell) (strea[kpr\\d ]*[\\dko])/i,/(le[- ]+pan)[- ]+(\\w{1,9}) bui/i,/(trinity)[- ]*(t\\d{3}) bui/i,/(gigaset)[- ]+(q\\w{1,9}) bui/i,/(vodafone) ([\\w ]+)(?:\\)| bui)/i],[Ce,$_BEK,[Ae,Pe]],[/(surface duo)/i],[$_BEK,[Ce,Le],[Ae,Pe]],[/droid [\\d\\.]+; (fp\\du?)(?: b|\\))/i],[$_BEK,[Ce,_MNVo.$_Cn(600)],[Ae,ke]],[/(u304aa)/i],[$_BEK,[Ce,_MNVo.$_Cn(698)],[Ae,ke]],[/\\bsie-(\\w*)/i],[$_BEK,[Ce,_MNVo.$_Cn(694)],[Ae,ke]],[/\\b(rct\\w+) b/i],[$_BEK,[Ce,_MNVo.$_Cn(697)],[Ae,Pe]],[/\\b(venue[\\d ]{2,7}) b/i],[$_BEK,[Ce,_MNVo.$_Cn(607)],[Ae,Pe]],[/\\b(q(?:mv|ta)\\w+) b/i],[$_BEK,[Ce,_MNVo.$_Cn(647)],[Ae,Pe]],[/\\b(?:barnes[& ]+noble |bn[rt])([\\w\\+ ]*) b/i],[$_BEK,[Ce,_MNVo.$_Cn(626)],[Ae,Pe]],[/\\b(tm\\d{3}\\w+) b/i],[$_BEK,[Ce,_MNVo.$_Cn(604)],[Ae,Pe]],[/\\b(k88) b/i],[$_BEK,[Ce,_MNVo.$_Cn(654)],[Ae,Pe]],[/\\b(nx\\d{3}j) b/i],[$_BEK,[Ce,_MNVo.$_Cn(654)],[Ae,ke]],[/\\b(gen\\d{3}) b.+49h/i],[$_BEK,[Ce,_MNVo.$_Cn(695)],[Ae,ke]],[/\\b(zur\\d{3}) b/i],[$_BEK,[Ce,_MNVo.$_Cn(695)],[Ae,Pe]],[/\\b((zeki)?tb.*\\b) b/i],[$_BEK,[Ce,_MNVo.$_Cn(672)],[Ae,Pe]],[/\\b([yr]\\d{2}) b/i,/\\b(dragon[- ]+touch |dt)(\\w{5}) b/i],[[Ce,_MNVo.$_Cn(623)],$_BEK,[Ae,Pe]],[/\\b(ns-?\\w{0,9}) b/i],[$_BEK,[Ce,_MNVo.$_Cn(609)],[Ae,Pe]],[/\\b((nxa|next)-?\\w{0,9}) b/i],[$_BEK,[Ce,_MNVo.$_Cn(601)],[Ae,Pe]],[/\\b(xtreme\\_)?(v(1[045]|2[015]|[3469]0|7[05])) b/i],[[Ce,_MNVo.$_Cn(668)],$_BEK,[Ae,ke]],[/\\b(lvtel\\-)?(v1[12]) b/i],[[Ce,_MNVo.$_Cn(628)],$_BEK,[Ae,ke]],[/\\b(ph-1) /i],[$_BEK,[Ce,_MNVo.$_Cn(658)],[Ae,ke]],[/\\b(v(100md|700na|7011|917g).*\\b) b/i],[$_BEK,[Ce,_MNVo.$_Cn(693)],[Ae,Pe]],[/\\b(trio[-\\w\\. ]+) b/i],[$_BEK,[Ce,_MNVo.$_Cn(643)],[Ae,Pe]],[/\\btu_(1491) b/i],[$_BEK,[Ce,_MNVo.$_Cn(629)],[Ae,Pe]],[/(shield[\\w ]+) b/i],[$_BEK,[Ce,_MNVo.$_Cn(656)],[Ae,Pe]],[/(sprint) (\\w+)/i],[Ce,$_BEK,[Ae,ke]],[/(kin\\.[onetw]{3})/i],[[$_BEK,/\\./g,_MNVo.$_Cn(155)],[Ce,Le],[Ae,ke]],[/droid.+; (cc6666?|et5[16]|mc[239][23]x?|vc8[03]x?)\\)/i],[$_BEK,[Ce,Ve],[Ae,Pe]],[/droid.+; (ec30|ps20|tc[2-8]\\d[kx])\\)/i],[$_BEK,[Ce,Ve],[Ae,ke]],[/(ouya)/i,/(nintendo) ([wids3utch]+)/i],[Ce,$_BEK,[Ae,xe]],[/droid.+; (shield) bui/i],[$_BEK,[Ce,_MNVo.$_Cn(656)],[Ae,xe]],[/(playstation [345portablevi]+)/i],[$_BEK,[Ce,He],[Ae,xe]],[/\\b(xbox(?: one)?(?!; xbox))[\\); ]/i],[$_BEK,[Ce,Le],[Ae,xe]],[/smart-tv.+(samsung)/i],[Ce,[Ae,Oe]],[/hbbtv.+maple;(\\d+)/i],[[$_BEK,/^/,_MNVo.$_Cn(684)],[Ce,Ge],[Ae,Oe]],[/(nux; netcast.+smarttv|lg (netcast\\.tv-201\\d|android tv))/i],[[Ce,_MNVo.$_Cn(549)],[Ae,Oe]],[/(apple) ?tv/i],[Ce,[$_BEK,Be+_MNVo.$_Cn(660)],[Ae,Oe]],[/crkey/i],[[$_BEK,Ie+_MNVo.$_Cn(676)],[Ce,Ue],[Ae,Oe]],[/droid.+aft(\\w)( bui|\\))/i],[$_BEK,[Ce,Ne],[Ae,Oe]],[/\\(dtv[\\);].+(aquos)/i],[$_BEK,[Ce,_MNVo.$_Cn(632)],[Ae,Oe]],[/\\b(roku)[\\dx]*[\\)\\/]((?:dvp-)?[\\d\\.]*)/i,/hbbtv\\/\\d+\\.\\d+\\.\\d+ +\\([\\w ]*; *(\\w[^;]*);([^;]*)/i],[[Ce,Ke],[$_BEK,Ke],[Ae,Oe]],[/\\b(android tv|smart[- ]?tv|opera tv|tv; rv:)\\b/i],[[Ae,Oe]],[/((pebble))app/i],[Ce,$_BEK,[Ae,De]],[/droid.+; (glass) \\d/i],[$_BEK,[Ce,Ue],[Ae,De]],[/droid.+; (wt63?0{2,3})\\)/i],[$_BEK,[Ce,Ve],[Ae,De]],[/(quest( 2)?)/i],[$_BEK,[Ce,We],[Ae,De]],[/(tesla)(?: qtcarbrowser|\\/[-\\w\\.]+)/i],[Ce,[Ae,Me]],[/droid .+?; ([^;]+?)(?: bui|\\) applew).+? mobile safari/i],[$_BEK,[Ae,ke]],[/droid .+?; ([^;]+?)(?: bui|\\) applew).+?(?! mobile) safari/i],[$_BEK,[Ae,Pe]],[/\\b((tablet|tab)[;\\/]|focus\\/\\d(?!.+mobile))/i],[[Ae,Pe]],[/(phone|mobile(?:[;\\/]| safari)|pda(?=.+windows ce))/i],[[Ae,ke]],[/(android[-\\w\\. ]{0,9});.+buil/i],[$_BEK,[Ce,_MNVo.$_Cn(666)]]],\"\\u0065\\u006e\\u0067\\u0069\\u006e\\u0065\":[[/windows.+ edge\\/([\\w\\.]+)/i],[Te,[Se,_MNVo.$_Cn(606)]],[/webkit\\/537\\.36.+chrome\\/(?!27)([\\w\\.]+)/i],[Te,[Se,_MNVo.$_Cn(680)]],[/(presto)\\/([\\w\\.]+)/i,/(webkit|trident|netfront|netsurf|amaya|lynx|w3m|goanna)\\/([\\w\\.]+)/i,/ekioh(flow)\\/([\\w\\.]+)/i,/(khtml|tasman|links)[\\/ ]\\(?([\\w\\.]+)/i,/(icab)[\\/ ]([23]\\.[\\d\\.]+)/i],[Se,Te],[/rv\\:([\\w\\.]{1,9})\\b.+(gecko)/i],[Te,Se]],\"\\u006f\\u0073\":[[/microsoft (windows) (vista|xp)/i],[Se,Te],[/(windows) nt 6\\.2; (arm)/i,/(windows (?:phone(?: os)?|mobile))[\\/ ]?([\\d\\.\\w ]*)/i,/(windows)[\\/ ]?([ntce\\d\\. ]+\\w)(?!.+xbox)/i],[Se,[Te,Ye,Qe]],[/(win(?=3|9|n)|win 9x )([nt\\d\\.]+)/i],[[Se,_MNVo.$_Cn(692)],[Te,Ye,Qe]],[/ip[honead]{2,4}\\b(?:.*os ([\\w]+) like mac|; opera)/i,/cfnetwork\\/.+darwin/i],[[Te,/_/g,_MNVo.$_Cn(650)],[Se,_MNVo.$_Cn(648)]],[/(mac os x) ?([\\w\\. ]*)/i,/(macintosh|mac_powerpc\\b)(?!.+haiku)/i],[[Se,_MNVo.$_Cn(605)],[Te,/_/g,_MNVo.$_Cn(650)]],[/droid ([\\w\\.]+)\\b.+(android[- ]x86)/i],[Te,Se],[/(android|webos|qnx|bada|rim tablet os|maemo|meego|sailfish)[-\\/ ]?([\\w\\.]*)/i,/(blackberry)\\w*\\/([\\w\\.]*)/i,/(tizen|kaios)[\\/ ]([\\w\\.]+)/i,/\\((series40);/i],[Se,Te],[/\\(bb(10);/i],[Te,[Se,Re]],[/(?:symbian ?os|symbos|s60(?=;)|series60)[-\\/ ]?([\\w\\.]*)/i],[Te,[Se,_MNVo.$_Cn(625)]],[/mozilla\\/[\\d\\.]+ \\((?:mobile|tablet|tv|mobile; [\\w ]+); rv:.+ gecko\\/([\\w\\.]+)/i],[Te,[Se,Fe+_MNVo.$_Cn(644)]],[/web0s;.+rt(tv)/i,/\\b(?:hp)?wos(?:browser)?\\/([\\w\\.]+)/i],[Te,[Se,_MNVo.$_Cn(659)]],[/crkey\\/([\\d\\.]+)/i],[Te,[Se,Ie+_MNVo.$_Cn(676)]],[/(cros) [\\w]+ ([\\w\\.]+\\w)/i],[[Se,_MNVo.$_Cn(655)],Te],[/(nintendo|playstation) ([wids345portablevuch]+)/i,/(xbox); +xbox ([^\\);]+)/i,/\\b(joli|palm)\\b ?(?:os)?\\/?([\\w\\.]*)/i,/(mint)[\\/\\(\\) ]?(\\w*)/i,/(mageia|vectorlinux)[; ]/i,/([kxln]?ubuntu|debian|suse|opensuse|gentoo|arch(?= linux)|slackware|fedora|mandriva|centos|pclinuxos|red ?hat|zenwalk|linpus|raspbian|plan 9|minix|risc os|contiki|deepin|manjaro|elementary os|sabayon|linspire)(?: gnu\\/linux)?(?: enterprise)?(?:[- ]linux)?(?:-gnu)?[-\\/ ]?(?!chrom|package)([-\\w\\.]*)/i,/(hurd|linux) ?([\\w\\.]*)/i,/(gnu) ?([\\w\\.]*)/i,/\\b([-frentopcghs]{0,5}bsd|dragonfly)[\\/ ]?(?!amd|[ix346]{1,2}86)([\\w\\.]*)/i,/(haiku) (\\w+)/i],[Se,Te],[/(sunos) ?([\\w\\.\\d]*)/i],[[Se,_MNVo.$_Cn(670)],Te],[/((?:open)?solaris)[-\\/ ]?([\\w\\.]*)/i,/(aix) ((\\d)(?=\\.|\\)| )[\\w\\.])*/i,/\\b(beos|os\\/2|amigaos|morphos|openvms|fuchsia|hp-ux)/i,/(unix) ?([\\w\\.]*)/i],[Se,Te]]},tt=function(e,t){if(void 0===t&&(t=null),typeof(e=void 0===e?null:e)===be&&(t=e,e=undefined),!(this instanceof tt))return new tt(e,t)[_MNVo.$_Cn(662)]();var n=e||(typeof window!=ge&&window[_MNVo.$_Cn(472)]&&window[_MNVo.$_Cn(472)][_MNVo.$_Cn(426)]?window[_MNVo.$_Cn(472)][_MNVo.$_Cn(426)]:ve),i=t?function(e,t){var n,i={};for(n in e)t[n]&&t[n][_MNVo.$_Cn(59)]%2==0?i[n]=t[n][_MNVo.$_Cn(75)](e[n]):i[n]=e[n];return i;}(et,t):et;return this[_MNVo.$_Cn(696)]=function(){var e,t={};return t[Se]=undefined,t[Te]=undefined,$e[_MNVo.$_Cn(92)](t,n,i[_MNVo.$_Cn(688)]),t[_MNVo.$_Cn(637)]=typeof(e=t[_MNVo.$_Cn(554)])===ye?e[_MNVo.$_Cn(503)](/[^\\d\\.]/g,ve)[_MNVo.$_Cn(228)](_MNVo.$_Cn(650))[0]:undefined,t;},this[_MNVo.$_Cn(610)]=function(){var e={};return e[Ee]=undefined,$e[_MNVo.$_Cn(92)](e,n,i[_MNVo.$_Cn(615)]),e;},this[_MNVo.$_Cn(677)]=function(){var e={};return e[Ce]=undefined,e[$_BEK]=undefined,e[Ae]=undefined,$e[_MNVo.$_Cn(92)](e,n,i[_MNVo.$_Cn(614)]),e;},this[_MNVo.$_Cn(687)]=function(){var e={};return e[Se]=undefined,e[Te]=undefined,$e[_MNVo.$_Cn(92)](e,n,i[_MNVo.$_Cn(652)]),e;},this[_MNVo.$_Cn(620)]=function(){var e={};return e[Se]=undefined,e[Te]=undefined,$e[_MNVo.$_Cn(92)](e,n,i[_MNVo.$_Cn(635)]),e;},this[_MNVo.$_Cn(662)]=function(){return{\"\\u0075\\u0061\":this[_MNVo.$_Cn(602)](),\"\\u0062\\u0072\\u006f\\u0077\\u0073\\u0065\\u0072\":this[_MNVo.$_Cn(696)](),\"\\u0065\\u006e\\u0067\\u0069\\u006e\\u0065\":this[_MNVo.$_Cn(687)](),\"\\u006f\\u0073\":this[_MNVo.$_Cn(620)](),\"\\u0064\\u0065\\u0076\\u0069\\u0063\\u0065\":this[_MNVo.$_Cn(677)](),\"\\u0063\\u0070\\u0075\":this[_MNVo.$_Cn(610)]()};},this[_MNVo.$_Cn(602)]=function(){return n;},this[_MNVo.$_Cn(645)]=function(e){return n=typeof e===ye&&255<e[_MNVo.$_Cn(59)]?Ke(e,255):e,this;},this[_MNVo.$_Cn(645)](n),this;};tt[_MNVo.$_Cn(653)]=_MNVo.$_Cn(617),tt[_MNVo.$_Cn(631)]=Ze([Se,Te,_MNVo.$_Cn(637)]),tt[_MNVo.$_Cn(679)]=Ze([Ee]),tt[_MNVo.$_Cn(612)]=Ze([$_BEK,Ce,Ae,xe,ke,Oe,Pe,De,Me]),tt[_MNVo.$_Cn(633)]=tt[_MNVo.$_Cn(678)]=Ze([Se,Te]);var nt,it=typeof window!=ge&&(window[_MNVo.$_Cn(664)]||window[_MNVo.$_Cn(622)]);it&&!it[_MNVo.$_Cn(603)]&&(nt=new tt(),it[_MNVo.$_Cn(603)]=nt[_MNVo.$_Cn(662)](),it[_MNVo.$_Cn(603)][_MNVo.$_Cn(536)]=function(){return nt[_MNVo.$_Cn(602)]();},it[_MNVo.$_Cn(603)][_MNVo.$_Cn(431)]=function(e){nt[_MNVo.$_Cn(645)](e);var t,n=nt[_MNVo.$_Cn(662)]();for(t in n)it[_MNVo.$_Cn(603)][t]=n[t];});var rt,ot,at,ct,st,ut,lt,dt,ft,ht,pt,mt,vt,wt,gt,bt={\"\\u0061\\u006e\\u0061\\u006c\\u0079\\u0073\\u0065\":function(t){var n={},i=tt(t[_MNVo.$_Cn(426)])[_MNVo.$_Cn(688)][_MNVo.$_Cn(637)],e=function(e){e=e(t);n[e[_MNVo.$_Cn(76)]]=e;};e(function(){var e=/PhantomJS/[_MNVo.$_Cn(496)](t[_MNVo.$_Cn(426)])?ot:at;return ct(rt[_MNVo.$_Cn(638)],e,null,_MNVo.$_Cn(675));}),e(function(){var e=t[_MNVo.$_Cn(611)][_MNVo.$_Cn(108)](function(e){return e;})?ot:at;return ct(rt[_MNVo.$_Cn(671)],e,null,_MNVo.$_Cn(624));}),e(function(){var e=/Trident|MSIE|Edge/[_MNVo.$_Cn(496)](t[_MNVo.$_Cn(426)])||t[_MNVo.$_Cn(247)]!==undefined?at:ot;return ct(rt[_MNVo.$_Cn(690)],e,null,_MNVo.$_Cn(661));}),e(function(){var e=/HeadlessChrome/[_MNVo.$_Cn(496)](t[_MNVo.$_Cn(426)])?ot:at;return ct(rt[_MNVo.$_Cn(686)],e,null,_MNVo.$_Cn(685));}),e(function(){var e=t[_MNVo.$_Cn(627)]?ot:at;return ct(rt[_MNVo.$_Cn(618)],e,null,_MNVo.$_Cn(616));}),e(function(){var e=_MNVo.$_Cn(646)===t[_MNVo.$_Cn(636)][_MNVo.$_Cn(608)]&&_MNVo.$_Cn(642)===t[_MNVo.$_Cn(636)][_MNVo.$_Cn(37)]?ot:at;return ct(rt[_MNVo.$_Cn(649)],e,null,_MNVo.$_Cn(699));}),e(function(){var e=/Chrome/[_MNVo.$_Cn(496)](t[_MNVo.$_Cn(426)])&&0===t[_MNVo.$_Cn(264)][_MNVo.$_Cn(59)]?_MNVo.$_Cn(318):at;return ct(rt[_MNVo.$_Cn(673)],e,null,_MNVo.$_Cn(665));}),e(function(){var e=t[_MNVo.$_Cn(621)][_MNVo.$_Cn(108)](function(e){return e;})?ot:at;return ct(rt[_MNVo.$_Cn(683)],e,null,_MNVo.$_Cn(669));}),e(function(){var e=/Chrome/[_MNVo.$_Cn(496)](t[_MNVo.$_Cn(426)])&&49<i&&!t[_MNVo.$_Cn(630)]?ot:at;return ct(rt[_MNVo.$_Cn(667)],e,null,_MNVo.$_Cn(640));}),e(function(){var e=t[_MNVo.$_Cn(641)][_MNVo.$_Cn(108)](function(e){return 28===e[_MNVo.$_Cn(59)]&&-1<e[_MNVo.$_Cn(94)](_MNVo.$_Cn(691))&&-1<e[_MNVo.$_Cn(94)](_MNVo.$_Cn(634));})?ot:at;return ct(rt[_MNVo.$_Cn(613)],e,t[_MNVo.$_Cn(641)],_MNVo.$_Cn(682));}),e(function(){var e=t[_MNVo.$_Cn(771)]&&t[_MNVo.$_Cn(784)]&&t[_MNVo.$_Cn(749)]?ot:at;return ct(rt[_MNVo.$_Cn(736)],e,[t[_MNVo.$_Cn(771)],t[_MNVo.$_Cn(784)],t[_MNVo.$_Cn(749)]],_MNVo.$_Cn(765));});var r={},o={};return Object[_MNVo.$_Cn(11)](n)[_MNVo.$_Cn(756)](function(e){r[e]=n[e][_MNVo.$_Cn(791)],n[e][_MNVo.$_Cn(770)]&&(o[e]=n[e][_MNVo.$_Cn(770)]);}),{\"\\u0072\\u006f\\u0065\\u0052\\u0065\\u0073\\u0075\\u006c\\u0074\":r,\"\\u0072\\u006f\\u0065\\u0049\\u006e\\u0066\\u006f\":o};},\"\\u0043\\u004f\\u004e\\u0053\\u0049\\u0053\\u0054\\u0045\\u004e\\u0054\":at=_MNVo.$_Cn(479),\"\\u0055\\u004e\\u0053\\u0055\\u0052\\u0045\":_MNVo.$_Cn(318),\"\\u0049\\u004e\\u0043\\u004f\\u004e\\u0053\\u0049\\u0053\\u0054\\u0045\\u004e\\u0054\":ot=_MNVo.$_Cn(316),\"\\u0054\\u0045\\u0053\\u0054\\u0053\":rt={\"\\u0050\\u0048\\u0041\\u004e\\u0054\\u004f\\u004d\\u005f\\u0055\\u0041\":_MNVo.$_Cn(796),\"\\u0050\\u0048\\u0041\\u004e\\u0054\\u004f\\u004d\\u005f\\u0050\\u0052\\u004f\\u0050\\u0045\\u0052\\u0054\\u0049\\u0045\\u0053\":_MNVo.$_Cn(781),\"\\u0050\\u0048\\u0041\\u004e\\u0054\\u004f\\u004d\\u005f\\u004c\\u0041\\u004e\\u0047\\u0055\\u0041\\u0047\\u0045\":_MNVo.$_Cn(745),\"\\u0048\\u0045\\u0041\\u0044\\u0043\\u0048\\u0052\\u005f\\u0055\\u0041\":_MNVo.$_Cn(719),\"\\u0057\\u0045\\u0042\\u0044\\u0052\\u0049\\u0056\\u0045\\u0052\":_MNVo.$_Cn(721),\"\\u0048\\u0045\\u0041\\u0044\\u0043\\u0048\\u0052\\u005f\\u0050\\u0045\\u0052\\u004d\\u0049\\u0053\\u0053\\u0049\\u004f\\u004e\\u0053\":_MNVo.$_Cn(738),\"\\u0048\\u0045\\u0041\\u0044\\u0043\\u0048\\u0052\\u005f\\u0050\\u004c\\u0055\\u0047\\u0049\\u004e\\u0053\":_MNVo.$_Cn(758),\"\\u0053\\u0045\\u004c\\u0045\\u004e\\u0049\\u0055\\u004d\\u005f\\u0044\\u0052\\u0049\\u0056\\u0045\\u0052\":_MNVo.$_Cn(701),\"\\u0043\\u0048\\u0052\\u005f\\u0042\\u0041\\u0054\\u0054\\u0045\\u0052\\u0059\":_MNVo.$_Cn(728),\"\\u0053\\u0045\\u004c\\u0045\\u004e\\u0049\\u0055\\u004d\\u005f\\u004c\\u0049\\u0045\":_MNVo.$_Cn(700),\"\\u0053\\u0054\\u0045\\u0041\\u004c\\u0054\\u0048\\u005f\\u0050\\u004c\\u0055\\u0047\\u0049\\u004e\":_MNVo.$_Cn(742)}},yt=(lt={\"\\u0070\\u006c\\u0075\\u0067\\u0069\\u006e\\u0073\":!(ut=_MNVo.$_Cn(741)),\"\\u006d\\u0069\\u006d\\u0065\\u0054\\u0079\\u0070\\u0065\\u0073\":!(ct=function(e,t,n,i){return{\"\\u006e\\u0061\\u006d\\u0065\":e,\"\\u0063\\u006f\\u006e\\u0073\\u0069\\u0073\\u0074\\u0065\\u006e\\u0074\":t,\"\\u0064\\u0061\\u0074\\u0061\":n,\"\\u0063\\u006f\\u0064\\u0065\":i};}),\"\\u0075\\u0073\\u0065\\u0072\\u0041\\u0067\\u0065\\u006e\\u0074\":!1,\"\\u0070\\u006c\\u0061\\u0074\\u0066\\u006f\\u0072\\u006d\":!1,\"\\u006c\\u0061\\u006e\\u0067\\u0075\\u0061\\u0067\\u0065\\u0073\":!1,\"\\u0070\\u0072\\u006f\\u0064\\u0075\\u0063\\u0074\\u0053\\u0075\\u0062\":!1,\"\\u0065\\u0074\\u0073\\u006c\":!1,\"\\u0070\\u0068\\u0061\\u006e\\u0074\\u006f\\u006d\\u004a\\u0053\":!1,\"\\u006e\\u0069\\u0067\\u0068\\u0074\\u006d\\u0061\\u0072\\u0065\\u004a\\u0053\":!1,\"\\u0073\\u0065\\u006c\\u0065\\u006e\\u0069\\u0075\\u006d\":!1,\"\\u0077\\u0065\\u0062\\u0044\\u0072\\u0069\\u0076\\u0065\\u0072\":!1,\"\\u0065\\u0072\\u0072\\u006f\\u0072\\u0073\\u0047\\u0065\\u006e\\u0065\\u0072\\u0061\\u0074\\u0065\\u0064\":!1,\"\\u0068\\u0061\\u0073\\u0043\\u0068\\u0072\\u006f\\u006d\\u0065\":!1,\"\\u0064\\u0065\\u0074\\u0061\\u0069\\u006c\\u0043\\u0068\\u0072\\u006f\\u006d\\u0065\":!1,\"\\u0070\\u0065\\u0072\\u006d\\u0069\\u0073\\u0073\\u0069\\u006f\\u006e\\u0073\":!0,\"\\u0069\\u0066\\u0072\\u0061\\u006d\\u0065\\u0043\\u0068\\u0072\\u006f\\u006d\\u0065\":!1,\"\\u0064\\u0065\\u0062\\u0075\\u0067\\u0054\\u006f\\u006f\\u006c\":!1,\"\\u0062\\u0061\\u0074\\u0074\\u0065\\u0072\\u0079\":!1,\"\\u0073\\u0065\\u0071\\u0075\\u0065\\u006e\\u0074\\u0075\\u006d\":!1,\"\\u0061\\u0075\\u0064\\u0069\\u006f\\u0043\\u006f\\u0064\\u0065\\u0063\\u0073\":!1,\"\\u0076\\u0069\\u0064\\u0065\\u006f\\u0043\\u006f\\u0064\\u0065\\u0063\\u0073\":!1,\"\\u0073\\u0065\\u006c\\u0065\\u006e\\u0069\\u0075\\u006d\\u004c\\u0069\\u0065\":!1,\"\\u0073\\u0065\\u006c\\u0065\\u006e\\u0069\\u0075\\u006d\\u0043\\u0061\\u0063\\u0068\\u0065\":!1,\"\\u0073\\u0074\\u0065\\u0061\\u006c\\u0074\\u0068\\u0049\\u0066\\u0072\\u0061\\u006d\\u0065\":!1,\"\\u0073\\u0074\\u0065\\u0061\\u006c\\u0074\\u0068\\u0050\\u006c\\u0075\\u0067\\u0069\\u006e\":!1,\"\\u0073\\u0074\\u0065\\u0061\\u006c\\u0074\\u0068\\u0045\\u0072\\u0072\\u006f\\u0072\":!1},dt={\"\\u0075\\u0073\\u0065\\u0072\\u0041\\u0067\\u0065\\u006e\\u0074\":function(){return navigator[_MNVo.$_Cn(426)];},\"\\u0070\\u006c\\u0075\\u0067\\u0069\\u006e\\u0073\":function(){for(var i=[],e=0;e<navigator[_MNVo.$_Cn(264)][_MNVo.$_Cn(59)];e++)!function(e){var t=navigator[_MNVo.$_Cn(264)][e],e=[t[_MNVo.$_Cn(76)],t[_MNVo.$_Cn(252)],t[_MNVo.$_Cn(734)],t[_MNVo.$_Cn(554)]][_MNVo.$_Cn(161)](_MNVo.$_Cn(751)),n=[];Object[_MNVo.$_Cn(11)](t)[_MNVo.$_Cn(756)](function(e){n[_MNVo.$_Cn(50)]([t[e][_MNVo.$_Cn(297)],t[e][_MNVo.$_Cn(292)],t[e][_MNVo.$_Cn(252)]][_MNVo.$_Cn(161)](_MNVo.$_Cn(790)));}),n=n[_MNVo.$_Cn(161)](_MNVo.$_Cn(236)),i[_MNVo.$_Cn(50)](e+_MNVo.$_Cn(776)+n);}(e);return i;},\"\\u006d\\u0069\\u006d\\u0065\\u0054\\u0079\\u0070\\u0065\\u0073\":function(){for(var e=[],t=0;t<navigator[_MNVo.$_Cn(715)][_MNVo.$_Cn(59)];t++){var n=navigator[_MNVo.$_Cn(715)][t];e[_MNVo.$_Cn(50)]([n[_MNVo.$_Cn(252)],n[_MNVo.$_Cn(297)],n[_MNVo.$_Cn(292)]][_MNVo.$_Cn(161)](_MNVo.$_Cn(797)));}return e;},\"\\u0070\\u006c\\u0061\\u0074\\u0066\\u006f\\u0072\\u006d\":function(){return navigator[_MNVo.$_Cn(275)]||ut;},\"\\u006c\\u0061\\u006e\\u0067\\u0075\\u0061\\u0067\\u0065\\u0073\":function(){return navigator[_MNVo.$_Cn(247)]||ut;},\"\\u0073\\u0065\\u006c\\u0065\\u006e\\u0069\\u0075\\u006d\\u004c\\u0069\\u0065\":function(){return Object[_MNVo.$_Cn(11)](document);},\"\\u0073\\u0065\\u006c\\u0065\\u006e\\u0069\\u0075\\u006d\\u0043\\u0061\\u0063\\u0068\\u0065\":function(){var i;return Object[_MNVo.$_Cn(11)](document)[_MNVo.$_Cn(756)](function(e){try{if(document[e]&&void 0===document[e][_MNVo.$_Cn(705)]&&void 0!==document[e][_MNVo.$_Cn(716)])for(var t in document[e][_MNVo.$_Cn(716)])t&&t[_MNVo.$_Cn(743)](/[\\d\\w]{8}\\-[\\d\\w]{4}\\-[\\d\\w]{4}\\-[\\d\\w]{4}\\-[\\d\\w]{12}/)&&(i=!0);}catch(n){}}),i;},\"\\u0070\\u0072\\u006f\\u0064\\u0075\\u0063\\u0074\\u0053\\u0075\\u0062\":function(){return navigator[_MNVo.$_Cn(702)];},\"\\u0065\\u0074\\u0073\\u006c\":function(){return eval[_MNVo.$_Cn(41)]()[_MNVo.$_Cn(59)];},\"\\u0070\\u0068\\u0061\\u006e\\u0074\\u006f\\u006d\\u004a\\u0053\":function(){return[_MNVo.$_Cn(793)in window,_MNVo.$_Cn(762)in window,_MNVo.$_Cn(723)in window];},\"\\u0073\\u0065\\u006c\\u0065\\u006e\\u0069\\u0075\\u006d\":function(){return[_MNVo.$_Cn(730)in window,_MNVo.$_Cn(788)in window,_MNVo.$_Cn(726)in window,_MNVo.$_Cn(735)in window,_MNVo.$_Cn(703)in window,_MNVo.$_Cn(757)in document,_MNVo.$_Cn(725)in document,_MNVo.$_Cn(729)in document,_MNVo.$_Cn(732)in document,_MNVo.$_Cn(709)in document,_MNVo.$_Cn(713)in document,_MNVo.$_Cn(755)in document,_MNVo.$_Cn(739)in document,_MNVo.$_Cn(707)in document,_MNVo.$_Cn(785)in document,_MNVo.$_Cn(772)in document,_MNVo.$_Cn(786)in document,_MNVo.$_Cn(706)in document,_MNVo.$_Cn(750)in document,_MNVo.$_Cn(740)in document,_MNVo.$_Cn(782)in document,_MNVo.$_Cn(757)in document,_MNVo.$_Cn(744)in document,_MNVo.$_Cn(795)in document,_MNVo.$_Cn(731)in document,_MNVo.$_Cn(775)in document,_MNVo.$_Cn(789)in document,_MNVo.$_Cn(753)in document,_MNVo.$_Cn(779)in document,_MNVo.$_Cn(769)in document,_MNVo.$_Cn(764)in document,_MNVo.$_Cn(703)in document,null!==document[_MNVo.$_Cn(761)][_MNVo.$_Cn(737)](_MNVo.$_Cn(621)),null!==document[_MNVo.$_Cn(761)][_MNVo.$_Cn(737)](_MNVo.$_Cn(788)),null!==document[_MNVo.$_Cn(761)][_MNVo.$_Cn(737)](_MNVo.$_Cn(748))];},\"\\u0077\\u0065\\u0062\\u0044\\u0072\\u0069\\u0076\\u0065\\u0072\":function(){return navigator[_MNVo.$_Cn(788)]||!!ft()[_MNVo.$_Cn(77)][_MNVo.$_Cn(472)][_MNVo.$_Cn(788)];},\"\\u0068\\u0061\\u0073\\u0043\\u0068\\u0072\\u006f\\u006d\\u0065\":function(){return!!window[_MNVo.$_Cn(335)];},\"\\u0070\\u0065\\u0072\\u006d\\u0069\\u0073\\u0073\\u0069\\u006f\\u006e\\u0073\":function(){return new Promise(function(t){navigator[_MNVo.$_Cn(636)]&&Notification?navigator[_MNVo.$_Cn(636)][_MNVo.$_Cn(327)]({\"\\u006e\\u0061\\u006d\\u0065\":_MNVo.$_Cn(759)})[_MNVo.$_Cn(23)](function(e){t({\"\\u0073\\u0074\\u0061\\u0074\\u0065\":e[_MNVo.$_Cn(37)],\"\\u0070\\u0065\\u0072\\u006d\\u0069\\u0073\\u0073\\u0069\\u006f\\u006e\":Notification[_MNVo.$_Cn(608)]});})[_MNVo.$_Cn(253)](function(){t({\"\\u0073\\u0074\\u0061\\u0074\\u0065\":_MNVo.$_Cn(56),\"\\u0070\\u0065\\u0072\\u006d\\u0069\\u0073\\u0073\\u0069\\u006f\\u006e\":_MNVo.$_Cn(56)});}):t({\"\\u0073\\u0074\\u0061\\u0074\\u0065\":_MNVo.$_Cn(56),\"\\u0070\\u0065\\u0072\\u006d\\u0069\\u0073\\u0073\\u0069\\u006f\\u006e\":_MNVo.$_Cn(56)});});},\"\\u0062\\u0061\\u0074\\u0074\\u0065\\u0072\\u0079\":function(){return!0;},\"\\u0073\\u0074\\u0065\\u0061\\u006c\\u0074\\u0068\\u0049\\u0066\\u0072\\u0061\\u006d\\u0065\":function(){return ft()[_MNVo.$_Cn(77)][_MNVo.$_Cn(754)]===window[_MNVo.$_Cn(754)]&&!!ft()[_MNVo.$_Cn(77)];},\"\\u0073\\u0074\\u0065\\u0061\\u006c\\u0074\\u0068\\u0050\\u006c\\u0075\\u0067\\u0069\\u006e\":function(){return!!(navigator[_MNVo.$_Cn(264)]&&0<navigator[_MNVo.$_Cn(264)][_MNVo.$_Cn(59)])&&(!(navigator[_MNVo.$_Cn(264)][0][0][_MNVo.$_Cn(787)]===navigator[_MNVo.$_Cn(264)][0])&&-1<Object[_MNVo.$_Cn(733)](navigator[_MNVo.$_Cn(718)],_MNVo.$_Cn(264))[_MNVo.$_Cn(536)][_MNVo.$_Cn(41)]()[_MNVo.$_Cn(94)](_MNVo.$_Cn(85)));},\"\\u0073\\u0074\\u0065\\u0061\\u006c\\u0074\\u0068\\u0045\\u0072\\u0072\\u006f\\u0072\":function(){var e,t,n,i;try{e=pt(Object[_MNVo.$_Cn(733)](navigator[_MNVo.$_Cn(718)],_MNVo.$_Cn(201))[_MNVo.$_Cn(536)]),t=ht(e);}catch(r){t=!1;}try{n=pt(Function[_MNVo.$_Cn(72)][_MNVo.$_Cn(41)]),i=ht(n);}catch(r){i=!1;}return t&&i;},\"\\u0061\\u0075\\u0064\\u0069\\u006f\\u0043\\u006f\\u0064\\u0065\\u0063\\u0073\":function(){var e={};try{var t=document[_MNVo.$_Cn(24)](_MNVo.$_Cn(777)),n=MediaSource||WebKitMediaSource;e[_MNVo.$_Cn(798)]=t[_MNVo.$_Cn(727)](_MNVo.$_Cn(704)),e[_MNVo.$_Cn(763)]=n[_MNVo.$_Cn(712)](_MNVo.$_Cn(704)),e[_MNVo.$_Cn(760)]=t[_MNVo.$_Cn(727)](_MNVo.$_Cn(794)),e[_MNVo.$_Cn(717)]=n[_MNVo.$_Cn(712)](_MNVo.$_Cn(720)),e[_MNVo.$_Cn(783)]=t[_MNVo.$_Cn(727)](_MNVo.$_Cn(711)),e[_MNVo.$_Cn(708)]=n[_MNVo.$_Cn(712)](_MNVo.$_Cn(711)),e[_MNVo.$_Cn(773)]=t[_MNVo.$_Cn(727)](_MNVo.$_Cn(778)),e[_MNVo.$_Cn(774)]=n[_MNVo.$_Cn(712)](_MNVo.$_Cn(778)),e[_MNVo.$_Cn(792)]=t[_MNVo.$_Cn(727)](_MNVo.$_Cn(747)),e[_MNVo.$_Cn(710)]=n[_MNVo.$_Cn(712)](_MNVo.$_Cn(747)),e[_MNVo.$_Cn(724)]=t[_MNVo.$_Cn(727)](_MNVo.$_Cn(722)),e[_MNVo.$_Cn(768)]=n[_MNVo.$_Cn(712)](_MNVo.$_Cn(722)),e[_MNVo.$_Cn(714)]=t[_MNVo.$_Cn(727)](_MNVo.$_Cn(766)),e[_MNVo.$_Cn(767)]=n[_MNVo.$_Cn(712)](_MNVo.$_Cn(766)),e[_MNVo.$_Cn(752)]=t[_MNVo.$_Cn(727)](_MNVo.$_Cn(746)),e[_MNVo.$_Cn(780)]=n[_MNVo.$_Cn(712)](_MNVo.$_Cn(746)),e[_MNVo.$_Cn(799)]=t[_MNVo.$_Cn(727)](_MNVo.$_Cn(828)),e[_MNVo.$_Cn(883)]=n[_MNVo.$_Cn(712)](_MNVo.$_Cn(828)),e[_MNVo.$_Cn(893)]=t[_MNVo.$_Cn(727)](_MNVo.$_Cn(861)),e[_MNVo.$_Cn(881)]=n[_MNVo.$_Cn(712)](_MNVo.$_Cn(861)),e[_MNVo.$_Cn(875)]=-1===t[_MNVo.$_Cn(727)][_MNVo.$_Cn(41)]()[_MNVo.$_Cn(94)](_MNVo.$_Cn(727));}catch(i){e[_MNVo.$_Cn(798)]=_MNVo.$_Cn(890),e[_MNVo.$_Cn(760)]=_MNVo.$_Cn(890),e[_MNVo.$_Cn(783)]=_MNVo.$_Cn(890),e[_MNVo.$_Cn(773)]=_MNVo.$_Cn(890),e[_MNVo.$_Cn(792)]=_MNVo.$_Cn(890),e[_MNVo.$_Cn(724)]=_MNVo.$_Cn(890),e[_MNVo.$_Cn(714)]=_MNVo.$_Cn(890),e[_MNVo.$_Cn(752)]=_MNVo.$_Cn(890),e[_MNVo.$_Cn(799)]=_MNVo.$_Cn(890),e[_MNVo.$_Cn(893)]=_MNVo.$_Cn(890),e[_MNVo.$_Cn(763)]=_MNVo.$_Cn(890),e[_MNVo.$_Cn(717)]=_MNVo.$_Cn(890),e[_MNVo.$_Cn(708)]=_MNVo.$_Cn(890),e[_MNVo.$_Cn(774)]=_MNVo.$_Cn(890),e[_MNVo.$_Cn(710)]=_MNVo.$_Cn(890),e[_MNVo.$_Cn(768)]=_MNVo.$_Cn(890),e[_MNVo.$_Cn(767)]=_MNVo.$_Cn(890),e[_MNVo.$_Cn(780)]=_MNVo.$_Cn(890),e[_MNVo.$_Cn(883)]=_MNVo.$_Cn(890),e[_MNVo.$_Cn(881)]=_MNVo.$_Cn(890);}return e;},\"\\u0076\\u0069\\u0064\\u0065\\u006f\\u0043\\u006f\\u0064\\u0065\\u0063\\u0073\":function(){var e={};try{var t=document[_MNVo.$_Cn(24)](_MNVo.$_Cn(884)),n=MediaSource||WebKitMediaSource;e[_MNVo.$_Cn(869)]=t[_MNVo.$_Cn(727)](_MNVo.$_Cn(844)),e[_MNVo.$_Cn(855)]=n[_MNVo.$_Cn(712)](_MNVo.$_Cn(844)),e[_MNVo.$_Cn(876)]=t[_MNVo.$_Cn(727)](_MNVo.$_Cn(820)),e[_MNVo.$_Cn(848)]=n[_MNVo.$_Cn(712)](_MNVo.$_Cn(820)),e[_MNVo.$_Cn(859)]=t[_MNVo.$_Cn(727)](_MNVo.$_Cn(826)),e[_MNVo.$_Cn(802)]=n[_MNVo.$_Cn(712)](_MNVo.$_Cn(826)),e[_MNVo.$_Cn(840)]=t[_MNVo.$_Cn(727)](_MNVo.$_Cn(818)),e[_MNVo.$_Cn(871)]=n[_MNVo.$_Cn(712)](_MNVo.$_Cn(818)),e[_MNVo.$_Cn(854)]=t[_MNVo.$_Cn(727)](_MNVo.$_Cn(879)),e[_MNVo.$_Cn(816)]=n[_MNVo.$_Cn(712)](_MNVo.$_Cn(895)),e[_MNVo.$_Cn(882)]=t[_MNVo.$_Cn(727)](_MNVo.$_Cn(880)),e[_MNVo.$_Cn(878)]=n[_MNVo.$_Cn(712)](_MNVo.$_Cn(880)),e[_MNVo.$_Cn(851)]=t[_MNVo.$_Cn(727)](_MNVo.$_Cn(856)),e[_MNVo.$_Cn(894)]=n[_MNVo.$_Cn(712)](_MNVo.$_Cn(856));}catch(i){e[_MNVo.$_Cn(869)]=_MNVo.$_Cn(890),e[_MNVo.$_Cn(876)]=_MNVo.$_Cn(890),e[_MNVo.$_Cn(859)]=_MNVo.$_Cn(890),e[_MNVo.$_Cn(840)]=_MNVo.$_Cn(890),e[_MNVo.$_Cn(854)]=_MNVo.$_Cn(890),e[_MNVo.$_Cn(882)]=_MNVo.$_Cn(890),e[_MNVo.$_Cn(851)]=_MNVo.$_Cn(890),e[_MNVo.$_Cn(855)]=_MNVo.$_Cn(890),e[_MNVo.$_Cn(848)]=_MNVo.$_Cn(890),e[_MNVo.$_Cn(802)]=_MNVo.$_Cn(890),e[_MNVo.$_Cn(871)]=_MNVo.$_Cn(890),e[_MNVo.$_Cn(816)]=_MNVo.$_Cn(890),e[_MNVo.$_Cn(878)]=_MNVo.$_Cn(890),e[_MNVo.$_Cn(894)]=_MNVo.$_Cn(890);}return e;}},ft=function(){if(st)return st;try{(st=document[_MNVo.$_Cn(24)](_MNVo.$_Cn(93)))[_MNVo.$_Cn(63)]=_MNVo.$_Cn(896),st[_MNVo.$_Cn(822)](_MNVo.$_Cn(86),_MNVo.$_Cn(845)),document&&document[_MNVo.$_Cn(842)]&&document[_MNVo.$_Cn(842)][_MNVo.$_Cn(78)](st);}catch(e){}return st;},ht=function(e){if(_MNVo.$_Cn(235)==typeof e[_MNVo.$_Cn(898)]){e=e[_MNVo.$_Cn(898)][_MNVo.$_Cn(228)](_MNVo.$_Cn(897));if(2<e[_MNVo.$_Cn(59)])return 0===e[0][_MNVo.$_Cn(94)](_MNVo.$_Cn(839))&&-1<e[1][_MNVo.$_Cn(94)](_MNVo.$_Cn(860));}return!1;},{\"\\u0061\\u0064\\u0064\\u0043\\u0075\\u0073\\u0074\\u006f\\u006d\\u0046\\u0075\\u006e\\u0063\\u0074\\u0069\\u006f\\u006e\":function(e,t,n){lt[e]=t,dt[e]=n;},\"\\u0067\\u0065\\u006e\\u0065\\u0072\\u0061\\u0074\\u0065\\u0043\\u006f\\u006c\\u006c\\u0065\\u0063\\u0074\":function(){return new Promise(function(e){var t=[],i={};return Object[_MNVo.$_Cn(11)](lt)[_MNVo.$_Cn(756)](function(n){if(i[n]={},lt[n])t[_MNVo.$_Cn(50)](new Promise(function(t){dt[n]()[_MNVo.$_Cn(23)](function(e){return i[n]=e,t();})[_MNVo.$_Cn(253)](function(e){return i[n]={\"\\u0065\\u0072\\u0072\\u006f\\u0072\":!0,\"\\u006d\\u0065\\u0073\\u0073\\u0061\\u0067\\u0065\":e[_MNVo.$_Cn(41)]()},t();});}));else try{i[n]=dt[n]();}catch(e){i[n]={\"\\u0065\\u0072\\u0072\\u006f\\u0072\":!0,\"\\u006d\\u0065\\u0073\\u0073\\u0061\\u0067\\u0065\":e[_MNVo.$_Cn(41)]()};}}),Promise[_MNVo.$_Cn(83)](t)[_MNVo.$_Cn(23)](function(){return e(i);});});}}),$_BGY={\"\\u0061\\u006e\\u0061\\u006c\\u0079\\u0073\\u0065\":function(t,n){var i={},e=function(e){e=e(t);i[e[_MNVo.$_Cn(76)]]=e;};e(function(){var e=t[_MNVo.$_Cn(520)]?_MNVo.$_Cn(316):_MNVo.$_Cn(479);return vt(mt[_MNVo.$_Cn(835)],e,{},_MNVo.$_Cn(815));}),e(function(){var e=1e4<t[_MNVo.$_Cn(853)]-n[_MNVo.$_Cn(867)]?_MNVo.$_Cn(316):_MNVo.$_Cn(479);return vt(mt[_MNVo.$_Cn(864)],e,{},_MNVo.$_Cn(675));});var r={};return Object[_MNVo.$_Cn(11)](i)[_MNVo.$_Cn(756)](function(e){r[e]=i[e][_MNVo.$_Cn(791)];}),r;},\"\\u0043\\u004f\\u004e\\u0053\\u0049\\u0053\\u0054\\u0045\\u004e\\u0054\":_MNVo.$_Cn(479),\"\\u0055\\u004e\\u0053\\u0055\\u0052\\u0045\":_MNVo.$_Cn(318),\"\\u0049\\u004e\\u0043\\u004f\\u004e\\u0053\\u0049\\u0053\\u0054\\u0045\\u004e\\u0054\":_MNVo.$_Cn(316),\"\\u0054\\u0045\\u0053\\u0054\\u0053\":mt={\"\\u0043\\u004f\\u004e\\u0053\\u004f\\u004c\\u0045\":_MNVo.$_Cn(808),\"\\u0044\\u0045\\u0042\\u0042\\u0055\\u0047\\u0045\\u0052\":_MNVo.$_Cn(814)}},St=(wt={\"\\u0064\\u0065\\u0062\\u0075\\u0067\\u0067\\u0065\\u0072\":!(vt=function(e,t,n,i){return{\"\\u006e\\u0061\\u006d\\u0065\":e,\"\\u0063\\u006f\\u006e\\u0073\\u0069\\u0073\\u0074\\u0065\\u006e\\u0074\":t,\"\\u0064\\u0061\\u0074\\u0061\":n,\"\\u0063\\u006f\\u0064\\u0065\":i};}),\"\\u0063\\u006f\\u006e\\u0073\\u006f\\u006c\\u0065\":!(pt=function(e){var t=Object[_MNVo.$_Cn(831)](e);try{Object[_MNVo.$_Cn(837)](e,e)[_MNVo.$_Cn(41)]();}catch(n){return n;}finally{Object[_MNVo.$_Cn(837)](e,t);}return!1;})},gt={\"\\u0064\\u0065\\u0062\\u0075\\u0067\\u0067\\u0065\\u0072\":function(){return new Date()[_MNVo.$_Cn(538)]();},\"\\u0063\\u006f\\u006e\\u0073\\u006f\\u006c\\u0065\":function(){var e=!1;return console[_MNVo.$_Cn(821)](Object[_MNVo.$_Cn(813)](new Error(),{\"\\u006d\\u0065\\u0073\\u0073\\u0061\\u0067\\u0065\":{\"\\u0067\\u0065\\u0074\":function(){e=!0;}},\"\\u0074\\u006f\\u0053\\u0074\\u0072\\u0069\\u006e\\u0067\":{\"\\u0076\\u0061\\u006c\\u0075\\u0065\":function(){new Error()[_MNVo.$_Cn(898)][_MNVo.$_Cn(887)](_MNVo.$_Cn(812))&&(e=!0);}}})),e;}},{\"\\u0061\\u0064\\u0064\\u0043\\u0075\\u0073\\u0074\\u006f\\u006d\\u0046\\u0075\\u006e\\u0063\\u0074\\u0069\\u006f\\u006e\":function(e,t,n){wt[e]=t,gt[e]=n;},\"\\u0067\\u0065\\u006e\\u0065\\u0072\\u0061\\u0074\\u0065\\u0043\\u006f\\u006c\\u006c\\u0065\\u0063\\u0074\":function(){return new Promise(function(e){var t=[],i={};return Object[_MNVo.$_Cn(11)](wt)[_MNVo.$_Cn(756)](function(n){if(i[n]={},wt[n])t[_MNVo.$_Cn(50)](new Promise(function(t){gt[n]()[_MNVo.$_Cn(23)](function(e){return i[n]=e,t();})[_MNVo.$_Cn(253)](function(e){return i[n]={\"\\u0065\\u0072\\u0072\\u006f\\u0072\":!0,\"\\u006d\\u0065\\u0073\\u0073\\u0061\\u0067\\u0065\":e[_MNVo.$_Cn(41)]()},t();});}));else try{i[n]=gt[n]();}catch(e){i[n]={\"\\u0065\\u0072\\u0072\\u006f\\u0072\":!0,\"\\u006d\\u0065\\u0073\\u0073\\u0061\\u0067\\u0065\":e[_MNVo.$_Cn(41)]()};}}),Promise[_MNVo.$_Cn(83)](t)[_MNVo.$_Cn(23)](function(){return e(i);});});}});var At=function(){var n=Object[_MNVo.$_Cn(326)]||function(e){return t[_MNVo.$_Cn(72)]=e,e=new t(),t[_MNVo.$_Cn(72)]=null,e;};function t(){var $_BAEr=_MNVo.$_Dt()[0][18];for(;$_BAEr!==_MNVo.$_Dt()[12][18];){switch($_BAEr){}}}var e={},i=e[_MNVo.$_Cn(823)]={},r=i[_MNVo.$_Cn(877)]={\"\\u0065\\u0078\\u0074\\u0065\\u006e\\u0064\":function(e){var t=n(this);return e&&t[_MNVo.$_Cn(841)](e),t[_MNVo.$_Cn(858)](_MNVo.$_Cn(857))&&this[_MNVo.$_Cn(857)]!==t[_MNVo.$_Cn(857)]||(t[_MNVo.$_Cn(857)]=function(){t[_MNVo.$_Cn(868)][_MNVo.$_Cn(857)][_MNVo.$_Cn(12)](this,arguments);}),(t[_MNVo.$_Cn(857)][_MNVo.$_Cn(72)]=t)[_MNVo.$_Cn(868)]=this,t;},\"\\u0063\\u0072\\u0065\\u0061\\u0074\\u0065\":function(){var e=this[_MNVo.$_Cn(870)]();return e[_MNVo.$_Cn(857)][_MNVo.$_Cn(12)](e,arguments),e;},\"\\u0069\\u006e\\u0069\\u0074\":function(){},\"\\u006d\\u0069\\u0078\\u0049\\u006e\":function(e){for(var t in e)e[_MNVo.$_Cn(858)](t)&&(this[t]=e[t]);e[_MNVo.$_Cn(858)](_MNVo.$_Cn(41))&&(this[_MNVo.$_Cn(41)]=e[_MNVo.$_Cn(41)]);}},u=i[_MNVo.$_Cn(850)]=r[_MNVo.$_Cn(870)]({\"\\u0069\\u006e\\u0069\\u0074\":function(e,t){e=this[_MNVo.$_Cn(829)]=e||[],t!=undefined?this[_MNVo.$_Cn(806)]=t:this[_MNVo.$_Cn(806)]=4*e[_MNVo.$_Cn(59)];},\"\\u0063\\u006f\\u006e\\u0063\\u0061\\u0074\":function(e){var t=this[_MNVo.$_Cn(829)],n=e[_MNVo.$_Cn(829)],i=this[_MNVo.$_Cn(806)],r=e[_MNVo.$_Cn(806)];if(this[_MNVo.$_Cn(849)](),i%4)for(var o=0;o<r;o++){var a=n[o>>>2]>>>24-o%4*8&255;t[i+o>>>2]|=a<<24-(i+o)%4*8;}else for(o=0;o<r;o+=4)t[i+o>>>2]=n[o>>>2];return this[_MNVo.$_Cn(806)]+=r,this;},\"\\u0063\\u006c\\u0061\\u006d\\u0070\":function(){var e=this[_MNVo.$_Cn(829)],t=this[_MNVo.$_Cn(806)];e[t>>>2]&=4294967295<<32-t%4*8,e[_MNVo.$_Cn(59)]=Math[_MNVo.$_Cn(804)](t/4);}}),o=e[_MNVo.$_Cn(807)]={},l=o[_MNVo.$_Cn(838)]={\"\\u0070\\u0061\\u0072\\u0073\\u0065\":function(e){for(var t=e[_MNVo.$_Cn(59)],n=[],i=0;i<t;i++)n[i>>>2]|=(255&e[_MNVo.$_Cn(6)](i))<<24-i%4*8;return new u[(_MNVo.$_Cn(857))](n,t);}},a=o[_MNVo.$_Cn(847)]={\"\\u0070\\u0061\\u0072\\u0073\\u0065\":function(e){return l[_MNVo.$_Cn(836)](unescape(encodeURIComponent(e)));}},c=i[_MNVo.$_Cn(862)]=r[_MNVo.$_Cn(870)]({\"\\u0072\\u0065\\u0073\\u0065\\u0074\":function(){this[_MNVo.$_Cn(446)]=new u[(_MNVo.$_Cn(857))](),this[_MNVo.$_Cn(824)]=0;},\"\\u0024\\u005f\\u0042\\u0049\\u007a\":function(e){_MNVo.$_Cn(235)==typeof e&&(e=a[_MNVo.$_Cn(836)](e)),this[_MNVo.$_Cn(446)][_MNVo.$_Cn(75)](e),this[_MNVo.$_Cn(824)]+=e[_MNVo.$_Cn(806)];},\"\\u0024\\u005f\\u0042\\u004a\\u0072\":function(e){var t=this[_MNVo.$_Cn(446)],n=t[_MNVo.$_Cn(829)],i=t[_MNVo.$_Cn(806)],r=this[_MNVo.$_Cn(885)],o=i/(4*r),a=(o=e?Math[_MNVo.$_Cn(804)](o):Math[_MNVo.$_Cn(263)]((0|o)-this[_MNVo.$_Cn(834)],0))*r,i=Math[_MNVo.$_Cn(51)](4*a,i);if(a){for(var c=0;c<a;c+=r)this[_MNVo.$_Cn(805)](n,c);var s=n[_MNVo.$_Cn(886)](0,a);t[_MNVo.$_Cn(806)]-=i;}return new u[(_MNVo.$_Cn(857))](s,i);},\"\\u0024\\u005f\\u0043\\u0041\\u0047\":0}),s=e[_MNVo.$_Cn(819)]={},d=i[_MNVo.$_Cn(846)]=c[_MNVo.$_Cn(870)]({\"\\u0063\\u0066\\u0067\":r[_MNVo.$_Cn(870)](),\"\\u0063\\u0072\\u0065\\u0061\\u0074\\u0065\\u0045\\u006e\\u0063\\u0072\\u0079\\u0070\\u0074\\u006f\\u0072\":function(e,t){return this[_MNVo.$_Cn(326)](this[_MNVo.$_Cn(866)],e,t);},\"\\u0069\\u006e\\u0069\\u0074\":function(e,t,n){this[_MNVo.$_Cn(889)]=this[_MNVo.$_Cn(889)][_MNVo.$_Cn(870)](n),this[_MNVo.$_Cn(872)]=e,this[_MNVo.$_Cn(430)]=t,this[_MNVo.$_Cn(120)]();},\"\\u0072\\u0065\\u0073\\u0065\\u0074\":function(){c[_MNVo.$_Cn(120)][_MNVo.$_Cn(92)](this),this[_MNVo.$_Cn(830)]();},\"\\u0070\\u0072\\u006f\\u0063\\u0065\\u0073\\u0073\":function(e){return this[_MNVo.$_Cn(809)](e),this[_MNVo.$_Cn(800)]();},\"\\u0066\\u0069\\u006e\\u0061\\u006c\\u0069\\u007a\\u0065\":function(e){return e&&this[_MNVo.$_Cn(809)](e),this[_MNVo.$_Cn(811)]();},\"\\u006b\\u0065\\u0079\\u0053\\u0069\\u007a\\u0065\":4,\"\\u0069\\u0076\\u0053\\u0069\\u007a\\u0065\":4,\"\\u0024\\u005f\\u0043\\u0043\\u0074\":1,\"\\u0024\\u005f\\u0043\\u0047\\u004e\":2,\"\\u0024\\u005f\\u0043\\u0048\\u004a\":function(s){return{\"\\u0065\\u006e\\u0063\\u0072\\u0079\\u0070\\u0074\":function(e,t,n){t=l[_MNVo.$_Cn(836)](t);n&&n[_MNVo.$_Cn(833)]||((n=n||{})[_MNVo.$_Cn(833)]=l[_MNVo.$_Cn(836)](_MNVo.$_Cn(865)));for(var n=p[_MNVo.$_Cn(584)](s,e,t,n),i=n[_MNVo.$_Cn(810)][_MNVo.$_Cn(829)],r=n[_MNVo.$_Cn(810)][_MNVo.$_Cn(806)],o=[],a=0;a<r;a++){var c=i[a>>>2]>>>24-a%4*8&255;o[_MNVo.$_Cn(50)](c);}i=n[_MNVo.$_Cn(810)][_MNVo.$_Cn(829)];return o;}};}}),f=e[_MNVo.$_Cn(863)]={},o=i[_MNVo.$_Cn(873)]=r[_MNVo.$_Cn(870)]({\"\\u0063\\u0072\\u0065\\u0061\\u0074\\u0065\\u0045\\u006e\\u0063\\u0072\\u0079\\u0070\\u0074\\u006f\\u0072\":function(e,t){return this[_MNVo.$_Cn(874)][_MNVo.$_Cn(326)](e,t);},\"\\u0069\\u006e\\u0069\\u0074\":function(e,t){this[_MNVo.$_Cn(825)]=e,this[_MNVo.$_Cn(803)]=t;}}),o=f[_MNVo.$_Cn(892)]=((f=o[_MNVo.$_Cn(870)]())[_MNVo.$_Cn(874)]=f[_MNVo.$_Cn(870)]({\"\\u0070\\u0072\\u006f\\u0063\\u0065\\u0073\\u0073\\u0042\\u006c\\u006f\\u0063\\u006b\":function(e,t){var n=this[_MNVo.$_Cn(825)],i=n[_MNVo.$_Cn(885)];!function(e,t,n){var i=this[_MNVo.$_Cn(803)];{var r;i?(r=i,this[_MNVo.$_Cn(803)]=undefined):r=this[_MNVo.$_Cn(801)];}for(var o=0;o<n;o++)e[t+o]^=r[o];}[_MNVo.$_Cn(92)](this,e,t,i),n[_MNVo.$_Cn(817)](e,t),this[_MNVo.$_Cn(801)]=e[_MNVo.$_Cn(82)](t,t+i);}}),f),f=(e[_MNVo.$_Cn(899)]={})[_MNVo.$_Cn(843)]={\"\\u0070\\u0061\\u0064\":function(e,t){for(var t=4*t,n=t-e[_MNVo.$_Cn(806)]%t,i=n<<24|n<<16|n<<8|n,r=[],o=0;o<n;o+=4)r[_MNVo.$_Cn(50)](i);t=u[_MNVo.$_Cn(326)](r,n);e[_MNVo.$_Cn(75)](t);}},f=i[_MNVo.$_Cn(852)]=d[_MNVo.$_Cn(870)]({\"\\u0063\\u0066\\u0067\":d[_MNVo.$_Cn(889)][_MNVo.$_Cn(870)]({\"\\u006d\\u006f\\u0064\\u0065\":o,\"\\u0070\\u0061\\u0064\\u0064\\u0069\\u006e\\u0067\":f}),\"\\u0072\\u0065\\u0073\\u0065\\u0074\":function(){d[_MNVo.$_Cn(120)][_MNVo.$_Cn(92)](this);var e,t=this[_MNVo.$_Cn(889)],n=t[_MNVo.$_Cn(833)],t=t[_MNVo.$_Cn(863)];this[_MNVo.$_Cn(872)]==this[_MNVo.$_Cn(866)]&&(e=t[_MNVo.$_Cn(832)]),this[_MNVo.$_Cn(888)]&&this[_MNVo.$_Cn(888)][_MNVo.$_Cn(891)]==e?this[_MNVo.$_Cn(888)][_MNVo.$_Cn(857)](this,n&&n[_MNVo.$_Cn(829)]):(this[_MNVo.$_Cn(888)]=e[_MNVo.$_Cn(92)](t,this,n&&n[_MNVo.$_Cn(829)]),this[_MNVo.$_Cn(888)][_MNVo.$_Cn(891)]=e);},\"\\u0024\\u005f\\u0043\\u0042\\u006a\":function(e,t){this[_MNVo.$_Cn(888)][_MNVo.$_Cn(827)](e,t);},\"\\u0024\\u005f\\u0043\\u0046\\u0063\":function(){var e,t=this[_MNVo.$_Cn(889)][_MNVo.$_Cn(956)];return this[_MNVo.$_Cn(872)]==this[_MNVo.$_Cn(866)]&&(t[_MNVo.$_Cn(899)](this[_MNVo.$_Cn(446)],this[_MNVo.$_Cn(885)]),e=this[_MNVo.$_Cn(800)](!0)),e;},\"\\u0062\\u006c\\u006f\\u0063\\u006b\\u0053\\u0069\\u007a\\u0065\":4}),h=i[_MNVo.$_Cn(921)]=r[_MNVo.$_Cn(870)]({\"\\u0069\\u006e\\u0069\\u0074\":function(e){this[_MNVo.$_Cn(841)](e);}}),p=i[_MNVo.$_Cn(926)]=r[_MNVo.$_Cn(870)]({\"\\u0063\\u0066\\u0067\":r[_MNVo.$_Cn(870)](),\"\\u0065\\u006e\\u0063\\u0072\\u0079\\u0070\\u0074\":function(e,t,n,i){i=this[_MNVo.$_Cn(889)][_MNVo.$_Cn(870)](i);var r=e[_MNVo.$_Cn(832)](n,i),t=r[_MNVo.$_Cn(914)](t),r=r[_MNVo.$_Cn(889)];return h[_MNVo.$_Cn(326)]({\"\\u0063\\u0069\\u0070\\u0068\\u0065\\u0072\\u0074\\u0065\\u0078\\u0074\":t,\"\\u006b\\u0065\\u0079\":n,\"\\u0069\\u0076\":r[_MNVo.$_Cn(833)],\"\\u0061\\u006c\\u0067\\u006f\\u0072\\u0069\\u0074\\u0068\\u006d\":e,\"\\u006d\\u006f\\u0064\\u0065\":r[_MNVo.$_Cn(863)],\"\\u0070\\u0061\\u0064\\u0064\\u0069\\u006e\\u0067\":r[_MNVo.$_Cn(956)],\"\\u0062\\u006c\\u006f\\u0063\\u006b\\u0053\\u0069\\u007a\\u0065\":e[_MNVo.$_Cn(885)],\"\\u0066\\u006f\\u0072\\u006d\\u0061\\u0074\\u0074\\u0065\\u0072\":i[_MNVo.$_Cn(968)]});}}),m=[],v=[],w=[],g=[],b=[],y=[],_=[],S=[],A=[],C=[];!function(){for(var e=[],t=0;t<256;t++)e[t]=t<128?t<<1:t<<1^283;for(var n=0,i=0,t=0;t<256;t++){var r=i^i<<1^i<<2^i<<3^i<<4;m[n]=r=r>>>8^255&r^99;var o=e[v[r]=n],a=e[o],c=e[a],s=257*e[r]^16843008*r;w[n]=s<<24|s>>>8,g[n]=s<<16|s>>>16,b[n]=s<<8|s>>>24,y[n]=s,_[r]=(s=16843009*c^65537*a^257*o^16843008*n)<<24|s>>>8,S[r]=s<<16|s>>>16,A[r]=s<<8|s>>>24,C[r]=s,n?(n=o^e[e[e[c^o]]],i^=e[e[i]]):n=i=1;}}();var T=[0,1,2,4,8,16,32,64,128,27,54],s=s[_MNVo.$_Cn(923)]=f[_MNVo.$_Cn(870)]({\"\\u0024\\u005f\\u0043\\u0045\\u004a\":function(){if(!this[_MNVo.$_Cn(982)]||this[_MNVo.$_Cn(908)]!==this[_MNVo.$_Cn(430)]){for(var e=this[_MNVo.$_Cn(908)]=this[_MNVo.$_Cn(430)],t=e[_MNVo.$_Cn(829)],n=e[_MNVo.$_Cn(806)]/4,i=4*(1+(this[_MNVo.$_Cn(982)]=6+n)),r=this[_MNVo.$_Cn(992)]=[],o=0;o<i;o++)o<n?r[o]=t[o]:(s=r[o-1],o%n?6<n&&o%n==4&&(s=m[s>>>24]<<24|m[s>>>16&255]<<16|m[s>>>8&255]<<8|m[255&s]):(s=m[(s=s<<8|s>>>24)>>>24]<<24|m[s>>>16&255]<<16|m[s>>>8&255]<<8|m[255&s],s^=T[o/n|0]<<24),r[o]=r[o-n]^s);for(var a=this[_MNVo.$_Cn(986)]=[],c=0;c<i;c++){var s,o=i-c;s=c%4?r[o]:r[o-4],a[c]=c<4||o<=4?s:_[m[s>>>24]]^S[m[s>>>16&255]]^A[m[s>>>8&255]]^C[m[255&s]];}}},\"\\u0065\\u006e\\u0063\\u0072\\u0079\\u0070\\u0074\\u0042\\u006c\\u006f\\u0063\\u006b\":function(e,t){this[_MNVo.$_Cn(906)](e,t,this[_MNVo.$_Cn(992)],w,g,b,y,m);},\"\\u0024\\u005f\\u0044\\u0048\\u0079\":function(e,t,n,i,r,o,a,c){for(var s=this[_MNVo.$_Cn(982)],u=e[t]^n[0],l=e[t+1]^n[1],d=e[t+2]^n[2],f=e[t+3]^n[3],h=4,p=1;p<s;p++)var m=i[u>>>24]^r[l>>>16&255]^o[d>>>8&255]^a[255&f]^n[h++],v=i[l>>>24]^r[d>>>16&255]^o[f>>>8&255]^a[255&u]^n[h++],w=i[d>>>24]^r[f>>>16&255]^o[u>>>8&255]^a[255&l]^n[h++],g=i[f>>>24]^r[u>>>16&255]^o[l>>>8&255]^a[255&d]^n[h++],u=m,l=v,d=w,f=g;m=(c[u>>>24]<<24|c[l>>>16&255]<<16|c[d>>>8&255]<<8|c[255&f])^n[h++],v=(c[l>>>24]<<24|c[d>>>16&255]<<16|c[f>>>8&255]<<8|c[255&u])^n[h++],w=(c[d>>>24]<<24|c[f>>>16&255]<<16|c[u>>>8&255]<<8|c[255&l])^n[h++],g=(c[f>>>24]<<24|c[u>>>16&255]<<16|c[l>>>8&255]<<8|c[255&d])^n[h++];e[t]=m,e[t+1]=v,e[t+2]=w,e[t+3]=g;},\"\\u006b\\u0065\\u0079\\u0053\\u0069\\u007a\\u0065\":8});return e[_MNVo.$_Cn(923)]=f[_MNVo.$_Cn(991)](s),e[_MNVo.$_Cn(923)];}(),Ct=function(){function t(){var $_BAFx=_MNVo.$_Dt()[0][18];for(;$_BAFx!==_MNVo.$_Dt()[12][17];){switch($_BAFx){case _MNVo.$_Dt()[8][18]:this[_MNVo.$_Cn(456)]=0,this[_MNVo.$_Cn(401)]=0,this[_MNVo.$_Cn(416)]=[];$_BAFx=_MNVo.$_Dt()[4][17];break;}}}t[_MNVo.$_Cn(72)][_MNVo.$_Cn(857)]=function(e){for(var t,n,i=0;i<256;++i)this[_MNVo.$_Cn(416)][i]=i;for(i=t=0;i<256;++i)t=t+this[_MNVo.$_Cn(416)][i]+e[i%e[_MNVo.$_Cn(59)]]&255,n=this[_MNVo.$_Cn(416)][i],this[_MNVo.$_Cn(416)][i]=this[_MNVo.$_Cn(416)][t],this[_MNVo.$_Cn(416)][t]=n;this[_MNVo.$_Cn(456)]=0,this[_MNVo.$_Cn(401)]=0;},t[_MNVo.$_Cn(72)][_MNVo.$_Cn(60)]=function(){var e;return this[_MNVo.$_Cn(456)]=this[_MNVo.$_Cn(456)]+1&255,this[_MNVo.$_Cn(401)]=this[_MNVo.$_Cn(401)]+this[_MNVo.$_Cn(416)][this[_MNVo.$_Cn(456)]]&255,e=this[_MNVo.$_Cn(416)][this[_MNVo.$_Cn(456)]],this[_MNVo.$_Cn(416)][this[_MNVo.$_Cn(456)]]=this[_MNVo.$_Cn(416)][this[_MNVo.$_Cn(401)]],this[_MNVo.$_Cn(416)][this[_MNVo.$_Cn(401)]]=e,this[_MNVo.$_Cn(416)][e+this[_MNVo.$_Cn(416)][this[_MNVo.$_Cn(456)]]&255];};var n,i,r,o=256;function a(){var $_BAGf=_MNVo.$_Dt()[8][18];for(;$_BAGf!==_MNVo.$_Dt()[8][16];){switch($_BAGf){case _MNVo.$_Dt()[12][18]:if(null==n){n=new t();while(r<o){var e=Math[_MNVo.$_Cn(913)](65536*Math[_MNVo.$_Cn(300)]());i[r++]=255&e;}for(n[_MNVo.$_Cn(857)](i),r=0;r<i[_MNVo.$_Cn(59)];++r)i[r]=0;r=0;}$_BAGf=_MNVo.$_Dt()[4][17];break;case _MNVo.$_Dt()[4][17]:return n[_MNVo.$_Cn(60)]();break;}}}function c(){var $_BAHq=_MNVo.$_Dt()[8][18];for(;$_BAHq!==_MNVo.$_Dt()[4][18];){switch($_BAHq){}}}function w(e,t,n){var $_BAId=_MNVo.$_Dt()[4][18];for(;$_BAId!==_MNVo.$_Dt()[8][17];){switch($_BAId){case _MNVo.$_Dt()[12][18]:null!=e&&(_MNVo.$_Cn(46)==typeof e?this[_MNVo.$_Cn(943)](e,t,n):null==t&&_MNVo.$_Cn(235)!=typeof e?this[_MNVo.$_Cn(940)](e,256):this[_MNVo.$_Cn(940)](e,t));$_BAId=_MNVo.$_Dt()[4][17];break;}}}function g(){var $_BAJL=_MNVo.$_Dt()[8][18];for(;$_BAJL!==_MNVo.$_Dt()[0][17];){switch($_BAJL){case _MNVo.$_Dt()[4][18]:return new w(null);break;}}}null==i&&(i=[],r=0),c[_MNVo.$_Cn(72)][_MNVo.$_Cn(955)]=function(e){for(var t=0;t<e[_MNVo.$_Cn(59)];++t)e[t]=a();},w[_MNVo.$_Cn(72)][_MNVo.$_Cn(934)]=function(e,t,n,i,r,o){while(0<=--o){var a=t*this[e++]+n[i]+r;r=Math[_MNVo.$_Cn(913)](a/67108864),n[i++]=67108863&a;}return r;},w[_MNVo.$_Cn(72)][_MNVo.$_Cn(947)]=26,w[_MNVo.$_Cn(72)][_MNVo.$_Cn(970)]=67108863,w[_MNVo.$_Cn(72)][_MNVo.$_Cn(942)]=1<<26;w[_MNVo.$_Cn(72)][_MNVo.$_Cn(911)]=Math[_MNVo.$_Cn(380)](2,52),w[_MNVo.$_Cn(72)][_MNVo.$_Cn(932)]=26;for(var s=_MNVo.$_Cn(917),u=[],e=_MNVo.$_Cn(90)[_MNVo.$_Cn(6)](w[_MNVo.$_Cn(72)][_MNVo.$_Cn(902)]=0),l=0;l<=9;++l)u[e++]=l;for(e=_MNVo.$_Cn(484)[_MNVo.$_Cn(6)](0),l=10;l<36;++l)u[e++]=l;for(e=_MNVo.$_Cn(438)[_MNVo.$_Cn(6)](0),l=10;l<36;++l)u[e++]=l;function d(e){var $_BBAk=_MNVo.$_Dt()[0][18];for(;$_BBAk!==_MNVo.$_Dt()[4][17];){switch($_BBAk){case _MNVo.$_Dt()[0][18]:return s[_MNVo.$_Cn(302)](e);break;}}}function f(e){var $_BBBc=_MNVo.$_Dt()[0][18];for(;$_BBBc!==_MNVo.$_Dt()[12][17];){switch($_BBBc){case _MNVo.$_Dt()[0][18]:var t=g();return t[_MNVo.$_Cn(981)](e),t;break;}}}function b(e){var $_BBCK=_MNVo.$_Dt()[4][18];for(;$_BBCK!==_MNVo.$_Dt()[4][17];){switch($_BBCK){case _MNVo.$_Dt()[12][18]:var t,n=1;return 0!=(t=e>>>16)&&(e=t,n+=16),0!=(t=e>>8)&&(e=t,n+=8),0!=(t=e>>4)&&(e=t,n+=4),0!=(t=e>>2)&&(e=t,n+=2),0!=(t=e>>1)&&(e=t,n+=1),n;break;}}}function h(e){var $_BBDw=_MNVo.$_Dt()[8][18];for(;$_BBDw!==_MNVo.$_Dt()[12][17];){switch($_BBDw){case _MNVo.$_Dt()[12][18]:this[_MNVo.$_Cn(482)]=e;$_BBDw=_MNVo.$_Dt()[0][17];break;}}}function p(e){var $_BBEM=_MNVo.$_Dt()[4][18];for(;$_BBEM!==_MNVo.$_Dt()[0][17];){switch($_BBEM){case _MNVo.$_Dt()[8][18]:this[_MNVo.$_Cn(482)]=e,this[_MNVo.$_Cn(948)]=e[_MNVo.$_Cn(920)](),this[_MNVo.$_Cn(912)]=32767&this[_MNVo.$_Cn(948)],this[_MNVo.$_Cn(996)]=this[_MNVo.$_Cn(948)]>>15,this[_MNVo.$_Cn(935)]=(1<<e[_MNVo.$_Cn(947)]-15)-1,this[_MNVo.$_Cn(931)]=2*e[_MNVo.$_Cn(477)];$_BBEM=_MNVo.$_Dt()[12][17];break;}}}function m(){var $_BBFX=_MNVo.$_Dt()[4][18];for(;$_BBFX!==_MNVo.$_Dt()[8][16];){switch($_BBFX){case _MNVo.$_Dt()[0][18]:this[_MNVo.$_Cn(451)]=null,this[_MNVo.$_Cn(414)]=0,this[_MNVo.$_Cn(437)]=null,this[_MNVo.$_Cn(411)]=null,this[_MNVo.$_Cn(429)]=null,this[_MNVo.$_Cn(958)]=null,this[_MNVo.$_Cn(998)]=null,this[_MNVo.$_Cn(951)]=null;$_BBFX=_MNVo.$_Dt()[0][17];break;case _MNVo.$_Dt()[0][17]:this[_MNVo.$_Cn(905)](_MNVo.$_Cn(937),_MNVo.$_Cn(950));$_BBFX=_MNVo.$_Dt()[12][16];break;}}}return h[_MNVo.$_Cn(72)][_MNVo.$_Cn(966)]=function(e){return e[_MNVo.$_Cn(425)]<0||0<=e[_MNVo.$_Cn(971)](this[_MNVo.$_Cn(482)])?e[_MNVo.$_Cn(990)](this[_MNVo.$_Cn(482)]):e;},h[_MNVo.$_Cn(72)][_MNVo.$_Cn(944)]=function(e){return e;},h[_MNVo.$_Cn(72)][_MNVo.$_Cn(7)]=function(e){e[_MNVo.$_Cn(939)](this[_MNVo.$_Cn(482)],null,e);},h[_MNVo.$_Cn(72)][_MNVo.$_Cn(933)]=function(e,t,n){e[_MNVo.$_Cn(964)](t,n),this[_MNVo.$_Cn(7)](n);},h[_MNVo.$_Cn(72)][_MNVo.$_Cn(974)]=function(e,t){e[_MNVo.$_Cn(946)](t),this[_MNVo.$_Cn(7)](t);},p[_MNVo.$_Cn(72)][_MNVo.$_Cn(966)]=function(e){var t=g();return e[_MNVo.$_Cn(295)]()[_MNVo.$_Cn(988)](this[_MNVo.$_Cn(482)][_MNVo.$_Cn(477)],t),t[_MNVo.$_Cn(939)](this[_MNVo.$_Cn(482)],null,t),e[_MNVo.$_Cn(425)]<0&&0<t[_MNVo.$_Cn(971)](w[_MNVo.$_Cn(994)])&&this[_MNVo.$_Cn(482)][_MNVo.$_Cn(922)](t,t),t;},p[_MNVo.$_Cn(72)][_MNVo.$_Cn(944)]=function(e){var t=g();return e[_MNVo.$_Cn(925)](t),this[_MNVo.$_Cn(7)](t),t;},p[_MNVo.$_Cn(72)][_MNVo.$_Cn(7)]=function(e){while(e[_MNVo.$_Cn(477)]<=this[_MNVo.$_Cn(931)])e[e[_MNVo.$_Cn(477)]++]=0;for(var t=0;t<this[_MNVo.$_Cn(482)][_MNVo.$_Cn(477)];++t){var n=32767&e[t],i=n*this[_MNVo.$_Cn(912)]+((n*this[_MNVo.$_Cn(996)]+(e[t]>>15)*this[_MNVo.$_Cn(912)]&this[_MNVo.$_Cn(935)])<<15)&e[_MNVo.$_Cn(970)];e[n=t+this[_MNVo.$_Cn(482)][_MNVo.$_Cn(477)]]+=this[_MNVo.$_Cn(482)][_MNVo.$_Cn(934)](0,i,e,t,0,this[_MNVo.$_Cn(482)][_MNVo.$_Cn(477)]);while(e[n]>=e[_MNVo.$_Cn(942)])e[n]-=e[_MNVo.$_Cn(942)],e[++n]++;}e[_MNVo.$_Cn(849)](),e[_MNVo.$_Cn(924)](this[_MNVo.$_Cn(482)][_MNVo.$_Cn(477)],e),0<=e[_MNVo.$_Cn(971)](this[_MNVo.$_Cn(482)])&&e[_MNVo.$_Cn(922)](this[_MNVo.$_Cn(482)],e);},p[_MNVo.$_Cn(72)][_MNVo.$_Cn(933)]=function(e,t,n){e[_MNVo.$_Cn(964)](t,n),this[_MNVo.$_Cn(7)](n);},p[_MNVo.$_Cn(72)][_MNVo.$_Cn(974)]=function(e,t){e[_MNVo.$_Cn(946)](t),this[_MNVo.$_Cn(7)](t);},w[_MNVo.$_Cn(72)][_MNVo.$_Cn(925)]=function(e){for(var t=this[_MNVo.$_Cn(477)]-1;0<=t;--t)e[t]=this[t];e[_MNVo.$_Cn(477)]=this[_MNVo.$_Cn(477)],e[_MNVo.$_Cn(425)]=this[_MNVo.$_Cn(425)];},w[_MNVo.$_Cn(72)][_MNVo.$_Cn(981)]=function(e){this[_MNVo.$_Cn(477)]=1,this[_MNVo.$_Cn(425)]=e<0?-1:0,0<e?this[0]=e:e<-1?this[0]=e+this[_MNVo.$_Cn(942)]:this[_MNVo.$_Cn(477)]=0;},w[_MNVo.$_Cn(72)][_MNVo.$_Cn(940)]=function(e,t){var n;if(16==t)n=4;else if(8==t)n=3;else if(256==t)n=8;else if(2==t)n=1;else if(32==t)n=5;else{if(4!=t)return void this[_MNVo.$_Cn(987)](e,t);n=2;}this[_MNVo.$_Cn(477)]=0,this[_MNVo.$_Cn(425)]=0;var i,r=e[_MNVo.$_Cn(59)],o=!1,a=0;while(0<=--r){var c=8==n?255&e[r]:(i=r,null==(c=u[(c=e)[_MNVo.$_Cn(6)](i)])?-1:c);c<0?_MNVo.$_Cn(370)==e[_MNVo.$_Cn(302)](r)&&(o=!0):(o=!1,0==a?this[this[_MNVo.$_Cn(477)]++]=c:a+n>this[_MNVo.$_Cn(947)]?(this[this[_MNVo.$_Cn(477)]-1]|=(c&(1<<this[_MNVo.$_Cn(947)]-a)-1)<<a,this[this[_MNVo.$_Cn(477)]++]=c>>this[_MNVo.$_Cn(947)]-a):this[this[_MNVo.$_Cn(477)]-1]|=c<<a,(a+=n)>=this[_MNVo.$_Cn(947)]&&(a-=this[_MNVo.$_Cn(947)]));}8==n&&0!=(128&e[0])&&(this[_MNVo.$_Cn(425)]=-1,0<a&&(this[this[_MNVo.$_Cn(477)]-1]|=(1<<this[_MNVo.$_Cn(947)]-a)-1<<a)),this[_MNVo.$_Cn(849)](),o&&w[_MNVo.$_Cn(994)][_MNVo.$_Cn(922)](this,this);},w[_MNVo.$_Cn(72)][_MNVo.$_Cn(849)]=function(){var e=this[_MNVo.$_Cn(425)]&this[_MNVo.$_Cn(970)];while(0<this[_MNVo.$_Cn(477)]&&this[this[_MNVo.$_Cn(477)]-1]==e)--this[_MNVo.$_Cn(477)];},w[_MNVo.$_Cn(72)][_MNVo.$_Cn(988)]=function(e,t){for(var n=this[_MNVo.$_Cn(477)]-1;0<=n;--n)t[n+e]=this[n];for(n=e-1;0<=n;--n)t[n]=0;t[_MNVo.$_Cn(477)]=this[_MNVo.$_Cn(477)]+e,t[_MNVo.$_Cn(425)]=this[_MNVo.$_Cn(425)];},w[_MNVo.$_Cn(72)][_MNVo.$_Cn(924)]=function(e,t){for(var n=e;n<this[_MNVo.$_Cn(477)];++n)t[n-e]=this[n];t[_MNVo.$_Cn(477)]=Math[_MNVo.$_Cn(263)](this[_MNVo.$_Cn(477)]-e,0),t[_MNVo.$_Cn(425)]=this[_MNVo.$_Cn(425)];},w[_MNVo.$_Cn(72)][_MNVo.$_Cn(915)]=function(e,t){for(var n=e%this[_MNVo.$_Cn(947)],i=this[_MNVo.$_Cn(947)]-n,r=(1<<i)-1,o=Math[_MNVo.$_Cn(913)](e/this[_MNVo.$_Cn(947)]),a=this[_MNVo.$_Cn(425)]<<n&this[_MNVo.$_Cn(970)],c=this[_MNVo.$_Cn(477)]-1;0<=c;--c)t[c+o+1]=this[c]>>i|a,a=(this[c]&r)<<n;for(c=o-1;0<=c;--c)t[c]=0;t[o]=a,t[_MNVo.$_Cn(477)]=this[_MNVo.$_Cn(477)]+o+1,t[_MNVo.$_Cn(425)]=this[_MNVo.$_Cn(425)],t[_MNVo.$_Cn(849)]();},w[_MNVo.$_Cn(72)][_MNVo.$_Cn(953)]=function(e,t){t[_MNVo.$_Cn(425)]=this[_MNVo.$_Cn(425)];var n=Math[_MNVo.$_Cn(913)](e/this[_MNVo.$_Cn(947)]);if(n>=this[_MNVo.$_Cn(477)])t[_MNVo.$_Cn(477)]=0;else{var i=e%this[_MNVo.$_Cn(947)],r=this[_MNVo.$_Cn(947)]-i,o=(1<<i)-1;t[0]=this[n]>>i;for(var a=n+1;a<this[_MNVo.$_Cn(477)];++a)t[a-n-1]|=(this[a]&o)<<r,t[a-n]=this[a]>>i;0<i&&(t[this[_MNVo.$_Cn(477)]-n-1]|=(this[_MNVo.$_Cn(425)]&o)<<r),t[_MNVo.$_Cn(477)]=this[_MNVo.$_Cn(477)]-n,t[_MNVo.$_Cn(849)]();}},w[_MNVo.$_Cn(72)][_MNVo.$_Cn(922)]=function(e,t){var n=0,i=0,r=Math[_MNVo.$_Cn(51)](e[_MNVo.$_Cn(477)],this[_MNVo.$_Cn(477)]);while(n<r)i+=this[n]-e[n],t[n++]=i&this[_MNVo.$_Cn(970)],i>>=this[_MNVo.$_Cn(947)];if(e[_MNVo.$_Cn(477)]<this[_MNVo.$_Cn(477)]){i-=e[_MNVo.$_Cn(425)];while(n<this[_MNVo.$_Cn(477)])i+=this[n],t[n++]=i&this[_MNVo.$_Cn(970)],i>>=this[_MNVo.$_Cn(947)];i+=this[_MNVo.$_Cn(425)];}else{i+=this[_MNVo.$_Cn(425)];while(n<e[_MNVo.$_Cn(477)])i-=e[n],t[n++]=i&this[_MNVo.$_Cn(970)],i>>=this[_MNVo.$_Cn(947)];i-=e[_MNVo.$_Cn(425)];}t[_MNVo.$_Cn(425)]=i<0?-1:0,i<-1?t[n++]=this[_MNVo.$_Cn(942)]+i:0<i&&(t[n++]=i),t[_MNVo.$_Cn(477)]=n,t[_MNVo.$_Cn(849)]();},w[_MNVo.$_Cn(72)][_MNVo.$_Cn(964)]=function(e,t){var n=this[_MNVo.$_Cn(295)](),i=e[_MNVo.$_Cn(295)](),r=n[_MNVo.$_Cn(477)];t[_MNVo.$_Cn(477)]=r+i[_MNVo.$_Cn(477)];while(0<=--r)t[r]=0;for(r=0;r<i[_MNVo.$_Cn(477)];++r)t[r+n[_MNVo.$_Cn(477)]]=n[_MNVo.$_Cn(934)](0,i[r],t,r,0,n[_MNVo.$_Cn(477)]);t[_MNVo.$_Cn(425)]=0,t[_MNVo.$_Cn(849)](),this[_MNVo.$_Cn(425)]!=e[_MNVo.$_Cn(425)]&&w[_MNVo.$_Cn(994)][_MNVo.$_Cn(922)](t,t);},w[_MNVo.$_Cn(72)][_MNVo.$_Cn(946)]=function(e){var t=this[_MNVo.$_Cn(295)](),n=e[_MNVo.$_Cn(477)]=2*t[_MNVo.$_Cn(477)];while(0<=--n)e[n]=0;for(n=0;n<t[_MNVo.$_Cn(477)]-1;++n){var i=t[_MNVo.$_Cn(934)](n,t[n],e,2*n,0,1);(e[n+t[_MNVo.$_Cn(477)]]+=t[_MNVo.$_Cn(934)](n+1,2*t[n],e,2*n+1,i,t[_MNVo.$_Cn(477)]-n-1))>=t[_MNVo.$_Cn(942)]&&(e[n+t[_MNVo.$_Cn(477)]]-=t[_MNVo.$_Cn(942)],e[n+t[_MNVo.$_Cn(477)]+1]=1);}0<e[_MNVo.$_Cn(477)]&&(e[e[_MNVo.$_Cn(477)]-1]+=t[_MNVo.$_Cn(934)](n,t[n],e,2*n,0,1)),e[_MNVo.$_Cn(425)]=0,e[_MNVo.$_Cn(849)]();},w[_MNVo.$_Cn(72)][_MNVo.$_Cn(939)]=function(e,t,n){var i=e[_MNVo.$_Cn(295)]();if(!(i[_MNVo.$_Cn(477)]<=0)){var r=this[_MNVo.$_Cn(295)]();if(r[_MNVo.$_Cn(477)]<i[_MNVo.$_Cn(477)])return null!=t&&t[_MNVo.$_Cn(981)](0),void(null!=n&&this[_MNVo.$_Cn(925)](n));null==n&&(n=g());var o=g(),a=this[_MNVo.$_Cn(425)],c=e[_MNVo.$_Cn(425)],e=this[_MNVo.$_Cn(947)]-b(i[i[_MNVo.$_Cn(477)]-1]);0<e?(i[_MNVo.$_Cn(915)](e,o),r[_MNVo.$_Cn(915)](e,n)):(i[_MNVo.$_Cn(925)](o),r[_MNVo.$_Cn(925)](n));var s=o[_MNVo.$_Cn(477)],u=o[s-1];if(0!=u){var r=u*(1<<this[_MNVo.$_Cn(932)])+(1<s?o[s-2]>>this[_MNVo.$_Cn(902)]:0),l=this[_MNVo.$_Cn(911)]/r,d=(1<<this[_MNVo.$_Cn(932)])/r,f=1<<this[_MNVo.$_Cn(902)],h=n[_MNVo.$_Cn(477)],p=h-s,m=null==t?g():t;o[_MNVo.$_Cn(988)](p,m),0<=n[_MNVo.$_Cn(971)](m)&&(n[n[_MNVo.$_Cn(477)]++]=1,n[_MNVo.$_Cn(922)](m,n)),w[_MNVo.$_Cn(916)][_MNVo.$_Cn(988)](s,m),m[_MNVo.$_Cn(922)](o,o);while(o[_MNVo.$_Cn(477)]<s)o[o[_MNVo.$_Cn(477)]++]=0;while(0<=--p){var v=n[--h]==u?this[_MNVo.$_Cn(970)]:Math[_MNVo.$_Cn(913)](n[h]*l+(n[h-1]+f)*d);if((n[h]+=o[_MNVo.$_Cn(934)](0,v,n,p,0,s))<v){o[_MNVo.$_Cn(988)](p,m),n[_MNVo.$_Cn(922)](m,n);while(n[h]<--v)n[_MNVo.$_Cn(922)](m,n);}}null!=t&&(n[_MNVo.$_Cn(924)](s,t),a!=c&&w[_MNVo.$_Cn(994)][_MNVo.$_Cn(922)](t,t)),n[_MNVo.$_Cn(477)]=s,n[_MNVo.$_Cn(849)](),0<e&&n[_MNVo.$_Cn(953)](e,n),a<0&&w[_MNVo.$_Cn(994)][_MNVo.$_Cn(922)](n,n);}}},w[_MNVo.$_Cn(72)][_MNVo.$_Cn(920)]=function(){if(this[_MNVo.$_Cn(477)]<1)return 0;var e=this[0];if(0==(1&e))return 0;var t=3&e;return 0<(t=(t=(t=(t=t*(2-(15&e)*t)&15)*(2-(255&e)*t)&255)*(2-((65535&e)*t&65535))&65535)*(2-e*t%this[_MNVo.$_Cn(942)])%this[_MNVo.$_Cn(942)])?this[_MNVo.$_Cn(942)]-t:-t;},w[_MNVo.$_Cn(72)][_MNVo.$_Cn(972)]=function(){return 0==(0<this[_MNVo.$_Cn(477)]?1&this[0]:this[_MNVo.$_Cn(425)]);},w[_MNVo.$_Cn(72)][_MNVo.$_Cn(310)]=function(e,t){if(4294967295<e||e<1)return w[_MNVo.$_Cn(916)];var n,i=g(),r=g(),o=t[_MNVo.$_Cn(966)](this),a=b(e)-1;o[_MNVo.$_Cn(925)](i);while(0<=--a)t[_MNVo.$_Cn(974)](i,r),0<(e&1<<a)?t[_MNVo.$_Cn(933)](r,o,i):(n=i,i=r,r=n);return t[_MNVo.$_Cn(944)](i);},w[_MNVo.$_Cn(72)][_MNVo.$_Cn(41)]=function(e){if(this[_MNVo.$_Cn(425)]<0)return _MNVo.$_Cn(370)+this[_MNVo.$_Cn(993)]()[_MNVo.$_Cn(41)](e);var t;if(16==e)t=4;else if(8==e)t=3;else if(2==e)t=1;else if(32==e)t=5;else{if(4!=e)return this[_MNVo.$_Cn(975)](e);t=2;}var n,i=(1<<t)-1,r=!1,o=_MNVo.$_Cn(56),a=this[_MNVo.$_Cn(477)],c=this[_MNVo.$_Cn(947)]-a*this[_MNVo.$_Cn(947)]%t;if(0<a--){c<this[_MNVo.$_Cn(947)]&&0<(n=this[a]>>c)&&(r=!0,o=d(n));while(0<=a)c<t?(n=(this[a]&(1<<c)-1)<<t-c,n|=this[--a]>>(c+=this[_MNVo.$_Cn(947)]-t)):(n=this[a]>>(c-=t)&i,c<=0&&(c+=this[_MNVo.$_Cn(947)],--a)),(r=0<n?!0:r)&&(o+=d(n));}return r?o:_MNVo.$_Cn(90);},w[_MNVo.$_Cn(72)][_MNVo.$_Cn(993)]=function(){var e=g();return w[_MNVo.$_Cn(994)][_MNVo.$_Cn(922)](this,e),e;},w[_MNVo.$_Cn(72)][_MNVo.$_Cn(295)]=function(){return this[_MNVo.$_Cn(425)]<0?this[_MNVo.$_Cn(993)]():this;},w[_MNVo.$_Cn(72)][_MNVo.$_Cn(971)]=function(e){var t=this[_MNVo.$_Cn(425)]-e[_MNVo.$_Cn(425)];if(0!=t)return t;var n=this[_MNVo.$_Cn(477)];if(0!=(t=n-e[_MNVo.$_Cn(477)]))return this[_MNVo.$_Cn(425)]<0?-t:t;while(0<=--n)if(0!=(t=this[n]-e[n]))return t;return 0;},w[_MNVo.$_Cn(72)][_MNVo.$_Cn(985)]=function(){return this[_MNVo.$_Cn(477)]<=0?0:this[_MNVo.$_Cn(947)]*(this[_MNVo.$_Cn(477)]-1)+b(this[this[_MNVo.$_Cn(477)]-1]^this[_MNVo.$_Cn(425)]&this[_MNVo.$_Cn(970)]);},w[_MNVo.$_Cn(72)][_MNVo.$_Cn(990)]=function(e){var t=g();return this[_MNVo.$_Cn(295)]()[_MNVo.$_Cn(939)](e,null,t),this[_MNVo.$_Cn(425)]<0&&0<t[_MNVo.$_Cn(971)](w[_MNVo.$_Cn(994)])&&e[_MNVo.$_Cn(922)](t,t),t;},w[_MNVo.$_Cn(72)][_MNVo.$_Cn(936)]=function(e,t){return t=new(e<256||(t[_MNVo.$_Cn(972)]())?h:p)(t),this[_MNVo.$_Cn(310)](e,t);},w[_MNVo.$_Cn(994)]=f(0),w[_MNVo.$_Cn(916)]=f(1),m[_MNVo.$_Cn(72)][_MNVo.$_Cn(997)]=function(e){return e[_MNVo.$_Cn(936)](this[_MNVo.$_Cn(414)],this[_MNVo.$_Cn(451)]);},m[_MNVo.$_Cn(72)][_MNVo.$_Cn(905)]=function(e,t){null!=e&&null!=t&&0<e[_MNVo.$_Cn(59)]&&0<t[_MNVo.$_Cn(59)]?(this[_MNVo.$_Cn(451)]=new w(e,16),this[_MNVo.$_Cn(414)]=parseInt(t,16)):console[_MNVo.$_Cn(339)](_MNVo.$_Cn(930));},m[_MNVo.$_Cn(72)][_MNVo.$_Cn(584)]=function(e){return null==(e=function(e,t){if(t<e[_MNVo.$_Cn(59)]+11)return console[_MNVo.$_Cn(339)](_MNVo.$_Cn(928)),null;var n=[],i=e[_MNVo.$_Cn(59)]-1;while(0<=i&&0<t){var r=e[_MNVo.$_Cn(6)](i--);r<128?n[--t]=r:127<r&&r<2048?(n[--t]=63&r|128,n[--t]=r>>6|192):(n[--t]=63&r|128,n[--t]=r>>6&63|128,n[--t]=r>>12|224);}n[--t]=0;var o=new c(),a=[];while(2<t){a[0]=0;while(0==a[0])o[_MNVo.$_Cn(955)](a);n[--t]=a[0];}return n[--t]=2,n[--t]=0,new w(n);}(e,this[_MNVo.$_Cn(451)][_MNVo.$_Cn(985)]()+7>>3))||null==(e=this[_MNVo.$_Cn(997)](e))?null:0==(1&(e=e[_MNVo.$_Cn(41)](16))[_MNVo.$_Cn(59)])?e:_MNVo.$_Cn(90)+e;},m;}();function Tt(e){var $_BBGY=_MNVo.$_Dt()[12][18];for(;$_BBGY!==_MNVo.$_Dt()[12][16];){switch($_BBGY){case _MNVo.$_Dt()[0][18]:var t=ae(32),n=new Ct()[_MNVo.$_Cn(584)](t);while(!n||256!==n[_MNVo.$_Cn(59)])t=ae(32),n=new Ct()[_MNVo.$_Cn(584)](t);$_BBGY=_MNVo.$_Dt()[8][17];break;case _MNVo.$_Dt()[12][17]:return function(e){for(var t=[],n=0,i=0;i<2*e[_MNVo.$_Cn(59)];i+=2)t[i>>>3]|=parseInt(e[n],10)<<24-i%8*4,n++;for(var r=[],i=0;i<e[_MNVo.$_Cn(59)];i++){var o=t[i>>>2]>>>24-i%4*8&255;r[_MNVo.$_Cn(50)]((o>>>4)[_MNVo.$_Cn(41)](16)),r[_MNVo.$_Cn(50)]((15&o)[_MNVo.$_Cn(41)](16));}return r[_MNVo.$_Cn(161)](_MNVo.$_Cn(56));}(At[_MNVo.$_Cn(584)](e,t))+n;break;}}}var Et,xt,kt,Pt,Ot,Dt=(Ze={\"\\u0073\\u0074\\u0072\\u0069\\u006e\\u0067\\u0069\\u0066\\u0079\":function(e){}},Ot=/[\\\\\"\\u0000-\\u001f\\u007f-\\u009f\\u00ad\\u0600-\\u0604\\u070f\\u17b4\\u17b5\\u200c-\\u200f\\u2028-\\u202f\\u2060-\\u206f\\ufeff\\ufff0-\\uffff]/g,_MNVo.$_Cn(61)!=typeof Date[_MNVo.$_Cn(72)][_MNVo.$_Cn(909)]&&(Date[_MNVo.$_Cn(72)][_MNVo.$_Cn(909)]=function(){return isFinite(this[_MNVo.$_Cn(941)]())?_MNVo.$_Cn(56)[_MNVo.$_Cn(75)](this[_MNVo.$_Cn(954)](),_MNVo.$_Cn(370))[_MNVo.$_Cn(75)](Mt(this[_MNVo.$_Cn(903)]()+1),_MNVo.$_Cn(370))[_MNVo.$_Cn(75)](Mt(this[_MNVo.$_Cn(960)]()),_MNVo.$_Cn(409))[_MNVo.$_Cn(75)](Mt(this[_MNVo.$_Cn(967)]()),_MNVo.$_Cn(978))[_MNVo.$_Cn(75)](Mt(this[_MNVo.$_Cn(963)]()),_MNVo.$_Cn(978))[_MNVo.$_Cn(75)](Mt(this[_MNVo.$_Cn(910)]()),_MNVo.$_Cn(492)):null;},Boolean[_MNVo.$_Cn(72)][_MNVo.$_Cn(909)]=Nt,Number[_MNVo.$_Cn(72)][_MNVo.$_Cn(909)]=Nt,String[_MNVo.$_Cn(72)][_MNVo.$_Cn(909)]=Nt),kt={\"\\u0008\":_MNVo.$_Cn(959),\"\\u0009\":_MNVo.$_Cn(901),\"\\u000a\":_MNVo.$_Cn(980),\"\\u000c\":_MNVo.$_Cn(995),\"\\u000d\":_MNVo.$_Cn(900),\"\\u0022\":_MNVo.$_Cn(977),\"\\u005c\":_MNVo.$_Cn(945)},Ze[_MNVo.$_Cn(984)]=function(e,t,n){var i;if(xt=Et=_MNVo.$_Cn(56),_MNVo.$_Cn(46)==typeof n)for(i=0;i<n;i+=1)xt+=_MNVo.$_Cn(155);else _MNVo.$_Cn(235)==typeof n&&(xt=n);if((Pt=t)&&_MNVo.$_Cn(61)!=typeof t&&(_MNVo.$_Cn(21)!=typeof t||_MNVo.$_Cn(46)!=typeof t[_MNVo.$_Cn(59)]))throw new Error(_MNVo.$_Cn(919));return function u(e,t){var n,i,r,o,a,c=Et,s=t[e];switch(s&&_MNVo.$_Cn(21)==typeof s&&_MNVo.$_Cn(61)==typeof s[_MNVo.$_Cn(909)]&&(s=s[_MNVo.$_Cn(909)](e)),typeof(s=_MNVo.$_Cn(61)==typeof Pt?Pt[_MNVo.$_Cn(92)](t,e,s):s)){case _MNVo.$_Cn(235):return Bt(s);case _MNVo.$_Cn(46):return isFinite(s)?String(s):_MNVo.$_Cn(455);case _MNVo.$_Cn(962):case _MNVo.$_Cn(455):return String(s);case _MNVo.$_Cn(21):if(!s)return _MNVo.$_Cn(455);if(Et+=xt,a=[],_MNVo.$_Cn(976)===Object[_MNVo.$_Cn(72)][_MNVo.$_Cn(41)][_MNVo.$_Cn(12)](s)){for(o=s[_MNVo.$_Cn(59)],n=0;n<o;n+=1)a[n]=u(n,s)||_MNVo.$_Cn(455);return r=0===a[_MNVo.$_Cn(59)]?_MNVo.$_Cn(927):Et?_MNVo.$_Cn(952)[_MNVo.$_Cn(75)](Et)[_MNVo.$_Cn(75)](a[_MNVo.$_Cn(161)](_MNVo.$_Cn(918)[_MNVo.$_Cn(75)](Et)),_MNVo.$_Cn(897))[_MNVo.$_Cn(75)](c,_MNVo.$_Cn(989)):_MNVo.$_Cn(965)[_MNVo.$_Cn(75)](a[_MNVo.$_Cn(161)](_MNVo.$_Cn(236)),_MNVo.$_Cn(989)),Et=c,r;}if(Pt&&_MNVo.$_Cn(21)==typeof Pt)for(o=Pt[_MNVo.$_Cn(59)],n=0;n<o;n+=1)_MNVo.$_Cn(235)==typeof Pt[n]&&(r=u(i=Pt[n],s))&&a[_MNVo.$_Cn(50)](Bt(i)+(Et?_MNVo.$_Cn(961):_MNVo.$_Cn(978))+r);else for(i in s)Object[_MNVo.$_Cn(72)][_MNVo.$_Cn(858)][_MNVo.$_Cn(92)](s,i)&&(r=u(i,s))&&a[_MNVo.$_Cn(50)](Bt(i)+(Et?_MNVo.$_Cn(961):_MNVo.$_Cn(978))+r);return r=0===a[_MNVo.$_Cn(59)]?_MNVo.$_Cn(949):Et?_MNVo.$_Cn(973)[_MNVo.$_Cn(75)](Et)[_MNVo.$_Cn(75)](a[_MNVo.$_Cn(161)](_MNVo.$_Cn(918)[_MNVo.$_Cn(75)](Et)),_MNVo.$_Cn(897))[_MNVo.$_Cn(75)](c,_MNVo.$_Cn(969)):_MNVo.$_Cn(938)[_MNVo.$_Cn(75)](a[_MNVo.$_Cn(161)](_MNVo.$_Cn(236)),_MNVo.$_Cn(969)),Et=c,r;}}(_MNVo.$_Cn(56),{\"\":e});},Ze);function Mt(e){var $_BBHs=_MNVo.$_Dt()[8][18];for(;$_BBHs!==_MNVo.$_Dt()[4][17];){switch($_BBHs){case _MNVo.$_Dt()[12][18]:return e<10?_MNVo.$_Cn(90)[_MNVo.$_Cn(75)](e):e;break;}}}function Nt(){var $_BBIt=_MNVo.$_Dt()[4][18];for(;$_BBIt!==_MNVo.$_Dt()[12][17];){switch($_BBIt){case _MNVo.$_Dt()[0][18]:return this[_MNVo.$_Cn(941)]();break;}}}function Bt(e){var $_BBJs=_MNVo.$_Dt()[12][18];for(;$_BBJs!==_MNVo.$_Dt()[4][17];){switch($_BBJs){case _MNVo.$_Dt()[4][18]:return Ot[_MNVo.$_Cn(983)]=0,Ot[_MNVo.$_Cn(496)](e)?_MNVo.$_Cn(999)[_MNVo.$_Cn(75)](e[_MNVo.$_Cn(503)](Ot,function(e){var t=kt[e];return _MNVo.$_Cn(235)==typeof t?t:_MNVo.$_Cn(929)[_MNVo.$_Cn(75)](_MNVo.$_Cn(904)[_MNVo.$_Cn(75)](e[_MNVo.$_Cn(6)](0)[_MNVo.$_Cn(41)](16))[_MNVo.$_Cn(82)](-4));}),_MNVo.$_Cn(999)):_MNVo.$_Cn(999)[_MNVo.$_Cn(75)](e,_MNVo.$_Cn(999));break;}}}var Rt,jt,It,Ft,Ut,Lt,zt,qt,Gt=(Rt=[_MNVo.$_Cn(438),_MNVo.$_Cn(473),_MNVo.$_Cn(402),_MNVo.$_Cn(434),_MNVo.$_Cn(440),_MNVo.$_Cn(468),_MNVo.$_Cn(412),_MNVo.$_Cn(493),_MNVo.$_Cn(467),_MNVo.$_Cn(494),_MNVo.$_Cn(486),_MNVo.$_Cn(410),_MNVo.$_Cn(489),_MNVo.$_Cn(452),_MNVo.$_Cn(422),_MNVo.$_Cn(436),_MNVo.$_Cn(424),_MNVo.$_Cn(404),_MNVo.$_Cn(416),_MNVo.$_Cn(409),_MNVo.$_Cn(433),_MNVo.$_Cn(445),_MNVo.$_Cn(491),_MNVo.$_Cn(442),_MNVo.$_Cn(408),_MNVo.$_Cn(492),_MNVo.$_Cn(484),_MNVo.$_Cn(470),_MNVo.$_Cn(458),_MNVo.$_Cn(437),_MNVo.$_Cn(414),_MNVo.$_Cn(441),_MNVo.$_Cn(460),_MNVo.$_Cn(498),_MNVo.$_Cn(456),_MNVo.$_Cn(401),_MNVo.$_Cn(471),_MNVo.$_Cn(459),_MNVo.$_Cn(482),_MNVo.$_Cn(451),_MNVo.$_Cn(490),_MNVo.$_Cn(411),_MNVo.$_Cn(429),_MNVo.$_Cn(466),_MNVo.$_Cn(425),_MNVo.$_Cn(477),_MNVo.$_Cn(427),_MNVo.$_Cn(418),_MNVo.$_Cn(448),_MNVo.$_Cn(419),_MNVo.$_Cn(476),_MNVo.$_Cn(403),_MNVo.$_Cn(90),_MNVo.$_Cn(316),_MNVo.$_Cn(318),_MNVo.$_Cn(479),_MNVo.$_Cn(407),_MNVo.$_Cn(454),_MNVo.$_Cn(435),_MNVo.$_Cn(423),_MNVo.$_Cn(462),_MNVo.$_Cn(457),_MNVo.$_Cn(231),_MNVo.$_Cn(513)],jt=[_MNVo.$_Cn(438),_MNVo.$_Cn(473),_MNVo.$_Cn(402),_MNVo.$_Cn(434),_MNVo.$_Cn(440),_MNVo.$_Cn(468),_MNVo.$_Cn(412),_MNVo.$_Cn(493),_MNVo.$_Cn(467),_MNVo.$_Cn(494),_MNVo.$_Cn(486),_MNVo.$_Cn(410),_MNVo.$_Cn(489),_MNVo.$_Cn(452),_MNVo.$_Cn(422),_MNVo.$_Cn(436),_MNVo.$_Cn(424),_MNVo.$_Cn(404),_MNVo.$_Cn(416),_MNVo.$_Cn(409),_MNVo.$_Cn(433),_MNVo.$_Cn(445),_MNVo.$_Cn(491),_MNVo.$_Cn(442),_MNVo.$_Cn(408),_MNVo.$_Cn(492),_MNVo.$_Cn(484),_MNVo.$_Cn(470),_MNVo.$_Cn(458),_MNVo.$_Cn(437),_MNVo.$_Cn(414),_MNVo.$_Cn(441),_MNVo.$_Cn(460),_MNVo.$_Cn(498),_MNVo.$_Cn(456),_MNVo.$_Cn(401),_MNVo.$_Cn(471),_MNVo.$_Cn(459),_MNVo.$_Cn(482),_MNVo.$_Cn(451),_MNVo.$_Cn(490),_MNVo.$_Cn(411),_MNVo.$_Cn(429),_MNVo.$_Cn(466),_MNVo.$_Cn(425),_MNVo.$_Cn(477),_MNVo.$_Cn(427),_MNVo.$_Cn(418),_MNVo.$_Cn(448),_MNVo.$_Cn(419),_MNVo.$_Cn(476),_MNVo.$_Cn(403),_MNVo.$_Cn(90),_MNVo.$_Cn(316),_MNVo.$_Cn(318),_MNVo.$_Cn(479),_MNVo.$_Cn(407),_MNVo.$_Cn(454),_MNVo.$_Cn(435),_MNVo.$_Cn(423),_MNVo.$_Cn(462),_MNVo.$_Cn(457),_MNVo.$_Cn(370),_MNVo.$_Cn(634)],It=function(e){var t=[];while(0<e){var n=e%2;e=Math[_MNVo.$_Cn(913)](e/2),t[_MNVo.$_Cn(50)](n);}return t[_MNVo.$_Cn(268)](),t;},Ft=function(e){for(var t=0,n=0,i=e[_MNVo.$_Cn(59)]-1;0<=i;--i)1==e[i]&&(t+=Math[_MNVo.$_Cn(380)](2,n)),++n;return t;},Ut=function(e,t){var n=8-(e+1)+6*(e-1)-t[_MNVo.$_Cn(59)];while(0<=--n)t[_MNVo.$_Cn(907)](0);var i=[],r=e;while(0<=--r)i[_MNVo.$_Cn(50)](1);i[_MNVo.$_Cn(50)](0);for(var o=0,a=8-(e+1);o<a;++o)i[_MNVo.$_Cn(50)](t[o]);for(var c=0;c<e-1;++c){i[_MNVo.$_Cn(50)](1),i[_MNVo.$_Cn(50)](0);var s=6;while(0<=--s)i[_MNVo.$_Cn(50)](t[o++]);}return i;},Lt=function(e,t){for(var n=[],i=function(e){for(var t=[],n=0,i=e[_MNVo.$_Cn(59)];n<i;++n){var r=e[_MNVo.$_Cn(6)](n),o=It(r);if(r<128){var a=8-o[_MNVo.$_Cn(59)];while(0<=--a)o[_MNVo.$_Cn(907)](0);t=t[_MNVo.$_Cn(75)](o);}else 128<=r&&r<=2047?t=t[_MNVo.$_Cn(75)](Ut(2,o)):2048<=r&&r<=65535?t=t[_MNVo.$_Cn(75)](Ut(3,o)):65536<=r&&r<=2097151?t=t[_MNVo.$_Cn(75)](Ut(4,o)):2097152<=r&&r<=67108863?t=t[_MNVo.$_Cn(75)](Ut(5,o)):4e6<=r&&r<=2147483647&&(t=t[_MNVo.$_Cn(75)](Ut(6,o)));}return t;}(e),r=t?jt:Rt,o=0,a=0,c=i[_MNVo.$_Cn(59)];a<c;a+=6){var s=a+6-c;2==s?o=2:4==s&&(o=4);var u=o;while(0<=--u)i[_MNVo.$_Cn(50)](0);n[_MNVo.$_Cn(50)](Ft(i[_MNVo.$_Cn(82)](a,a+6)));}for(var l=_MNVo.$_Cn(56),a=0,c=n[_MNVo.$_Cn(59)];a<c;++a)l+=r[n[a]];for(a=0,c=o/2;a<c;++a)l+=_MNVo.$_Cn(330);return l;},zt=function(e,t){for(var n=e[_MNVo.$_Cn(59)],i=0,r=t?jt:Rt,o=[],a=0,c=(e=_MNVo.$_Cn(330)==e[_MNVo.$_Cn(302)](n-1)?_MNVo.$_Cn(330)==e[_MNVo.$_Cn(302)](n-2)?(i=4,e[_MNVo.$_Cn(391)](0,n-2)):(i=2,e[_MNVo.$_Cn(391)](0,n-1)):e)[_MNVo.$_Cn(59)];a<c;++a)for(var s=e[_MNVo.$_Cn(302)](a),u=0,l=r[_MNVo.$_Cn(59)];u<l;++u)if(s==r[u]){var d=It(u),f=d[_MNVo.$_Cn(59)];if(0<6-f)for(var h=6-f;0<h;--h)d[_MNVo.$_Cn(907)](0);o=o[_MNVo.$_Cn(75)](d);break;}return function(e){for(var t,n=[],i=_MNVo.$_Cn(56),r=0,o=e[_MNVo.$_Cn(59)];r<o;)if(0==e[r])t=Ft(e[_MNVo.$_Cn(82)](r,r+8)),i+=String[_MNVo.$_Cn(325)](t),r+=8;else{var a=0;while(r<o){if(1!=e[r])break;++a,++r;}n=n[_MNVo.$_Cn(75)](e[_MNVo.$_Cn(82)](r+1,r+8-a)),r+=8-a;while(1<a)n=n[_MNVo.$_Cn(75)](e[_MNVo.$_Cn(82)](r+2,r+8)),r+=8,--a;t=Ft(n),i+=String[_MNVo.$_Cn(325)](t),n=[];}return i;}(o=0<i?o[_MNVo.$_Cn(82)](0,o[_MNVo.$_Cn(59)]-i):o);},{\"\\u0065\\u006e\\u0063\\u006f\\u0064\\u0065\":function(e){return Lt(e,!1);},\"\\u0064\\u0065\\u0063\\u006f\\u0064\\u0065\":function(e){return zt(e,!1);},\"\\u0075\\u0072\\u006c\\u0073\\u0061\\u0066\\u0065\\u005f\\u0065\\u006e\\u0063\\u006f\\u0064\\u0065\":function(e){return Lt(e,!0);},\"\\u0075\\u0072\\u006c\\u0073\\u0061\\u0066\\u0065\\u005f\\u0064\\u0065\\u0063\\u006f\\u0064\\u0065\":function(e){return zt(e,!0);}});function Ht(e){var $_BCAI=_MNVo.$_Dt()[4][18];for(;$_BCAI!==_MNVo.$_Dt()[8][16];){switch($_BCAI){case _MNVo.$_Dt()[8][18]:var t=function(e,t){if(_MNVo.$_Cn(61)==typeof Object[_MNVo.$_Cn(979)])return Object[_MNVo.$_Cn(979)][_MNVo.$_Cn(12)](Object,arguments);if(null==e)throw new TypeError(_MNVo.$_Cn(957));e=Object(e);for(var n=1;n<arguments[_MNVo.$_Cn(59)];n++){var i=arguments[n];if(null!=i)for(var r in i)Object[_MNVo.$_Cn(72)][_MNVo.$_Cn(858)][_MNVo.$_Cn(92)](i,r)&&(e[r]=i[r]);}return e;}({},e),n=tt(),i=n[_MNVo.$_Cn(688)],r=n[_MNVo.$_Cn(614)],o=n[_MNVo.$_Cn(652)],e=n[_MNVo.$_Cn(635)],n=n[_MNVo.$_Cn(603)];$_BCAI=_MNVo.$_Dt()[0][17];break;case _MNVo.$_Dt()[4][17]:return t[_MNVo.$_Cn(1043)]={\"\\u0064\\u0061\\u0074\\u0061\":n},t[_MNVo.$_Cn(1047)]={\"\\u0064\\u0061\\u0074\\u0061\":{\"\\u0062\\u0072\\u006f\\u0077\\u0073\\u0065\\u0072\":i,\"\\u0064\\u0065\\u0076\\u0069\\u0063\\u0065\":r,\"\\u0065\\u006e\\u0067\\u0069\\u006e\\u0065\":o,\"\\u006f\\u0073\":e}},t;break;}}}function Vt(e){var $_BCBh=_MNVo.$_Dt()[12][18];for(;$_BCBh!==_MNVo.$_Dt()[12][17];){switch($_BCBh){case _MNVo.$_Dt()[8][18]:return function(e,t){void 0===t&&(t=Infinity);var n=window[_MNVo.$_Cn(1081)];return n?new Promise(function(e){return n[_MNVo.$_Cn(92)](window,function(){return e();},{\"\\u0074\\u0069\\u006d\\u0065\\u006f\\u0075\\u0074\":t});}):u(Math[_MNVo.$_Cn(51)](e,t));}(e=void 0===e?50:e,2*e);break;}}}function Wt(e){var $_BCCA=_MNVo.$_Dt()[0][18];for(;$_BCCA!==_MNVo.$_Dt()[4][16];){switch($_BCCA){case _MNVo.$_Dt()[0][18]:var t=void 0===e?{}:e,l=t[_MNVo.$_Cn(1068)],e=t[_MNVo.$_Cn(44)],d=void 0===e?700:e,e=t[_MNVo.$_Cn(1075)],f=void 0===e?_MNVo.$_Cn(56):e,t=t[_MNVo.$_Cn(1073)],h=void 0!==t&&t;$_BCCA=_MNVo.$_Dt()[0][17];break;case _MNVo.$_Dt()[0][17]:return p(this,void 0,void 0,function(){var n,r,o,a,c,s,u;return m(this,function(e){switch(e[_MNVo.$_Cn(15)]){case 0:return n=new Date()[_MNVo.$_Cn(538)](),[4,Vt(l)];case 1:return e[_MNVo.$_Cn(57)](),c=_(V,{\"\\u0064\\u0065\\u0062\\u0075\\u0067\":!1},[]),qt?[3,3]:[4,Promise[_MNVo.$_Cn(1089)]([c(),(t=d,new Promise(function(e){setTimeout(function(){e({});},t);}))])];case 2:qt=e[_MNVo.$_Cn(57)](),e[_MNVo.$_Cn(15)]=3;case 3:return[4,(i=new ue(),new Promise(function(n){i[_MNVo.$_Cn(536)](re[_MNVo.$_Cn(488)],undefined,function(e){if(0===e)me(n,i);else try{e=pe[_MNVo.$_Cn(1096)](re[_MNVo.$_Cn(488)],e),window[_MNVo.$_Cn(346)]=e,n(e);}catch(t){me(n,i);}});}))];case 4:return r=e[_MNVo.$_Cn(57)](),o=Ht(qt),[4,function(r){return p(this,void 0,void 0,function(){var t,n,i;return m(this,function(e){switch(e[_MNVo.$_Cn(15)]){case 0:return[4,yt[_MNVo.$_Cn(1012)]()];case 1:return n=e[_MNVo.$_Cn(57)](),i=bt[_MNVo.$_Cn(1049)](n),t=i[_MNVo.$_Cn(1056)],n=i[_MNVo.$_Cn(1066)],[4,St[_MNVo.$_Cn(1012)]()];case 2:return i=e[_MNVo.$_Cn(57)](),i=$_BGY[_MNVo.$_Cn(1049)](i,r),[2,{\"\\u0072\\u006f\\u0065\":t,\"\\u0067\\u0075\\u0064\":i,\"\\u006b\\u006f\\u0068\":{},\"\\u0069\\u006e\\u0066\\u006f\":n}];}});});}({\"\\u0073\\u0074\\u0061\\u0072\\u0074\\u0054\\u0069\\u006d\\u0065\":n})];case 5:return s=e[_MNVo.$_Cn(57)](),a=s[_MNVo.$_Cn(1020)],u=s[_MNVo.$_Cn(1055)],c=s[_MNVo.$_Cn(1093)],s=s[_MNVo.$_Cn(1060)],a={\"\\u006c\\u006f\\u0063\\u0061\\u006c\\u005f\\u0069\\u0064\":r,\"\\u0065\\u006e\\u0076\":o,\"\\u0063\\u0074\":_MNVo.$_Cn(479),\"\\u0067\\u0054\\u006f\\u006b\\u0065\\u006e\":f,\"\\u0074\\u0073\":new Date()[_MNVo.$_Cn(538)](),\"\\u0072\\u006f\\u0065\":a,\"\\u0067\\u0075\\u0064\":u,\"\\u006b\\u006f\\u0068\":c,\"\\u0066\\u006f\\u0069\":s},(c=te(u={\"\\u006c\\u0061\\u006e\\u0067\":{},\"\\u0065\\u0070\":{}}))[_MNVo.$_Cn(390)]&&(s=function(e){for(var t in e)if(_MNVo.$_Cn(306)!==t&&_MNVo.$_Cn(390)!==t)return t;return _MNVo.$_Cn(1077);}(u),u=function(e,t,n){for(var i,r=new e[(_MNVo.$_Cn(319))][(_MNVo.$_Cn(441))](t,n),o=[_MNVo.$_Cn(451),_MNVo.$_Cn(425),_MNVo.$_Cn(414),_MNVo.$_Cn(1082),_MNVo.$_Cn(1028),_MNVo.$_Cn(448),_MNVo.$_Cn(1015),_MNVo.$_Cn(1042)],a=o[_MNVo.$_Cn(59)]-2,c=0;c<n[_MNVo.$_Cn(59)];c++){var s=Math[_MNVo.$_Cn(295)](n[c][_MNVo.$_Cn(6)]()-70)[_MNVo.$_Cn(41)]()[1];i=Number(s)>a?e[_MNVo.$_Cn(319)][o[1+a]](r):e[_MNVo.$_Cn(319)][o[s]](r);for(var u=Math[_MNVo.$_Cn(295)](n[c][_MNVo.$_Cn(6)]()-70)[_MNVo.$_Cn(41)]()[0],l=0;l<Number(u);l++)i[_MNVo.$_Cn(1009)]();}return r[_MNVo.$_Cn(300)][_MNVo.$_Cn(161)](_MNVo.$_Cn(56))[_MNVo.$_Cn(82)](0,10);}(c,u,s),a[s]=u),h?[2,{\"\\u0064\\u0065\\u0062\\u0075\\u0067\\u0067\\u0065\\u0065\":a,\"\\u006c\\u006f\\u0063\\u0061\\u006c\\u005f\\u0069\\u0064\":r,\"\\u0067\\u0065\\u0065\\u005f\\u0074\\u006f\\u006b\\u0065\\u006e\":Gt[_MNVo.$_Cn(1033)](_MNVo.$_Cn(1087)+Tt(Dt[_MNVo.$_Cn(984)](a)))}]:[2,{\"\\u006c\\u006f\\u0063\\u0061\\u006c\\u005f\\u0069\\u0064\":r,\"\\u0067\\u0065\\u0065\\u005f\\u0074\\u006f\\u006b\\u0065\\u006e\":Gt[_MNVo.$_Cn(1033)](_MNVo.$_Cn(1087)+Tt(Dt[_MNVo.$_Cn(984)](a)))}];}var i,t;});});break;}}}function Zt(t){var $_BCDD=_MNVo.$_Dt()[4][18];for(;$_BCDD!==_MNVo.$_Dt()[8][16];){switch($_BCDD){case _MNVo.$_Dt()[12][18]:var n=this[_MNVo.$_Cn(1008)];$_BCDD=_MNVo.$_Dt()[12][17];break;case _MNVo.$_Dt()[12][17]:return this[_MNVo.$_Cn(23)](function(e){return n[_MNVo.$_Cn(1076)](t())[_MNVo.$_Cn(23)](function(){return e;});},function(e){return n[_MNVo.$_Cn(1076)](t())[_MNVo.$_Cn(23)](function(){return n[_MNVo.$_Cn(1065)](e);});});break;}}}function Jt(n){var $_BCEE=_MNVo.$_Dt()[0][18];for(;$_BCEE!==_MNVo.$_Dt()[4][17];){switch($_BCEE){case _MNVo.$_Dt()[0][18]:return new this(function(i,e){if(!n||_MNVo.$_Cn(443)==typeof n[_MNVo.$_Cn(59)])return e(new TypeError(typeof n+_MNVo.$_Cn(155)+n+_MNVo.$_Cn(1035)));var r=Array[_MNVo.$_Cn(72)][_MNVo.$_Cn(82)][_MNVo.$_Cn(92)](n);if(0===r[_MNVo.$_Cn(59)])return i([]);var o=r[_MNVo.$_Cn(59)];for(var t=0;t<r[_MNVo.$_Cn(59)];t++)!function a(t,e){if(e&&(_MNVo.$_Cn(21)==typeof e||_MNVo.$_Cn(61)==typeof e)){var n=e[_MNVo.$_Cn(23)];if(_MNVo.$_Cn(61)==typeof n)return void n[_MNVo.$_Cn(92)](e,function(e){a(t,e);},function(e){r[t]={\"\\u0073\\u0074\\u0061\\u0074\\u0075\\u0073\":_MNVo.$_Cn(1021),\"\\u0072\\u0065\\u0061\\u0073\\u006f\\u006e\":e},0==--o&&i(r);});}r[t]={\"\\u0073\\u0074\\u0061\\u0074\\u0075\\u0073\":_MNVo.$_Cn(1053),\"\\u0076\\u0061\\u006c\\u0075\\u0065\":e},0==--o&&i(r);}(t,r[t]);});break;}}}var Xt=setTimeout,Kt=_MNVo.$_Cn(443)!=typeof setImmediate?setImmediate:null;function $t(e){var $_BCFn=_MNVo.$_Dt()[8][18];for(;$_BCFn!==_MNVo.$_Dt()[4][17];){switch($_BCFn){case _MNVo.$_Dt()[4][18]:return Boolean(e&&_MNVo.$_Cn(443)!=typeof e[_MNVo.$_Cn(59)]);break;}}}function Yt(){var $_BCGP=_MNVo.$_Dt()[12][18];for(;$_BCGP!==_MNVo.$_Dt()[0][18];){switch($_BCGP){}}}function Qt(e){var $_BCHo=_MNVo.$_Dt()[12][18];for(;$_BCHo!==_MNVo.$_Dt()[12][16];){switch($_BCHo){case _MNVo.$_Dt()[4][18]:if(!(this instanceof Qt))throw new TypeError(_MNVo.$_Cn(1040));if(_MNVo.$_Cn(61)!=typeof e)throw new TypeError(_MNVo.$_Cn(1069));$_BCHo=_MNVo.$_Dt()[4][17];break;case _MNVo.$_Dt()[12][17]:this[_MNVo.$_Cn(1029)]=0,this[_MNVo.$_Cn(1094)]=!1,this[_MNVo.$_Cn(1032)]=undefined,this[_MNVo.$_Cn(1079)]=[],an(e,this);$_BCHo=_MNVo.$_Dt()[0][16];break;}}}function en(i,r){var $_BCId=_MNVo.$_Dt()[8][18];for(;$_BCId!==_MNVo.$_Dt()[4][17];){switch($_BCId){case _MNVo.$_Dt()[4][18]:while(3===i[_MNVo.$_Cn(1029)])i=i[_MNVo.$_Cn(1032)];0!==i[_MNVo.$_Cn(1029)]?(i[_MNVo.$_Cn(1094)]=!0,Qt[_MNVo.$_Cn(1072)](function(){var e,t=1===i[_MNVo.$_Cn(1029)]?r[_MNVo.$_Cn(1037)]:r[_MNVo.$_Cn(1014)];if(null!==t){try{e=t(i[_MNVo.$_Cn(1032)]);}catch(n){return void nn(r[_MNVo.$_Cn(1086)],n);}tn(r[_MNVo.$_Cn(1086)],e);}else(1===i[_MNVo.$_Cn(1029)]?tn:nn)(r[_MNVo.$_Cn(1086)],i[_MNVo.$_Cn(1032)]);})):i[_MNVo.$_Cn(1079)][_MNVo.$_Cn(50)](r);$_BCId=_MNVo.$_Dt()[12][17];break;}}}function tn(e,t){var $_BCJS=_MNVo.$_Dt()[8][18];for(;$_BCJS!==_MNVo.$_Dt()[0][16];){switch($_BCJS){case _MNVo.$_Dt()[12][18]:try{if(t===e)throw new TypeError(_MNVo.$_Cn(1025));if(t&&(_MNVo.$_Cn(21)==typeof t||_MNVo.$_Cn(61)==typeof t)){var n=t[_MNVo.$_Cn(23)];if(t instanceof Qt)return e[_MNVo.$_Cn(1029)]=3,e[_MNVo.$_Cn(1032)]=t,void rn(e);if(_MNVo.$_Cn(61)==typeof n)return void an((i=n,r=t,function(){i[_MNVo.$_Cn(12)](r,arguments);}),e);}e[_MNVo.$_Cn(1029)]=1,e[_MNVo.$_Cn(1032)]=t,rn(e);}catch(o){nn(e,o);}$_BCJS=_MNVo.$_Dt()[8][17];break;case _MNVo.$_Dt()[12][17]:var i,r;$_BCJS=_MNVo.$_Dt()[8][16];break;}}}function nn(e,t){var $_BDAT=_MNVo.$_Dt()[4][18];for(;$_BDAT!==_MNVo.$_Dt()[12][17];){switch($_BDAT){case _MNVo.$_Dt()[12][18]:e[_MNVo.$_Cn(1029)]=2,e[_MNVo.$_Cn(1032)]=t,rn(e);$_BDAT=_MNVo.$_Dt()[12][17];break;}}}function rn(e){var $_BDBx=_MNVo.$_Dt()[0][18];for(;$_BDBx!==_MNVo.$_Dt()[8][15];){switch($_BDBx){case _MNVo.$_Dt()[4][18]:2===e[_MNVo.$_Cn(1029)]&&0===e[_MNVo.$_Cn(1079)][_MNVo.$_Cn(59)]&&Qt[_MNVo.$_Cn(1072)](function(){e[_MNVo.$_Cn(1094)]||Qt[_MNVo.$_Cn(1010)](e[_MNVo.$_Cn(1032)]);});$_BDBx=_MNVo.$_Dt()[12][17];break;case _MNVo.$_Dt()[0][17]:for(var t=0,n=e[_MNVo.$_Cn(1079)][_MNVo.$_Cn(59)];t<n;t++)en(e,e[_MNVo.$_Cn(1079)][t]);$_BDBx=_MNVo.$_Dt()[8][16];break;case _MNVo.$_Dt()[0][16]:e[_MNVo.$_Cn(1079)]=null;$_BDBx=_MNVo.$_Dt()[0][15];break;}}}function on(e,t,n){var $_BDCc=_MNVo.$_Dt()[8][18];for(;$_BDCc!==_MNVo.$_Dt()[8][17];){switch($_BDCc){case _MNVo.$_Dt()[4][18]:this[_MNVo.$_Cn(1037)]=_MNVo.$_Cn(61)==typeof e?e:null,this[_MNVo.$_Cn(1014)]=_MNVo.$_Cn(61)==typeof t?t:null,this[_MNVo.$_Cn(1086)]=n;$_BDCc=_MNVo.$_Dt()[4][17];break;}}}function an(e,t){var $_BDDr=_MNVo.$_Dt()[4][18];for(;$_BDDr!==_MNVo.$_Dt()[4][16];){switch($_BDDr){case _MNVo.$_Dt()[8][18]:var n=!1;$_BDDr=_MNVo.$_Dt()[8][17];break;case _MNVo.$_Dt()[12][17]:try{e(function(e){n||(n=!0,tn(t,e));},function(e){n||(n=!0,nn(t,e));});}catch(i){if(n)return;n=!0,nn(t,i);}$_BDDr=_MNVo.$_Dt()[12][16];break;}}}Qt[_MNVo.$_Cn(72)][_MNVo.$_Cn(253)]=function(e){return this[_MNVo.$_Cn(23)](null,e);},Qt[_MNVo.$_Cn(72)][_MNVo.$_Cn(23)]=function(e,t){var n=new this[(_MNVo.$_Cn(1008))](Yt);return en(this,new on(e,t,n)),n;},Qt[_MNVo.$_Cn(72)][_MNVo.$_Cn(1061)]=Zt,Qt[_MNVo.$_Cn(83)]=function(t){return new Qt(function(r,o){if(!$t(t))return o(new TypeError(_MNVo.$_Cn(1036)));var a=Array[_MNVo.$_Cn(72)][_MNVo.$_Cn(82)][_MNVo.$_Cn(92)](t);if(0===a[_MNVo.$_Cn(59)])return r([]);var c=a[_MNVo.$_Cn(59)];function s(t,e){var $_BDEt=_MNVo.$_Dt()[0][18];for(;$_BDEt!==_MNVo.$_Dt()[12][17];){switch($_BDEt){case _MNVo.$_Dt()[12][18]:try{if(e&&(_MNVo.$_Cn(21)==typeof e||_MNVo.$_Cn(61)==typeof e)){var n=e[_MNVo.$_Cn(23)];if(_MNVo.$_Cn(61)==typeof n)return void n[_MNVo.$_Cn(92)](e,function(e){s(t,e);},o);}a[t]=e,0==--c&&r(a);}catch(i){o(i);}$_BDEt=_MNVo.$_Dt()[12][17];break;}}}for(var e=0;e<a[_MNVo.$_Cn(59)];e++)s(e,a[e]);});},Qt[_MNVo.$_Cn(1099)]=Jt,Qt[_MNVo.$_Cn(1076)]=function(t){return t&&_MNVo.$_Cn(21)==typeof t&&t[_MNVo.$_Cn(1008)]===Qt?t:new Qt(function(e){e(t);});},Qt[_MNVo.$_Cn(1065)]=function(n){return new Qt(function(e,t){t(n);});},Qt[_MNVo.$_Cn(1089)]=function(r){return new Qt(function(e,t){if(!$t(r))return t(new TypeError(_MNVo.$_Cn(1052)));for(var n=0,i=r[_MNVo.$_Cn(59)];n<i;n++)Qt[_MNVo.$_Cn(1076)](r[n])[_MNVo.$_Cn(23)](e,t);});},Qt[_MNVo.$_Cn(1072)]=_MNVo.$_Cn(61)==typeof Kt?function(e){Kt(e);}:function(e){Xt(e,0);},Qt[_MNVo.$_Cn(1010)]=function(e){_MNVo.$_Cn(443)!=typeof console&&console&&console[_MNVo.$_Cn(821)](_MNVo.$_Cn(1080),e);};Ze=function(){if(_MNVo.$_Cn(443)!=typeof self)return self;if(_MNVo.$_Cn(443)!=typeof window)return window;if(_MNVo.$_Cn(443)!=typeof global)return global;throw new Error(_MNVo.$_Cn(1038));}();_MNVo.$_Cn(61)!=typeof Ze[_MNVo.$_Cn(1027)]?Ze[_MNVo.$_Cn(1027)]=Qt:(Ze[_MNVo.$_Cn(1027)][_MNVo.$_Cn(72)][_MNVo.$_Cn(1061)]||(Ze[_MNVo.$_Cn(1027)][_MNVo.$_Cn(72)][_MNVo.$_Cn(1061)]=Zt),Ze[_MNVo.$_Cn(1027)][_MNVo.$_Cn(1099)]||(Ze[_MNVo.$_Cn(1027)][_MNVo.$_Cn(1099)]=Jt));Ze={\"\\u006c\\u006f\\u0061\\u0064\":cn};function cn(e){var $_BDFq=_MNVo.$_Dt()[4][18];for(;$_BDFq!==_MNVo.$_Dt()[12][17];){switch($_BDFq){case _MNVo.$_Dt()[0][18]:return _MNVo.$_Cn(1059)===e[_MNVo.$_Cn(297)]?Wt(e):new Promise(function(e){e({\"\\u006d\\u0073\\u0067\":_MNVo.$_Cn(1070)});});break;}}}return window[_MNVo.$_Cn(1074)](_MNVo.$_Cn(1097),function(e){console[_MNVo.$_Cn(387)](_MNVo.$_Cn(1023),e);}),e[_MNVo.$_Cn(1051)]=Ze,e[_MNVo.$_Cn(1011)]=cn,Object[_MNVo.$_Cn(1048)](e,_MNVo.$_Cn(1092),{\"\\u0076\\u0061\\u006c\\u0075\\u0065\":!0}),e;}({});window[_MNVo.$_Cn(1039)]=GeeGuard;}();"
  },
  {
    "path": "src/app/bots/xunfei/index.ts",
    "content": "import { requestHostPermission } from '~app/utils/permissions'\nimport { Base64 } from 'js-base64'\nimport { AbstractBot, SendMessageParams } from '../abstract-bot'\nimport { createConversation, getGeeToken } from './api'\nimport { ChatError, ErrorCode } from '~utils/errors'\nimport { parseSSEResponse } from '~utils/sse'\n\ninterface ConversationContext {\n  geeToken: string\n  chatId: number\n}\n\nfunction generateFD() {\n  const ms = String(+new Date())\n  return ms.substring(ms.length - 6)\n}\n\nexport class XunfeiBot extends AbstractBot {\n  private conversationContext?: ConversationContext\n\n  async doSendMessage(params: SendMessageParams) {\n    if (!(await requestHostPermission('https://*.xfyun.cn/'))) {\n      throw new ChatError('Missing xfyun.cn permission', ErrorCode.MISSING_HOST_PERMISSION)\n    }\n\n    if (!this.conversationContext) {\n      const [geeToken, { chatId }] = await Promise.all([getGeeToken(), createConversation()])\n      this.conversationContext = { geeToken, chatId }\n    }\n\n    const form = new FormData()\n    form.append('chatId', this.conversationContext.chatId.toString())\n    form.append('text', params.prompt)\n    form.append('clientType', '1')\n    form.append('GtToken', this.conversationContext.geeToken)\n    form.append('fd', generateFD())\n    form.append('isBot', '0')\n\n    const resp = await fetch('https://xinghuo.xfyun.cn/iflygpt-chat/u/chat_message/chat', {\n      method: 'POST',\n      signal: params.signal,\n      body: form,\n    })\n\n    let answer = ''\n    let done = false\n\n    await parseSSEResponse(resp, (message) => {\n      console.debug('xunfei sse', message)\n      if (message === '<end>') {\n        done = true\n        params.onEvent({ type: 'DONE' })\n      } else if (message === '<kx>') {\n        throw new ChatError('讯飞无法继续这个话题，请重启会话', ErrorCode.CONVERSATION_LIMIT)\n      } else if (/\\[.*\\]/.test(message)) {\n        return\n      } else if (message.includes('descr')) {\n        const payload = JSON.parse(message)\n        throw new Error(payload.descr)\n      } else if (!done) {\n        let decoded: string\n        try {\n          decoded = Base64.decode(message)\n        } catch (err) {\n          throw new ChatError('讯飞无法回答该问题', ErrorCode.CONVERSATION_LIMIT)\n        }\n        answer += decoded\n        params.onEvent({ type: 'UPDATE_ANSWER', data: { text: answer } })\n      }\n    })\n  }\n\n  resetConversation() {\n    this.conversationContext = undefined\n  }\n\n  get name() {\n    return '讯飞星火'\n  }\n}\n"
  },
  {
    "path": "src/app/components/Button.tsx",
    "content": "import { cx } from '~/utils'\nimport { ButtonHTMLAttributes, FC, ReactNode } from 'react'\nimport { BeatLoader } from 'react-spinners'\nimport React from 'react'\nimport { motion } from 'framer-motion'\n\nexport interface Props {\n  text: string\n  className?: string\n  color?: 'primary' | 'flat'\n  type?: ButtonHTMLAttributes<HTMLButtonElement>['type']\n  onClick?: () => void\n  isLoading?: boolean\n  size?: 'small' | 'normal' | 'tiny'\n  icon?: ReactNode\n}\n\nconst Button = React.forwardRef<HTMLButtonElement, Props>((props, ref) => {\n  const size = props.size || 'normal'\n  const type = props.type || 'button'\n  return (\n    <button\n      ref={ref}\n      type={type}\n      className={cx(\n        size === 'normal' && 'text-base font-medium px-6 py-[5px] rounded-full',\n        size === 'small' && 'text-sm px-4 py-1 rounded-xl',\n        size === 'tiny' && 'text-xs px-3 py-[3px] rounded-lg',\n        props.color === 'primary' ? 'text-white bg-primary-blue' : 'text-primary-text bg-secondary',\n        props.className,\n      )}\n      onClick={props.onClick}\n    >\n      {props.isLoading ? (\n        <BeatLoader size={size === 'normal' ? 10 : 5} color={props.color === 'primary' ? 'white' : '#303030'} />\n      ) : (\n        <div className=\"flex flex-row items-center gap-1 min-w-max\">\n          {props.icon}\n          <span>{props.text}</span>\n        </div>\n      )}\n    </button>\n  )\n})\n\nButton.displayName = 'Button'\n\nexport default Button\n\nexport const MotionButton = motion(Button)\n"
  },
  {
    "path": "src/app/components/Chat/ChatMessageCard.tsx",
    "content": "import { cx } from '~/utils'\nimport { FC, memo, useEffect, useMemo, useState } from 'react'\nimport { CopyToClipboard } from 'react-copy-to-clipboard'\nimport { IoCheckmarkSharp, IoCopyOutline } from 'react-icons/io5'\nimport { BeatLoader } from 'react-spinners'\nimport { ChatMessageModel } from '~/types'\nimport Markdown from '../Markdown'\nimport ErrorAction from './ErrorAction'\nimport MessageBubble from './MessageBubble'\n\nconst COPY_ICON_CLASS = 'self-top cursor-pointer invisible group-hover:visible mt-[12px] text-primary-text'\n\ninterface Props {\n  message: ChatMessageModel\n  className?: string\n}\n\nconst ChatMessageCard: FC<Props> = ({ message, className }) => {\n  const [copied, setCopied] = useState(false)\n\n  const imageUrl = useMemo(() => {\n    return message.image ? URL.createObjectURL(message.image) : ''\n  }, [message.image])\n\n  const copyText = useMemo(() => {\n    if (message.text) {\n      return message.text\n    }\n    if (message.error) {\n      return message.error.message\n    }\n  }, [message.error, message.text])\n\n  useEffect(() => {\n    if (copied) {\n      setTimeout(() => setCopied(false), 1000)\n    }\n  }, [copied])\n\n  return (\n    <div\n      className={cx('group flex gap-3 w-full', message.author === 'user' ? 'flex-row-reverse' : 'flex-row', className)}\n    >\n      <div className=\"flex flex-col w-11/12  max-w-fit items-start gap-2\">\n        <MessageBubble color={message.author === 'user' ? 'primary' : 'flat'}>\n          {!!imageUrl && <img src={imageUrl} className=\"max-w-xs my-2\" />}\n          {message.text ? (\n            <Markdown>{message.text}</Markdown>\n          ) : (\n            !message.error && <BeatLoader size={10} className=\"leading-tight\" color=\"rgb(var(--primary-text))\" />\n          )}\n          {!!message.error && <p className=\"text-[#cc0000] dark:text-[#ff0033]\">{message.error.message}</p>}\n        </MessageBubble>\n        {!!message.error && <ErrorAction error={message.error} />}\n      </div>\n      {!!copyText && (\n        <CopyToClipboard text={copyText} onCopy={() => setCopied(true)}>\n          {copied ? <IoCheckmarkSharp className={COPY_ICON_CLASS} /> : <IoCopyOutline className={COPY_ICON_CLASS} />}\n        </CopyToClipboard>\n      )}\n    </div>\n  )\n}\n\nexport default memo(ChatMessageCard)\n"
  },
  {
    "path": "src/app/components/Chat/ChatMessageInput.tsx",
    "content": "import {\n  FloatingFocusManager,\n  FloatingList,\n  autoUpdate,\n  flip,\n  offset,\n  shift,\n  useDismiss,\n  useFloating,\n  useInteractions,\n  useListNavigation,\n  useRole,\n} from '@floating-ui/react'\nimport { fileOpen } from 'browser-fs-access'\nimport { cx } from '~/utils'\nimport { ClipboardEventHandler, FC, ReactNode, memo, useCallback, useMemo, useRef, useState } from 'react'\nimport { useTranslation } from 'react-i18next'\nimport { GoBook, GoImage } from 'react-icons/go'\nimport { RiDeleteBackLine } from 'react-icons/ri'\nimport { trackEvent } from '~app/plausible'\nimport { Prompt } from '~services/prompts'\nimport Button from '../Button'\nimport PromptCombobox, { ComboboxContext } from '../PromptCombobox'\nimport PromptLibraryDialog from '../PromptLibrary/Dialog'\nimport TextInput from './TextInput'\n\ninterface Props {\n  mode: 'full' | 'compact'\n  onSubmit: (value: string, image?: File) => void\n  className?: string\n  disabled?: boolean\n  placeholder?: string\n  actionButton?: ReactNode | null\n  autoFocus?: boolean\n  supportImageInput?: boolean\n}\n\nconst ChatMessageInput: FC<Props> = (props) => {\n  const { t } = useTranslation()\n  const { placeholder = t('Use / to select prompts, Shift+Enter to add new line') } = props\n\n  const [value, setValue] = useState('')\n  const [image, setImage] = useState<File | undefined>(undefined)\n  const formRef = useRef<HTMLFormElement>(null)\n  const inputRef = useRef<HTMLTextAreaElement>(null)\n  const [isPromptLibraryDialogOpen, setIsPromptLibraryDialogOpen] = useState(false)\n\n  const [activeIndex, setActiveIndex] = useState<number | null>(null)\n  const [isComboboxOpen, setIsComboboxOpen] = useState(false)\n\n  const { refs, floatingStyles, context } = useFloating({\n    whileElementsMounted: autoUpdate,\n    middleware: [offset(15), flip(), shift()],\n    placement: 'top-start',\n    open: isComboboxOpen,\n    onOpenChange: setIsComboboxOpen,\n  })\n\n  const floatingListRef = useRef([])\n\n  const handleSelect = useCallback((p: Prompt) => {\n    if (p.id === 'PROMPT_LIBRARY') {\n      setIsPromptLibraryDialogOpen(true)\n      setIsComboboxOpen(false)\n      trackEvent('open_prompt_library', { source: 'combobox' })\n    } else {\n      setValue(p.prompt)\n      setIsComboboxOpen(false)\n      inputRef.current?.focus()\n      trackEvent('use_prompt', { source: 'combobox' })\n    }\n  }, [])\n\n  const listNavigation = useListNavigation(context, {\n    listRef: floatingListRef,\n    activeIndex,\n    onNavigate: setActiveIndex,\n    loop: true,\n    focusItemOnOpen: true,\n    openOnArrowKeyDown: false,\n  })\n\n  const dismiss = useDismiss(context)\n  const role = useRole(context, { role: 'listbox' })\n\n  const { getReferenceProps, getFloatingProps, getItemProps } = useInteractions([role, dismiss, listNavigation])\n\n  const comboboxContext = useMemo(\n    () => ({\n      activeIndex,\n      getItemProps,\n      handleSelect,\n      setIsComboboxOpen: (open: boolean) => {\n        setIsComboboxOpen(open)\n        if (open) {\n          trackEvent('open_prompt_combobox')\n        } else {\n          inputRef.current?.focus()\n        }\n      },\n    }),\n    [activeIndex, getItemProps, handleSelect],\n  )\n\n  const onFormSubmit = useCallback(\n    (e: React.FormEvent<HTMLFormElement>) => {\n      e.preventDefault()\n      if (value.trim()) {\n        props.onSubmit(value, image)\n      }\n      setValue('')\n      setImage(undefined)\n    },\n    [image, props, value],\n  )\n\n  const onValueChange = useCallback((v: string) => {\n    setValue(v)\n    setIsComboboxOpen(v === '/')\n  }, [])\n\n  const insertTextAtCursor = useCallback(\n    (text: string) => {\n      const cursorPosition = inputRef.current?.selectionStart || 0\n      const textBeforeCursor = value.slice(0, cursorPosition)\n      const textAfterCursor = value.slice(cursorPosition)\n      setValue(`${textBeforeCursor}${text}${textAfterCursor}`)\n      setIsPromptLibraryDialogOpen(false)\n      inputRef.current?.focus()\n    },\n    [value],\n  )\n\n  const openPromptLibrary = useCallback(() => {\n    setIsPromptLibraryDialogOpen(true)\n    trackEvent('open_prompt_library')\n  }, [])\n\n  const selectImage = useCallback(async () => {\n    const file = await fileOpen({\n      mimeTypes: ['image/jpg', 'image/jpeg', 'image/png', 'image/gif'],\n      extensions: ['.jpg', '.jpeg', '.png', '.gif'],\n    })\n    setImage(file)\n    inputRef.current?.focus()\n  }, [])\n\n  const onPaste: ClipboardEventHandler<HTMLTextAreaElement> = useCallback((event) => {\n    const files = event.clipboardData.files\n    if (!files.length) {\n      return\n    }\n    const imageFile = Array.from(files).find((file) => file.type.startsWith('image/'))\n    if (imageFile) {\n      event.preventDefault()\n      setImage(imageFile)\n      inputRef.current?.focus()\n    }\n  }, [])\n\n  return (\n    <form className={cx('flex flex-row items-center gap-3', props.className)} onSubmit={onFormSubmit} ref={formRef}>\n      {props.mode === 'full' && (\n        <>\n          <GoBook\n            size={22}\n            color=\"#707070\"\n            className=\"cursor-pointer\"\n            onClick={openPromptLibrary}\n            title=\"Prompt library\"\n          />\n          {isPromptLibraryDialogOpen && (\n            <PromptLibraryDialog\n              isOpen={true}\n              onClose={() => setIsPromptLibraryDialogOpen(false)}\n              insertPrompt={insertTextAtCursor}\n            />\n          )}\n          <ComboboxContext.Provider value={comboboxContext}>\n            {isComboboxOpen && (\n              <FloatingFocusManager context={context} modal={false} initialFocus={-1}>\n                <div ref={refs.setFloating} style={{ ...floatingStyles }} {...getFloatingProps()}>\n                  <FloatingList elementsRef={floatingListRef}>\n                    <PromptCombobox />\n                  </FloatingList>\n                </div>\n              </FloatingFocusManager>\n            )}\n          </ComboboxContext.Provider>\n          {props.supportImageInput && (\n            <GoImage size={22} color=\"#707070\" className=\"cursor-pointer\" onClick={selectImage} title=\"Image input\" />\n          )}\n        </>\n      )}\n      <div className=\"w-full flex flex-col justify-center\" ref={refs.setReference} {...getReferenceProps()}>\n        {image && (\n          <div className=\"flex flex-row items-center w-fit mb-1 gap-1\">\n            <span className=\"text-xs text-primary-text font-semibold cursor-default\">{image.name}</span>\n            <RiDeleteBackLine size={10} className=\"cursor-pointer\" onClick={() => setImage(undefined)} />\n          </div>\n        )}\n        <TextInput\n          ref={inputRef}\n          formref={formRef}\n          name=\"input\"\n          disabled={props.disabled}\n          placeholder={placeholder as string}\n          value={value}\n          onValueChange={onValueChange}\n          autoFocus={props.autoFocus}\n          onPaste={props.supportImageInput ? onPaste : undefined}\n        />\n      </div>\n      {props.actionButton || <Button text=\"-\" className=\"invisible\" size={props.mode === 'full' ? 'normal' : 'tiny'} />}\n    </form>\n  )\n}\n\nexport default memo(ChatMessageInput)\n"
  },
  {
    "path": "src/app/components/Chat/ChatMessageList.tsx",
    "content": "import { FC } from 'react'\nimport { cx } from '~/utils'\nimport ScrollToBottom from 'react-scroll-to-bottom'\nimport { BotId } from '~app/bots'\nimport { ChatMessageModel } from '~types'\nimport ChatMessageCard from './ChatMessageCard'\n\ninterface Props {\n  botId: BotId\n  messages: ChatMessageModel[]\n  className?: string\n}\n\nconst ChatMessageList: FC<Props> = (props) => {\n  return (\n    <ScrollToBottom className=\"overflow-auto h-full\">\n      <div className={cx('flex flex-col gap-3 h-full', props.className)}>\n        {props.messages.map((message, index) => {\n          return <ChatMessageCard key={message.id} message={message} className={index === 0 ? 'mt-5' : undefined} />\n        })}\n      </div>\n    </ScrollToBottom>\n  )\n}\n\nexport default ChatMessageList\n"
  },
  {
    "path": "src/app/components/Chat/ChatbotName.tsx",
    "content": "import { FC, memo } from 'react'\nimport dropdownIcon from '~/assets/icons/dropdown.svg'\nimport { BotId } from '~app/bots'\nimport SwitchBotDropdown from '../SwitchBotDropdown'\nimport Tooltip from '../Tooltip'\n\ninterface Props {\n  botId: BotId\n  name: string\n  fullName?: string\n  onSwitchBot?: (botId: BotId) => void\n}\n\nconst ChatbotName: FC<Props> = (props) => {\n  const node = (\n    <Tooltip content={props.fullName || props.name}>\n      <span className=\"font-semibold text-primary-text text-sm cursor-pointer\">{props.name}</span>\n    </Tooltip>\n  )\n  if (!props.onSwitchBot) {\n    return node\n  }\n  const triggerNode = (\n    <div className=\"flex flex-row items-center gap-[2px]\">\n      {node}\n      <img src={dropdownIcon} className=\"w-5 h-5\" />\n    </div>\n  )\n  return <SwitchBotDropdown selectedBotId={props.botId} onChange={props.onSwitchBot} triggerNode={triggerNode} />\n}\n\nexport default memo(ChatbotName)\n"
  },
  {
    "path": "src/app/components/Chat/ConversationPanel.tsx",
    "content": "import { motion } from 'framer-motion'\nimport { FC, ReactNode, useCallback, useMemo, useState } from 'react'\nimport { useTranslation } from 'react-i18next'\nimport clearIcon from '~/assets/icons/clear.svg'\nimport historyIcon from '~/assets/icons/history.svg'\nimport shareIcon from '~/assets/icons/share.svg'\nimport { cx } from '~/utils'\nimport { CHATBOTS } from '~app/consts'\nimport { ConversationContext, ConversationContextValue } from '~app/context'\nimport { trackEvent } from '~app/plausible'\nimport { ChatMessageModel } from '~types'\nimport { BotId, BotInstance } from '../../bots'\nimport Button from '../Button'\nimport HistoryDialog from '../History/Dialog'\nimport ShareDialog from '../Share/Dialog'\nimport Tooltip from '../Tooltip'\nimport ChatMessageInput from './ChatMessageInput'\nimport ChatMessageList from './ChatMessageList'\nimport ChatbotName from './ChatbotName'\nimport WebAccessCheckbox from './WebAccessCheckbox'\n\ninterface Props {\n  botId: BotId\n  bot: BotInstance\n  messages: ChatMessageModel[]\n  onUserSendMessage: (input: string, image?: File) => void\n  resetConversation: () => void\n  generating: boolean\n  stopGenerating: () => void\n  mode?: 'full' | 'compact'\n  onSwitchBot?: (botId: BotId) => void\n}\n\nconst ConversationPanel: FC<Props> = (props) => {\n  const { t } = useTranslation()\n  const botInfo = CHATBOTS[props.botId]\n  const mode = props.mode || 'full'\n  const marginClass = 'mx-5'\n  const [showHistory, setShowHistory] = useState(false)\n  const [showShareDialog, setShowShareDialog] = useState(false)\n\n  const context: ConversationContextValue = useMemo(() => {\n    return {\n      reset: props.resetConversation,\n    }\n  }, [props.resetConversation])\n\n  const onSubmit = useCallback(\n    async (input: string, image?: File) => {\n      props.onUserSendMessage(input as string, image)\n    },\n    [props],\n  )\n\n  const resetConversation = useCallback(() => {\n    if (!props.generating) {\n      props.resetConversation()\n    }\n  }, [props])\n\n  const openHistoryDialog = useCallback(() => {\n    setShowHistory(true)\n    trackEvent('open_history_dialog', { botId: props.botId })\n  }, [props.botId])\n\n  const openShareDialog = useCallback(() => {\n    setShowShareDialog(true)\n    trackEvent('open_share_dialog', { botId: props.botId })\n  }, [props.botId])\n\n  let inputActionButton: ReactNode = null\n  if (props.generating) {\n    inputActionButton = (\n      <Button text={t('Stop')} color=\"flat\" size={mode === 'full' ? 'normal' : 'tiny'} onClick={props.stopGenerating} />\n    )\n  } else if (mode === 'full') {\n    inputActionButton = (\n      <div className=\"flex flex-row items-center gap-[10px] shrink-0\">\n        <Button text={t('Send')} color=\"primary\" type=\"submit\" />\n      </div>\n    )\n  }\n\n  return (\n    <ConversationContext.Provider value={context}>\n      <div className={cx('flex flex-col overflow-hidden bg-primary-background h-full rounded-2xl')}>\n        <div\n          className={cx(\n            'border-b border-solid border-primary-border flex flex-row items-center justify-between gap-2 py-[10px]',\n            marginClass,\n          )}\n        >\n          <div className=\"flex flex-row items-center\">\n            <motion.img\n              src={botInfo.avatar}\n              className=\"w-[18px] h-[18px] object-contain rounded-sm mr-2\"\n              whileHover={{ rotate: 180 }}\n            />\n            <ChatbotName\n              botId={props.botId}\n              name={botInfo.name}\n              fullName={props.bot.name}\n              onSwitchBot={mode === 'compact' ? props.onSwitchBot : undefined}\n            />\n          </div>\n          <WebAccessCheckbox botId={props.botId} />\n          <div className=\"flex flex-row items-center gap-3\">\n            <Tooltip content={t('Share conversation')}>\n              <motion.img\n                src={shareIcon}\n                className=\"w-5 h-5 cursor-pointer\"\n                onClick={openShareDialog}\n                whileHover={{ scale: 1.1 }}\n              />\n            </Tooltip>\n            <Tooltip content={t('Clear conversation')}>\n              <motion.img\n                src={clearIcon}\n                className={cx('w-5 h-5', props.generating ? 'cursor-not-allowed' : 'cursor-pointer')}\n                onClick={resetConversation}\n                whileHover={{ scale: 1.1 }}\n              />\n            </Tooltip>\n            <Tooltip content={t('View history')}>\n              <motion.img\n                src={historyIcon}\n                className=\"w-5 h-5 cursor-pointer\"\n                onClick={openHistoryDialog}\n                whileHover={{ scale: 1.1 }}\n              />\n            </Tooltip>\n          </div>\n        </div>\n        <ChatMessageList botId={props.botId} messages={props.messages} className={marginClass} />\n        <div className={cx('mt-3 flex flex-col ', marginClass, mode === 'full' ? 'mb-3' : 'mb-[5px]')}>\n          <div className={cx('flex flex-row items-center gap-[5px]', mode === 'full' ? 'mb-3' : 'mb-0')}>\n            {mode === 'compact' && (\n              <span className=\"font-medium text-xs text-light-text cursor-default\">Send to {botInfo.name}</span>\n            )}\n            <hr className=\"grow border-primary-border\" />\n          </div>\n          <ChatMessageInput\n            mode={mode}\n            disabled={props.generating}\n            placeholder={mode === 'compact' ? '' : undefined}\n            onSubmit={onSubmit}\n            autoFocus={mode === 'full'}\n            supportImageInput={mode === 'full' && props.bot.supportsImageInput}\n            actionButton={inputActionButton}\n          />\n        </div>\n      </div>\n      {showShareDialog && (\n        <ShareDialog open={true} onClose={() => setShowShareDialog(false)} messages={props.messages} />\n      )}\n      {showHistory && <HistoryDialog botId={props.botId} open={true} onClose={() => setShowHistory(false)} />}\n    </ConversationContext.Provider>\n  )\n}\n\nexport default ConversationPanel\n"
  },
  {
    "path": "src/app/components/Chat/ErrorAction.tsx",
    "content": "import { FC, useCallback, useContext, useMemo, useState } from 'react'\nimport { useTranslation } from 'react-i18next'\nimport Browser from 'webextension-polyfill'\nimport { chatGPTClient } from '~app/bots/chatgpt-webapp/client'\nimport { ConversationContext } from '~app/context'\nimport { ChatError, ErrorCode } from '~utils/errors'\nimport Button, { Props as ButtonProps } from '../Button'\nimport MessageBubble from './MessageBubble'\n\nconst ActionButton: FC<ButtonProps> = (props) => {\n  return <Button {...props} size=\"small\" className=\"font-medium underline\" color=\"primary\" />\n}\n\nconst ChatGPTAuthErrorAction = () => {\n  const { t } = useTranslation()\n  const [fixing, setFixing] = useState(false)\n  const [fixed, setFixed] = useState(false)\n  const isSidePanel = useMemo(() => location.href.includes('sidepanel.html'), [])\n\n  const fixChatGPT = useCallback(async () => {\n    setFixing(true)\n    try {\n      await chatGPTClient.fixAuthState()\n    } catch (e) {\n      console.error(e)\n      return\n    } finally {\n      setFixing(false)\n    }\n    setFixed(true)\n  }, [])\n\n  if (fixed) {\n    return <MessageBubble color=\"flat\">Fixed, please retry chat</MessageBubble>\n  }\n\n  return (\n    <div className=\"flex flex-row gap-2 items-center\">\n      <ActionButton text={t('Login to ChatGPT')} onClick={fixChatGPT} isLoading={fixing} />\n      <span className=\"text-sm text-primary-text\">OR</span>\n      <a\n        href={Browser.runtime.getURL('app.html#/setting')}\n        target={isSidePanel ? '_blank' : undefined}\n        rel=\"noreferrer\"\n      >\n        <ActionButton text={t('Switch to API mode')} />\n      </a>\n    </div>\n  )\n}\n\nconst ErrorAction: FC<{ error: ChatError }> = ({ error }) => {\n  const conversation = useContext(ConversationContext)\n  const { t } = useTranslation()\n\n  if (error.code === ErrorCode.BING_UNAUTHORIZED) {\n    return (\n      <a href=\"https://bing.com\" target=\"_blank\" rel=\"noreferrer\">\n        <ActionButton text={t('Login at bing.com')} />\n      </a>\n    )\n  }\n  if (error.code === ErrorCode.POE_UNAUTHORIZED) {\n    return (\n      <a href=\"https://poe.com\" target=\"_blank\" rel=\"noreferrer\">\n        <ActionButton text={t('Login at poe.com')} />\n      </a>\n    )\n  }\n  if (error.code === ErrorCode.XUNFEI_UNAUTHORIZED) {\n    return (\n      <a href=\"https://xinghuo.xfyun.cn\" target=\"_blank\" rel=\"noreferrer\">\n        <ActionButton text={t('Login at xfyun.cn')} />\n      </a>\n    )\n  }\n  if (error.code === ErrorCode.QIANWEN_WEB_UNAUTHORIZED) {\n    return (\n      <a href=\"https://qianwen.aliyun.com\" target=\"_blank\" rel=\"noreferrer\">\n        <ActionButton text={t('Login at qianwen.aliyun.com')} />\n      </a>\n    )\n  }\n  if (error.code === ErrorCode.BAICHUAN_WEB_UNAUTHORIZED) {\n    return (\n      <a href=\"https://www.baichuan-ai.com\" target=\"_blank\" rel=\"noreferrer\">\n        <ActionButton text={t('Login at baichuan-ai.com')} />\n      </a>\n    )\n  }\n  if (error.code === ErrorCode.GPT4_MODEL_WAITLIST) {\n    return (\n      <a href=\"https://openai.com/waitlist/gpt-4-api\" target=\"_blank\" rel=\"noreferrer\">\n        <ActionButton text={t('Join the waitlist')} />\n      </a>\n    )\n  }\n  if (error.code === ErrorCode.CHATGPT_AUTH) {\n    return (\n      <a href=\"https://chat.openai.com\" target=\"_blank\" rel=\"noreferrer\">\n        <ActionButton text={t('Login to ChatGPT')} />\n      </a>\n    )\n  }\n  if (error.code === ErrorCode.CLAUDE_WEB_UNAUTHORIZED) {\n    return (\n      <a href=\"https://claude.ai\" target=\"_blank\" rel=\"noreferrer\">\n        <ActionButton text={t('Login to Claude.ai')} />\n      </a>\n    )\n  }\n  if (error.code === ErrorCode.BARD_UNAUTHORIZED) {\n    return (\n      <a href=\"https://bard.google.com\" target=\"_blank\" rel=\"noreferrer\">\n        <ActionButton text={t('Login to Bard')} />\n      </a>\n    )\n  }\n  if (error.code === ErrorCode.TWITTER_UNAUTHORIZED) {\n    return (\n      <a href=\"https://twitter.com\" target=\"_blank\" rel=\"noreferrer\">\n        <ActionButton text={t('Login to Twitter')} />\n      </a>\n    )\n  }\n  if (error.code === ErrorCode.CHATGPT_CLOUDFLARE || error.code === ErrorCode.CHATGPT_UNAUTHORIZED) {\n    return <ChatGPTAuthErrorAction />\n  }\n  if (error.code === ErrorCode.CONVERSATION_LIMIT || error.code === ErrorCode.LMSYS_SESSION_EXPIRED) {\n    return <ActionButton text=\"Restart\" onClick={() => conversation?.reset()} />\n  }\n  if (error.code === ErrorCode.BARD_EMPTY_RESPONSE) {\n    return (\n      <a href=\"https://bard.google.com\" target=\"_blank\" rel=\"noreferrer\">\n        <ActionButton text=\"Visit bard.google.com\" />\n      </a>\n    )\n  }\n  if (error.code === ErrorCode.BING_CAPTCHA) {\n    return (\n      <a href=\"https://www.bing.com/turing/captcha/challenge\" target=\"_blank\" rel=\"noreferrer\">\n        <ActionButton text={t('Verify')} />\n      </a>\n    )\n  }\n  if (error.code === ErrorCode.CHATGPT_INSUFFICIENT_QUOTA) {\n    return (\n      <p className=\"ml-2 text-secondary-text text-sm\">\n        {t('This usually mean you need to add a payment method to your OpenAI account, checkout: ')}\n        <a href=\"https://platform.openai.com/account/billing/\" target=\"_blank\" rel=\"noreferrer\" className=\"underline\">\n          OpenAI billing\n        </a>\n      </p>\n    )\n  }\n  if (error.code === ErrorCode.LMSYS_WS_ERROR) {\n    return (\n      <p className=\"ml-2 text-secondary-text text-sm\">\n        Please visit{' '}\n        <a href=\"https://chat.lmsys.org\" target=\"_blank\" rel=\"noreferrer\" className=\"underline\">\n          LMSYS.org\n        </a>{' '}\n        and try again\n      </p>\n    )\n  }\n  if (error.code === ErrorCode.PPLX_FORBIDDEN_ERROR) {\n    return (\n      <p className=\"ml-2 text-secondary-text text-sm\">\n        Please visit{' '}\n        <a href=\"https://labs.perplexity.ai\" target=\"_blank\" rel=\"noreferrer\" className=\"underline\">\n          labs.perplexity.ai\n        </a>{' '}\n        and try again\n      </p>\n    )\n  }\n  if (\n    error.code === ErrorCode.NETWORK_ERROR ||\n    (error.code === ErrorCode.UNKOWN_ERROR && error.message.includes('Failed to fetch'))\n  ) {\n    return (\n      <div>\n        <p className=\"ml-2 text-secondary-text text-sm\">{t('Please check your network connection')}</p>\n      </div>\n    )\n  }\n  if (error.code === ErrorCode.POE_MESSAGE_LIMIT) {\n    return <p className=\"ml-2 text-secondary-text text-sm\">{t('This is a limitation set by poe.com')}</p>\n  }\n\n  return null\n}\n\nexport default ErrorAction\n"
  },
  {
    "path": "src/app/components/Chat/LayoutSwitch.tsx",
    "content": "import { cx } from '~/utils'\nimport { FC } from 'react'\nimport { Layout } from '~app/consts'\nimport layoutFourIcon from '~assets/icons/layout-four.svg'\nimport layoutImageIcon from '~assets/icons/layout-image-input.svg'\nimport layoutThreeIcon from '~assets/icons/layout-three.svg'\nimport layoutTwoIcon from '~assets/icons/layout-two.svg'\nimport layoutSixIcon from '~assets/icons/layout-six.svg'\n\nconst Item: FC<{ icon: string; active: boolean; onClick: () => void }> = (props) => {\n  return (\n    <a className={cx(!!props.active && 'bg-[#00000014] dark:bg-[#ffffff26] rounded-[6px]')} onClick={props.onClick}>\n      <img src={props.icon} className=\"w-8 h-8 cursor-pointer\" />\n    </a>\n  )\n}\n\ninterface Props {\n  layout: Layout\n  onChange: (layout: Layout) => void\n}\n\nconst LayoutSwitch: FC<Props> = (props) => {\n  return (\n    <div className=\"flex flex-row items-center gap-2 bg-primary-background rounded-2xl px-4\">\n      <Item\n        icon={layoutTwoIcon}\n        active={props.layout === 2 || props.layout === 'twoVertical'}\n        onClick={() => props.onChange(2)}\n      />\n      <Item icon={layoutThreeIcon} active={props.layout === 3} onClick={() => props.onChange(3)} />\n      <Item icon={layoutFourIcon} active={props.layout === 4} onClick={() => props.onChange(4)} />\n      <Item icon={layoutSixIcon} active={props.layout === 'sixGrid'} onClick={() => props.onChange('sixGrid')} />\n      <Item\n        icon={layoutImageIcon}\n        active={props.layout === 'imageInput'}\n        onClick={() => props.onChange('imageInput')}\n      />\n    </div>\n  )\n}\n\nexport default LayoutSwitch\n"
  },
  {
    "path": "src/app/components/Chat/MessageBubble.tsx",
    "content": "import { cx } from '~/utils'\nimport { FC, PropsWithChildren } from 'react'\n\ninterface Props {\n  color: 'primary' | 'flat'\n  className?: string\n}\n\nconst MessageBubble: FC<PropsWithChildren<Props>> = (props) => {\n  return (\n    <div\n      className={cx(\n        'rounded-[15px] px-4 py-2 w-full',\n        props.color === 'primary' ? 'bg-primary-blue text-white' : 'bg-secondary text-primary-text',\n        props.className,\n      )}\n    >\n      {props.children}\n    </div>\n  )\n}\n\nexport default MessageBubble\n"
  },
  {
    "path": "src/app/components/Chat/TextInput.tsx",
    "content": "import { cx } from '~/utils'\nimport React, { KeyboardEventHandler, useCallback, useImperativeHandle, useRef } from 'react'\nimport TextareaAutosize, { TextareaAutosizeProps } from 'react-textarea-autosize'\n\ntype Props = TextareaAutosizeProps & {\n  onValueChange: (value: string) => void\n  formref?: React.RefObject<HTMLFormElement>\n}\n\nconst TextInput = React.forwardRef<HTMLTextAreaElement, Props>((props, ref) => {\n  const {\n    className,\n    value = '',\n    onValueChange,\n    minRows = 1,\n    formref,\n    disabled,\n    ...textareaProps\n  } = props as Props & { value: string }\n\n  const inputRef = useRef<HTMLTextAreaElement>(null)\n\n  useImperativeHandle(ref, () => inputRef.current!)\n\n  const onKeyDown: KeyboardEventHandler<HTMLTextAreaElement> = useCallback(\n    (e) => {\n      if (e.keyCode === 13) {\n        e.preventDefault()\n        if (e.shiftKey) {\n          const pos = inputRef.current?.selectionStart || 0\n          onValueChange(`${value.slice(0, pos)}\\n${value.slice(pos)}`)\n          setTimeout(() => {\n            inputRef.current!.setSelectionRange(pos + 1, pos + 1)\n          }, 0)\n        } else if (!disabled) {\n          formref?.current?.requestSubmit()\n        }\n      }\n    },\n    [disabled, formref, onValueChange, value],\n  )\n\n  return (\n    <TextareaAutosize\n      ref={inputRef}\n      className={cx(\n        'resize-none overflow-x-hidden overflow-y-auto  w-full outline-none text-sm text-primary-text bg-transparent scrollbar-thin',\n        disabled && 'cursor-wait',\n        className,\n      )}\n      onKeyDown={onKeyDown}\n      value={value}\n      onChange={(event) => onValueChange(event.target.value)}\n      autoComplete=\"off\"\n      minRows={minRows}\n      maxRows={5}\n      {...textareaProps}\n    />\n  )\n})\n\nTextInput.displayName = 'TextInput'\n\nexport default TextInput\n"
  },
  {
    "path": "src/app/components/Chat/WebAccessCheckbox.tsx",
    "content": "import { Switch } from '@headlessui/react'\nimport { useSetAtom } from 'jotai'\nimport { FC, memo, useCallback, useEffect, useMemo, useState } from 'react'\nimport { useTranslation } from 'react-i18next'\nimport { BotId } from '~app/bots'\nimport { usePremium } from '~app/hooks/use-premium'\nimport { trackEvent } from '~app/plausible'\nimport { showPremiumModalAtom } from '~app/state'\nimport { requestHostPermission } from '~app/utils/permissions'\nimport { getUserConfig, updateUserConfig } from '~services/user-config'\nimport Toggle from '../Toggle'\n\ninterface Props {\n  botId: BotId\n}\n\nconst WebAccessCheckbox: FC<Props> = (props) => {\n  const { t } = useTranslation()\n  const [checked, setChecked] = useState<boolean | null>(null)\n  const setPremiumModalOpen = useSetAtom(showPremiumModalAtom)\n  const premiumState = usePremium()\n\n  const configKey = useMemo(() => {\n    if (props.botId === 'chatgpt') {\n      return 'chatgptWebAccess'\n    }\n    if (props.botId === 'claude') {\n      return 'claudeWebAccess'\n    }\n  }, [props.botId])\n\n  useEffect(() => {\n    if (!configKey) {\n      return\n    }\n    if (premiumState.activated === false) {\n      setChecked(false)\n      updateUserConfig({ [configKey]: false })\n    } else if (premiumState.activated) {\n      getUserConfig().then((config) => setChecked(config[configKey]))\n    }\n  }, [configKey, premiumState.activated])\n\n  const onToggle = useCallback(\n    async (newValue: boolean) => {\n      trackEvent('toggle_web_access', { botId: props.botId })\n      if (!premiumState.activated && newValue) {\n        setPremiumModalOpen('web-access')\n        return\n      }\n      if (!(await requestHostPermission('https://*.duckduckgo.com/'))) {\n        return\n      }\n      setChecked(newValue)\n      if (configKey) {\n        updateUserConfig({ [configKey]: newValue })\n      }\n    },\n    [configKey, premiumState.activated, props.botId, setPremiumModalOpen],\n  )\n\n  if (checked === null) {\n    return null\n  }\n\n  return (\n    <div className=\"flex flex-row items-center gap-2 shrink-0 cursor-pointer group\">\n      <Switch.Group>\n        <div className=\"flex flex-row items-center gap-2\">\n          <Toggle enabled={checked} onChange={onToggle} />\n          <Switch.Label className=\"text-[13px] whitespace-nowrap text-light-text font-medium select-none\">\n            {t('Web Access')}\n          </Switch.Label>\n        </div>\n      </Switch.Group>\n    </div>\n  )\n}\n\nexport default memo(WebAccessCheckbox)\n"
  },
  {
    "path": "src/app/components/Dialog.tsx",
    "content": "import { Dialog as HeadlessDialog, Transition } from '@headlessui/react'\nimport { FC, Fragment, PropsWithChildren } from 'react'\nimport closeIcon from '~/assets/icons/close.svg'\nimport { cx } from '~/utils'\n\ninterface Props {\n  title?: string\n  open: boolean\n  onClose: () => void\n  className?: string\n  borderless?: boolean\n}\n\nconst Dialog: FC<PropsWithChildren<Props>> = (props) => {\n  return (\n    <Transition.Root show={props.open} as={Fragment}>\n      <HeadlessDialog as=\"div\" onClose={props.onClose} className=\"relative z-50\">\n        <Transition.Child\n          as={Fragment}\n          enter=\"ease-out duration-200\"\n          enterFrom=\"opacity-0\"\n          enterTo=\"opacity-100\"\n          leave=\"ease-in duration-200\"\n          leaveFrom=\"opacity-100\"\n          leaveTo=\"opacity-0\"\n        >\n          <div className=\"fixed inset-0 bg-black/30 bg-opacity-75 transition-opacity\" />\n        </Transition.Child>\n        <div className=\"fixed inset-0 flex items-center justify-center max-h-screen m-5\">\n          <Transition.Child\n            as={Fragment}\n            enter=\"ease-out duration-300\"\n            enterFrom=\"opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95\"\n            enterTo=\"opacity-100 translate-y-0 sm:scale-100\"\n            leave=\"ease-in duration-200\"\n            leaveFrom=\"opacity-100 translate-y-0 sm:scale-100\"\n            leaveTo=\"opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95\"\n          >\n            <HeadlessDialog.Panel\n              className={cx(\n                'mx-auto rounded-2xl bg-primary-background shadow-2xl max-h-full overflow-hidden flex flex-col',\n                props.className,\n              )}\n            >\n              {props.title ? (\n                <HeadlessDialog.Title\n                  className={cx(\n                    !props.borderless && 'border-b',\n                    'border-solid border-primary-border flex flex-row justify-center items-center py-3 px-5',\n                  )}\n                >\n                  <span className=\"ml-auto\" />\n                  <span className=\"font-bold text-primary-text text-base\">{props.title}</span>\n                  <img src={closeIcon} className=\"w-4 h-4 ml-auto mr-[10px] cursor-pointer\" onClick={props.onClose} />\n                </HeadlessDialog.Title>\n              ) : (\n                <HeadlessDialog.Title></HeadlessDialog.Title>\n              )}\n              {props.children}\n            </HeadlessDialog.Panel>\n          </Transition.Child>\n        </div>\n      </HeadlessDialog>\n    </Transition.Root>\n  )\n}\n\nexport default Dialog\n"
  },
  {
    "path": "src/app/components/GuideModal.tsx",
    "content": "import { FC, useEffect, useState } from 'react'\nimport { useTranslation } from 'react-i18next'\nimport { incrAppOpenTimes } from '~services/storage/open-times'\nimport Button from './Button'\nimport Dialog from './Dialog'\n\nconst GuideModal: FC = () => {\n  const { t } = useTranslation()\n  const [open, setOpen] = useState(false)\n  const [openTimes, setOpenTimes] = useState(0)\n\n  useEffect(() => {\n    incrAppOpenTimes().then((t) => {\n      if (t === 15) {\n        setOpen(true)\n      }\n      setOpenTimes(t)\n    })\n  }, [])\n\n  if (openTimes === 15) {\n    return (\n      <Dialog title=\"🌟🌟🌟🌟🌟\" open={open} onClose={() => setOpen(false)} className=\"rounded-2xl w-[600px]\">\n        <div className=\"flex flex-col items-center gap-4 py-6\">\n          <p className=\"font-semibold text-primary-text\">{t('Enjoy ChatHub? Give us a 5-star rating!')}</p>\n          <a\n            href=\"https://chrome.google.com/webstore/detail/chathub-all-in-one-chatbo/iaakpnchhognanibcahlpcplchdfmgma\"\n            target=\"_blank\"\n            rel=\"noreferrer\"\n          >\n            <Button text={t('Write review')} />\n          </a>\n        </div>\n      </Dialog>\n    )\n  }\n\n  return null\n}\n\nexport default GuideModal\n"
  },
  {
    "path": "src/app/components/History/ChatMessage.tsx",
    "content": "import { cx } from '~/utils'\nimport { FC, memo, useCallback } from 'react'\nimport { FiTrash2 } from 'react-icons/fi'\nimport { useSWRConfig } from 'swr'\nimport { CHATBOTS } from '~/app/consts'\nimport { BotId } from '~app/bots'\nimport { deleteHistoryMessage } from '~services/chat-history'\nimport { ChatMessageModel } from '~types'\nimport Markdown from '../Markdown'\n\ninterface Props {\n  botId: BotId\n  message: ChatMessageModel\n  conversationId: string\n}\n\nconst ChatMessage: FC<Props> = ({ botId, message, conversationId }) => {\n  const { mutate } = useSWRConfig()\n\n  const deleteMessage = useCallback(async () => {\n    await deleteHistoryMessage(botId, conversationId, message.id)\n    mutate(`history:${botId}`)\n  }, [botId, conversationId, message.id, mutate])\n\n  if (!message.text) {\n    return null\n  }\n\n  return (\n    <div\n      className={cx(\n        'group relative py-5 flex flex-col gap-1 px-5 text-primary-text',\n        message.author === 'user' ? 'bg-secondary' : 'bg-primary-background',\n      )}\n    >\n      <div className=\"flex flex-row justify-between\">\n        <span className=\"text-xs text-secondary-tex\">\n          {message.author === 'user' ? 'You' : CHATBOTS[message.author].name}\n        </span>\n        {!!conversationId && (\n          <FiTrash2 className=\"invisible group-hover:visible cursor-pointer\" onClick={deleteMessage} />\n        )}\n      </div>\n      <Markdown>{message.text}</Markdown>\n    </div>\n  )\n}\n\nexport default memo(ChatMessage)\n"
  },
  {
    "path": "src/app/components/History/Content.tsx",
    "content": "import Fuse from 'fuse.js'\nimport { flatMap } from 'lodash-es'\nimport { FC, memo, useMemo, useRef } from 'react'\nimport { ViewportList } from 'react-viewport-list'\nimport useSWR from 'swr'\nimport { BotId } from '~app/bots'\nimport { loadHistoryMessages } from '~services/chat-history'\nimport { ChatMessageModel } from '~types'\nimport { formatTime } from '~utils/format'\nimport ChatMessage from './ChatMessage'\n\ntype ViewportListItem =\n  | {\n      type: 'conversation'\n      createdAt: number\n    }\n  | {\n      type: 'message'\n      message: ChatMessageModel\n      conversationId: string\n    }\n\nconst Timestamp = memo((props: { timestamp: number }) => {\n  return (\n    <span className=\"text-secondary-text bg-secondary text-xs px-2 py-1 w-fit rounded\">\n      {formatTime(props.timestamp)}\n    </span>\n  )\n})\n\nTimestamp.displayName = 'Timestamp'\n\nconst HistoryContent: FC<{ botId: BotId; keyword: string }> = ({ botId, keyword }) => {\n  const historyQuery = useSWR(`history:${botId}`, () => loadHistoryMessages(botId), { suspense: true })\n  const ref = useRef<HTMLDivElement | null>(null)\n\n  const fuse = useMemo(() => {\n    return new Fuse(\n      flatMap(historyQuery.data, (c) => c.messages),\n      { keys: ['text'] },\n    )\n  }, [historyQuery.data])\n\n  const items: ViewportListItem[] = useMemo(() => {\n    const results: ViewportListItem[] = []\n    for (const c of Array.from(historyQuery.data).reverse()) {\n      const messages = c.messages.filter((m) => m.text)\n      if (!messages.length) {\n        continue\n      }\n      results.push({ type: 'conversation', createdAt: c.createdAt })\n      for (const m of messages) {\n        results.push({ type: 'message', message: m, conversationId: c.id })\n      }\n    }\n    return results\n  }, [historyQuery.data])\n\n  const filteredItems: ViewportListItem[] = useMemo(() => {\n    if (!keyword) {\n      return []\n    }\n    const result = fuse.search(keyword)\n    return result.map((r) => ({ type: 'message', message: r.item, conversationId: '' }))\n  }, [fuse, keyword])\n\n  return (\n    <div className=\"flex flex-col overflow-y-auto\" ref={ref}>\n      <ViewportList\n        viewportRef={ref}\n        items={filteredItems.length ? filteredItems : items}\n        initialAlignToTop={true}\n        initialIndex={filteredItems.length || items.length}\n      >\n        {(item) => {\n          if (item.type === 'conversation') {\n            return (\n              <div className=\"text-center my-5\" key={item.createdAt}>\n                <Timestamp timestamp={item.createdAt} />\n              </div>\n            )\n          }\n          return (\n            <ChatMessage\n              key={item.message.id}\n              botId={botId}\n              message={item.message}\n              conversationId={item.conversationId}\n            />\n          )\n        }}\n      </ViewportList>\n    </div>\n  )\n}\n\nexport default HistoryContent\n"
  },
  {
    "path": "src/app/components/History/Dialog.tsx",
    "content": "import { cx } from '~/utils'\nimport { FC, useCallback, useMemo, useState } from 'react'\nimport { useTranslation } from 'react-i18next'\nimport { FiSearch } from 'react-icons/fi'\nimport { VscClearAll } from 'react-icons/vsc'\nimport { BotId } from '~app/bots'\nimport { CHATBOTS } from '~app/consts'\nimport { usePremium } from '~app/hooks/use-premium'\nimport { clearHistoryMessages } from '~services/chat-history'\nimport Dialog from '../Dialog'\nimport Tooltip from '../Tooltip'\nimport HistoryContent from './Content'\n\nconst SearchInput: FC<{ disabled: boolean; value: string; onChange: (v: string) => void }> = (props) => {\n  const { t } = useTranslation()\n  return (\n    <div className=\"rounded-xl bg-secondary h-9 flex flex-row items-center px-4 grow\">\n      <FiSearch size={18} className=\"mr-[6px] opacity-30\" />\n      <input\n        className={cx('bg-transparent w-full outline-none text-sm', props.disabled && 'cursor-not-allowed')}\n        placeholder={`${t('Search')} ${props.disabled ? `(${t('Premium Feature')})` : ''}`}\n        value={props.value}\n        onChange={(e) => props.onChange(e.target.value)}\n        disabled={props.disabled}\n      />\n    </div>\n  )\n}\n\ninterface Props {\n  botId: BotId\n  open: boolean\n  onClose: () => void\n}\n\nconst HistoryDialog: FC<Props> = (props) => {\n  const botName = useMemo(() => CHATBOTS[props.botId].name, [props.botId])\n  const { t } = useTranslation()\n  const premiumState = usePremium()\n  const [keyword, setKeyword] = useState('')\n\n  const clearAll = useCallback(async () => {\n    if (confirm(t('Are you sure you want to clear history messages?')!)) {\n      await clearHistoryMessages(props.botId)\n    }\n  }, [props.botId, t])\n\n  return (\n    <Dialog\n      title={`History conversations with ${botName}`}\n      open={props.open}\n      onClose={props.onClose}\n      className=\"rounded-2xl w-[1000px] min-h-[400px]\"\n      borderless={true}\n    >\n      <div className=\"border-b border-solid border-primary-border pb-[10px] mx-5 flex flex-row items-center gap-4\">\n        <Tooltip content={t('Clear history messages')}>\n          <div className=\"bg-secondary p-2 rounded-xl cursor-pointer\" onClick={clearAll}>\n            <VscClearAll size={18} className=\"opacity-80\" />\n          </div>\n        </Tooltip>\n        <SearchInput disabled={!premiumState.activated} value={keyword} onChange={setKeyword} />\n      </div>\n      <HistoryContent botId={props.botId} keyword={keyword} />\n    </Dialog>\n  )\n}\n\nexport default HistoryDialog\n"
  },
  {
    "path": "src/app/components/Input.tsx",
    "content": "import { cx } from '~/utils'\nimport { FC, HTMLProps } from 'react'\nimport TextareaAutosize, { TextareaAutosizeProps } from 'react-textarea-autosize'\n\ntype InputProps = HTMLProps<HTMLInputElement>\n\nexport const Input: FC<InputProps> = (props) => {\n  const { className, ...extraProps } = props\n  return (\n    <input\n      className={cx(\n        'px-3 py-1.5 outline-none bg-white text-[#303030] text-sm block rounded-md border-0 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6',\n        className,\n      )}\n      {...extraProps}\n    />\n  )\n}\n\nexport const Textarea: FC<TextareaAutosizeProps> = (props) => {\n  const { className, ...extraProps } = props\n  return (\n    <TextareaAutosize\n      className={cx(\n        'px-3 py-1.5 outline-none bg-white text-[#303030] text-sm  block rounded-md border-0  shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6',\n        className,\n      )}\n      minRows={2}\n      maxRows={5}\n      {...extraProps}\n    />\n  )\n}\n"
  },
  {
    "path": "src/app/components/Layout.tsx",
    "content": "import { Outlet } from '@tanstack/react-router'\nimport { useAtomValue } from 'jotai'\nimport { followArcThemeAtom, themeColorAtom } from '~app/state'\nimport ReleaseNotesModal from './Modals/ReleaseNotesModal'\nimport DiscountModal from './Premium/DiscountModal'\nimport PremiumModal from './Premium/Modal'\nimport Sidebar from './Sidebar'\n\nfunction Layout() {\n  const themeColor = useAtomValue(themeColorAtom)\n  const followArcTheme = useAtomValue(followArcThemeAtom)\n  return (\n    <main\n      className=\"h-screen grid grid-cols-[auto_1fr]\"\n      style={{ backgroundColor: followArcTheme ? 'var(--arc-palette-foregroundPrimary)' : themeColor }}\n    >\n      <Sidebar />\n      <div className=\"px-[15px] py-3 h-full overflow-hidden\">\n        <Outlet />\n      </div>\n      <DiscountModal />\n      <PremiumModal />\n      <ReleaseNotesModal />\n    </main>\n  )\n}\n\nexport default Layout\n"
  },
  {
    "path": "src/app/components/Markdown/index.tsx",
    "content": "/* eslint-disable react/prop-types */\n\nimport { cx } from '~/utils'\nimport 'github-markdown-css'\nimport { FC, ReactNode, useEffect, useMemo, useState } from 'react'\nimport { CopyToClipboard } from 'react-copy-to-clipboard'\nimport { BsClipboard } from 'react-icons/bs'\nimport ReactMarkdown from 'react-markdown'\nimport reactNodeToString from 'react-node-to-string'\nimport rehypeHighlight from 'rehype-highlight'\nimport remarkBreaks from 'remark-breaks'\nimport remarkGfm from 'remark-gfm'\nimport remarkMath from 'remark-math'\nimport supersub from 'remark-supersub'\nimport Tooltip from '../Tooltip'\nimport './markdown.css'\n\nfunction CustomCode(props: { children: ReactNode; className?: string }) {\n  const [copied, setCopied] = useState(false)\n\n  const code = useMemo(() => reactNodeToString(props.children), [props.children])\n\n  useEffect(() => {\n    if (copied) {\n      setTimeout(() => setCopied(false), 1000)\n    }\n  }, [copied])\n\n  return (\n    <div className=\"flex flex-col\">\n      <div className=\"bg-[#e6e7e8] dark:bg-[#444a5354] text-xs p-2\">\n        <CopyToClipboard text={code} onCopy={() => setCopied(true)}>\n          <div className=\"flex flex-row items-center gap-2 cursor-pointer w-fit ml-1\">\n            <BsClipboard />\n            <span>{copied ? 'copied' : 'copy code'}</span>\n          </div>\n        </CopyToClipboard>\n      </div>\n      <code className={cx(props.className, 'px-4')}>{props.children}</code>\n    </div>\n  )\n}\n\nconst Markdown: FC<{ children: string }> = ({ children }) => {\n  return (\n    <ReactMarkdown\n      remarkPlugins={[remarkMath, supersub, remarkBreaks, remarkGfm]}\n      rehypePlugins={[[rehypeHighlight, { detect: true, ignoreMissing: true }]]}\n      className={`markdown-body markdown-custom-styles !text-base font-normal`}\n      linkTarget=\"_blank\"\n      components={{\n        a: ({ node, ...props }) => {\n          if (!props.title) {\n            return <a {...props} />\n          }\n          return (\n            <Tooltip content={props.title}>\n              <a {...props} title={undefined} />\n            </Tooltip>\n          )\n        },\n        code: ({ node, inline, className, children, ...props }) => {\n          if (inline) {\n            return (\n              <code className={className} {...props}>\n                {children}\n              </code>\n            )\n          }\n          return <CustomCode className={className}>{children}</CustomCode>\n        },\n      }}\n    >\n      {children}\n    </ReactMarkdown>\n  )\n}\n\nexport default Markdown\n"
  },
  {
    "path": "src/app/components/Markdown/markdown.css",
    "content": ".markdown-custom-styles {\n  color: inherit;\n  background-color: transparent;\n  > p {\n    margin-bottom: 5px;\n  }\n  > ul,\n  ol {\n    list-style: disc;\n    padding-left: 1em;\n    margin-bottom: 5px;\n  }\n  & li p {\n    margin-top: 5px;\n    margin-bottom: 5px;\n  }\n  & pre {\n    padding: 0;\n    margin-top: 10px;\n    margin-bottom: 10px;\n  }\n  & pre code {\n    white-space: pre-wrap;\n    padding: 10px;\n  }\n  & img {\n    max-width: min(80%, 300px);\n    margin-top: 5px;\n  }\n  & a:not(:has(sup)) {\n    color: inherit;\n    text-decoration: underline;\n  }\n}\n"
  },
  {
    "path": "src/app/components/Modals/ReleaseNotesModal.tsx",
    "content": "import { useAtom } from 'jotai'\nimport { FC } from 'react'\nimport { useTranslation } from 'react-i18next'\nimport { releaseNotesAtom } from '~app/state'\nimport Dialog from '../Dialog'\n\nconst ReleaseNotesModal: FC = () => {\n  const { t } = useTranslation()\n  const [notes, setNotes] = useAtom(releaseNotesAtom)\n  return (\n    <Dialog title={t('Recent Updates')} open={notes.length > 0} onClose={() => setNotes([])} className=\"w-[600px]\">\n      <div className=\"flex flex-col gap-3 px-5 py-5\">\n        {notes.map((note, i) => {\n          return (\n            <div key={i} className=\"flex flex-row gap-2 items-center\">\n              <div className=\"flex-none rounded-full p-1 text-green-400 bg-green-400/10\">\n                <div className=\"h-2 w-2 rounded-full bg-current\" />\n              </div>\n              <span className=\"text-primary-text font-medium\">{t(note)}</span>\n            </div>\n          )\n        })}\n      </div>\n    </Dialog>\n  )\n}\n\nexport default ReleaseNotesModal\n"
  },
  {
    "path": "src/app/components/Page.tsx",
    "content": "import { FC, PropsWithChildren } from 'react'\n\nconst PagePanel: FC<PropsWithChildren<{ title: string }>> = (props) => {\n  return (\n    <div className=\"flex flex-col overflow-hidden bg-primary-background dark:text-primary-text rounded-2xl h-full\">\n      <div className=\"text-center border-b border-solid border-primary-border flex flex-col justify-center mx-10 py-2\">\n        <span className=\"font-semibold text-lg\">{props.title}</span>\n      </div>\n      <div className=\"h-full overflow-auto\">{props.children}</div>\n    </div>\n  )\n}\n\nexport default PagePanel\n"
  },
  {
    "path": "src/app/components/Premium/DiscountBadge.tsx",
    "content": "import { FC } from 'react'\nimport { useTranslation } from 'react-i18next'\n\nconst DiscountBadge: FC = () => {\n  const { t } = useTranslation()\n  return (\n    <p className=\"bg-[#FAE387] text-[#303030] w-fit rounded-[5px] px-2 py-[4px] text-sm font-semibold\">\n      {t('Buy once, use forever')}\n    </p>\n  )\n}\n\nexport default DiscountBadge\n"
  },
  {
    "path": "src/app/components/Premium/DiscountModal.tsx",
    "content": "import { useAtom, useSetAtom } from 'jotai'\nimport { FC, useCallback, useEffect, useState } from 'react'\nimport { useTranslation } from 'react-i18next'\nimport * as api from '~/services/server-api'\nimport { trackEvent } from '~app/plausible'\nimport { showDiscountModalAtom, showPremiumModalAtom } from '~app/state'\nimport discountBg from '~assets/discount-bg.png'\nimport Button from '../Button'\nimport Dialog from '../Dialog'\n\ninterface DiscountDialogProps {\n  open: boolean\n  setOpen: (open: boolean) => void\n  title: string\n  subtitle?: string\n  onConfirm: () => void\n  loading?: boolean\n}\n\nconst DiscountDialog: FC<DiscountDialogProps> = (props) => {\n  const { t } = useTranslation()\n  return (\n    <Dialog title=\"\" open={props.open} onClose={() => props.setOpen(false)} className=\"min-w-[600px] shadow-inner\">\n      <div\n        className=\"flex flex-col items-center gap-1 pb-7\"\n        style={{ backgroundImage: 'linear-gradient(to bottom, #AEA5DB 0%, #FFFFFF 100%)' }}\n      >\n        <div className=\"w-full h-[250px] relative\">\n          <img src={discountBg} className=\"absolute w-full h-full top-0 left-0\" />\n          <div className=\"flex flex-col items-center justify-center gap-4 h-full relative\">\n            <span className=\"text-4xl\">🎁</span>\n            <p className=\"font-black text-4xl text-[#303030]\">{props.title}</p>\n            {!!props.subtitle && <p className=\"font-bold text-2xl text-[#303030]\">{props.subtitle}</p>}\n          </div>\n        </div>\n        <Button\n          text={t('Get Discount')}\n          color=\"primary\"\n          onClick={props.onConfirm}\n          isLoading={props.loading}\n          className=\"px-10 py-[10px]\"\n        />\n      </div>\n    </Dialog>\n  )\n}\n\nconst DiscountModal: FC = () => {\n  const [open, setOpen] = useAtom(showDiscountModalAtom)\n  const [creating, setCreating] = useState(false)\n  const setShowPremiumModal = useSetAtom(showPremiumModalAtom)\n  const { t } = useTranslation()\n\n  const createDiscount = useCallback(async () => {\n    trackEvent('create_discount')\n    setCreating(true)\n    await api.createDiscount()\n    setCreating(false)\n    setOpen(false)\n    setShowPremiumModal(true)\n  }, [setOpen, setShowPremiumModal])\n\n  const showPremiumModal = useCallback(() => {\n    setOpen(false)\n    setShowPremiumModal(true)\n  }, [setOpen, setShowPremiumModal])\n\n  useEffect(() => {\n    if (open) {\n      trackEvent('show_discount_modal')\n    }\n  }, [open])\n\n  return (\n    <DiscountDialog\n      open={!!open}\n      setOpen={setOpen}\n      title={typeof open !== 'boolean' ? open.description : t('Special Offer: 20% OFF')}\n      subtitle={typeof open !== 'boolean' ? undefined : t('TODAY ONLY')}\n      onConfirm={typeof open !== 'boolean' ? showPremiumModal : createDiscount}\n      loading={creating}\n    />\n  )\n}\n\nexport default DiscountModal\n"
  },
  {
    "path": "src/app/components/Premium/FeatureList.tsx",
    "content": "import { FC, useMemo } from 'react'\nimport { useTranslation } from 'react-i18next'\nimport { BsQuestionCircle } from 'react-icons/bs'\nimport { cx } from '~/utils'\nimport checkIcon from '~assets/icons/check.svg'\n\nexport type FeatureId = 'web-access' | 'all-in-one-layout'\n\ninterface Feature {\n  id?: FeatureId\n  title: string\n  desc?: string\n  link?: string\n}\n\nconst FeatureItem: FC<Feature & { highlight?: boolean }> = (props) => {\n  return (\n    <div className=\"flex flex-row items-center gap-3\">\n      <img src={checkIcon} className=\"w-6 h-6\" />\n      <div className=\"flex flex-col\">\n        <div className=\"flex flex-row items-center gap-2\">\n          <span className={cx('text-primary-text', props.highlight ? 'font-bold text-lg' : 'font-medium')}>\n            {props.title}\n          </span>\n          {!!props.link && (\n            <a href={props.link} target=\"_blank\" rel=\"noreferrer\">\n              <BsQuestionCircle className=\"cursor-pointer\" size=\"14\" />\n            </a>\n          )}\n        </div>\n        {!!props.desc && (\n          <span className={cx('text-secondary-text', props.highlight && 'font-medium')}>{props.desc}</span>\n        )}\n      </div>\n    </div>\n  )\n}\n\nconst FeatureList: FC<{ highlightFeature?: FeatureId }> = (props) => {\n  const { t, i18n } = useTranslation()\n\n  const features: Feature[] = useMemo(() => {\n    return [\n      {\n        id: 'all-in-one-layout',\n        title: t('More layouts in All-In-One mode'),\n        desc: t('Chat with more than 2 bots simultaneously'),\n      },\n      {\n        id: 'web-access',\n        title: t('Web Access'),\n        desc: t('Improving accuracy by searching up-to-date information from the internet'),\n        link: 'https://github.com/chathub-dev/chathub/wiki/Web-Access',\n      },\n      {\n        title: t('Full-text search for chat history'),\n      },\n      {\n        title: t('Customize theme'),\n      },\n      {\n        title: t('Quick access in Chrome side bar'),\n        link: 'https://github.com/chathub-dev/chathub/wiki/Access-from-Chrome-side-panel',\n      },\n      {\n        title: t('Compare with image input'),\n      },\n      {\n        title: t('Activate up to 5 devices'),\n      },\n      {\n        title: t('Support the development of ChatHub'),\n      },\n    ]\n  }, [t])\n\n  return (\n    <div className=\"flex flex-col gap-4\">\n      {features.map((feature) => (\n        <FeatureItem\n          key={feature.title}\n          {...feature}\n          highlight={props.highlightFeature && props.highlightFeature === feature.id}\n        />\n      ))}\n      {i18n.language === 'zh-CN' && (\n        <span className=\"text-sm text-secondary-text\">请注意：ChatHub会员并不为您提供ChatGPT账号或API key</span>\n      )}\n    </div>\n  )\n}\n\nexport default FeatureList\n"
  },
  {
    "path": "src/app/components/Premium/Modal.tsx",
    "content": "import { useNavigate } from '@tanstack/react-router'\nimport { useAtom } from 'jotai'\nimport { FC, useCallback, useEffect } from 'react'\nimport { useTranslation } from 'react-i18next'\nimport { useDiscountCode } from '~app/hooks/use-purchase-info'\nimport { trackEvent } from '~app/plausible'\nimport { showPremiumModalAtom } from '~app/state'\nimport { incrPremiumModalOpenTimes } from '~services/storage/open-times'\nimport Button from '../Button'\nimport Dialog from '../Dialog'\nimport DiscountBadge from './DiscountBadge'\nimport FeatureList from './FeatureList'\nimport PriceSection from './PriceSection'\nimport Testimonials from './Testimonials'\n\nconst PremiumModal: FC = () => {\n  const { t } = useTranslation()\n  const navigate = useNavigate()\n  const [open, setOpen] = useAtom(showPremiumModalAtom)\n  const discountCode = useDiscountCode()\n\n  const feature = typeof open === 'string' ? open : undefined\n\n  useEffect(() => {\n    if (open) {\n      incrPremiumModalOpenTimes().then((openTimes) => {\n        trackEvent('show_premium_modal', { source: feature, openTimes })\n      })\n    }\n  }, [feature, open])\n\n  const onClickBuy = useCallback(() => {\n    trackEvent('click_buy_premium', { source: 'premium_modal' })\n    setOpen(false)\n    navigate({ to: '/premium', search: { source: 'after_click_buy_premium' } })\n  }, [navigate, setOpen])\n\n  const close = useCallback(() => {\n    setOpen(false)\n  }, [setOpen])\n\n  return (\n    <Dialog title={t('Premium Feature')} open={!!open} onClose={close} className=\"min-w-[600px]\">\n      <div className=\"flex flex-col items-center my-7 gap-7 overflow-y-auto\">\n        <div className=\"flex flex-col items-center gap-3\">\n          <PriceSection align=\"center\" />\n          <DiscountBadge />\n        </div>\n        <div className=\"w-full px-20\">\n          <FeatureList highlightFeature={feature} />\n        </div>\n        <a\n          href={`https://chathub.gg/api/premium/redirect?source=${feature || ''}&discountCode=${discountCode || ''}`}\n          target=\"_blank\"\n          rel=\"noreferrer\"\n          onClick={onClickBuy}\n        >\n          <Button text={t('Buy premium license')} color=\"primary\" className=\"!py-[11px] px-16 rounded-lg\" />\n        </a>\n        <Testimonials />\n      </div>\n    </Dialog>\n  )\n}\n\nexport default PremiumModal\n"
  },
  {
    "path": "src/app/components/Premium/PriceSection.tsx",
    "content": "import dayjs, { Dayjs } from 'dayjs'\nimport humanizeDuration from 'humanize-duration'\nimport { FC, useEffect, useMemo, useState } from 'react'\nimport { useTranslation } from 'react-i18next'\nimport { usePurchaseInfo } from '~app/hooks/use-purchase-info'\nimport { Campaign } from '~services/server-api'\nimport { cx } from '~utils'\n\nconst DiscountCountDown: FC<{ originalPrice: number; endsAt: Dayjs }> = (props) => {\n  const [now, setNow] = useState(() => dayjs())\n  const { t } = useTranslation()\n\n  useEffect(() => {\n    const interval = setInterval(() => {\n      setNow(dayjs())\n    }, 1000)\n    return () => clearInterval(interval)\n  }, [])\n\n  if (props.endsAt.isBefore(now)) {\n    return null\n  }\n\n  return (\n    <div className=\"bg-[#FF6B6B] text-white px-4 py-1 rounded-xl font-medium text-sm mt-2 flex flex-row items-center gap-1\">\n      <del className=\"font-bold\">${props.originalPrice / 100}</del>\n      <span>\n        {t('20% OFF: ends in')} {humanizeDuration(props.endsAt.diff(now), { units: ['d', 'h', 'm', 's'], round: true })}\n      </span>\n    </div>\n  )\n}\n\nconst CampaignBanner: FC<{ campaign: Campaign }> = (props) => {\n  return (\n    <div className=\"bg-[#FF6B6B] text-white px-4 py-1 rounded-xl font-medium text-sm mb-3\">\n      <span>{props.campaign.description}</span>\n    </div>\n  )\n}\n\nconst PriceSection: FC<{ align: 'center' | 'left' }> = (props) => {\n  const { t } = useTranslation()\n  const purchaseInfoQuery = usePurchaseInfo()\n\n  const calculatedPrice = useMemo(() => {\n    if (!purchaseInfoQuery.data) {\n      return null\n    }\n    const { price, discount, campaign } = purchaseInfoQuery.data\n    if (discount) {\n      return discount.price / 100\n    }\n    if (campaign) {\n      return campaign.price / 100\n    }\n    return price / 100\n  }, [purchaseInfoQuery.data])\n\n  const discountEndsAt = useMemo(() => {\n    if (!purchaseInfoQuery.data) {\n      return null\n    }\n    const { discount } = purchaseInfoQuery.data\n    if (discount) {\n      return dayjs(discount.startTime).add(1, 'day')\n    }\n  }, [purchaseInfoQuery.data])\n\n  return (\n    <div className={cx('flex flex-col', props.align === 'center' ? 'items-center' : 'items-start')}>\n      {purchaseInfoQuery.data?.campaign && <CampaignBanner campaign={purchaseInfoQuery.data.campaign} />}\n      <div className=\"flex flex-row gap-3\">\n        <span className=\"text-[64px] leading-none font-bold text-primary-blue\">\n          {calculatedPrice ? `$${calculatedPrice}` : '$$$'}\n        </span>\n        <div className=\"flex flex-col text-secondary-text font-medium justify-center gap-1\">\n          <span className=\"text-2xl leading-none line-through\">$49</span>\n          <span className=\"text-sm\">/ {t('Lifetime license')}</span>\n        </div>\n      </div>\n      {discountEndsAt && purchaseInfoQuery.data && (\n        <DiscountCountDown originalPrice={purchaseInfoQuery.data.price} endsAt={discountEndsAt} />\n      )}\n    </div>\n  )\n}\n\nexport default PriceSection\n"
  },
  {
    "path": "src/app/components/Premium/Testimonials.tsx",
    "content": "import { sample } from 'lodash-es'\nimport { FC } from 'react'\nimport { AiFillStar } from 'react-icons/ai'\n\nconst Testimonials: FC = () => {\n  return (\n    <div className=\"flex flex-col items-center gap-2\">\n      <div className=\"border-primary-border rounded-full border px-4 py-1 flex flex-row items-center gap-2 w-fit\">\n        <div className=\"flex flex-row\">\n          <AiFillStar color=\"gold\" size={15} />\n          <AiFillStar color=\"gold\" size={15} />\n          <AiFillStar color=\"gold\" size={15} />\n          <AiFillStar color=\"gold\" size={15} />\n          <AiFillStar color=\"gold\" size={15} />\n        </div>\n        <span className=\"text-sm font-medium text-primary-text\">Loved by 100,000+ users</span>\n      </div>\n      <p className=\"italic text-sm text-center text-secondary-text w-3/4\">\n        {sample([\n          '\"What a great idea AND implementation - to have all the major chats on one page\" - Chad Tunis',\n          '\"Very helpful, works great and is exactly what i was looking for, I bought premium\" - Artush Foto',\n        ])}\n      </p>\n    </div>\n  )\n}\n\nexport default Testimonials\n"
  },
  {
    "path": "src/app/components/PromptCombobox.tsx",
    "content": "import { useInteractions, useListItem } from '@floating-ui/react'\nimport { cx } from '~/utils'\nimport { t } from 'i18next'\nimport { FC, createContext, useContext } from 'react'\nimport useSWR from 'swr'\nimport { Prompt, loadLocalPrompts } from '~services/prompts'\n\nconst LIBRARY_PROMPT: Prompt = {\n  id: 'PROMPT_LIBRARY',\n  title: t('Open Prompt Library'),\n  prompt: '',\n}\n\nexport interface ComboboxContextValue {\n  activeIndex: number | null\n  getItemProps: ReturnType<typeof useInteractions>['getItemProps']\n  handleSelect: (prompt: Prompt) => void\n  setIsComboboxOpen: (open: boolean) => void\n}\n\nexport const ComboboxContext = createContext<ComboboxContextValue>({} as ComboboxContextValue)\n\nconst PromptItem: FC<{ prompt: Prompt }> = ({ prompt }) => {\n  const context = useContext(ComboboxContext)\n  const { ref, index } = useListItem()\n  const isActive = index === context.activeIndex\n  return (\n    <div\n      ref={ref}\n      tabIndex={isActive ? 0 : -1}\n      className={cx(\n        'cursor-default select-none py-2 px-4',\n        isActive ? 'bg-primary-blue text-white' : 'text-secondary-text',\n      )}\n      {...context.getItemProps({\n        onClick: () => {\n          context.handleSelect(prompt)\n        },\n        onKeyDown: (e) => {\n          if (e.keyCode === 13) {\n            context.handleSelect(prompt)\n            e.preventDefault()\n          } else if (e.key === 'Backspace' || e.key === 'Delete') {\n            context.setIsComboboxOpen(false)\n          }\n        },\n      })}\n    >\n      {prompt.title}\n    </div>\n  )\n}\n\nconst PromptCombobox: FC = () => {\n  const promptsQuery = useSWR('user-prompts', loadLocalPrompts)\n  if (!promptsQuery.data) {\n    return null\n  }\n  return (\n    <div className=\"overflow-auto rounded-md py-1 shadow-lg ring-1 ring-primary-border focus:outline-none text-sm min-w-[150px] bg-primary-background\">\n      {promptsQuery.data.map((prompt) => {\n        return <PromptItem key={prompt.id} prompt={prompt} />\n      })}\n      {promptsQuery.data.length > 0 && <div className=\"h-[1px] bg-primary-border\" />}\n      <PromptItem key={LIBRARY_PROMPT.id} prompt={LIBRARY_PROMPT} />\n    </div>\n  )\n}\n\nexport default PromptCombobox\n"
  },
  {
    "path": "src/app/components/PromptLibrary/Dialog.tsx",
    "content": "import PromptLibrary from './Library'\nimport Dialog from '../Dialog'\n\ninterface Props {\n  isOpen: boolean\n  onClose: () => void\n  insertPrompt: (text: string) => void\n}\n\nconst PromptLibraryDialog = (props: Props) => {\n  return (\n    <Dialog title=\"Prompt Library\" open={props.isOpen} onClose={props.onClose} className=\"w-[800px] min-h-[400px]\">\n      <div className=\"p-5 overflow-auto\">\n        <PromptLibrary insertPrompt={props.insertPrompt} />\n      </div>\n    </Dialog>\n  )\n}\n\nexport default PromptLibraryDialog\n"
  },
  {
    "path": "src/app/components/PromptLibrary/Library.tsx",
    "content": "import { Suspense, useCallback, useMemo, useState } from 'react'\nimport { useTranslation } from 'react-i18next'\nimport { BeatLoader } from 'react-spinners'\nimport useSWR from 'swr'\nimport closeIcon from '~/assets/icons/close.svg'\nimport { trackEvent } from '~app/plausible'\nimport { Prompt, loadLocalPrompts, loadRemotePrompts, removeLocalPrompt, saveLocalPrompt } from '~services/prompts'\nimport { uuid } from '~utils'\nimport Button from '../Button'\nimport { Input, Textarea } from '../Input'\nimport Tabs, { Tab } from '../Tabs'\n\nconst ActionButton = (props: { text: string; onClick: () => void }) => {\n  return (\n    <a\n      className=\"inline-flex items-center rounded-full bg-white px-2.5 py-1 text-xs font-semibold text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-50 cursor-pointer\"\n      onClick={props.onClick}\n    >\n      {props.text}\n    </a>\n  )\n}\n\nconst PromptItem = (props: {\n  title: string\n  prompt: string\n  edit?: () => void\n  remove?: () => void\n  copyToLocal?: () => void\n  insertPrompt: (text: string) => void\n}) => {\n  const { t } = useTranslation()\n  const [saved, setSaved] = useState(false)\n\n  const copyToLocal = useCallback(() => {\n    props.copyToLocal?.()\n    setSaved(true)\n  }, [props])\n\n  return (\n    <div className=\"group relative flex items-center space-x-3 rounded-lg border border-primary-border bg-primary-background px-5 py-4 shadow-sm hover:border-gray-400\">\n      <div className=\"min-w-0 flex-1\">\n        <p title={props.prompt} className=\"truncate text-sm font-medium text-primary-text\">\n          {props.title}\n        </p>\n      </div>\n      <div className=\"flex flex-row gap-1\">\n        {props.edit && <ActionButton text={t('Edit')} onClick={props.edit} />}\n        {props.copyToLocal && <ActionButton text={t(saved ? 'Saved' : 'Save')} onClick={copyToLocal} />}\n        <ActionButton text={t('Use')} onClick={() => props.insertPrompt(props.prompt)} />\n      </div>\n      {props.remove && (\n        <img\n          src={closeIcon}\n          className=\"hidden group-hover:block absolute right-[-8px] top-[-8px] cursor-pointer w-4 h-4 rounded-full bg-primary-background\"\n          onClick={props.remove}\n        />\n      )}\n    </div>\n  )\n}\n\nfunction PromptForm(props: { initialData: Prompt; onSubmit: (data: Prompt) => void; onClose: () => void }) {\n  const { t } = useTranslation()\n\n  const onSubmit = useCallback(\n    (e: React.FormEvent<HTMLFormElement>) => {\n      e.preventDefault()\n      e.stopPropagation()\n      const formdata = new FormData(e.currentTarget)\n      const json = Object.fromEntries(formdata.entries())\n      if (json.title && json.prompt) {\n        props.onSubmit({\n          id: props.initialData.id,\n          title: json.title as string,\n          prompt: json.prompt as string,\n        })\n      }\n    },\n    [props],\n  )\n\n  return (\n    <form className=\"flex flex-col gap-2 w-full\" onSubmit={onSubmit}>\n      <div className=\"w-full\">\n        <span className=\"text-sm font-semibold block mb-1 text-primary-text\">Prompt {t('Title')}</span>\n        <Input className=\"w-full\" name=\"title\" defaultValue={props.initialData.title} />\n      </div>\n      <div className=\"w-full\">\n        <span className=\"text-sm font-semibold block mb-1 text-primary-text\">Prompt {t('Content')}</span>\n        <Textarea className=\"w-full\" name=\"prompt\" defaultValue={props.initialData.prompt} />\n      </div>\n      <div className=\"flex flex-row gap-2 mt-1\">\n        <Button color=\"primary\" text={t('Save')} className=\"w-fit\" size=\"small\" type=\"submit\" />\n        <Button color=\"flat\" text={t('Cancel')} className=\"w-fit\" size=\"small\" onClick={props.onClose} />\n      </div>\n    </form>\n  )\n}\n\nfunction LocalPrompts(props: { insertPrompt: (text: string) => void }) {\n  const { t } = useTranslation()\n  const [formData, setFormData] = useState<Prompt | null>(null)\n  const localPromptsQuery = useSWR('local-prompts', () => loadLocalPrompts(), { suspense: true })\n\n  const savePrompt = useCallback(\n    async (prompt: Prompt) => {\n      const existed = await saveLocalPrompt(prompt)\n      localPromptsQuery.mutate()\n      setFormData(null)\n      trackEvent(existed ? 'edit_local_prompt' : 'add_local_prompt')\n    },\n    [localPromptsQuery],\n  )\n\n  const removePrompt = useCallback(\n    async (id: string) => {\n      await removeLocalPrompt(id)\n      localPromptsQuery.mutate()\n      trackEvent('remove_local_prompt')\n    },\n    [localPromptsQuery],\n  )\n\n  const create = useCallback(() => {\n    setFormData({ id: uuid(), title: '', prompt: '' })\n  }, [])\n\n  return (\n    <>\n      {localPromptsQuery.data.length ? (\n        <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 pt-2\">\n          {localPromptsQuery.data.map((prompt) => (\n            <PromptItem\n              key={prompt.id}\n              title={prompt.title}\n              prompt={prompt.prompt}\n              edit={() => !formData && setFormData(prompt)}\n              remove={() => removePrompt(prompt.id)}\n              insertPrompt={props.insertPrompt}\n            />\n          ))}\n        </div>\n      ) : (\n        <div className=\"relative block w-full rounded-lg border-2 border-dashed border-gray-300 p-3 text-center text-sm mt-5 text-primary-text\">\n          You have no prompts.\n        </div>\n      )}\n      <div className=\"mt-5\">\n        {formData ? (\n          <PromptForm initialData={formData} onSubmit={savePrompt} onClose={() => setFormData(null)} />\n        ) : (\n          <Button text={t('Create new prompt')} size=\"small\" onClick={create} />\n        )}\n      </div>\n    </>\n  )\n}\n\nfunction CommunityPrompts(props: { insertPrompt: (text: string) => void }) {\n  const promptsQuery = useSWR('community-prompts', () => loadRemotePrompts(), { suspense: true })\n\n  const copyToLocal = useCallback(async (prompt: Prompt) => {\n    await saveLocalPrompt({ ...prompt, id: uuid() })\n  }, [])\n\n  return (\n    <>\n      <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 pt-2\">\n        {promptsQuery.data.map((prompt, index) => (\n          <PromptItem\n            key={index}\n            title={prompt.title}\n            prompt={prompt.prompt}\n            insertPrompt={props.insertPrompt}\n            copyToLocal={() => copyToLocal(prompt)}\n          />\n        ))}\n      </div>\n      <span className=\"text-sm mt-5 block text-primary-text\">\n        Contribute on{' '}\n        <a\n          href=\"https://github.com/chathub-dev/community-prompts\"\n          target=\"_blank\"\n          rel=\"noreferrer\"\n          className=\"underline\"\n        >\n          GitHub\n        </a>{' '}\n        or{' '}\n        <a href=\"https://openprompt.co/?utm_source=chathub\" target=\"_blank\" rel=\"noreferrer\" className=\"underline\">\n          OpenPrompt\n        </a>\n      </span>\n    </>\n  )\n}\n\nconst PromptLibrary = (props: { insertPrompt: (text: string) => void }) => {\n  const { t } = useTranslation()\n\n  const insertPrompt = useCallback(\n    (text: string) => {\n      props.insertPrompt(text)\n      trackEvent('use_prompt')\n    },\n    [props],\n  )\n\n  const tabs = useMemo<Tab[]>(\n    () => [\n      { name: t('Your Prompts'), value: 'local' },\n      { name: t('Community Prompts'), value: 'community' },\n    ],\n    [t],\n  )\n\n  return (\n    <Tabs\n      tabs={tabs}\n      renderTab={(tab: (typeof tabs)[0]['value']) => {\n        if (tab === 'local') {\n          return (\n            <Suspense fallback={<BeatLoader size={10} className=\"mt-5\" color=\"rgb(var(--primary-text))\" />}>\n              <LocalPrompts insertPrompt={insertPrompt} />\n            </Suspense>\n          )\n        }\n        if (tab === 'community') {\n          return (\n            <Suspense fallback={<BeatLoader size={10} className=\"mt-5\" color=\"rgb(var(--primary-text))\" />}>\n              <CommunityPrompts insertPrompt={insertPrompt} />\n            </Suspense>\n          )\n        }\n      }}\n    />\n  )\n}\n\nexport default PromptLibrary\n"
  },
  {
    "path": "src/app/components/RadioGroup.tsx",
    "content": "import { FC, useId } from 'react'\n\ninterface Option {\n  label: string\n  value: string\n}\n\nconst RadioItem = (props: { option: Option; checked: boolean; onChange: (v: string) => void }) => {\n  const id = useId()\n  return (\n    <div className=\"flex items-center\">\n      <input\n        id={id}\n        type=\"radio\"\n        checked={props.checked}\n        className=\"h-4 w-4 border-gray-300 text-indigo-600 focus:ring-indigo-600\"\n        value={props.option.value}\n        onChange={(e) => props.onChange(e.currentTarget.value)}\n      />\n      <label htmlFor={id} className=\"ml-2 block text-sm font-medium leading-6\">\n        {props.option.label}\n      </label>\n    </div>\n  )\n}\n\ninterface Props {\n  options: Option[]\n  value: string\n  onChange: (v: string) => void\n}\n\nconst RadioGroup: FC<Props> = (props) => {\n  return (\n    <div className=\"space-y-4 sm:flex sm:items-center sm:space-y-0 sm:space-x-3 mb-1\">\n      {props.options.map((option) => (\n        <RadioItem\n          key={option.value}\n          option={option}\n          checked={option.value === props.value}\n          onChange={props.onChange}\n        />\n      ))}\n    </div>\n  )\n}\n\nexport default RadioGroup\n"
  },
  {
    "path": "src/app/components/Select.tsx",
    "content": "import { Listbox, Transition } from '@headlessui/react'\nimport { CheckIcon, ChevronUpDownIcon } from '@heroicons/react/20/solid'\nimport { cx } from '~/utils'\nimport { Fragment, useMemo } from 'react'\n\ninterface Props<T> {\n  options: { value: T; name: string }[]\n  value: T\n  onChange: (value: T) => void\n  size?: 'normal' | 'small'\n  disabled?: boolean\n  position?: 'top' | 'down'\n}\n\nfunction Select<T extends string>(props: Props<T>) {\n  const { options, value, onChange, size = 'normal', disabled, position = 'down' } = props\n  const selectedName = useMemo(() => options.find((o) => o.value === value)!.name, [options, value])\n  return (\n    <Listbox value={value} onChange={onChange} disabled={disabled}>\n      {({ open }) => (\n        <>\n          <div className=\"relative\">\n            <Listbox.Button\n              className={cx(\n                'relative w-full cursor-default rounded-md bg-white pl-3 pr-10 text-left text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 focus:outline-none leading-6',\n                size === 'normal' ? 'text-sm py-1.5' : 'text-xs py-1',\n                disabled && 'cursor-not-allowed opacity-50',\n              )}\n            >\n              <span className=\"block truncate\">{selectedName}</span>\n              <span className=\"pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2\">\n                <ChevronUpDownIcon className=\"h-5 w-5 text-gray-400\" aria-hidden=\"true\" />\n              </span>\n            </Listbox.Button>\n            <Transition\n              show={open}\n              as={Fragment}\n              leave=\"transition ease-in duration-100\"\n              leaveFrom=\"opacity-100\"\n              leaveTo=\"opacity-0\"\n            >\n              <Listbox.Options\n                className={cx(\n                  'absolute z-10 mt-1 max-h-60 w-full overflow-auto rounded-md bg-white py-1 text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none',\n                  size === 'normal' ? 'text-sm' : 'text-xs',\n                  position === 'top' && 'bottom-full',\n                )}\n              >\n                {options.map((option) => (\n                  <Listbox.Option\n                    key={option.value}\n                    className={({ active }) =>\n                      cx(\n                        active ? 'bg-primary-blue text-white' : 'text-[#303030]',\n                        'relative cursor-default select-none py-2 pl-3 pr-9',\n                      )\n                    }\n                    value={option.value}\n                  >\n                    {({ selected, active }) => (\n                      <>\n                        <span className={cx(selected ? 'font-semibold' : 'font-normal', 'block truncate')}>\n                          {option.name}\n                        </span>\n                        {selected ? (\n                          <span\n                            className={cx(\n                              active ? 'text-white' : 'text-[#303030]',\n                              'absolute inset-y-0 right-0 flex items-center pr-4',\n                            )}\n                          >\n                            <CheckIcon className=\"h-5 w-5\" aria-hidden=\"true\" />\n                          </span>\n                        ) : null}\n                      </>\n                    )}\n                  </Listbox.Option>\n                ))}\n              </Listbox.Options>\n            </Transition>\n          </div>\n        </>\n      )}\n    </Listbox>\n  )\n}\n\nexport default Select\n"
  },
  {
    "path": "src/app/components/Settings/Blockquote.tsx",
    "content": "import { FC, PropsWithChildren } from 'react'\nimport { cx } from '~utils'\n\nconst Blockquote: FC<PropsWithChildren<{ className?: string }>> = (props) => {\n  return (\n    <blockquote className={cx('text-sm border-l-4 border-gray-300 pl-2 italic', props.className)}>\n      {props.children}\n    </blockquote>\n  )\n}\n\nexport default Blockquote\n"
  },
  {
    "path": "src/app/components/Settings/ChatGPTAPISettings.tsx",
    "content": "import { FC } from 'react'\nimport { useTranslation } from 'react-i18next'\nimport { CHATGPT_API_MODELS, DEFAULT_CHATGPT_SYSTEM_MESSAGE } from '~app/consts'\nimport { UserConfig } from '~services/user-config'\nimport { Input, Textarea } from '../Input'\nimport Select from '../Select'\nimport Blockquote from './Blockquote'\n\ninterface Props {\n  userConfig: UserConfig\n  updateConfigValue: (update: Partial<UserConfig>) => void\n}\n\nconst ChatGPTAPISettings: FC<Props> = ({ userConfig, updateConfigValue }) => {\n  const { t } = useTranslation()\n  return (\n    <div className=\"flex flex-col gap-2 w-[400px]\">\n      <div className=\"flex flex-col gap-1\">\n        <p className=\"font-medium text-sm\">API Key</p>\n        <Input\n          placeholder=\"sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\"\n          value={userConfig.openaiApiKey}\n          onChange={(e) => updateConfigValue({ openaiApiKey: e.currentTarget.value })}\n          type=\"password\"\n        />\n        <Blockquote className=\"mt-1\">{t('Your keys are stored locally')}</Blockquote>\n      </div>\n      <div className=\"flex flex-col gap-1\">\n        <p className=\"font-medium text-sm\">API Host</p>\n        <Input\n          placeholder=\"https://api.openai.com\"\n          value={userConfig.openaiApiHost}\n          onChange={(e) => updateConfigValue({ openaiApiHost: e.currentTarget.value })}\n        />\n      </div>\n      <div className=\"flex flex-col gap-1\">\n        <p className=\"font-medium text-sm\">API Model</p>\n        <Select\n          options={CHATGPT_API_MODELS.map((m) => ({ name: m, value: m }))}\n          value={userConfig.chatgptApiModel}\n          onChange={(v) => updateConfigValue({ chatgptApiModel: v })}\n        />\n      </div>\n      <div className=\"flex flex-col gap-1\">\n        <p className=\"font-medium text-sm\">System Message</p>\n        <Textarea\n          maxRows={3}\n          value={userConfig.chatgptApiSystemMessage || DEFAULT_CHATGPT_SYSTEM_MESSAGE}\n          onChange={(e) => updateConfigValue({ chatgptApiSystemMessage: e.currentTarget.value })}\n        />\n      </div>\n    </div>\n  )\n}\n\nexport default ChatGPTAPISettings\n"
  },
  {
    "path": "src/app/components/Settings/ChatGPTAzureSettings.tsx",
    "content": "import { FC } from 'react'\nimport { UserConfig } from '~services/user-config'\nimport { Input } from '../Input'\n\ninterface Props {\n  userConfig: UserConfig\n  updateConfigValue: (update: Partial<UserConfig>) => void\n}\n\nconst ChatGPTAzureSettings: FC<Props> = ({ userConfig, updateConfigValue }) => {\n  return (\n    <div className=\"flex flex-col gap-3\">\n      <div className=\"flex flex-col gap-1\">\n        <p className=\"font-medium text-sm\">Azure Instance Name</p>\n        <Input\n          className=\"w-[300px]\"\n          value={userConfig.azureOpenAIApiInstanceName}\n          onChange={(e) => updateConfigValue({ azureOpenAIApiInstanceName: e.currentTarget.value.trim() })}\n        />\n      </div>\n      <div className=\"flex flex-col gap-1\">\n        <p className=\"font-medium text-sm\">Azure API Key</p>\n        <Input\n          className=\"w-[300px]\"\n          value={userConfig.azureOpenAIApiKey}\n          onChange={(e) => updateConfigValue({ azureOpenAIApiKey: e.currentTarget.value.trim() })}\n          type=\"password\"\n        />\n      </div>\n      <div className=\"flex flex-col gap-1\">\n        <p className=\"font-medium text-sm\">Azure Deployment Name</p>\n        <Input\n          className=\"w-[300px]\"\n          value={userConfig.azureOpenAIApiDeploymentName}\n          onChange={(e) => updateConfigValue({ azureOpenAIApiDeploymentName: e.currentTarget.value.trim() })}\n        />\n      </div>\n    </div>\n  )\n}\n\nexport default ChatGPTAzureSettings\n"
  },
  {
    "path": "src/app/components/Settings/ChatGPTOpenRouterSettings.tsx",
    "content": "import { FC } from 'react'\nimport { CHATGPT_API_MODELS } from '~app/consts'\nimport { UserConfig } from '~services/user-config'\nimport { Input } from '../Input'\nimport Select from '../Select'\n\ninterface Props {\n  userConfig: UserConfig\n  updateConfigValue: (update: Partial<UserConfig>) => void\n}\n\nconst ChatGPTOpenRouterSettings: FC<Props> = ({ userConfig, updateConfigValue }) => {\n  return (\n    <div className=\"flex flex-col gap-2 w-[300px]\">\n      <div className=\"flex flex-col gap-1\">\n        <p className=\"font-medium text-sm\">\n          API Key (\n          <a href=\"https://openrouter.ai/keys\" target=\"_blank\" rel=\"noreferrer\" className=\"underline\">\n            create key here\n          </a>\n          )\n        </p>\n        <Input\n          placeholder=\"sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\"\n          value={userConfig.openrouterApiKey}\n          onChange={(e) => updateConfigValue({ openrouterApiKey: e.currentTarget.value })}\n          type=\"password\"\n        />\n      </div>\n      <div className=\"flex flex-col gap-1\">\n        <p className=\"font-medium text-sm\">API Model</p>\n        <Select\n          options={CHATGPT_API_MODELS.map((m) => ({ name: m, value: m }))}\n          value={userConfig.openrouterOpenAIModel}\n          onChange={(v) => updateConfigValue({ openrouterOpenAIModel: v })}\n        />\n      </div>\n    </div>\n  )\n}\n\nexport default ChatGPTOpenRouterSettings\n"
  },
  {
    "path": "src/app/components/Settings/ChatGPTPoeSettings.tsx",
    "content": "import { FC } from 'react'\nimport { useTranslation } from 'react-i18next'\nimport { PoeGPTModel, UserConfig } from '~services/user-config'\nimport Select from '../Select'\n\ninterface Props {\n  userConfig: UserConfig\n  updateConfigValue: (update: Partial<UserConfig>) => void\n}\n\nconst ChatGPTPoeSettings: FC<Props> = ({ userConfig, updateConfigValue }) => {\n  const { t } = useTranslation()\n  return (\n    <div className=\"flex flex-col gap-1\">\n      <p className=\"font-medium text-sm\">{t('Model')}</p>\n      <div className=\"w-[250px] mb-1\">\n        <Select\n          options={Object.entries(PoeGPTModel).map(([k, v]) => ({ name: k, value: v }))}\n          value={userConfig.chatgptPoeModelName}\n          onChange={(v) => updateConfigValue({ chatgptPoeModelName: v })}\n        />\n      </div>\n      {userConfig.chatgptPoeModelName === PoeGPTModel['GPT-4'] && (\n        <p className=\"text-sm text-secondary-text\">{t('Poe subscribers only')}</p>\n      )}\n    </div>\n  )\n}\n\nexport default ChatGPTPoeSettings\n"
  },
  {
    "path": "src/app/components/Settings/ChatGPTWebSettings.tsx",
    "content": "import { FC } from 'react'\nimport { useTranslation } from 'react-i18next'\nimport { ChatGPTWebModel, UserConfig } from '~services/user-config'\nimport Select from '../Select'\nimport Blockquote from './Blockquote'\n\ninterface Props {\n  userConfig: UserConfig\n  updateConfigValue: (update: Partial<UserConfig>) => void\n}\n\nconst ChatGPWebSettings: FC<Props> = ({ userConfig, updateConfigValue }) => {\n  const { t } = useTranslation()\n  return (\n    <div className=\"flex flex-col gap-1\">\n      <Blockquote className=\"mb-1\">{t('Webapp mode uses your login session in current browser')}</Blockquote>\n      <p className=\"font-medium text-sm\">{t('Model')}</p>\n      <div className=\"w-[250px] mb-1\">\n        <Select\n          options={Object.entries(ChatGPTWebModel).map(([k, v]) => ({ name: k, value: v }))}\n          value={userConfig.chatgptWebappModelName}\n          onChange={(v) => updateConfigValue({ chatgptWebappModelName: v })}\n        />\n      </div>\n      {userConfig.chatgptWebappModelName.startsWith('gpt-4') && (\n        <p className=\"text-sm text-secondary-text\">{t('GPT-4 models require ChatGPT Plus')}</p>\n      )}\n    </div>\n  )\n}\n\nexport default ChatGPWebSettings\n"
  },
  {
    "path": "src/app/components/Settings/ClaudeAPISettings.tsx",
    "content": "import { FC } from 'react'\nimport { useTranslation } from 'react-i18next'\nimport { ClaudeAPIModel, UserConfig } from '~services/user-config'\nimport { Input } from '../Input'\nimport Select from '../Select'\nimport Blockquote from './Blockquote'\n\ninterface Props {\n  userConfig: UserConfig\n  updateConfigValue: (update: Partial<UserConfig>) => void\n}\n\nconst ClaudeAPISettings: FC<Props> = ({ userConfig, updateConfigValue }) => {\n  const { t } = useTranslation()\n  return (\n    <div className=\"flex flex-col gap-2 w-[400px]\">\n      <div className=\"flex flex-col gap-1\">\n        <p className=\"font-medium text-sm\">API Key</p>\n        <Input\n          placeholder=\"sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\"\n          value={userConfig.claudeApiKey}\n          onChange={(e) => updateConfigValue({ claudeApiKey: e.currentTarget.value })}\n          type=\"password\"\n        />\n        <Blockquote className=\"mt-1\">{t('Your keys are stored locally')}</Blockquote>\n      </div>\n      <div className=\"flex flex-col gap-1\">\n        <p className=\"font-medium text-sm\">{t('API Model')}</p>\n        <Select\n          options={Object.entries(ClaudeAPIModel).map(([k, v]) => ({ name: k, value: v }))}\n          value={userConfig.claudeApiModel}\n          onChange={(v) => updateConfigValue({ claudeApiModel: v })}\n        />\n      </div>\n    </div>\n  )\n}\n\nexport default ClaudeAPISettings\n"
  },
  {
    "path": "src/app/components/Settings/ClaudeOpenRouterSettings.tsx",
    "content": "import { FC } from 'react'\nimport { useTranslation } from 'react-i18next'\nimport { OpenRouterClaudeModel, UserConfig } from '~services/user-config'\nimport { Input } from '../Input'\nimport Select from '../Select'\n\ninterface Props {\n  userConfig: UserConfig\n  updateConfigValue: (update: Partial<UserConfig>) => void\n}\n\nconst ClaudeOpenRouterSettings: FC<Props> = ({ userConfig, updateConfigValue }) => {\n  const { t } = useTranslation()\n  return (\n    <div className=\"flex flex-col gap-2 w-[300px]\">\n      <div className=\"flex flex-col gap-1\">\n        <p className=\"font-medium text-sm\">\n          API Key (\n          <a href=\"https://openrouter.ai/keys\" target=\"_blank\" rel=\"noreferrer\" className=\"underline\">\n            create key here\n          </a>\n          )\n        </p>\n        <Input\n          placeholder=\"sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\"\n          value={userConfig.openrouterApiKey}\n          onChange={(e) => updateConfigValue({ openrouterApiKey: e.currentTarget.value })}\n          type=\"password\"\n        />\n      </div>\n      <div className=\"flex flex-col gap-1\">\n        <p className=\"font-medium text-sm\">{t('Model')}</p>\n        <Select\n          options={Object.entries(OpenRouterClaudeModel).map(([k, v]) => ({ name: k, value: v }))}\n          value={userConfig.openrouterClaudeModel}\n          onChange={(v) => updateConfigValue({ openrouterClaudeModel: v })}\n        />\n      </div>\n    </div>\n  )\n}\n\nexport default ClaudeOpenRouterSettings\n"
  },
  {
    "path": "src/app/components/Settings/ClaudePoeSettings.tsx",
    "content": "import { FC } from 'react'\nimport { useTranslation } from 'react-i18next'\nimport { PoeClaudeModel, UserConfig } from '~services/user-config'\nimport Select from '../Select'\n\ninterface Props {\n  userConfig: UserConfig\n  updateConfigValue: (update: Partial<UserConfig>) => void\n}\n\nconst ClaudePoeSettings: FC<Props> = ({ userConfig, updateConfigValue }) => {\n  const { t } = useTranslation()\n  return (\n    <div className=\"flex flex-col gap-1\">\n      <p className=\"font-medium text-sm\">{t('Model')}</p>\n      <div className=\"w-[250px] mb-1\">\n        <Select\n          options={Object.entries(PoeClaudeModel).map(([k, v]) => ({ name: k, value: v }))}\n          value={userConfig.poeModel}\n          onChange={(v) => updateConfigValue({ poeModel: v })}\n        />\n      </div>\n      {userConfig.poeModel === PoeClaudeModel['claude-2-100k'] && (\n        <p className=\"text-sm mt-1 text-secondary-text\">{t('Limited Access')}</p>\n      )}\n      {userConfig.poeModel === PoeClaudeModel['claude-instant-100k'] && (\n        <p className=\"text-sm mt-1 text-secondary-text\">{t('Poe subscribers only')}</p>\n      )}\n    </div>\n  )\n}\n\nexport default ClaudePoeSettings\n"
  },
  {
    "path": "src/app/components/Settings/ClaudeWebappSettings.tsx",
    "content": "import { FC } from 'react'\nimport { useTranslation } from 'react-i18next'\nimport { UserConfig } from '~services/user-config'\nimport Select from '../Select'\nimport Blockquote from './Blockquote'\n\ninterface Props {\n  userConfig: UserConfig\n  updateConfigValue: (update: Partial<UserConfig>) => void\n}\n\nconst ClaudeWebappSettings: FC<Props> = () => {\n  const { t } = useTranslation()\n  return (\n    <div className=\"flex flex-col gap-1\">\n      <Blockquote className=\"mb-1\">{t('Webapp mode uses your login session in current browser')}</Blockquote>\n      <p className=\"font-medium text-sm\">{t('Model')}</p>\n      <div className=\"w-[250px] mb-1\">\n        <Select options={[{ name: 'Claude 2', value: 'claude-2' }]} value=\"claude-2\" onChange={console.log} />\n      </div>\n    </div>\n  )\n}\n\nexport default ClaudeWebappSettings\n"
  },
  {
    "path": "src/app/components/Settings/EnabledBotsSettings.tsx",
    "content": "import { FC, useCallback } from 'react'\nimport { BotId } from '~app/bots'\nimport { CHATBOTS } from '~app/consts'\nimport { UserConfig } from '~services/user-config'\n\ninterface Props {\n  userConfig: UserConfig\n  updateConfigValue: (update: Partial<UserConfig>) => void\n}\n\nconst EnabledBotsSettings: FC<Props> = ({ userConfig, updateConfigValue }) => {\n  const updateStatus = useCallback(\n    (botId: BotId, enabled: boolean) => {\n      const bots = new Set(userConfig.enabledBots)\n      if (enabled) {\n        bots.add(botId)\n      } else {\n        if (bots.size === 1) {\n          alert('At least one bot should be enabled')\n          return\n        } else {\n          bots.delete(botId)\n        }\n      }\n      updateConfigValue({ enabledBots: Array.from(bots) })\n    },\n    [updateConfigValue, userConfig.enabledBots],\n  )\n\n  return (\n    <div className=\"flex flex-row gap-3 flex-wrap max-w-[720px]\">\n      {Object.entries(CHATBOTS).map(([botId, bot]) => {\n        const enabled = userConfig.enabledBots.includes(botId as BotId)\n        return (\n          <div className=\"flex flex-row gap-[6px]\" key={botId}>\n            <input\n              type=\"checkbox\"\n              id={`bot-checkbox-${botId}`}\n              checked={enabled}\n              onChange={(e) => updateStatus(botId as BotId, e.target.checked)}\n            />\n            <label htmlFor={`bot-checkbox-${botId}`} className=\"font-medium text-sm\">\n              {bot.name}\n            </label>\n          </div>\n        )\n      })}\n    </div>\n  )\n}\n\nexport default EnabledBotsSettings\n"
  },
  {
    "path": "src/app/components/Settings/ExportDataPanel.tsx",
    "content": "import { useTranslation } from 'react-i18next'\nimport { BiExport, BiImport } from 'react-icons/bi'\nimport { exportData, importData } from '~app/utils/export'\nimport Button from '../Button'\n\nfunction ExportDataPanel() {\n  const { t } = useTranslation()\n  return (\n    <div>\n      <p className=\"font-bold mb-1 text-lg\">{t('Export/Import All Data')}</p>\n      <p className=\"mb-3 opacity-80\">{t('Data includes all your settings, chat histories, and local prompts')}</p>\n      <div className=\"flex flex-row gap-3\">\n        <Button size=\"small\" text={t('Export')} icon={<BiExport />} onClick={exportData} />\n        <Button size=\"small\" text={t('Import')} icon={<BiImport />} onClick={importData} />\n      </div>\n    </div>\n  )\n}\n\nexport default ExportDataPanel\n"
  },
  {
    "path": "src/app/components/Settings/KDB.tsx",
    "content": "export default function KDB(props: { text: string }) {\n  return (\n    <kbd className=\"px-2 py-1.5 text-sm font-semibold text-gray-800 bg-gray-100 border border-gray-200 rounded-lg dark:bg-gray-600 dark:text-gray-100 dark:border-gray-500\">\n      {props.text}\n    </kbd>\n  )\n}\n"
  },
  {
    "path": "src/app/components/Settings/PerplexityAPISettings.tsx",
    "content": "import { FC } from 'react'\nimport { useTranslation } from 'react-i18next'\nimport { UserConfig } from '~services/user-config'\nimport { Input } from '../Input'\nimport Blockquote from './Blockquote'\n\ninterface Props {\n  userConfig: UserConfig\n  updateConfigValue: (update: Partial<UserConfig>) => void\n}\n\nconst PerplexityAPISettings: FC<Props> = ({ userConfig, updateConfigValue }) => {\n  const { t } = useTranslation()\n  return (\n    <div className=\"flex flex-col gap-2\">\n      <div className=\"flex flex-col gap-1\">\n        <p className=\"font-medium text-sm\">\n          API Key (\n          <a\n            href=\"https://docs.perplexity.ai/docs/getting-started\"\n            target=\"_blank\"\n            rel=\"noreferrer\"\n            className=\"underline\"\n          >\n            how to create key\n          </a>\n          )\n        </p>\n        <Input\n          className=\"w-[300px]\"\n          placeholder=\"pplx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\"\n          value={userConfig.perplexityApiKey}\n          onChange={(e) => updateConfigValue({ perplexityApiKey: e.currentTarget.value })}\n          type=\"password\"\n        />\n        <Blockquote className=\"mt-1\">{t('Your keys are stored locally')}</Blockquote>\n      </div>\n    </div>\n  )\n}\n\nexport default PerplexityAPISettings\n"
  },
  {
    "path": "src/app/components/Settings/ShortcutPanel.tsx",
    "content": "import { useEffect, useState } from 'react'\nimport { useTranslation } from 'react-i18next'\nimport Browser from 'webextension-polyfill'\nimport Button from '~app/components/Button'\nimport KDB from '~app/components/Settings/KDB'\n\nfunction ShortcutPanel() {\n  const [shortcuts, setShortcuts] = useState<string[]>([])\n  const { t } = useTranslation()\n\n  useEffect(() => {\n    Browser.commands.getAll().then((commands) => {\n      for (const c of commands) {\n        if (c.name === 'open-app' && c.shortcut) {\n          console.debug(c.shortcut)\n          setShortcuts(c.shortcut ? [c.shortcut] : [])\n        }\n      }\n    })\n  }, [])\n\n  return (\n    <div className=\"flex flex-col gap-2\">\n      <p className=\"font-bold text-lg\">{t('Shortcut to open this app')}</p>\n      <div className=\"flex flex-row gap-2 items-center\">\n        {shortcuts.length > 0 && (\n          <div className=\"flex flex-row gap-1\">\n            {shortcuts.map((s) => (\n              <KDB key={s} text={s} />\n            ))}\n          </div>\n        )}\n        <Button\n          text={t('Change shortcut')}\n          size=\"small\"\n          onClick={() => Browser.tabs.create({ url: 'chrome://extensions/shortcuts' })}\n        />\n      </div>\n    </div>\n  )\n}\n\nexport default ShortcutPanel\n"
  },
  {
    "path": "src/app/components/Share/Dialog.tsx",
    "content": "import { useState } from 'react'\nimport { cx } from '~/utils'\nimport { AiFillCloud, AiFillFileMarkdown } from 'react-icons/ai'\nimport { ChatMessageModel } from '~types'\nimport Button from '../Button'\nimport Dialog from '../Dialog'\nimport MarkdownView from './MarkdownView'\nimport ShareGPTView from './ShareGPTView'\n\ninterface Props {\n  open: boolean\n  onClose: () => void\n  messages: ChatMessageModel[]\n}\n\nconst ShareDialog = (props: Props) => {\n  const [mode, setMode] = useState<'markdown' | 'sharegpt' | undefined>()\n  return (\n    <Dialog\n      title=\"Share Chat\"\n      open={props.open}\n      onClose={props.onClose}\n      className={cx('rounded-xl', mode ? 'w-[800px] h-[400px]' : 'w-[600px] h-[250px]')}\n    >\n      {(() => {\n        if (mode === 'markdown') {\n          return <MarkdownView messages={props.messages} />\n        }\n        if (mode === 'sharegpt') {\n          return <ShareGPTView messages={props.messages} />\n        }\n        return (\n          <div className=\"flex flex-col gap-5 justify-center items-center p-5 h-full\">\n            <Button\n              text=\"Markdown\"\n              color=\"primary\"\n              icon={<AiFillFileMarkdown className=\"mr-1\" />}\n              onClick={() => setMode('markdown')}\n            />\n            <Button\n              text=\"ShareGPT\"\n              color=\"primary\"\n              icon={<AiFillCloud className=\"mr-1\" />}\n              onClick={() => setMode('sharegpt')}\n            />\n          </div>\n        )\n      })()}\n    </Dialog>\n  )\n}\n\nexport default ShareDialog\n"
  },
  {
    "path": "src/app/components/Share/MarkdownView.tsx",
    "content": "import { FC, useCallback, useMemo, useState } from 'react'\nimport { trackEvent } from '~app/plausible'\nimport { ChatMessageModel } from '~types'\nimport Button from '../Button'\n\ninterface Props {\n  messages: ChatMessageModel[]\n}\n\nconst MarkdownView: FC<Props> = ({ messages }) => {\n  const [copied, setCopied] = useState(false)\n\n  const content = useMemo(() => {\n    return messages\n      .filter((m) => !!m.text)\n      .map((m) => `**${m.author}**: ` + m.text)\n      .join('\\n\\n')\n  }, [messages])\n\n  const copy = useCallback(() => {\n    navigator.clipboard.writeText(content)\n    setCopied(true)\n    setTimeout(() => setCopied(false), 500)\n    trackEvent('share_chat_copy_markdown')\n  }, [content])\n\n  return (\n    <div className=\"px-5 pt-3 pb-4 overflow-hidden flex flex-col h-full\">\n      <div className=\"mb-3\">\n        <Button size=\"small\" text={copied ? 'Copied!' : 'Copy'} onClick={copy} />\n      </div>\n      <pre className=\"text-sm whitespace-pre-wrap text-primary-text p-2 rounded-md overflow-auto h-full bg-secondary\">\n        {content}\n      </pre>\n    </div>\n  )\n}\n\nexport default MarkdownView\n"
  },
  {
    "path": "src/app/components/Share/ShareGPTView.tsx",
    "content": "import { FC, useCallback, useState } from 'react'\nimport { trackEvent } from '~app/plausible'\nimport { ChatMessageModel } from '~types'\nimport Button from '../Button'\nimport { Input } from '../Input'\nimport { uploadToShareGPT } from './sharegpt'\n\ninterface Props {\n  messages: ChatMessageModel[]\n}\n\nconst ShareGPTView: FC<Props> = ({ messages }) => {\n  const [uploading, setUploading] = useState(false)\n  const [resultId, setResultId] = useState<string | undefined>(undefined)\n  const [copied, setCopied] = useState(false)\n\n  const upload = useCallback(async () => {\n    setUploading(true)\n    trackEvent('share_chat_sharegpt')\n    try {\n      const id = await uploadToShareGPT(messages)\n      setResultId(id)\n    } finally {\n      setUploading(false)\n    }\n  }, [messages])\n\n  const copy = useCallback(() => {\n    navigator.clipboard.writeText(`https://shareg.pt/${resultId}`)\n    setCopied(true)\n    setTimeout(() => setCopied(false), 500)\n  }, [resultId])\n\n  return (\n    <div className=\"p-5 flex flex-col items-center justify-center gap-5 h-full\">\n      <p className=\"w-[400px] text-center text-primary-text\">\n        This will upload this conversation to <b>sharegpt.com</b> and generate a link to share <b>publicly</b>.\n      </p>\n      {resultId ? (\n        <div className=\"flex flex-row items-center gap-3 w-[300px]\">\n          <Input value={`https://shareg.pt/${resultId}`} readOnly className=\"grow\" />\n          <Button size=\"small\" color=\"primary\" text={copied ? 'Copied' : 'Copy'} onClick={copy} />\n        </div>\n      ) : (\n        <Button text=\"Share\" color=\"primary\" onClick={upload} isLoading={uploading} />\n      )}\n    </div>\n  )\n}\n\nexport default ShareGPTView\n"
  },
  {
    "path": "src/app/components/Share/sharegpt.ts",
    "content": "import { ofetch } from 'ofetch'\nimport rehypeStringify from 'rehype-stringify'\nimport remarkGfm from 'remark-gfm'\nimport remarkParse from 'remark-parse'\nimport remarkRehype from 'remark-rehype'\nimport supersub from 'remark-supersub'\nimport { unified } from 'unified'\nimport { ChatMessageModel } from '~types'\n\nconst USER_AVATAR_URI =\n  \"data:image/svg+xml,%3C%3Fxml version='1.0' encoding='UTF-8'%3F%3E%3Csvg viewBox='0 0 128 128' version='1.1' xmlns='http://www.w3.org/2000/svg' role='img' aria-label='xxlarge'%3E%3Cg%3E%3Ccircle cx='64' cy='64' r='64' fill='%23c1c7d0' /%3E%3Cg%3E%3Cpath fill='%23fff' d='M103,102.1388 C93.094,111.92 79.3504,118 64.1638,118 C48.8056,118 34.9294,111.768 25,101.7892 L25,95.2 C25,86.8096 31.981,80 40.6,80 L87.4,80 C96.019,80 103,86.8096 103,95.2 L103,102.1388 Z' /%3E%3Cpath fill='%23fff' d='M63.9961647,24 C51.2938136,24 41,34.2938136 41,46.9961647 C41,59.7061864 51.2938136,70 63.9961647,70 C76.6985159,70 87,59.7061864 87,46.9961647 C87,34.2938136 76.6985159,24 63.9961647,24' /%3E%3C/g%3E%3C/g%3E%3C/svg%3E%0A\"\n\ninterface ShareGPTItem {\n  from: string\n  value: string\n}\n\nasync function markdown2html(markdown: string) {\n  const file = await unified()\n    .use(remarkParse)\n    .use(supersub)\n    .use(remarkGfm)\n    .use(remarkRehype)\n    .use(rehypeStringify)\n    .process(markdown)\n  return String(file)\n}\n\nasync function buildItems(messages: ChatMessageModel[]): Promise<ShareGPTItem[]> {\n  const items = [\n    {\n      from: 'system',\n      value:\n        '<div><small><i>This conversation is shared from <a href=\"https://chathub.gg\"><b>ChatHub</b></a></i></small></div>',\n    },\n  ]\n  for (const m of messages) {\n    if (m.text) {\n      items.push({\n        from: m.author === 'user' ? 'human' : m.author,\n        value: m.author === 'user' ? m.text : await markdown2html(m.text),\n      })\n    }\n  }\n  return items\n}\n\nexport async function uploadToShareGPT(messages: ChatMessageModel[]) {\n  const items = await buildItems(messages)\n  const resp = await ofetch('https://sharegpt.com/api/conversations', {\n    method: 'POST',\n    body: {\n      avatarUrl: USER_AVATAR_URI,\n      items,\n    },\n  })\n  return resp.id as string\n}\n"
  },
  {
    "path": "src/app/components/Sidebar/NavLink.tsx",
    "content": "import { Link, LinkOptions } from '@tanstack/react-router'\nimport { cx } from '~/utils'\n\nfunction NavLink(props: LinkOptions & { text: string; icon: any; iconOnly?: boolean }) {\n  const { text, icon, iconOnly, ...linkProps } = props\n  return (\n    <Link\n      className={cx(\n        'rounded-[10px] w-full pl-3 flex flex-row gap-3 items-center shrink-0 py-[11px]',\n        iconOnly && 'justify-center',\n      )}\n      activeOptions={{ exact: true }}\n      activeProps={{ className: 'bg-white text-primary-text dark:bg-primary-blue' }}\n      inactiveProps={{\n        className: 'bg-secondary bg-opacity-20 text-primary-text opacity-80 hover:opacity-100',\n      }}\n      title={text}\n      {...linkProps}\n    >\n      <img src={icon} className=\"w-5 h-5\" />\n      {<span className=\"font-medium text-sm\">{iconOnly ? '' : text}</span>}\n    </Link>\n  )\n}\n\nexport default NavLink\n"
  },
  {
    "path": "src/app/components/Sidebar/PremiumEntry.tsx",
    "content": "import { motion } from 'framer-motion'\nimport { Link } from '@tanstack/react-router'\nimport { FC } from 'react'\nimport premiumIcon from '~assets/icons/premium.svg'\n\nconst PremiumEntry: FC<{ text: string }> = ({ text }) => {\n  return (\n    <Link to=\"/premium\">\n      <motion.div\n        className=\"flex flex-row items-center gap-[10px] rounded-[10px] px-4 py-[6px] cursor-pointer\"\n        style={{\n          background:\n            'linear-gradient(to left, rgb(var(--color-primary-purple)) 1.65%, rgb(var(--color-primary-blue)) 100%)',\n        }}\n        whileHover=\"hover\"\n      >\n        <motion.img\n          src={premiumIcon}\n          className=\"w-8 h-8\"\n          variants={{\n            hover: { rotate: [0, 10, -10, 10, -10, 0] },\n          }}\n          transition={{ duration: 1 }}\n        />\n        {!!text && <span className=\"text-white font-semibold text-base\">{text}</span>}\n      </motion.div>\n    </Link>\n  )\n}\n\nexport default PremiumEntry\n"
  },
  {
    "path": "src/app/components/Sidebar/index.tsx",
    "content": "import { Link } from '@tanstack/react-router'\nimport { motion } from 'framer-motion'\nimport { useAtom, useSetAtom } from 'jotai'\nimport { useEffect, useState } from 'react'\nimport { useTranslation } from 'react-i18next'\nimport allInOneIcon from '~/assets/all-in-one.svg'\nimport collapseIcon from '~/assets/icons/collapse.svg'\nimport feedbackIcon from '~/assets/icons/feedback.svg'\nimport githubIcon from '~/assets/icons/github.svg'\nimport settingIcon from '~/assets/icons/setting.svg'\nimport themeIcon from '~/assets/icons/theme.svg'\nimport minimalLogo from '~/assets/minimal-logo.svg'\nimport logo from '~/assets/santa-logo.png'\nimport { cx } from '~/utils'\nimport { useEnabledBots } from '~app/hooks/use-enabled-bots'\nimport { releaseNotesAtom, showDiscountModalAtom, sidebarCollapsedAtom } from '~app/state'\nimport { getPremiumActivation } from '~services/premium'\nimport { checkReleaseNotes } from '~services/release-notes'\nimport * as api from '~services/server-api'\nimport { getAppOpenTimes, getPremiumModalOpenTimes } from '~services/storage/open-times'\nimport GuideModal from '../GuideModal'\nimport ThemeSettingModal from '../ThemeSettingModal'\nimport Tooltip from '../Tooltip'\nimport NavLink from './NavLink'\nimport PremiumEntry from './PremiumEntry'\n\nfunction IconButton(props: { icon: string; onClick?: () => void }) {\n  return (\n    <div\n      className=\"p-[6px] rounded-[10px] w-fit cursor-pointer hover:opacity-80 bg-secondary bg-opacity-20\"\n      onClick={props.onClick}\n    >\n      <img src={props.icon} className=\"w-6 h-6\" />\n    </div>\n  )\n}\n\nfunction Sidebar() {\n  const { t } = useTranslation()\n  const [collapsed, setCollapsed] = useAtom(sidebarCollapsedAtom)\n  const [themeSettingModalOpen, setThemeSettingModalOpen] = useState(false)\n  const enabledBots = useEnabledBots()\n  const setShowDiscountModal = useSetAtom(showDiscountModalAtom)\n  const setReleaseNotes = useSetAtom(releaseNotesAtom)\n\n  useEffect(() => {\n    Promise.all([getAppOpenTimes(), getPremiumModalOpenTimes(), checkReleaseNotes()]).then(\n      async ([appOpenTimes, premiumModalOpenTimes, releaseNotes]) => {\n        if (!getPremiumActivation()) {\n          const { show, campaign } = await api.checkDiscount({ appOpenTimes, premiumModalOpenTimes })\n          if (show) {\n            setShowDiscountModal(true)\n            return\n          }\n          if (campaign) {\n            setShowDiscountModal(campaign)\n            return\n          }\n        }\n        setReleaseNotes(releaseNotes)\n      },\n    )\n  }, [])\n\n  return (\n    <motion.aside\n      className={cx(\n        'flex flex-col bg-primary-background bg-opacity-40 overflow-hidden',\n        collapsed ? 'items-center px-[15px]' : 'w-[230px] px-4',\n      )}\n    >\n      <div className={cx('flex mt-8 gap-3 items-center', collapsed ? 'flex-col-reverse' : 'flex-row justify-between')}>\n        {collapsed ? <img src={minimalLogo} className=\"w-[30px]\" /> : <img src={logo} className=\"w-[100px] ml-2\" />}\n        <motion.img\n          src={collapseIcon}\n          className={cx('w-6 h-6 cursor-pointer')}\n          animate={{ rotate: collapsed ? 180 : 0 }}\n          onClick={() => setCollapsed((c) => !c)}\n        />\n      </div>\n      <div className=\"flex flex-col gap-[13px] mt-10 overflow-y-auto scrollbar-none\">\n        <NavLink to=\"/\" text={'All-In-One'} icon={allInOneIcon} iconOnly={collapsed} />\n        {enabledBots.map(({ botId, bot }) => (\n          <NavLink\n            key={botId}\n            to=\"/chat/$botId\"\n            params={{ botId }}\n            text={bot.name}\n            icon={bot.avatar}\n            iconOnly={collapsed}\n          />\n        ))}\n      </div>\n      <div className=\"mt-auto pt-2\">\n        {!collapsed && <hr className=\"border-[#ffffff4d]\" />}\n        {!collapsed && (\n          <div className=\"my-5\">\n            <PremiumEntry text={t('Premium')} />\n          </div>\n        )}\n        <div className={cx('flex mt-5 gap-[10px] mb-4', collapsed ? 'flex-col' : 'flex-row ')}>\n          {!collapsed && (\n            <Tooltip content={t('GitHub')}>\n              <a href=\"https://github.com/chathub-dev/chathub?utm_source=extension\" target=\"_blank\" rel=\"noreferrer\">\n                <IconButton icon={githubIcon} />\n              </a>\n            </Tooltip>\n          )}\n          {!collapsed && (\n            <Tooltip content={t('Feedback')}>\n              <a href=\"https://github.com/chathub-dev/chathub/issues\" target=\"_blank\" rel=\"noreferrer\">\n                <IconButton icon={feedbackIcon} />\n              </a>\n            </Tooltip>\n          )}\n          {!collapsed && (\n            <Tooltip content={t('Display')}>\n              <a onClick={() => setThemeSettingModalOpen(true)}>\n                <IconButton icon={themeIcon} />\n              </a>\n            </Tooltip>\n          )}\n          <Tooltip content={t('Settings')}>\n            <Link to=\"/setting\">\n              <IconButton icon={settingIcon} />\n            </Link>\n          </Tooltip>\n        </div>\n      </div>\n      <GuideModal />\n      <ThemeSettingModal open={themeSettingModalOpen} onClose={() => setThemeSettingModalOpen(false)} />\n    </motion.aside>\n  )\n}\n\nexport default Sidebar\n"
  },
  {
    "path": "src/app/components/SwitchBotDropdown.tsx",
    "content": "import { Menu, Transition } from '@headlessui/react'\nimport { FC, Fragment, ReactNode } from 'react'\nimport { BotId } from '~app/bots'\nimport { useEnabledBots } from '~app/hooks/use-enabled-bots'\n\ninterface Props {\n  triggerNode: ReactNode\n  selectedBotId: BotId\n  onChange: (botId: BotId) => void\n}\n\nconst SwitchBotDropdown: FC<Props> = (props) => {\n  const enabledBots = useEnabledBots()\n  return (\n    <Menu as=\"div\" className=\"relative inline-block text-left h-5\">\n      <Menu.Button className=\"flex\">{props.triggerNode}</Menu.Button>\n      <Transition\n        as={Fragment}\n        enter=\"transition ease-out duration-100\"\n        enterFrom=\"transform opacity-0 scale-95\"\n        enterTo=\"transform opacity-100 scale-100\"\n        leave=\"transition ease-in duration-75\"\n        leaveFrom=\"transform opacity-100 scale-100\"\n        leaveTo=\"transform opacity-0 scale-95\"\n      >\n        <Menu.Items className=\"absolute left-0 z-10 mt-1 py-1 rounded-md bg-secondary shadow-lg focus:outline-none max-h-[300px] overflow-y-auto\">\n          {enabledBots.map(({ botId, bot }) => {\n            if (botId === props.selectedBotId) {\n              return null\n            }\n            return (\n              <Menu.Item key={botId}>\n                <div\n                  className=\"px-4 py-2 ui-active:bg-primary-blue ui-active:text-white ui-not-active:text-secondary-text cursor-pointer flex flex-row items-center gap-3 pr-8\"\n                  onClick={() => props.onChange(botId)}\n                >\n                  <div className=\"w-4 h-4\">\n                    <img src={bot.avatar} className=\"w-4 h-4\" />\n                  </div>\n                  <p className=\"text-sm whitespace-nowrap\">{bot.name}</p>\n                </div>\n              </Menu.Item>\n            )\n          })}\n        </Menu.Items>\n      </Transition>\n    </Menu>\n  )\n}\n\nexport default SwitchBotDropdown\n"
  },
  {
    "path": "src/app/components/Tabs.tsx",
    "content": "import { FC, useState } from 'react'\nimport { cx } from '~/utils'\n\nexport interface Tab {\n  name: string\n  value: string\n}\n\ninterface Props {\n  tabs: Tab[]\n  renderTab: (value: string) => JSX.Element | undefined\n}\n\nconst Tabs: FC<Props> = ({ tabs, renderTab }) => {\n  const [selected, setSelected] = useState(tabs[0].value)\n  return (\n    <>\n      <nav className=\"w-full flex space-x-4 mb-3\" aria-label=\"Tabs\">\n        {tabs.map((tab) => (\n          <a\n            key={tab.name}\n            className={cx(\n              'rounded-md px-3 py-2 text-sm font-medium cursor-pointer',\n              tab.value === selected ? 'bg-primary-blue text-white' : 'text-secondary-text hover:text-primary-text',\n            )}\n            onClick={() => setSelected(tab.value)}\n          >\n            {tab.name}\n          </a>\n        ))}\n      </nav>\n      {renderTab(selected)}\n    </>\n  )\n}\n\nexport default Tabs\n"
  },
  {
    "path": "src/app/components/ThemeSettingModal/index.tsx",
    "content": "import { Link } from '@tanstack/react-router'\nimport { cx } from '~/utils'\nimport { useAtom } from 'jotai'\nimport { ComponentPropsWithoutRef, FC, useCallback, useEffect, useMemo, useState } from 'react'\nimport { ColorResult, TwitterPicker } from 'react-color'\nimport { useTranslation } from 'react-i18next'\nimport Browser from 'webextension-polyfill'\nimport { usePremium } from '~app/hooks/use-premium'\nimport { trackEvent } from '~app/plausible'\nimport { followArcThemeAtom, themeColorAtom } from '~app/state'\nimport { applyThemeMode } from '~app/utils/color-scheme'\nimport { isArcBrowser } from '~app/utils/env'\nimport { getLanguage, setLanguage } from '~services/storage/language'\nimport { ThemeMode, getUserThemeMode, setUserThemeMode } from '~services/theme'\nimport { languageCodes } from '../../i18n'\nimport Dialog from '../Dialog'\nimport Select from '../Select'\n\nconst Button: FC<ComponentPropsWithoutRef<'button'>> = (props) => {\n  const { className, ...extraProps } = props\n  return (\n    <button\n      type=\"button\"\n      className={cx(\n        'relative inline-flex items-center bg-primary-background px-3 py-2 text-sm font-semibold text-primary-text ring-1 ring-inset ring-gray-300 hover:opacity-80 focus:z-10',\n        className,\n      )}\n      {...extraProps}\n    />\n  )\n}\n\nconst THEME_COLORS = [\n  '#7EB8D6',\n  '#FF6900',\n  '#7BDCB5',\n  '#00D084',\n  '#8ED1FC',\n  '#0693E3',\n  '#ABB8C3',\n  '#EB144C',\n  '#F78DA7',\n  '#555555',\n]\n\ninterface Props {\n  open: boolean\n  onClose: () => void\n}\n\nconst ThemeSettingModal: FC<Props> = (props) => {\n  const { t, i18n } = useTranslation()\n  const [themeColor, setThemeColor] = useAtom(themeColorAtom)\n  const [themeMode, setThemeMode] = useState(getUserThemeMode())\n  const premiumState = usePremium()\n  const [followArcTheme, setFollowArcTheme] = useAtom(followArcThemeAtom)\n  const [zoomLevel, setZoomLevel] = useState<number | null>(null)\n  const [lang, setLang] = useState(() => getLanguage() || 'auto')\n\n  const languageOptions = useMemo(() => {\n    const nameGenerator = new Intl.DisplayNames('en', { type: 'language' })\n    return languageCodes.map((code) => {\n      let name: string\n      if (code === 'zh-CN') {\n        name = '简体中文'\n      } else if (code === 'zh-TW') {\n        name = '繁體中文'\n      } else {\n        name = nameGenerator.of(code) || code\n      }\n      return { name, value: code }\n    })\n  }, [])\n\n  useEffect(() => {\n    Browser.tabs.getZoom().then((zoom) => setZoomLevel(zoom))\n  }, [])\n\n  const updateZoomLevel = useCallback(\n    (op: '+' | '-') => {\n      if (!zoomLevel) {\n        return\n      }\n      const newZoom = op === '+' ? zoomLevel + 0.1 : zoomLevel - 0.1\n      if (newZoom < 0.7 || newZoom > 1.2) {\n        return\n      }\n      Browser.tabs.setZoom(newZoom)\n      setZoomLevel(newZoom)\n      trackEvent('change_zoom_level', { zoom: newZoom })\n    },\n    [zoomLevel],\n  )\n\n  const onThemeModeChange = useCallback((mode: ThemeMode) => {\n    setUserThemeMode(mode)\n    setThemeMode(mode)\n    applyThemeMode(mode)\n    trackEvent('change_theme_mode', { mode })\n  }, [])\n\n  const onThemeColorChange = useCallback(\n    (color: ColorResult) => {\n      setThemeColor(color.hex)\n      trackEvent('change_theme_color', { color: color.hex })\n    },\n    [setThemeColor],\n  )\n\n  const onLanguageChange = useCallback(\n    (lang: string) => {\n      setLang(lang)\n      setLanguage(lang === 'auto' ? undefined : lang)\n      i18n.changeLanguage(lang === 'auto' ? undefined : lang)\n      trackEvent('change_language', { lang })\n    },\n    [i18n],\n  )\n\n  return (\n    <Dialog\n      title={t('Display Settings')}\n      open={props.open}\n      onClose={props.onClose}\n      className=\"rounded-xl w-[600px] min-h-[300px]\"\n    >\n      <div className=\"p-5 pb-10 flex flex-col gap-5\">\n        <div className=\"w-[300px]\">\n          <p className=\"font-bold text-lg mb-3\">{t('Theme Mode')}</p>\n          <Select\n            options={[\n              { name: t('Auto'), value: ThemeMode.Auto },\n              { name: t('Light'), value: ThemeMode.Light },\n              { name: t('Dark'), value: ThemeMode.Dark },\n            ]}\n            value={themeMode}\n            onChange={onThemeModeChange}\n          />\n        </div>\n        <div>\n          <p className=\"font-bold text-lg mb-3\">\n            {t('Theme Color')}{' '}\n            {!premiumState.activated && (\n              <Link\n                to=\"/premium\"\n                search={{ source: 'theme' }}\n                className=\"text-sm font-normal ml-1 underline italic\"\n                onClick={() => props.onClose()}\n              >\n                ({t('Premium Feature')})\n              </Link>\n            )}\n          </p>\n          <div className={cx('flex flex-col gap-3', !premiumState.activated && 'opacity-50 pointer-events-none')}>\n            {isArcBrowser() && (\n              <div className=\"flex flex-row items-center gap-2\">\n                <input\n                  type=\"checkbox\"\n                  id=\"arc-theme-check\"\n                  checked={followArcTheme}\n                  onChange={(e) => setFollowArcTheme(e.target.checked)}\n                  disabled={!premiumState.activated}\n                />\n                <label htmlFor=\"arc-theme-check\">{t('Follow Arc browser theme')}</label>\n              </div>\n            )}\n            {!followArcTheme && (\n              <TwitterPicker\n                colors={THEME_COLORS}\n                color={themeColor}\n                onChange={onThemeColorChange}\n                triangle=\"hide\"\n                width=\"300px\"\n              />\n            )}\n          </div>\n        </div>\n        <div>\n          <p className=\"font-bold text-lg mb-3\">{t('Display size')}</p>\n          <span className=\"isolate inline-flex rounded-md shadow-sm\">\n            <Button className=\"rounded-l-md\" onClick={() => updateZoomLevel('-')}>\n              -\n            </Button>\n            <Button className=\"-ml-px cursor-default\">{zoomLevel === null ? '-' : Math.floor(zoomLevel * 100)}%</Button>\n            <Button className=\"-ml-px rounded-r-md\" onClick={() => updateZoomLevel('+')}>\n              +\n            </Button>\n          </span>\n        </div>\n        <div className=\"w-[300px]\">\n          <p className=\"font-bold text-lg mb-3\">{t('Language')}</p>\n          <Select\n            options={[{ name: t('Auto'), value: 'auto' }, { name: 'English', value: 'en' }, ...languageOptions]}\n            value={lang}\n            onChange={onLanguageChange}\n            position=\"top\"\n          />\n        </div>\n      </div>\n    </Dialog>\n  )\n}\n\nexport default ThemeSettingModal\n"
  },
  {
    "path": "src/app/components/Toggle.tsx",
    "content": "import { Switch } from '@headlessui/react'\nimport { cx } from '~/utils'\nimport { FC } from 'react'\n\ninterface Props {\n  enabled: boolean\n  onChange?: (enabled: boolean) => void\n}\n\nconst Toggle: FC<Props> = (props) => {\n  return (\n    <Switch\n      checked={props.enabled}\n      onChange={props.onChange}\n      className={cx(\n        props.enabled ? 'bg-primary-blue' : 'bg-secondary',\n        'relative inline-flex h-4 w-7 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out',\n      )}\n    >\n      <span\n        className={cx(\n          props.enabled ? 'translate-x-3' : 'translate-x-0',\n          'pointer-events-none inline-block h-3 w-3 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out',\n        )}\n      />\n    </Switch>\n  )\n}\n\nexport default Toggle\n"
  },
  {
    "path": "src/app/components/Tooltip.tsx",
    "content": "import * as ReactTooltip from '@radix-ui/react-tooltip'\nimport { FC, PropsWithChildren } from 'react'\n\ninterface Props {\n  content: string\n  align?: ReactTooltip.TooltipContentProps['align']\n}\n\nconst Tooltip: FC<PropsWithChildren<Props>> = (props) => {\n  return (\n    <ReactTooltip.Provider delayDuration={1}>\n      <ReactTooltip.Root>\n        <ReactTooltip.Trigger asChild>{props.children}</ReactTooltip.Trigger>\n        <ReactTooltip.Portal>\n          <ReactTooltip.Content\n            className=\"data-[state=delayed-open]:data-[side=top]:animate-slideDownAndFade data-[state=delayed-open]:data-[side=right]:animate-slideLeftAndFade data-[state=delayed-open]:data-[side=left]:animate-slideRightAndFade data-[state=delayed-open]:data-[side=bottom]:animate-slideUpAndFade select-none rounded-md bg-black text-white bg-opacity-90 px-[14px] py-2 text-sm leading-none shadow-[hsl(206_22%_7%_/_35%)_0px_10px_38px_-10px,_hsl(206_22%_7%_/_20%)_0px_10px_20px_-15px] will-change-[transform,opacity] z-50\"\n            sideOffset={5}\n            align={props.align}\n          >\n            {props.content}\n          </ReactTooltip.Content>\n        </ReactTooltip.Portal>\n      </ReactTooltip.Root>\n    </ReactTooltip.Provider>\n  )\n}\n\nexport default Tooltip\n"
  },
  {
    "path": "src/app/consts.ts",
    "content": "import claudeLogo from '~/assets/logos/anthropic.png'\nimport baichuanLogo from '~/assets/logos/baichuan.png'\nimport bardLogo from '~/assets/logos/bard.svg'\nimport bingLogo from '~/assets/logos/bing.svg'\nimport chatglmLogo from '~/assets/logos/chatglm.svg'\nimport chatgptLogo from '~/assets/logos/chatgpt.svg'\nimport falconLogo from '~/assets/logos/falcon.jpeg'\nimport geminiLogo from '~/assets/logos/gemini.png'\nimport grokLogo from '~/assets/logos/grok.png'\nimport llamaLogo from '~/assets/logos/llama.png'\nimport mistralLogo from '~/assets/logos/mistral.png'\nimport piLogo from '~/assets/logos/pi.png'\nimport pplxLogo from '~/assets/logos/pplx.jpg'\nimport qianwenLogo from '~/assets/logos/qianwen.png'\nimport vicunaLogo from '~/assets/logos/vicuna.jpg'\nimport wizardlmLogo from '~/assets/logos/wizardlm.png'\nimport xunfeiLogo from '~/assets/logos/xunfei.png'\nimport yiLogo from '~/assets/logos/yi.svg'\nimport { BotId } from './bots'\n\nexport const CHATBOTS: Record<BotId, { name: string; avatar: string }> = {\n  chatgpt: {\n    name: 'ChatGPT',\n    avatar: chatgptLogo,\n  },\n  claude: {\n    name: 'Claude',\n    avatar: claudeLogo,\n  },\n  bard: {\n    name: 'Bard',\n    avatar: bardLogo,\n  },\n  bing: {\n    name: 'Bing',\n    avatar: bingLogo,\n  },\n  perplexity: {\n    name: 'Perplexity',\n    avatar: pplxLogo,\n  },\n  llama: {\n    name: 'Llama 2',\n    avatar: llamaLogo,\n  },\n  gemini: {\n    name: 'Gemini Pro',\n    avatar: geminiLogo,\n  },\n  mistral: {\n    name: 'Mixtral',\n    avatar: mistralLogo,\n  },\n  vicuna: {\n    name: 'Vicuna',\n    avatar: vicunaLogo,\n  },\n  falcon: {\n    name: 'Falcon',\n    avatar: falconLogo,\n  },\n  grok: {\n    name: 'Grok',\n    avatar: grokLogo,\n  },\n  pi: {\n    name: 'Pi',\n    avatar: piLogo,\n  },\n  wizardlm: {\n    name: 'WizardLM',\n    avatar: wizardlmLogo,\n  },\n  chatglm: {\n    name: 'ChatGLM2',\n    avatar: chatglmLogo,\n  },\n  xunfei: {\n    name: 'iFlytek Spark',\n    avatar: xunfeiLogo,\n  },\n  qianwen: {\n    name: 'Qianwen',\n    avatar: qianwenLogo,\n  },\n  baichuan: {\n    name: 'Baichuan',\n    avatar: baichuanLogo,\n  },\n  yi: {\n    name: 'Yi-Chat',\n    avatar: yiLogo,\n  },\n}\n\nexport const CHATGPT_HOME_URL = 'https://chat.openai.com'\nexport const CHATGPT_API_MODELS = ['gpt-3.5-turbo', 'gpt-4', 'gpt-4-turbo'] as const\nexport const ALL_IN_ONE_PAGE_ID = 'all'\n\nexport const DEFAULT_CHATGPT_SYSTEM_MESSAGE =\n  'You are ChatGPT, a large language model trained by OpenAI. Answer as concisely as possible. Knowledge cutoff: 2021-09-01. Current date: {current_date}'\n\nexport type Layout = 2 | 3 | 4 | 'imageInput' | 'twoVertical' | 'sixGrid' // twoVertical is deprecated\n"
  },
  {
    "path": "src/app/context.ts",
    "content": "import { createContext } from 'react'\n\nexport interface ConversationContextValue {\n  reset: () => void\n}\n\nexport const ConversationContext = createContext<ConversationContextValue | null>(null)\n"
  },
  {
    "path": "src/app/hooks/use-chat.ts",
    "content": "import { useAtom } from 'jotai'\nimport { useCallback, useEffect, useMemo } from 'react'\nimport { trackEvent } from '~app/plausible'\nimport { chatFamily } from '~app/state'\nimport { compressImageFile } from '~app/utils/image-compression'\nimport { setConversationMessages } from '~services/chat-history'\nimport { ChatMessageModel } from '~types'\nimport { uuid } from '~utils'\nimport { ChatError } from '~utils/errors'\nimport { BotId } from '../bots'\n\nexport function useChat(botId: BotId) {\n  const chatAtom = useMemo(() => chatFamily({ botId, page: 'singleton' }), [botId])\n  const [chatState, setChatState] = useAtom(chatAtom)\n\n  const updateMessage = useCallback(\n    (messageId: string, updater: (message: ChatMessageModel) => void) => {\n      setChatState((draft) => {\n        const message = draft.messages.find((m) => m.id === messageId)\n        if (message) {\n          updater(message)\n        }\n      })\n    },\n    [setChatState],\n  )\n\n  const sendMessage = useCallback(\n    async (input: string, image?: File) => {\n      trackEvent('send_message', { botId, withImage: !!image, name: chatState.bot.name })\n\n      const botMessageId = uuid()\n      setChatState((draft) => {\n        draft.messages.push(\n          { id: uuid(), text: input, image, author: 'user' },\n          { id: botMessageId, text: '', author: botId },\n        )\n      })\n\n      const abortController = new AbortController()\n      setChatState((draft) => {\n        draft.generatingMessageId = botMessageId\n        draft.abortController = abortController\n      })\n\n      let compressedImage: File | undefined = undefined\n      if (image) {\n        compressedImage = await compressImageFile(image)\n      }\n\n      const resp = await chatState.bot.sendMessage({\n        prompt: input,\n        image: compressedImage,\n        signal: abortController.signal,\n      })\n\n      try {\n        for await (const answer of resp) {\n          updateMessage(botMessageId, (message) => {\n            message.text = answer.text\n          })\n        }\n      } catch (err: unknown) {\n        if (!abortController.signal.aborted) {\n          abortController.abort()\n        }\n        const error = err as ChatError\n        console.error('sendMessage error', error.code, error)\n        updateMessage(botMessageId, (message) => {\n          message.error = error\n        })\n        setChatState((draft) => {\n          draft.abortController = undefined\n          draft.generatingMessageId = ''\n        })\n      }\n\n      setChatState((draft) => {\n        draft.abortController = undefined\n        draft.generatingMessageId = ''\n      })\n    },\n    [botId, chatState.bot, setChatState, updateMessage],\n  )\n\n  const resetConversation = useCallback(() => {\n    chatState.bot.resetConversation()\n    setChatState((draft) => {\n      draft.abortController = undefined\n      draft.generatingMessageId = ''\n      draft.messages = []\n      draft.conversationId = uuid()\n    })\n  }, [chatState.bot, setChatState])\n\n  const stopGenerating = useCallback(() => {\n    chatState.abortController?.abort()\n    if (chatState.generatingMessageId) {\n      updateMessage(chatState.generatingMessageId, (message) => {\n        if (!message.text && !message.error) {\n          message.text = 'Cancelled'\n        }\n      })\n    }\n    setChatState((draft) => {\n      draft.generatingMessageId = ''\n    })\n  }, [chatState.abortController, chatState.generatingMessageId, setChatState, updateMessage])\n\n  useEffect(() => {\n    if (chatState.messages.length) {\n      setConversationMessages(botId, chatState.conversationId, chatState.messages)\n    }\n  }, [botId, chatState.conversationId, chatState.messages])\n\n  const chat = useMemo(\n    () => ({\n      botId,\n      bot: chatState.bot,\n      messages: chatState.messages,\n      sendMessage,\n      resetConversation,\n      generating: !!chatState.generatingMessageId,\n      stopGenerating,\n    }),\n    [\n      botId,\n      chatState.bot,\n      chatState.generatingMessageId,\n      chatState.messages,\n      resetConversation,\n      sendMessage,\n      stopGenerating,\n    ],\n  )\n\n  return chat\n}\n"
  },
  {
    "path": "src/app/hooks/use-enabled-bots.ts",
    "content": "import useSWR from 'swr/immutable'\nimport { BotId } from '~app/bots'\nimport { CHATBOTS } from '~app/consts'\nimport { getUserConfig } from '~services/user-config'\n\nexport function useEnabledBots() {\n  const query = useSWR('enabled-bots', async () => {\n    const { enabledBots } = await getUserConfig()\n    return Object.keys(CHATBOTS)\n      .filter((botId) => enabledBots.includes(botId as BotId))\n      .map((botId) => {\n        const bid = botId as BotId\n        return { botId: bid, bot: CHATBOTS[bid] }\n      })\n  })\n  return query.data || []\n}\n"
  },
  {
    "path": "src/app/hooks/use-premium.ts",
    "content": "import { FetchError } from 'ofetch'\nimport useSWR from 'swr'\nimport { getPremiumActivation, validatePremium } from '~services/premium'\n\nexport function usePremium() {\n  const validationQuery = useSWR<{ valid: true } | { valid: false; error?: string }>(\n    'premium-validation',\n    async () => {\n      try {\n        return await validatePremium()\n      } catch (err) {\n        if (err instanceof FetchError) {\n          if (err.status === 404) {\n            return { valid: false }\n          }\n          if (err.status === 400) {\n            return { valid: false, error: err.data.error }\n          }\n        }\n        throw err\n      }\n    },\n    {\n      fallbackData: getPremiumActivation() ? { valid: true } : undefined,\n      revalidateOnFocus: false,\n      dedupingInterval: 10 * 60 * 1000,\n    },\n  )\n\n  return {\n    activated: validationQuery.data?.valid,\n    isLoading: validationQuery.isLoading,\n    error: validationQuery.data?.valid === true ? undefined : validationQuery.data?.error,\n  }\n}\n"
  },
  {
    "path": "src/app/hooks/use-purchase-info.ts",
    "content": "import dayjs from 'dayjs'\nimport useSWR from 'swr'\nimport { fetchPurchaseInfo } from '~services/server-api'\n\nexport function usePurchaseInfo() {\n  return useSWR('premium-info', fetchPurchaseInfo)\n}\n\nexport function useDiscountCode() {\n  const { data } = usePurchaseInfo()\n  if (!data) {\n    return undefined\n  }\n  const { discount, campaign } = data\n  if (discount && dayjs(discount.startTime).add(1, 'day').isAfter()) {\n    return discount.code\n  }\n  if (campaign) {\n    return campaign.code\n  }\n}\n"
  },
  {
    "path": "src/app/hooks/use-user-config.ts",
    "content": "import useSWRImmutable from 'swr/immutable'\nimport { getUserConfig } from '~services/user-config'\n\nexport function useUserConfig() {\n  const { data } = useSWRImmutable('user-config', getUserConfig, { suspense: true })\n  return data\n}\n"
  },
  {
    "path": "src/app/i18n/index.ts",
    "content": "import i18n, { Resource } from 'i18next'\nimport LanguageDetector from 'i18next-browser-languagedetector'\nimport { initReactI18next } from 'react-i18next'\nimport { getLanguage } from '~services/storage/language'\nimport french from './locales/french.json'\nimport german from './locales/german.json'\nimport indonesia from './locales/indonesia.json'\nimport japanese from './locales/japanese.json'\nimport portuguese from './locales/portuguese.json'\nimport simplifiedChinese from './locales/simplified-chinese.json'\nimport spanish from './locales/spanish.json'\nimport thai from './locales/thai.json'\nimport traditionalChinese from './locales/traditional-chinese.json'\n\nconst resources: Resource = {\n  'zh-CN': { translation: simplifiedChinese },\n  'zh-TW': { translation: traditionalChinese },\n  es: { translation: spanish },\n  pt: { translation: portuguese },\n  ja: { translation: japanese },\n  de: { translation: german },\n  fr: { translation: french },\n  in: { translation: indonesia },\n  th: { translation: thai },\n}\n\nexport const languageCodes = Object.keys(resources)\n\ni18n\n  .use(initReactI18next)\n  .use(LanguageDetector)\n  .init({\n    lng: getLanguage(),\n    fallbackLng: 'en',\n    resources,\n    interpolation: {\n      escapeValue: false, // react already safes from xss\n    },\n    detection: {\n      order: ['navigator'],\n      caches: [],\n    },\n  })\n\nexport default i18n\n"
  },
  {
    "path": "src/app/i18n/locales/french.json",
    "content": "{\n  \"Shortcut to open this app\": \"Raccourci pour ouvrir cette application\",\n  \"Settings\": \"Paramètres\",\n  \"Startup page\": \"Page de démarrage\",\n  \"Chat style\": \"Style de chat\",\n  \"Change shortcut\": \"Changer de raccourci\",\n  \"Save\": \"Enregistrer\",\n  \"Saved\": \"Enregistré\",\n  \"Export\": \"Exporter\",\n  \"Import\": \"Importer\",\n  \"Export/Import All Data\": \"Exporter/Importer toutes les données\",\n  \"Data includes all your settings, chat histories, and local prompts\": \"Les données incluent tous vos paramètres, historiques de chat et invites locales\",\n  \"Edit\": \"Modifier\",\n  \"Use\": \"Utiliser\",\n  \"Send\": \"Envoyer\",\n  \"Stop\": \"Arrêter\",\n  \"Title\": \"Titre\",\n  \"Content\": \"Contenu\",\n  \"Search\": \"Rechercher\",\n  \"Model\": \"Modèle\",\n  \"Cancel\": \"Annuler\",\n  \"Presale discount\": \"Remise de prévente\",\n  \"More layouts in All-In-One mode\": \"Plus de mises en page en mode Tout-en-un\",\n  \"Chat with more than 2 bots simultaneously\": \"Discuter avec plus de 2 bots simultanément\",\n  \"Full-text search for chat history\": \"Recherche de texte intégral pour l'historique des chats\",\n  \"Customize theme\": \"Personnaliser le thème\",\n  \"Support the development of ChatHub\": \"Soutenir le développement de ChatHub\",\n  \"Enjoy ChatHub? Give us a 5-star rating!\": \"Aimez-vous ChatHub ? Donnez-nous une note de 5 étoiles !\",\n  \"Write review\": \"Écrire un commentaire\",\n  \"Activate license\": \"Activer la licence\",\n  \"🎉 License activated\": \"🎉 Licence activée\",\n  \"All-In-One Mode\": \"Mode Tout-en-un\",\n  \"Two in one\": \"Deux en un\",\n  \"Three in one\": \"Trois en un\",\n  \"Four in one\": \"Quatre en un\",\n  \"Activate up to 5 devices\": \"Activer jusqu'à 5 appareils\",\n  \"Deactivate\": \"Désactiver\",\n  \"Buy premium license\": \"Obtenir une licence premium\",\n  \"Theme Settings\": \"Paramètres du thème\",\n  \"Theme Mode\": \"Mode du thème\",\n  \"Theme Color\": \"Couleur du thème\",\n  \"Follow Arc browser theme\": \"Suivre le thème du navigateur Arc\",\n  \"iFlytek Spark\": \"iFlytek Spark\",\n  \"You need to login to Poe first\": \"Vous devez d'abord vous connecter à Poe\",\n  \"Login at bing.com\": \"Se connecter sur bing.com\",\n  \"Login at poe.com\": \"Se connecter sur poe.com\",\n  \"Login at xfyun.cn\": \"Se connecter à xfyun.cn\",\n  \"Lifetime license\": \"Licence à vie\",\n  \"Join the waitlist\": \"Rejoindre la liste d'attente\",\n  \"GPT-4 models require ChatGPT Plus\": \"Les modèles GPT-4 nécessitent ChatGPT Plus\",\n  \"Model used by ChatGPT iOS app, potentially faster\": \"Modèle utilisé par l'application iOS ChatGPT, potentiellement plus rapide\",\n  \"Poe subscribers only\": \"Uniquement pour les abonnés Poe\",\n  \"Quick access in Chrome side bar\": \"Accès rapide dans la barre latérale de Chrome\",\n  \"You have opened ChatHub {{openTimes}} times, consider unlock all features?\": \"Vous avez ouvert ChatHub {{openTimes}} fois, envisagez de déverrouiller toutes les fonctionnalités ? 🥺\",\n  \"Open Prompt Library\": \"Ouvrir la bibliothèque de prompts\",\n  \"Use / to select prompts, Shift+Enter to add new line\": \"Utilisez / pour sélectionner des invites, Shift+Enter pour ajouter une nouvelle ligne\",\n  \"Your Prompts\": \"Vos invites\",\n  \"Community Prompts\": \"Invites de la communauté\",\n  \"Create new prompt\": \"Créer une nouvelle invite\",\n  \"Earlybird price\": \"Prix Earlybird\",\n  \"Share conversation\": \"Partager la conversation\",\n  \"Clear conversation\": \"Effacer la conversation\",\n  \"View history\": \"Voir l'historique\",\n  \"Premium Feature\": \"Fonctionnalité premium\",\n  \"Upgrade to unlock\": \"Mettre à niveau pour déverrouiller\",\n  \"Please check your network connection\": \"Veuillez vérifier votre connexion réseau\",\n  \"Display size\": \"Taille de l'affichage\",\n  \"You’ve reached the daily free message limit for this model\": \"Vous avez atteint la limite quotidienne de messages gratuits pour ce modèle\",\n  \"This is a limitation set by poe.com\": \"Il s'agit d'une limitation fixée par poe.com\",\n  \"Feedback\": \"Retour d'information\",\n  \"Theme\": \"Thème\",\n  \"Premium\": \"Premium\",\n  \"Chatbots\": \"Chatbots\",\n  \"Manage order and devices\": \"Gérer les commandes et les appareils\",\n  \"Upgrade\": \"Mettre à niveau\",\n  \"This usually mean you need to add a payment method to your OpenAI account, checkout: \": \"Cela signifie généralement que vous devez ajouter un mode de paiement à votre compte OpenAI, vérifiez :\",\n  \"Are you sure you want to clear history messages?\": \"Êtes-vous sûr de vouloir effacer l'historique des messages ?\",\n  \"Clear history messages\": \"Effacer l'historique des messages\",\n  \"Compare with image input\": \"Comparer avec une entrée d'image\",\n  \"Web Access\": \"Accès Web\",\n  \"Upgrade to Premium for web access and more features\": \"Mettez à niveau vers Premium pour un accès Web et plus de fonctionnalités\",\n  \"Improving accuracy by searching up-to-date information from the internet\": \"Amélioration de la précision en recherchant des informations à jour sur Internet\",\n  \"Checkout premium features\": \"Vérifier les fonctionnalités premium\",\n  \"Login to ChatGPT\": \"Se connecter à ChatGPT\",\n  \"Switch to API mode\": \"Passer en mode API\",\n  \"Mode\": \"Mode\",\n  \"Display\": \"Affichage\",\n  \"Display Settings\": \"Paramètres d'affichage\",\n  \"Auto\": \"Auto\",\n  \"Language\": \"Langue\"\n}\n"
  },
  {
    "path": "src/app/i18n/locales/german.json",
    "content": "{\n  \"Shortcut to open this app\": \"Verknüpfung zum Öffnen dieser App\",\n  \"Settings\": \"Einstellungen\",\n  \"Startup page\": \"Startseite\",\n  \"Chat style\": \"Chat-Stil\",\n  \"Change shortcut\": \"Verknüpfung ändern\",\n  \"Save\": \"Speichern\",\n  \"Saved\": \"Gespeichert\",\n  \"Export\": \"Exportieren\",\n  \"Import\": \"Importieren\",\n  \"Export/Import All Data\": \"Alle Daten exportieren/importieren\",\n  \"Data includes all your settings, chat histories, and local prompts\": \"Daten umfassen alle Einstellungen, Chat-Verläufe und lokale Prompts\",\n  \"Edit\": \"Bearbeiten\",\n  \"Use\": \"Verwenden\",\n  \"Send\": \"Senden\",\n  \"Stop\": \"Stoppen\",\n  \"Title\": \"Titel\",\n  \"Content\": \"Inhalt\",\n  \"Search\": \"Suchen\",\n  \"Model\": \"Modell\",\n  \"Cancel\": \"Abbrechen\",\n  \"Presale discount\": \"Vorverkaufsrabatt\",\n  \"More layouts in All-In-One mode\": \"Mehr Layouts im All-In-One-Modus\",\n  \"Chat with more than 2 bots simultaneously\": \"Gleichzeitiges Chatten mit mehr als 2 Bots\",\n  \"Full-text search for chat history\": \"Volltextsuche für Chat-Verlauf\",\n  \"Customize theme\": \"Thema anpassen\",\n  \"Support the development of ChatHub\": \"Unterstützen Sie die Entwicklung von ChatHub\",\n  \"Enjoy ChatHub? Give us a 5-star rating!\": \"Gefällt Ihnen ChatHub? Geben Sie uns eine 5-Sterne-Bewertung!\",\n  \"Write review\": \"Rezension schreiben\",\n  \"Activate license\": \"Lizenz aktivieren\",\n  \"🎉 License activated\": \"🎉 Lizenz aktiviert\",\n  \"All-In-One Mode\": \"All-In-One-Modus\",\n  \"Two in one\": \"Zwei in einem\",\n  \"Three in one\": \"Drei in einem\",\n  \"Four in one\": \"Vier in einem\",\n  \"Activate up to 5 devices\": \"Aktivieren Sie bis zu 5 Geräte\",\n  \"Deactivate\": \"Deaktivieren\",\n  \"Buy premium license\": \"Premium-Lizenz erhalten\",\n  \"Theme Settings\": \"Thema-Einstellungen\",\n  \"Theme Mode\": \"Thema-Modus\",\n  \"Theme Color\": \"Thema-Farbe\",\n  \"Follow Arc browser theme\": \"Folgen Sie dem Arc-Browser-Thema\",\n  \"iFlytek Spark\": \"iFlytek Spark\",\n  \"You need to login to Poe first\": \"Sie müssen sich zuerst bei Poe anmelden\",\n  \"Login at bing.com\": \"Bei bing.com anmelden\",\n  \"Login at poe.com\": \"Bei poe.com anmelden\",\n  \"Login at xfyun.cn\": \"Bei xfyun.cn anmelden\",\n  \"Lifetime license\": \"Lebenslange Lizenz\",\n  \"Join the waitlist\": \"In die Warteliste eintragen\",\n  \"GPT-4 models require ChatGPT Plus\": \"GPT-4-Modelle erfordern ChatGPT Plus\",\n  \"Model used by ChatGPT iOS app, potentially faster\": \"Modell, das von der ChatGPT iOS-App verwendet wird, möglicherweise schneller\",\n  \"Poe subscribers only\": \"Nur Poe-Abonnenten\",\n  \"Quick access in Chrome side bar\": \"Schneller Zugriff in der Chrome-Seitenleiste\",\n  \"You have opened ChatHub {{openTimes}} times, consider unlock all features?\": \"Sie haben ChatHub {{openTimes}} Mal geöffnet. Möchten Sie alle Funktionen freischalten?🥺\",\n  \"Open Prompt Library\": \"Prompt-Bibliothek öffnen\",\n  \"Use / to select prompts, Shift+Enter to add new line\": \"Verwenden Sie /, um Prompts auszuwählen, und Shift+Enter, um eine neue Zeile hinzuzufügen\",\n  \"Your Prompts\": \"Ihre Prompts\",\n  \"Community Prompts\": \"Community-Prompts\",\n  \"Create new prompt\": \"Neuen Prompt erstellen\",\n  \"Earlybird price\": \"Frühbucherpreis\",\n  \"Share conversation\": \"Konversation teilen\",\n  \"Clear conversation\": \"Konversation löschen\",\n  \"View history\": \"Verlauf anzeigen\",\n  \"Premium Feature\": \"Premium-Funktion\",\n  \"Upgrade to unlock\": \"Upgrade zum Freischalten\",\n  \"Please check your network connection\": \"Bitte überprüfen Sie Ihre Netzwerkverbindung\",\n  \"Display size\": \"Anzeigegröße\",\n  \"You’ve reached the daily free message limit for this model\": \"Sie haben das tägliche kostenlose Nachrichtenlimit für dieses Modell erreicht\",\n  \"This is a limitation set by poe.com\": \"Dies ist eine Einschränkung, die von poe.com festgelegt wurde\",\n  \"Feedback\": \"Feedback\",\n  \"Theme\": \"Thema\",\n  \"Premium\": \"Premium\",\n  \"Chatbots\": \"Chatbots\",\n  \"Manage order and devices\": \"Bestellung und Geräte verwalten\",\n  \"Upgrade\": \"Upgrade\",\n  \"This usually mean you need to add a payment method to your OpenAI account, checkout: \": \"Dies bedeutet in der Regel, dass Sie eine Zahlungsmethode zu Ihrem OpenAI-Konto hinzufügen müssen. Kasse:\",\n  \"Are you sure you want to clear history messages?\": \"Möchten Sie wirklich die Verlaufsnachrichten löschen?\",\n  \"Clear history messages\": \"Verlaufsnachrichten löschen\",\n  \"Compare with image input\": \"Mit Bild-Eingabe vergleichen\",\n  \"Web Access\": \"Webzugriff\",\n  \"Upgrade to Premium for web access and more features\": \"Upgrade auf Premium für Webzugriff und weitere Funktionen\",\n  \"Improving accuracy by searching up-to-date information from the internet\": \"Verbesserung der Genauigkeit durch Suche nach aktuellen Informationen aus dem Internet\",\n  \"Checkout premium features\": \"Premium-Funktionen auschecken\",\n  \"Login to ChatGPT\": \"Bei ChatGPT anmelden\",\n  \"Switch to API mode\": \"In den API-Modus wechseln\",\n  \"Mode\": \"Modus\",\n  \"Display\": \"Anzeige\",\n  \"Display Settings\": \"Anzeigeeinstellungen\",\n  \"Auto\": \"Auto\",\n  \"Language\": \"Sprache\"\n}\n"
  },
  {
    "path": "src/app/i18n/locales/indonesia.json",
    "content": "{\n  \"Shortcut to open this app\": \"Jalan pintas untuk membuka aplikasi ini\",\n  \"Settings\": \"Pengaturan\",\n  \"Startup page\": \"Halaman awal\",\n  \"Chat style\": \"Gaya obrolan\",\n  \"Change shortcut\": \"Ubah jalan pintas\",\n  \"Save\": \"Simpan\",\n  \"Saved\": \"Tersimpan\",\n  \"Export\": \"Ekspor\",\n  \"Import\": \"Impor\",\n  \"Export/Import All Data\": \"Ekspor/Impor Semua Data\",\n  \"Data includes all your settings, chat histories, and local prompts\": \"Data mencakup semua pengaturan, riwayat obrolan, dan prompt lokal Anda\",\n  \"Edit\": \"Edit\",\n  \"Use\": \"Gunakan\",\n  \"Send\": \"Kirim\",\n  \"Stop\": \"Berhenti\",\n  \"Title\": \"Judul\",\n  \"Content\": \"Konten\",\n  \"Search\": \"Cari\",\n  \"Model\": \"Model\",\n  \"Cancel\": \"Batal\",\n  \"Presale discount\": \"Diskon pra-penjualan\",\n  \"More layouts in All-In-One mode\": \"Lebih banyak tata letak dalam mode All-In-One\",\n  \"Chat with more than 2 bots simultaneously\": \"Obrolan dengan lebih dari 2 bot secara bersamaan\",\n  \"Full-text search for chat history\": \"Pencarian teks penuh untuk riwayat obrolan\",\n  \"Customize theme\": \"Sesuaikan tema\",\n  \"Support the development of ChatHub\": \"Dukung pengembangan ChatHub\",\n  \"Enjoy ChatHub? Give us a 5-star rating!\": \"Menikmati ChatHub? Beri kami rating 5 bintang!\",\n  \"Write review\": \"Tulis ulasan\",\n  \"Activate license\": \"Aktifkan lisensi\",\n  \"🎉 License activated\": \"🎉 Lisensi diaktifkan\",\n  \"All-In-One Mode\": \"Mode All-In-One\",\n  \"Two in one\": \"Dua dalam satu\",\n  \"Three in one\": \"Tiga dalam satu\",\n  \"Four in one\": \"Empat dalam satu\",\n  \"Activate up to 5 devices\": \"Aktifkan hingga 5 perangkat\",\n  \"Deactivate\": \"Nonaktifkan\",\n  \"Buy premium license\": \"Dapatkan lisensi premium\",\n  \"Theme Settings\": \"Pengaturan tema\",\n  \"Theme Mode\": \"Mode tema\",\n  \"Theme Color\": \"Warna tema\",\n  \"Follow Arc browser theme\": \"Ikuti tema browser Arc\",\n  \"iFlytek Spark\": \"iFlytek Spark\",\n  \"You need to login to Poe first\": \"Anda perlu login ke Poe terlebih dahulu\",\n  \"Login at bing.com\": \"Login di bing.com\",\n  \"Login at poe.com\": \"Login di poe.com\",\n  \"Login at xfyun.cn\": \"Login ke akun xfyun\",\n  \"Lifetime license\": \"Lisensi seumur hidup\",\n  \"Join the waitlist\": \"Bergabung dengan daftar tunggu\",\n  \"GPT-4 models require ChatGPT Plus\": \"Model GPT-4 memerlukan ChatGPT Plus\",\n  \"Model used by ChatGPT iOS app, potentially faster\": \"Model yang digunakan oleh aplikasi ChatGPT iOS, mungkin lebih cepat\",\n  \"Poe subscribers only\": \"Hanya pelanggan Poe\",\n  \"Quick access in Chrome side bar\": \"Akses cepat di bilah sisi Chrome\",\n  \"You have opened ChatHub {{openTimes}} times, consider unlock all features?\": \"Anda telah membuka ChatHub {{openTimes}} kali, pertimbangkan untuk membuka semua fitur?\",\n  \"Open Prompt Library\": \"Buka Perpustakaan Prompt\",\n  \"Use / to select prompts, Shift+Enter to add new line\": \"Gunakan / untuk memilih prompt, Shift+Enter untuk menambahkan baris baru\",\n  \"Your Prompts\": \"Prompt Anda\",\n  \"Community Prompts\": \"Prompt Komunitas\",\n  \"Create new prompt\": \"Buat prompt baru\",\n  \"Earlybird price\": \"Harga earlybird\",\n  \"Share conversation\": \"Bagikan percakapan\",\n  \"Clear conversation\": \"Hapus percakapan\",\n  \"View history\": \"Lihat riwayat\",\n  \"Premium Feature\": \"Fitur premium\",\n  \"Upgrade to unlock\": \"Tingkatkan untuk membuka kunci\",\n  \"Please check your network connection\": \"Harap periksa koneksi jaringan Anda\",\n  \"Display size\": \"Ukuran tampilan\",\n  \"You’ve reached the daily free message limit for this model\": \"Anda telah mencapai batas pesan gratis harian untuk model ini\",\n  \"This is a limitation set by poe.com\": \"Ini adalah batasan yang ditetapkan oleh poe.com\",\n  \"Feedback\": \"Umpan balik\",\n  \"Theme\": \"Tema\",\n  \"Premium\": \"Premium\",\n  \"Chatbots\": \"Chatbot\",\n  \"Manage order and devices\": \"Kelola pesanan dan perangkat\",\n  \"Upgrade\": \"Tingkatkan\",\n  \"This usually mean you need to add a payment method to your OpenAI account, checkout: \": \"Ini biasanya berarti Anda perlu menambahkan metode pembayaran ke akun OpenAI Anda, checkout:\",\n  \"Are you sure you want to clear history messages?\": \"Apakah Anda yakin ingin menghapus pesan riwayat?\",\n  \"Clear history messages\": \"Hapus pesan riwayat\",\n  \"Compare with image input\": \"Bandingkan dengan masukan gambar\",\n  \"Web Access\": \"Akses web\",\n  \"Upgrade to Premium for web access and more features\": \"Tingkatkan ke Premium untuk akses web dan fitur lainnya\",\n  \"Improving accuracy by searching up-to-date information from the internet\": \"Meningkatkan akurasi dengan mencari informasi terbaru dari internet\",\n  \"Checkout premium features\": \"Periksa fitur premium\",\n  \"Login to ChatGPT\": \"Login ke ChatGPT\",\n  \"Switch to API mode\": \"Beralih ke mode API\",\n  \"Mode\": \"Mode\",\n  \"Display\": \"Tampilan\",\n  \"Display Settings\": \"Pengaturan tampilan\",\n  \"Auto\": \"Otomatis\",\n  \"Language\": \"Bahasa\"\n}\n"
  },
  {
    "path": "src/app/i18n/locales/japanese.json",
    "content": "{\n  \"Shortcut to open this app\": \"このアプリを開くショートカット\",\n  \"Settings\": \"設定\",\n  \"Startup page\": \"スタートアップページ\",\n  \"Chat style\": \"チャットスタイル\",\n  \"Change shortcut\": \"ショートカットの変更\",\n  \"Save\": \"保存する\",\n  \"Saved\": \"保存済み\",\n  \"Export\": \"エクスポート\",\n  \"Import\": \"インポート\",\n  \"Export/Import All Data\": \"すべてのデータのエクスポート/インポート\",\n  \"Data includes all your settings, chat histories, and local prompts\": \"データにはすべての設定、チャット履歴、ローカルプロンプトが含まれます\",\n  \"Edit\": \"編集する\",\n  \"Use\": \"使用する\",\n  \"Send\": \"送信する\",\n  \"Stop\": \"停止する\",\n  \"Title\": \"タイトル\",\n  \"Content\": \"内容\",\n  \"Search\": \"検索\",\n  \"Model\": \"モデル\",\n  \"Cancel\": \"キャンセル\",\n  \"Presale discount\": \"先行販売割引\",\n  \"More layouts in All-In-One mode\": \"All-In-Oneモードでより多くのレイアウト\",\n  \"Chat with more than 2 bots simultaneously\": \"2つ以上のボットと同時にチャットする\",\n  \"Full-text search for chat history\": \"チャット履歴の全文検索\",\n  \"Customize theme\": \"テーマのカスタマイズ\",\n  \"Support the development of ChatHub\": \"ChatHubの開発をサポートする\",\n  \"Enjoy ChatHub? Give us a 5-star rating!\": \"ChatHubをお楽しみいただけましたか？5つ星の評価をお願いします！\",\n  \"Write review\": \"レビューを書く\",\n  \"Activate license\": \"ライセンスをアクティブ化する\",\n  \"🎉 License activated\": \"🎉 ライセンスがアクティブ化されました\",\n  \"All-In-One Mode\": \"All-In-Oneモード\",\n  \"Two in one\": \"2つ合わせる\",\n  \"Three in one\": \"3つ合わせる\",\n  \"Four in one\": \"4つ合わせる\",\n  \"Activate up to 5 devices\": \"最大5台のデバイスをアクティブ化する\",\n  \"Deactivate\": \"非アクティブ化\",\n  \"Buy premium license\": \"プレミアムライセンスを入手する\",\n  \"Theme Settings\": \"テーマ設定\",\n  \"Theme Mode\": \"テーマモード\",\n  \"Theme Color\": \"テーマカラー\",\n  \"Follow Arc browser theme\": \"Arcブラウザのテーマカラーに従う\",\n  \"iFlytek Spark\": \"讯飞星火\",\n  \"You need to login to Poe first\": \"最初にPoeにログインする必要があります\",\n  \"Login at bing.com\": \"bing.comでログインする\",\n  \"Login at poe.com\": \"poe.comでログインする\",\n  \"Login at xfyun.cn\": \"讯飞アカウントにログインする\",\n  \"Lifetime license\": \"ライフタイムライセンス\",\n  \"Join the waitlist\": \"ウェイトリストに参加する\",\n  \"GPT-4 models require ChatGPT Plus\": \"GPT-4モデルにはChatGPT Plusが必要です\",\n  \"Model used by ChatGPT iOS app, potentially faster\": \"ChatGPT iOSアプリで使用されるモデル、スピードが速いかもしれません\",\n  \"Poe subscribers only\": \"Poeのサブスクリプション会員のみ利用可能\",\n  \"Quick access in Chrome side bar\": \"Chromeサイドバーでのクイックアクセス\",\n  \"You have opened ChatHub {{openTimes}} times, consider unlock all features?\": \"ChatHubを{{openTimes}}回開いています。すべての機能を解除しますか？🥺\",\n  \"Open Prompt Library\": \"プロンプトライブラリを開く\",\n  \"Use / to select prompts, Shift+Enter to add new line\": \"プロンプトを選択するには/を使用し、Shift+Enterで新しい行を追加します\",\n  \"Your Prompts\": \"あなたのプロンプト\",\n  \"Community Prompts\": \"コミュニティプロンプト\",\n  \"Create new prompt\": \"新しいプロンプトを作成する\",\n  \"Earlybird price\": \"早期割引価格\",\n  \"Share conversation\": \"会話を共有する\",\n  \"Clear conversation\": \"会話をクリアする\",\n  \"View history\": \"履歴を表示する\",\n  \"Premium Feature\": \"プレミアム機能\",\n  \"Upgrade to unlock\": \"アップグレードしてロックを解除する\",\n  \"Please check your network connection\": \"ネットワーク接続を確認してください\",\n  \"Display size\": \"表示サイズ\",\n  \"You’ve reached the daily free message limit for this model\": \"このモデルの1日の無料メッセージ制限に達しました\",\n  \"This is a limitation set by poe.com\": \"これはpoe.comによって設定された制限です\",\n  \"Feedback\": \"フィードバックする\",\n  \"Theme\": \"テーマ\",\n  \"Premium\": \"プレミアム\",\n  \"Chatbots\": \"チャットボット\",\n  \"Manage order and devices\": \"注文とデバイスを管理する\",\n  \"Upgrade\": \"アップグレードする\",\n  \"This usually mean you need to add a payment method to your OpenAI account, checkout: \": \"これは通常、OpenAIアカウントに支払い方法を追加する必要があることを意味します。ご確認ください！\",\n  \"Are you sure you want to clear history messages?\": \"履歴メッセージをクリアしてもよろしいですか？\",\n  \"Clear history messages\": \"履歴メッセージをクリアする\",\n  \"Compare with image input\": \"画像入力と比較する\",\n  \"Web Access\": \"Webアクセス\",\n  \"Upgrade to Premium for web access and more features\": \"Webアクセスとその他の機能を利用するにはプレミアムにアップグレードしてください\",\n  \"Improving accuracy by searching up-to-date information from the internet\": \"インターネットから最新情報を検索して精度を向上させる\",\n  \"Checkout premium features\": \"プレミアム機能をチェックアウトする\",\n  \"Login to ChatGPT\": \"ChatGPTにログインする\",\n  \"Switch to API mode\": \"APIモードに切り替える\",\n  \"Mode\": \"モード\",\n  \"Display\": \"表示します\",\n  \"Display Settings\": \"表示設定\",\n  \"Auto\": \"自動\",\n  \"Language\": \"言語\",\n  \"Buy once, use forever\": \"一度購入し、永久に使用する\",\n  \"20% OFF: ends in\": \"20％オフ：終了日\",\n  \"Special Offer: 20% OFF\": \"特別オファー：20％オフ\",\n  \"TODAY ONLY\": \"今日限り\",\n  \"Get Discount\": \"割引を入手する\",\n  \"Webapp mode uses your login session in current browser\": \"Webアプリモードでは、現在のブラウザでのログインセッションが使用されます\",\n  \"Your keys are stored locally\": \"キーはローカルに保存されます\",\n  \"Login to Claude.ai\": \"Claude.aiにログインする\",\n  \"Login to Bard\": \"Bardにログインする\",\n  \"Recent Updates\": \"最近の更新\",\n  \"Added a separate Gemini Pro bot, can be enabled in the settings\": \"独立したGemini Proボットを追加しました。設定で有効にできます\",\n  \"Save changes\": \"変更を保存する\"\n}\n"
  },
  {
    "path": "src/app/i18n/locales/portuguese.json",
    "content": "{\n  \"Shortcut to open this app\": \"Atalho para abrir este aplicativo\",\n  \"Settings\": \"Configurações\",\n  \"Startup page\": \"Página inicial\",\n  \"Chat style\": \"Estilo de bate-papo\",\n  \"Change shortcut\": \"Alterar atalho\",\n  \"Save\": \"Salvar\",\n  \"Saved\": \"Salvo\",\n  \"Export\": \"Exportar\",\n  \"Import\": \"Importar\",\n  \"Export/Import All Data\": \"Exportar/Importar todos os dados\",\n  \"Data includes all your settings, chat histories, and local prompts\": \"Os dados incluem todas as suas configurações, históricos de bate-papo e prompts locais\",\n  \"Edit\": \"Editar\",\n  \"Use\": \"Usar\",\n  \"Send\": \"Enviar\",\n  \"Stop\": \"Parar\",\n  \"Title\": \"Título\",\n  \"Content\": \"Conteúdo\",\n  \"Search\": \"Pesquisar\",\n  \"Model\": \"Modelo\",\n  \"Cancel\": \"Cancelar\",\n  \"Presale discount\": \"Desconto de pré-venda\",\n  \"More layouts in All-In-One mode\": \"Mais layouts no modo All-In-One\",\n  \"Chat with more than 2 bots simultaneously\": \"Converse com mais de 2 bots simultaneamente\",\n  \"Full-text search for chat history\": \"Pesquisa de texto completo para histórico de bate-papo\",\n  \"Customize theme\": \"Personalizar tema\",\n  \"Support the development of ChatHub\": \"Apoie o desenvolvimento do ChatHub\",\n  \"Enjoy ChatHub? Give us a 5-star rating!\": \"Está gostando do ChatHub? Dê-nos uma classificação de 5 estrelas!\",\n  \"Write review\": \"Escrever uma avaliação\",\n  \"Activate license\": \"Ativar licença\",\n  \"🎉 License activated\": \"🎉 Licença ativada\",\n  \"All-In-One Mode\": \"Modo All-In-One\",\n  \"Two in one\": \"Dois em um\",\n  \"Three in one\": \"Três em um\",\n  \"Four in one\": \"Quatro em um\",\n  \"Activate up to 5 devices\": \"Ativar até 5 dispositivos\",\n  \"Deactivate\": \"Desativar\",\n  \"Buy premium license\": \"Obter licença premium\",\n  \"Theme Settings\": \"Configurações do tema\",\n  \"Theme Mode\": \"Modo do tema\",\n  \"Theme Color\": \"Cor do tema\",\n  \"Follow Arc browser theme\": \"Seguir o tema do navegador Arc\",\n  \"iFlytek Spark\": \"iFlytek Spark\",\n  \"You need to login to Poe first\": \"Você precisa fazer login no Poe primeiro\",\n  \"Login at bing.com\": \"Faça login em bing.com\",\n  \"Login at poe.com\": \"Faça login em poe.com\",\n  \"Login at xfyun.cn\": \"Faça login em xfyun.cn\",\n  \"Lifetime license\": \"Licença vitalícia\",\n  \"Join the waitlist\": \"Entrar na lista de espera\",\n  \"GPT-4 models require ChatGPT Plus\": \"Os modelos GPT-4 requerem ChatGPT Plus\",\n  \"Model used by ChatGPT iOS app, potentially faster\": \"Modelo usado pelo aplicativo ChatGPT iOS, potencialmente mais rápido\",\n  \"Poe subscribers only\": \"Somente assinantes Poe\",\n  \"Quick access in Chrome side bar\": \"Acesso rápido na barra lateral do Chrome\",\n  \"You have opened ChatHub {{openTimes}} times, consider unlock all features?\": \"Você abriu o ChatHub {{openTimes}} vezes, considere desbloquear todos os recursos? 🥺\",\n  \"Open Prompt Library\": \"Abrir biblioteca de prompts\",\n  \"Use / to select prompts, Shift+Enter to add new line\": \"Use / para selecionar prompts, Shift+Enter para adicionar nova linha\",\n  \"Your Prompts\": \"Seus prompts\",\n  \"Community Prompts\": \"Prompts da comunidade\",\n  \"Create new prompt\": \"Criar novo prompt\",\n  \"Earlybird price\": \"Preço de lançamento\",\n  \"Share conversation\": \"Compartilhar conversa\",\n  \"Clear conversation\": \"Limpar conversa\",\n  \"View history\": \"Ver histórico\",\n  \"Premium Feature\": \"Recurso premium\",\n  \"Upgrade to unlock\": \"Atualize para desbloquear\",\n  \"Please check your network connection\": \"Verifique sua conexão de rede\",\n  \"Display size\": \"Tamanho da tela\",\n  \"You’ve reached the daily free message limit for this model\": \"Você atingiu o limite diário de mensagens gratuitas para este modelo\",\n  \"This is a limitation set by poe.com\": \"Esta é uma limitação definida por poe.com\",\n  \"Feedback\": \"Feedback\",\n  \"Theme\": \"Tema\",\n  \"Premium\": \"Premium\",\n  \"Chatbots\": \"Chatbots\",\n  \"Manage order and devices\": \"Gerenciar pedidos e dispositivos\",\n  \"Upgrade\": \"Atualizar\",\n  \"This usually mean you need to add a payment method to your OpenAI account, checkout: \": \"Isso geralmente significa que você precisa adicionar um método de pagamento à sua conta OpenAI, confira:\",\n  \"Are you sure you want to clear history messages?\": \"Tem certeza de que deseja limpar as mensagens de histórico?\",\n  \"Clear history messages\": \"Limpar mensagens de histórico\",\n  \"Compare with image input\": \"Comparar com entrada de imagem\",\n  \"Web Access\": \"Acesso à web\",\n  \"Upgrade to Premium for web access and more features\": \"Atualize para Premium para acesso à web e mais recursos\",\n  \"Improving accuracy by searching up-to-date information from the internet\": \"Melhorando a precisão pesquisando informações atualizadas na internet\",\n  \"Checkout premium features\": \"Ver recursos premium\",\n  \"Login to ChatGPT\": \"Faça login no ChatGPT\",\n  \"Switch to API mode\": \"Mudar para o modo API\",\n  \"Mode\": \"Modo\",\n  \"Display\": \"Exibição\",\n  \"Display Settings\": \"Configurações de exibição\",\n  \"Auto\": \"Automático\",\n  \"Language\": \"Idioma\"\n}\n"
  },
  {
    "path": "src/app/i18n/locales/simplified-chinese.json",
    "content": "{\n  \"Shortcut to open this app\": \"打开ChatHub的快捷键\",\n  \"Settings\": \"设置\",\n  \"Startup page\": \"启动页面\",\n  \"Chat style\": \"会话风格\",\n  \"Change shortcut\": \"修改快捷键\",\n  \"Save\": \"保存\",\n  \"Saved\": \"已保存\",\n  \"Export\": \"导出\",\n  \"Import\": \"导入\",\n  \"Export/Import All Data\": \"导出/导入数据\",\n  \"Data includes all your settings, chat histories, and local prompts\": \"数据包括所有设置、聊天记录和本地prompts\",\n  \"Edit\": \"编辑\",\n  \"Use\": \"使用\",\n  \"Send\": \"发送\",\n  \"Stop\": \"停止\",\n  \"Title\": \"标题\",\n  \"Content\": \"内容\",\n  \"Search\": \"搜索\",\n  \"Model\": \"模型\",\n  \"Cancel\": \"取消\",\n  \"Presale discount\": \"预售折扣\",\n  \"More layouts in All-In-One mode\": \"解锁All-In-One模式下更多布局\",\n  \"Chat with more than 2 bots simultaneously\": \"同时和两个以上的机器人聊天\",\n  \"Full-text search for chat history\": \"全文搜索聊天记录\",\n  \"Customize theme\": \"自定义主题\",\n  \"Support the development of ChatHub\": \"支持ChatHub的开发\",\n  \"Enjoy ChatHub? Give us a 5-star rating!\": \"喜欢ChatHub吗？给我们个5星好评吧！\",\n  \"Write review\": \"去评价\",\n  \"Activate license\": \"激活License\",\n  \"🎉 License activated\": \"🎉 License已激活\",\n  \"All-In-One Mode\": \"All-In-One模式\",\n  \"Two in one\": \"二合一\",\n  \"Three in one\": \"三合一\",\n  \"Four in one\": \"四合一\",\n  \"Activate up to 5 devices\": \"最多可激活5台设备\",\n  \"Deactivate\": \"反激活\",\n  \"Buy premium license\": \"购买会员\",\n  \"Theme Settings\": \"主题设置\",\n  \"Theme Mode\": \"主题模式\",\n  \"Theme Color\": \"主题色\",\n  \"Follow Arc browser theme\": \"跟随Arc浏览器主题色\",\n  \"iFlytek Spark\": \"讯飞星火\",\n  \"You need to login to Poe first\": \"需要先登录Poe账号\",\n  \"Login at bing.com\": \"去 bing.com 登录\",\n  \"Login at poe.com\": \"去 poe.com 登录\",\n  \"Login at xfyun.cn\": \"登录讯飞账号\",\n  \"Lifetime license\": \"终身授权\",\n  \"Join the waitlist\": \"加入waitlist\",\n  \"GPT-4 models require ChatGPT Plus\": \"ChatGPT Plus账号可使用\",\n  \"Model used by ChatGPT iOS app, potentially faster\": \"ChatGPT iOS app使用的模型，可能更快\",\n  \"Poe subscribers only\": \"Poe订阅会员可用\",\n  \"Quick access in Chrome side bar\": \"在Chrome侧边栏快速访问\",\n  \"You have opened ChatHub {{openTimes}} times, consider unlock all features?\": \"哇！你已经打开ChatHub {{openTimes}}次了，是否要解锁全部功能呢？🥺\",\n  \"Open Prompt Library\": \"管理提示词\",\n  \"Use / to select prompts, Shift+Enter to add new line\": \"使用 / 选择提示词，Shift+Enter添加换行\",\n  \"Your Prompts\": \"你的提示词\",\n  \"Community Prompts\": \"提示词社区\",\n  \"Create new prompt\": \"创建提示词\",\n  \"Earlybird price\": \"夏日特惠\",\n  \"Share conversation\": \"分享会话\",\n  \"Clear conversation\": \"清空会话\",\n  \"View history\": \"查看历史消息\",\n  \"Premium Feature\": \"会员功能\",\n  \"Upgrade to unlock\": \"升级解锁\",\n  \"Please check your network connection\": \"请检查您的网络连接，中国用户可能需要科学上网\",\n  \"Display size\": \"显示大小\",\n  \"You’ve reached the daily free message limit for this model\": \"你已经达到了该模型今日免费消息上限\",\n  \"This is a limitation set by poe.com\": \"这是poe.com的限制\",\n  \"Feedback\": \"反馈\",\n  \"Theme\": \"主题\",\n  \"Premium\": \"付费会员\",\n  \"Chatbots\": \"聊天机器人\",\n  \"Manage order and devices\": \"管理订单与设备\",\n  \"Upgrade\": \"升级\",\n  \"This usually mean you need to add a payment method to your OpenAI account, checkout: \": \"这通常意味着您需要在OpenAI账户中添加付款方式，请查看：\",\n  \"Are you sure you want to clear history messages?\": \"确定要清空历史消息吗？\",\n  \"Clear history messages\": \"清空消息\",\n  \"Compare with image input\": \"用图片作为输入\",\n  \"Web Access\": \"联网搜索\",\n  \"Upgrade to Premium for web access and more features\": \"升级会员，解锁联网搜索和更多功能\",\n  \"Improving accuracy by searching up-to-date information from the internet\": \"通过智能联网搜索最新信息，提高回答准确度\",\n  \"Checkout premium features\": \"查看会员功能\",\n  \"Login to ChatGPT\": \"登录ChatGPT\",\n  \"Switch to API mode\": \"切换到API模式\",\n  \"Mode\": \"模式\",\n  \"Display\": \"显示\",\n  \"Display Settings\": \"显示设置\",\n  \"Auto\": \"自动\",\n  \"Language\": \"语言\",\n  \"Limited-time offer\": \"限时特惠\",\n  \"Buy once, use forever\": \"一次性买断价\",\n  \"20% OFF: ends in\": \"八折优惠，限时\",\n  \"Special Offer: 20% OFF\": \"特别优惠：立享八折\",\n  \"TODAY ONLY\": \"今日限定\",\n  \"Get Discount\": \"获取优惠\",\n  \"Webapp mode uses your login session in current browser\": \"Webapp模式会使用当前浏览器中的登录状态\",\n  \"Your keys are stored locally\": \"您的key只会保存在本地\",\n  \"Login to Claude.ai\": \"登录Claude.ai\",\n  \"Login to Bard\": \"登录Bard\",\n  \"Recent Updates\": \"最近更新\",\n  \"Added a separate Gemini Pro bot, can be enabled in the settings\": \"添加了Gemini Pro，可在设置中启用\",\n  \"Save changes\": \"保存更改\"\n}\n"
  },
  {
    "path": "src/app/i18n/locales/spanish.json",
    "content": "{\n  \"Shortcut to open this app\": \"Atajo para abrir esta aplicación\",\n  \"Settings\": \"Configuración\",\n  \"Startup page\": \"Página de inicio\",\n  \"Chat style\": \"Estilo de chat\",\n  \"Change shortcut\": \"Cambiar atajo\",\n  \"Save\": \"Guardar\",\n  \"Saved\": \"Guardado\",\n  \"Export\": \"Exportar\",\n  \"Import\": \"Importar\",\n  \"Export/Import All Data\": \"Exportar/Importar todos los datos\",\n  \"Data includes all your settings, chat histories, and local prompts\": \"Los datos incluyen todas las configuraciones, historiales de chat y promts locales\",\n  \"Edit\": \"Editar\",\n  \"Use\": \"Usar\",\n  \"Send\": \"Enviar\",\n  \"Stop\": \"Detener\",\n  \"Title\": \"Título\",\n  \"Content\": \"Contenido\",\n  \"Search\": \"Buscar\",\n  \"Model\": \"Modelo\",\n  \"Cancel\": \"Cancelar\",\n  \"Presale discount\": \"Descuento de preventa\",\n  \"More layouts in All-In-One mode\": \"Más diseños en el modo Todo en uno\",\n  \"Chat with more than 2 bots simultaneously\": \"Chatear con más de 2 bots simultáneamente\",\n  \"Full-text search for chat history\": \"Búsqueda de texto completo para el historial de chat\",\n  \"Customize theme\": \"Personalizar tema\",\n  \"Support the development of ChatHub\": \"Apoyar el desarrollo de ChatHub\",\n  \"Enjoy ChatHub? Give us a 5-star rating!\": \"¿Disfrutas de ChatHub? ¡Danos una calificación de 5 estrellas!\",\n  \"Write review\": \"Escribir reseña\",\n  \"Activate license\": \"Activar licencia\",\n  \"🎉 License activated\": \"🎉 Licencia activada\",\n  \"All-In-One Mode\": \"Modo Todo en uno\",\n  \"Two in one\": \"Dos en uno\",\n  \"Three in one\": \"Tres en uno\",\n  \"Four in one\": \"Cuatro en uno\",\n  \"Activate up to 5 devices\": \"Activar hasta 5 dispositivos\",\n  \"Deactivate\": \"Desactivar\",\n  \"Buy premium license\": \"Obtener licencia premium\",\n  \"Theme Settings\": \"Configuración del tema\",\n  \"Theme Mode\": \"Modo de tema\",\n  \"Theme Color\": \"Color del tema\",\n  \"Follow Arc browser theme\": \"Seguir el tema del navegador Arc\",\n  \"iFlytek Spark\": \"iFlytek Spark\",\n  \"You need to login to Poe first\": \"Necesitas iniciar sesión en Poe primero\",\n  \"Login at bing.com\": \"Iniciar sesión en bing.com\",\n  \"Login at poe.com\": \"Iniciar sesión en poe.com\",\n  \"Login at xfyun.cn\": \"Iniciar sesión en xfyun.cn\",\n  \"Lifetime license\": \"Licencia de por vida\",\n  \"Join the waitlist\": \"Unirse a la lista de espera\",\n  \"GPT-4 models require ChatGPT Plus\": \"Los modelos GPT-4 requieren ChatGPT Plus\",\n  \"Model used by ChatGPT iOS app, potentially faster\": \"Modelo utilizado por la aplicación ChatGPT iOS, potencialmente más rápido\",\n  \"Poe subscribers only\": \"Solo suscriptores de Poe\",\n  \"Quick access in Chrome side bar\": \"Acceso rápido en la barra lateral de Chrome\",\n  \"You have opened ChatHub {{openTimes}} times, consider unlock all features?\": \"Has abierto ChatHub {{openTimes}} veces, ¿consideras desbloquear todas las funciones? 🥺\",\n  \"Open Prompt Library\": \"Abrir biblioteca de promts\",\n  \"Use / to select prompts, Shift+Enter to add new line\": \"Usar / para seleccionar promts, Shift+Enter para agregar nueva línea\",\n  \"Your Prompts\": \"Tus promts\",\n  \"Community Prompts\": \"Promts de la comunidad\",\n  \"Create new prompt\": \"Crear nuevo prompt\",\n  \"Earlybird price\": \"Precio de Earlybird\",\n  \"Share conversation\": \"Compartir conversación\",\n  \"Clear conversation\": \"Borrar conversación\",\n  \"View history\": \"Ver historial\",\n  \"Premium Feature\": \"Función premium\",\n  \"Upgrade to unlock\": \"Actualizar para desbloquear\",\n  \"Please check your network connection\": \"Por favor, comprueba tu conexión de red\",\n  \"Display size\": \"Tamaño de pantalla\",\n  \"You’ve reached the daily free message limit for this model\": \"Has alcanzado el límite diario de mensajes gratuitos para este modelo\",\n  \"This is a limitation set by poe.com\": \"Esta es una limitación establecida por poe.com\",\n  \"Feedback\": \"Comentarios\",\n  \"Theme\": \"Tema\",\n  \"Premium\": \"Premium\",\n  \"Chatbots\": \"Chatbots\",\n  \"Manage order and devices\": \"Gestionar pedidos y dispositivos\",\n  \"Upgrade\": \"Actualizar\",\n  \"This usually mean you need to add a payment method to your OpenAI account, checkout: \": \"Esto suele significar que necesitas agregar un método de pago a tu cuenta de OpenAI, consulta: \",\n  \"Are you sure you want to clear history messages?\": \"¿Estás seguro de que quieres borrar los mensajes del historial?\",\n  \"Clear history messages\": \"Borrar mensajes del historial\",\n  \"Compare with image input\": \"Comparar con entrada de imagen\",\n  \"Web Access\": \"Acceso web\",\n  \"Upgrade to Premium for web access and more features\": \"Actualiza a Premium para acceder a la web y más funciones\",\n  \"Improving accuracy by searching up-to-date information from the internet\": \"Mejorar la precisión buscando información actualizada en Internet\",\n  \"Checkout premium features\": \"Ver funciones premium\",\n  \"Login to ChatGPT\": \"Iniciar sesión en ChatGPT\",\n  \"Switch to API mode\": \"Cambiar a modo API\",\n  \"Mode\": \"Modo\",\n  \"Display\": \"Mostrar\",\n  \"Display Settings\": \"Configuración de pantalla\",\n  \"Auto\": \"Automático\",\n  \"Language\": \"Idioma\"\n}\n"
  },
  {
    "path": "src/app/i18n/locales/thai.json",
    "content": "{\n  \"Shortcut to open this app\": \"ทางลัดเพื่อเปิดแอปนี้\",\n  \"Settings\": \"การตั้งค่า\",\n  \"Startup page\": \"หน้าเริ่มต้น\",\n  \"Chat style\": \"สไตล์แชท\",\n  \"Change shortcut\": \"เปลี่ยนทางลัด\",\n  \"Save\": \"บันทึก\",\n  \"Saved\": \"บันทึกแล้ว\",\n  \"Export\": \"ส่งออก\",\n  \"Import\": \"นำเข้า\",\n  \"Export/Import All Data\": \"ส่งออก/นำเข้าข้อมูลทั้งหมด\",\n  \"Data includes all your settings, chat histories, and local prompts\": \"ข้อมูลรวมถึงการตั้งค่าทั้งหมดของคุณ ประวัติการแชท และ prompts ท้องถิ่น\",\n  \"Edit\": \"แก้ไข\",\n  \"Use\": \"ใช้\",\n  \"Send\": \"ส่ง\",\n  \"Stop\": \"หยุด\",\n  \"Title\": \"หัวข้อ\",\n  \"Content\": \"เนื้อหา\",\n  \"Search\": \"ค้นหา\",\n  \"Model\": \"โมเดล\",\n  \"Cancel\": \"ยกเลิก\",\n  \"Presale discount\": \"ส่วนลดก่อนขาย\",\n  \"More layouts in All-In-One mode\": \"เลย์เอาท์เพิ่มเติมในโหมด All-In-One\",\n  \"Chat with more than 2 bots simultaneously\": \"แชทกับบอทมากกว่า 2 ตัวพร้อมกัน\",\n  \"Full-text search for chat history\": \"ค้นหาข้อความเต็มรูปแบบสำหรับประวัติการแชท\",\n  \"Customize theme\": \"ปรับแต่งธีม\",\n  \"Support the development of ChatHub\": \"สนับสนุนการพัฒนา ChatHub\",\n  \"Enjoy ChatHub? Give us a 5-star rating!\": \"ชอบ ChatHub หรือไม่? ให้เราคะแนน 5 ดาว!\",\n  \"Write review\": \"เขียนรีวิว\",\n  \"Activate license\": \"เปิดใช้งานใบอนุญาต\",\n  \"🎉 License activated\": \"🎉 เปิดใช้งานใบอนุญาตแล้ว\",\n  \"All-In-One Mode\": \"โหมด All-In-One\",\n  \"Two in one\": \"สองในหนึ่ง\",\n  \"Three in one\": \"สามในหนึ่ง\",\n  \"Four in one\": \"สี่ในหนึ่ง\",\n  \"Activate up to 5 devices\": \"เปิดใช้งานได้สูงสุด 5 เครื่อง\",\n  \"Deactivate\": \"ปิดใช้งาน\",\n  \"Buy premium license\": \"รับใบอนุญาตพรีเมียม\",\n  \"Theme Settings\": \"การตั้งค่าธีม\",\n  \"Theme Mode\": \"โหมดธีม\",\n  \"Theme Color\": \"สีธีม\",\n  \"Follow Arc browser theme\": \"ตามธีมเบราว์เซอร์ Arc\",\n  \"iFlytek Spark\": \"iFlytek Spark\",\n  \"You need to login to Poe first\": \"คุณต้องเข้าสู่ระบบ Poe ก่อน\",\n  \"Login at bing.com\": \"เข้าสู่ระบบที่ bing.com\",\n  \"Login at poe.com\": \"เข้าสู่ระบบที่ poe.com\",\n  \"Login at xfyun.cn\": \"เข้าสู่ระบบ xfyun\",\n  \"Lifetime license\": \"ใบอนุญาตตลอดชีพ\",\n  \"Join the waitlist\": \"เข้าร่วมรายการรอ\",\n  \"GPT-4 models require ChatGPT Plus\": \"โมเดล GPT-4 ต้องการ ChatGPT Plus\",\n  \"Model used by ChatGPT iOS app, potentially faster\": \"โมเดลที่ใช้โดยแอป ChatGPT iOS อาจเร็วกว่า\",\n  \"Poe subscribers only\": \"สำหรับสมาชิก Poe เท่านั้น\",\n  \"Quick access in Chrome side bar\": \"เข้าถึงได้อย่างรวดเร็วในแถบด้านข้างของ Chrome\",\n  \"You have opened ChatHub {{openTimes}} times, consider unlock all features?\": \"คุณเปิด ChatHub {{openTimes}} ครั้ง คุณควรพิจารณาปลดล็อกคุณสมบัติทั้งหมดหรือไม่? 🥺\",\n  \"Open Prompt Library\": \"เปิด Prompt Library\",\n  \"Use / to select prompts, Shift+Enter to add new line\": \"ใช้ / เพื่อเลือก prompts ใช้ Shift+Enter เพื่อเพิ่มบรรทัดใหม่\",\n  \"Your Prompts\": \"Prompts ของคุณ\",\n  \"Community Prompts\": \"Prompts ชุมชน\",\n  \"Create new prompt\": \"สร้าง prompt ใหม่\",\n  \"Earlybird price\": \"ราคา Earlybird\",\n  \"Share conversation\": \"แชร์การสนทนา\",\n  \"Clear conversation\": \"ล้างการสนทนา\",\n  \"View history\": \"ดูประวัติ\",\n  \"Premium Feature\": \"คุณสมบัติพรีเมียม\",\n  \"Upgrade to unlock\": \"อัปเกรดเพื่อปลดล็อก\",\n  \"Please check your network connection\": \"โปรดตรวจสอบการเชื่อมต่อเครือข่ายของคุณ\",\n  \"Display size\": \"ขนาดหน้าจอ\",\n  \"You’ve reached the daily free message limit for this model\": \"คุณได้ถึงขีดจำกัดข้อความฟรีรายวันสำหรับโมเดลนี้แล้ว\",\n  \"This is a limitation set by poe.com\": \"นี่เป็นข้อจำกัดที่ตั้งค่าโดย poe.com\",\n  \"Feedback\": \"คำติชม\",\n  \"Theme\": \"ธีม\",\n  \"Premium\": \"พรีเมียม\",\n  \"Chatbots\": \"แชทบอท\",\n  \"Manage order and devices\": \"จัดการคำสั่งซื้อและอุปกรณ์\",\n  \"Upgrade\": \"อัพเกรด\",\n  \"This usually mean you need to add a payment method to your OpenAI account, checkout: \": \"นี้มักหมายความว่าคุณต้องเพิ่มวิธีการชำระเงินในบัญชี OpenAI ของคุณ ชำระเงิน: \",\n  \"Are you sure you want to clear history messages?\": \"คุณแน่ใจหรือว่าต้องการล้างข้อความประวัติ?\",\n  \"Clear history messages\": \"ล้างข้อความประวัติ\",\n  \"Compare with image input\": \"เปรียบเทียบกับการป้อนรูปภาพ\",\n  \"Web Access\": \"เข้าถึงเว็บ\",\n  \"Upgrade to Premium for web access and more features\": \"อัปเกรดเป็นพรีเมียมเพื่อเข้าถึงเว็บและคุณสมบัติเพิ่มเติม\",\n  \"Improving accuracy by searching up-to-date information from the internet\": \"ปรับปรุงความแม่นยำโดยการค้นหาข้อมูลล่าสุดจากอินเทอร์เน็ต\",\n  \"Checkout premium features\": \"ตรวจสอบคุณสมบัติพรีเมียม\",\n  \"Login to ChatGPT\": \"เข้าสู่ระบบ ChatGPT\",\n  \"Switch to API mode\": \"สลับเป็นโหมด API\",\n  \"Mode\": \"โหมด\",\n  \"Display\": \"แสดง\",\n  \"Display Settings\": \"การตั้งค่าการแสดงผล\",\n  \"Auto\": \"อัตโนมัติ\",\n  \"Language\": \"ภาษา\"\n}\n"
  },
  {
    "path": "src/app/i18n/locales/traditional-chinese.json",
    "content": "{\n  \"Shortcut to open this app\": \"打開ChatHub的快捷鍵\",\n  \"Settings\": \"設置\",\n  \"Startup page\": \"啟動頁面\",\n  \"Chat style\": \"會話風格\",\n  \"Change shortcut\": \"修改快捷鍵\",\n  \"Save\": \"保存\",\n  \"Saved\": \"已保存\",\n  \"Export\": \"導出\",\n  \"Import\": \"導入\",\n  \"Export/Import All Data\": \"導出/導入數據\",\n  \"Data includes all your settings, chat histories, and local prompts\": \"數據包括所有設置、聊天記錄和本地prompts\",\n  \"Edit\": \"編輯\",\n  \"Use\": \"使用\",\n  \"Send\": \"發送\",\n  \"Stop\": \"停止\",\n  \"Title\": \"標題\",\n  \"Content\": \"內容\",\n  \"Search\": \"搜索\",\n  \"Model\": \"模型\",\n  \"Cancel\": \"取消\",\n  \"Presale discount\": \"預售折扣\",\n  \"More layouts in All-In-One mode\": \"解鎖All-In-One模式下更多佈局\",\n  \"Chat with more than 2 bots simultaneously\": \"同時與超過2個機器人聊天\",\n  \"Full-text search for chat history\": \"聊天記錄的全文搜索\",\n  \"Customize theme\": \"自定義主題\",\n  \"Support the development of ChatHub\": \"支持ChatHub的開發\",\n  \"Enjoy ChatHub? Give us a 5-star rating!\": \"喜歡ChatHub嗎？給我們個5星好評吧！\",\n  \"Write review\": \"去評價\",\n  \"Activate license\": \"啟用License\",\n  \"🎉 License activated\": \"🎉 License已啟用\",\n  \"All-In-One Mode\": \"All-In-One模式\",\n  \"Two in one\": \"二合一\",\n  \"Three in one\": \"三合一\",\n  \"Four in one\": \"四合一\",\n  \"Activate up to 5 devices\": \"最多可啟用5台設備\",\n  \"Deactivate\": \"反啟用\",\n  \"Buy premium license\": \"購買會員\",\n  \"Theme Settings\": \"主題設置\",\n  \"Theme Mode\": \"主題模式\",\n  \"Theme Color\": \"主題色\",\n  \"Follow Arc browser theme\": \"跟隨Arc瀏覽器主題色\",\n  \"iFlytek Spark\": \"訊飛星火\",\n  \"You need to login to Poe first\": \"需要先登錄Poe賬號\",\n  \"Login at bing.com\": \"去 bing.com 登錄\",\n  \"Login at poe.com\": \"去 poe.com 登錄\",\n  \"Login at xfyun.cn\": \"登錄訊飛賬號\",\n  \"Lifetime license\": \"終身授權\",\n  \"Join the waitlist\": \"加入waitlist\",\n  \"GPT-4 models require ChatGPT Plus\": \"ChatGPT Plus賬號可使用\",\n  \"Model used by ChatGPT iOS app, potentially faster\": \"ChatGPT iOS app使用的模型，可能更快\",\n  \"Poe subscribers only\": \"Poe訂閱會員可用\",\n  \"Quick access in Chrome side bar\": \"在Chrome側邊欄快速訪問\",\n  \"You have opened ChatHub {{openTimes}} times, consider unlock all features?\": \"哇！你已經打開ChatHub {{openTimes}}次了，是否要解鎖全部功能呢？🥺\",\n  \"Open Prompt Library\": \"管理提示詞\",\n  \"Use / to select prompts, Shift+Enter to add new line\": \"使用 / 選擇提示詞，Shift+Enter添加換行\",\n  \"Your Prompts\": \"你的提示詞\",\n  \"Community Prompts\": \"提示詞社區\",\n  \"Create new prompt\": \"創建提示詞\",\n  \"Earlybird price\": \"夏日特惠\",\n  \"Share conversation\": \"分享會話\",\n  \"Clear conversation\": \"清空會話\",\n  \"View history\": \"查看歷史消息\",\n  \"Premium Feature\": \"會員功能\",\n  \"Upgrade to unlock\": \"升級解鎖\",\n  \"Please check your network connection\": \"請檢查您的網絡連接\",\n  \"Display size\": \"顯示大小\",\n  \"You’ve reached the daily free message limit for this model\": \"你已經達到了該模型今日免費消息上限\",\n  \"This is a limitation set by poe.com\": \"這是poe.com的限制\",\n  \"Feedback\": \"反饋\",\n  \"Theme\": \"主題\",\n  \"Premium\": \"付費會員\",\n  \"Chatbots\": \"聊天機器人\",\n  \"Manage order and devices\": \"管理訂單與設備\",\n  \"Upgrade\": \"升級\",\n  \"This usually mean you need to add a payment method to your OpenAI account, checkout: \": \"這通常意味着您需要在OpenAI賬戶中添加付款方式，請查看：\",\n  \"Are you sure you want to clear history messages?\": \"確定要清空歷史消息嗎？\",\n  \"Clear history messages\": \"清空消息\",\n  \"Compare with image input\": \"用圖片作為輸入\",\n  \"Web Access\": \"聯網搜索\",\n  \"Upgrade to Premium for web access and more features\": \"升級會員，解鎖聯網搜索和更多功能\",\n  \"Improving accuracy by searching up-to-date information from the internet\": \"通過智能聯網搜索最新信息，提高回答準確度\",\n  \"Checkout premium features\": \"查看會員功能\",\n  \"Login to ChatGPT\": \"登錄ChatGPT\",\n  \"Switch to API mode\": \"切換到API模式\",\n  \"Mode\": \"模式\",\n  \"Display\": \"顯示\",\n  \"Display Settings\": \"顯示設置\",\n  \"Auto\": \"自動\",\n  \"Language\": \"語言\",\n  \"Limited-time offer\": \"限時優惠\",\n  \"Buy once, use forever\": \"買一次，永久使用\",\n  \"20% OFF: ends in\": \"八折優惠：即將結束\",\n  \"Special Offer: 20% OFF\": \"特別優惠：八折優惠\",\n  \"TODAY ONLY\": \"今日限定\",\n  \"Get Discount\": \"獲取優惠\"\n}\n"
  },
  {
    "path": "src/app/main.tsx",
    "content": "import { RouterProvider } from '@tanstack/react-router'\nimport { createRoot } from 'react-dom/client'\nimport '../services/sentry'\nimport './base.scss'\nimport './i18n'\nimport { plausible } from './plausible'\nimport { router } from './router'\n\nconst container = document.getElementById('app')!\nconst root = createRoot(container)\nroot.render(<RouterProvider router={router} />)\n\nplausible.enableAutoPageviews()\n"
  },
  {
    "path": "src/app/pages/MultiBotChatPanel.tsx",
    "content": "import { useAtom, useAtomValue, useSetAtom } from 'jotai'\nimport { atomWithStorage } from 'jotai/utils'\nimport { sample, uniqBy } from 'lodash-es'\nimport { FC, Suspense, useCallback, useEffect, useMemo } from 'react'\nimport { useTranslation } from 'react-i18next'\nimport { cx } from '~/utils'\nimport Button from '~app/components/Button'\nimport ChatMessageInput from '~app/components/Chat/ChatMessageInput'\nimport LayoutSwitch from '~app/components/Chat/LayoutSwitch'\nimport { CHATBOTS, Layout } from '~app/consts'\nimport { useChat } from '~app/hooks/use-chat'\nimport { usePremium } from '~app/hooks/use-premium'\nimport { trackEvent } from '~app/plausible'\nimport { showPremiumModalAtom } from '~app/state'\nimport { BotId } from '../bots'\nimport ConversationPanel from '../components/Chat/ConversationPanel'\n\nconst DEFAULT_BOTS: BotId[] = Object.keys(CHATBOTS).slice(0, 6) as BotId[]\n\nconst layoutAtom = atomWithStorage<Layout>('multiPanelLayout', 2, undefined, { getOnInit: true })\nconst twoPanelBotsAtom = atomWithStorage<BotId[]>('multiPanelBots:2', DEFAULT_BOTS.slice(0, 2))\nconst threePanelBotsAtom = atomWithStorage<BotId[]>('multiPanelBots:3', DEFAULT_BOTS.slice(0, 3))\nconst fourPanelBotsAtom = atomWithStorage<BotId[]>('multiPanelBots:4', DEFAULT_BOTS.slice(0, 4))\nconst sixPanelBotsAtom = atomWithStorage<BotId[]>('multiPanelBots:6', DEFAULT_BOTS.slice(0, 6))\n\nfunction replaceDeprecatedBots(bots: BotId[]): BotId[] {\n  return bots.map((bot) => {\n    if (CHATBOTS[bot]) {\n      return bot\n    }\n    return sample(DEFAULT_BOTS)!\n  })\n}\n\nconst GeneralChatPanel: FC<{\n  chats: ReturnType<typeof useChat>[]\n  setBots?: ReturnType<typeof useSetAtom<typeof twoPanelBotsAtom>>\n  supportImageInput?: boolean\n}> = ({ chats, setBots, supportImageInput }) => {\n  const { t } = useTranslation()\n  const generating = useMemo(() => chats.some((c) => c.generating), [chats])\n  const [layout, setLayout] = useAtom(layoutAtom)\n\n  const setPremiumModalOpen = useSetAtom(showPremiumModalAtom)\n  const premiumState = usePremium()\n  const disabled = useMemo(() => !premiumState.isLoading && !premiumState.activated, [premiumState])\n\n  useEffect(() => {\n    if (disabled && (chats.length > 2 || supportImageInput)) {\n      setPremiumModalOpen('all-in-one-layout')\n    }\n  }, [chats.length, disabled, setPremiumModalOpen, supportImageInput])\n\n  const sendSingleMessage = useCallback(\n    (input: string, botId: BotId) => {\n      const chat = chats.find((c) => c.botId === botId)\n      chat?.sendMessage(input)\n    },\n    [chats],\n  )\n\n  const sendAllMessage = useCallback(\n    (input: string, image?: File) => {\n      if (disabled && chats.length > 2) {\n        setPremiumModalOpen('all-in-one-layout')\n        return\n      }\n      uniqBy(chats, (c) => c.botId).forEach((c) => c.sendMessage(input, image))\n      trackEvent('send_messages', { layout, disabled })\n    },\n    [chats, disabled, layout, setPremiumModalOpen],\n  )\n\n  const onSwitchBot = useCallback(\n    (botId: BotId, index: number) => {\n      if (!setBots) {\n        return\n      }\n      trackEvent('switch_bot', { botId, panel: chats.length })\n      setBots((bots) => {\n        const newBots = [...bots]\n        newBots[index] = botId\n        return newBots\n      })\n    },\n    [chats.length, setBots],\n  )\n\n  const onLayoutChange = useCallback(\n    (v: Layout) => {\n      trackEvent('switch_all_in_one_layout', { layout: v })\n      setLayout(v)\n    },\n    [setLayout],\n  )\n\n  return (\n    <div className=\"flex flex-col overflow-hidden h-full\">\n      <div\n        className={cx(\n          'grid overflow-hidden grow auto-rows-fr',\n          chats.length % 3 === 0 ? 'grid-cols-3' : 'grid-cols-2',\n          chats.length > 3 ? 'gap-2 mb-2' : 'gap-3 mb-3',\n        )}\n      >\n        {chats.map((chat, index) => (\n          <ConversationPanel\n            key={`${chat.botId}-${index}`}\n            botId={chat.botId}\n            bot={chat.bot}\n            messages={chat.messages}\n            onUserSendMessage={(input) => sendSingleMessage(input, chat.botId)}\n            generating={chat.generating}\n            stopGenerating={chat.stopGenerating}\n            mode=\"compact\"\n            resetConversation={chat.resetConversation}\n            onSwitchBot={setBots ? (botId) => onSwitchBot(botId, index) : undefined}\n          />\n        ))}\n      </div>\n      <div className=\"flex flex-row gap-3\">\n        <LayoutSwitch layout={layout} onChange={onLayoutChange} />\n        <ChatMessageInput\n          mode=\"full\"\n          className=\"rounded-2xl bg-primary-background px-4 py-2 grow\"\n          disabled={generating}\n          onSubmit={sendAllMessage}\n          actionButton={!generating && <Button text={t('Send')} color=\"primary\" type=\"submit\" />}\n          autoFocus={true}\n          supportImageInput={supportImageInput}\n        />\n      </div>\n    </div>\n  )\n}\n\nconst TwoBotChatPanel = () => {\n  const [bots, setBots] = useAtom(twoPanelBotsAtom)\n  const multiPanelBotIds = useMemo(() => replaceDeprecatedBots(bots), [bots])\n  const chat1 = useChat(multiPanelBotIds[0])\n  const chat2 = useChat(multiPanelBotIds[1])\n  const chats = useMemo(() => [chat1, chat2], [chat1, chat2])\n  return <GeneralChatPanel chats={chats} setBots={setBots} />\n}\n\nconst ThreeBotChatPanel = () => {\n  const [bots, setBots] = useAtom(threePanelBotsAtom)\n  const multiPanelBotIds = useMemo(() => replaceDeprecatedBots(bots), [bots])\n  const chat1 = useChat(multiPanelBotIds[0])\n  const chat2 = useChat(multiPanelBotIds[1])\n  const chat3 = useChat(multiPanelBotIds[2])\n  const chats = useMemo(() => [chat1, chat2, chat3], [chat1, chat2, chat3])\n  return <GeneralChatPanel chats={chats} setBots={setBots} />\n}\n\nconst FourBotChatPanel = () => {\n  const [bots, setBots] = useAtom(fourPanelBotsAtom)\n  const multiPanelBotIds = useMemo(() => replaceDeprecatedBots(bots), [bots])\n  const chat1 = useChat(multiPanelBotIds[0])\n  const chat2 = useChat(multiPanelBotIds[1])\n  const chat3 = useChat(multiPanelBotIds[2])\n  const chat4 = useChat(multiPanelBotIds[3])\n  const chats = useMemo(() => [chat1, chat2, chat3, chat4], [chat1, chat2, chat3, chat4])\n  return <GeneralChatPanel chats={chats} setBots={setBots} />\n}\n\nconst SixBotChatPanel = () => {\n  const [bots, setBots] = useAtom(sixPanelBotsAtom)\n  const multiPanelBotIds = useMemo(() => replaceDeprecatedBots(bots), [bots])\n  const chat1 = useChat(multiPanelBotIds[0])\n  const chat2 = useChat(multiPanelBotIds[1])\n  const chat3 = useChat(multiPanelBotIds[2])\n  const chat4 = useChat(multiPanelBotIds[3])\n  const chat5 = useChat(multiPanelBotIds[4])\n  const chat6 = useChat(multiPanelBotIds[5])\n  const chats = useMemo(() => [chat1, chat2, chat3, chat4, chat5, chat6], [chat1, chat2, chat3, chat4, chat5, chat6])\n  return <GeneralChatPanel chats={chats} setBots={setBots} />\n}\n\nconst ImageInputPanel = () => {\n  const chat1 = useChat('chatgpt')\n  const chat2 = useChat('bing')\n  const chat3 = useChat('bard')\n  const chats = useMemo(() => [chat1, chat2, chat3], [chat1, chat2, chat3])\n  return <GeneralChatPanel chats={chats} supportImageInput={true} />\n}\n\nconst MultiBotChatPanel: FC = () => {\n  const layout = useAtomValue(layoutAtom)\n  if (layout === 'sixGrid') {\n    return <SixBotChatPanel />\n  }\n  if (layout === 4) {\n    return <FourBotChatPanel />\n  }\n  if (layout === 3) {\n    return <ThreeBotChatPanel />\n  }\n  if (layout === 'imageInput') {\n    return <ImageInputPanel />\n  }\n  return <TwoBotChatPanel />\n}\n\nconst MultiBotChatPanelPage: FC = () => {\n  return (\n    <Suspense>\n      <MultiBotChatPanel />\n    </Suspense>\n  )\n}\n\nexport default MultiBotChatPanelPage\n"
  },
  {
    "path": "src/app/pages/PremiumPage.tsx",
    "content": "import { useSearch } from '@tanstack/react-router'\nimport { get as getPath } from 'lodash-es'\nimport { useCallback, useState } from 'react'\nimport ConfettiExplosion from 'react-confetti-explosion'\nimport { Toaster } from 'react-hot-toast'\nimport { useTranslation } from 'react-i18next'\nimport Button from '~app/components/Button'\nimport DiscountBadge from '~app/components/Premium/DiscountBadge'\nimport FeatureList from '~app/components/Premium/FeatureList'\nimport PriceSection from '~app/components/Premium/PriceSection'\nimport { usePremium } from '~app/hooks/use-premium'\nimport { useDiscountCode } from '~app/hooks/use-purchase-info'\nimport { trackEvent } from '~app/plausible'\nimport { premiumRoute } from '~app/router'\nimport { activatePremium, deactivatePremium } from '~services/premium'\n\nfunction PremiumPage() {\n  const { t } = useTranslation()\n  const premiumState = usePremium()\n  const [activating, setActivating] = useState(false)\n  const [deactivating, setDeactivating] = useState(false)\n  const [activationError, setActivationError] = useState('')\n  const { source } = useSearch({ from: premiumRoute.id })\n  const [isExploding, setIsExploding] = useState(false)\n  const discountCode = useDiscountCode()\n\n  const activate = useCallback(async () => {\n    const key = window.prompt('Enter your license key', '')\n    if (!key) {\n      return\n    }\n    setActivationError('')\n    setActivating(true)\n    trackEvent('activate_license')\n    try {\n      await activatePremium(key)\n    } catch (err) {\n      console.error('activation', err)\n      setActivationError(getPath(err, 'data.error') || 'Activation failed')\n      setActivating(false)\n      return\n    }\n    setTimeout(() => location.reload(), 500)\n  }, [])\n\n  const deactivateLicense = useCallback(async () => {\n    if (!window.confirm('Are you sure to deactivate this device?')) {\n      return\n    }\n    setDeactivating(true)\n    trackEvent('deactivate_license')\n    await deactivatePremium()\n    setTimeout(() => location.reload(), 500)\n  }, [])\n\n  return (\n    <div className=\"flex flex-col bg-primary-background dark:text-primary-text rounded-[20px] h-full p-[50px] overflow-y-auto\">\n      <h1 className=\"font-bold text-[40px] leading-none text-primary-text\">{t('Premium')}</h1>\n      {!premiumState.activated && (\n        <div className=\"flex flex-col gap-4 mt-9\">\n          <DiscountBadge />\n          <PriceSection align=\"left\" />\n        </div>\n      )}\n      <div className=\"mt-8\">\n        <FeatureList />\n      </div>\n      <div className=\"flex flex-row items-center gap-3 mt-10\">\n        {premiumState.activated ? (\n          <>\n            <Button\n              text={t('🎉 License activated')}\n              color=\"primary\"\n              className=\"w-fit !py-2\"\n              onClick={() => setIsExploding(true)}\n            />\n            <Button\n              text={t('Deactivate')}\n              className=\"w-fit !py-2\"\n              onClick={deactivateLicense}\n              isLoading={deactivating}\n            />\n          </>\n        ) : (\n          <>\n            <a\n              href={`https://chathub.gg/api/premium/redirect?source=${source || ''}&discountCode=${discountCode || ''}`}\n              target=\"_blank\"\n              rel=\"noreferrer\"\n              onClick={() => trackEvent('click_buy_premium', { source: 'premium_page' })}\n            >\n              <Button text={t('Buy premium license')} color=\"primary\" className=\"w-fit !py-2 rounded-lg\" />\n            </a>\n            <Button\n              text={t('Activate license')}\n              color=\"flat\"\n              className=\"w-fit !py-2 rounded-lg\"\n              onClick={activate}\n              isLoading={activating || premiumState.isLoading}\n            />\n          </>\n        )}\n        <a\n          href=\"https://app.lemonsqueezy.com/my-orders/\"\n          target=\"_blank\"\n          rel=\"noreferrer\"\n          className=\"underline ml-2 text-sm text-secondary-text font-medium w-fit\"\n        >\n          {t('Manage order and devices')}\n        </a>\n      </div>\n      {!!(premiumState.error || activationError) && (\n        <span className=\"mt-3 text-red-500 font-medium\">{premiumState.error || activationError}</span>\n      )}\n      <Toaster position=\"top-right\" />\n      {isExploding && <ConfettiExplosion duration={3000} onComplete={() => setIsExploding(false)} />}\n    </div>\n  )\n}\n\nexport default PremiumPage\n"
  },
  {
    "path": "src/app/pages/SettingPage.tsx",
    "content": "import { motion } from 'framer-motion'\nimport { FC, PropsWithChildren, useCallback, useEffect, useState } from 'react'\nimport toast, { Toaster } from 'react-hot-toast'\nimport { useTranslation } from 'react-i18next'\nimport Browser from 'webextension-polyfill'\nimport Button from '~app/components/Button'\nimport { Input } from '~app/components/Input'\nimport RadioGroup from '~app/components/RadioGroup'\nimport Select from '~app/components/Select'\nimport Blockquote from '~app/components/Settings/Blockquote'\nimport ChatGPTAPISettings from '~app/components/Settings/ChatGPTAPISettings'\nimport ChatGPTAzureSettings from '~app/components/Settings/ChatGPTAzureSettings'\nimport ChatGPTOpenRouterSettings from '~app/components/Settings/ChatGPTOpenRouterSettings'\nimport ChatGPTPoeSettings from '~app/components/Settings/ChatGPTPoeSettings'\nimport ChatGPWebSettings from '~app/components/Settings/ChatGPTWebSettings'\nimport ClaudeAPISettings from '~app/components/Settings/ClaudeAPISettings'\nimport ClaudeOpenRouterSettings from '~app/components/Settings/ClaudeOpenRouterSettings'\nimport ClaudePoeSettings from '~app/components/Settings/ClaudePoeSettings'\nimport ClaudeWebappSettings from '~app/components/Settings/ClaudeWebappSettings'\nimport EnabledBotsSettings from '~app/components/Settings/EnabledBotsSettings'\nimport ExportDataPanel from '~app/components/Settings/ExportDataPanel'\nimport PerplexityAPISettings from '~app/components/Settings/PerplexityAPISettings'\nimport ShortcutPanel from '~app/components/Settings/ShortcutPanel'\nimport { ALL_IN_ONE_PAGE_ID, CHATBOTS } from '~app/consts'\nimport {\n  BingConversationStyle,\n  ChatGPTMode,\n  ClaudeMode,\n  PerplexityMode,\n  UserConfig,\n  getUserConfig,\n  updateUserConfig,\n} from '~services/user-config'\nimport { getVersion } from '~utils'\nimport PagePanel from '../components/Page'\n\nconst BING_STYLE_OPTIONS = [\n  { name: 'Precise', value: BingConversationStyle.Precise },\n  { name: 'Balanced', value: BingConversationStyle.Balanced },\n  { name: 'Creative', value: BingConversationStyle.Creative },\n]\n\nconst ChatBotSettingPanel: FC<PropsWithChildren<{ title: string }>> = (props) => {\n  return (\n    <div className=\"flex flex-col gap-1 border border-primary-border px-5 py-4 rounded-lg shadow-sm\">\n      <p className=\"font-bold text-md\">{props.title}</p>\n      {props.children}\n    </div>\n  )\n}\n\nfunction SettingPage() {\n  const { t } = useTranslation()\n  const [userConfig, setUserConfig] = useState<UserConfig | undefined>(undefined)\n  const [dirty, setDirty] = useState(false)\n\n  useEffect(() => {\n    getUserConfig().then((config) => setUserConfig(config))\n  }, [])\n\n  const updateConfigValue = useCallback(\n    (update: Partial<UserConfig>) => {\n      setUserConfig({ ...userConfig!, ...update })\n      setDirty(true)\n    },\n    [userConfig],\n  )\n\n  const save = useCallback(async () => {\n    let apiHost = userConfig?.openaiApiHost\n    if (apiHost) {\n      apiHost = apiHost.replace(/\\/$/, '')\n      if (!apiHost.startsWith('http')) {\n        apiHost = 'https://' + apiHost\n      }\n      // request host permission to prevent CORS issues\n      try {\n        await Browser.permissions.request({ origins: [apiHost + '/'] })\n      } catch (e) {\n        console.error(e)\n      }\n    } else {\n      apiHost = undefined\n    }\n    await updateUserConfig({ ...userConfig!, openaiApiHost: apiHost })\n    setDirty(false)\n    toast.success('Saved')\n    setTimeout(() => location.reload(), 500)\n  }, [userConfig])\n\n  if (!userConfig) {\n    return null\n  }\n\n  return (\n    <PagePanel title={`${t('Settings')} (v${getVersion()})`}>\n      <div className=\"flex flex-col gap-5 mt-3 mb-10 px-10\">\n        <div>\n          <p className=\"font-bold mb-2 text-lg\">{t('Startup page')}</p>\n          <div className=\"w-[200px]\">\n            <Select\n              options={[\n                { name: 'All-In-One', value: ALL_IN_ONE_PAGE_ID },\n                ...Object.entries(CHATBOTS).map(([botId, bot]) => ({ name: bot.name, value: botId })),\n              ]}\n              value={userConfig.startupPage}\n              onChange={(v) => updateConfigValue({ startupPage: v })}\n            />\n          </div>\n        </div>\n        <div className=\"flex flex-col gap-2 max-w-[700px]\">\n          <p className=\"font-bold text-lg\">{t('Chatbots')}</p>\n          <EnabledBotsSettings userConfig={userConfig} updateConfigValue={updateConfigValue} />\n        </div>\n        <div className=\"flex flex-col gap-5 w-fit max-w-[700px]\">\n          <ChatBotSettingPanel title=\"ChatGPT\">\n            <RadioGroup\n              options={Object.entries(ChatGPTMode).map(([k, v]) => ({ label: `${k} ${t('Mode')}`, value: v }))}\n              value={userConfig.chatgptMode}\n              onChange={(v) => updateConfigValue({ chatgptMode: v as ChatGPTMode })}\n            />\n            {userConfig.chatgptMode === ChatGPTMode.API ? (\n              <ChatGPTAPISettings userConfig={userConfig} updateConfigValue={updateConfigValue} />\n            ) : userConfig.chatgptMode === ChatGPTMode.Azure ? (\n              <ChatGPTAzureSettings userConfig={userConfig} updateConfigValue={updateConfigValue} />\n            ) : userConfig.chatgptMode === ChatGPTMode.Poe ? (\n              <ChatGPTPoeSettings userConfig={userConfig} updateConfigValue={updateConfigValue} />\n            ) : userConfig.chatgptMode === ChatGPTMode.OpenRouter ? (\n              <ChatGPTOpenRouterSettings userConfig={userConfig} updateConfigValue={updateConfigValue} />\n            ) : (\n              <ChatGPWebSettings userConfig={userConfig} updateConfigValue={updateConfigValue} />\n            )}\n          </ChatBotSettingPanel>\n          <ChatBotSettingPanel title=\"Claude\">\n            <RadioGroup\n              options={Object.entries(ClaudeMode).map(([k, v]) => ({ label: `${k} ${t('Mode')}`, value: v }))}\n              value={userConfig.claudeMode}\n              onChange={(v) => updateConfigValue({ claudeMode: v as ClaudeMode })}\n            />\n            {userConfig.claudeMode === ClaudeMode.API ? (\n              <ClaudeAPISettings userConfig={userConfig} updateConfigValue={updateConfigValue} />\n            ) : userConfig.claudeMode === ClaudeMode.Webapp ? (\n              <ClaudeWebappSettings userConfig={userConfig} updateConfigValue={updateConfigValue} />\n            ) : userConfig.claudeMode === ClaudeMode.OpenRouter ? (\n              <ClaudeOpenRouterSettings userConfig={userConfig} updateConfigValue={updateConfigValue} />\n            ) : (\n              <ClaudePoeSettings userConfig={userConfig} updateConfigValue={updateConfigValue} />\n            )}\n          </ChatBotSettingPanel>\n          <ChatBotSettingPanel title=\"Gemini Pro\">\n            <div className=\"flex flex-col gap-1\">\n              <p className=\"font-medium text-sm\">\n                API Key (\n                <a\n                  href=\"https://makersuite.google.com/app/apikey\"\n                  target=\"_blank\"\n                  rel=\"noreferrer\"\n                  className=\"underline\"\n                >\n                  how to create key\n                </a>\n                )\n              </p>\n              <Input\n                className=\"w-[400px]\"\n                placeholder=\"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\"\n                value={userConfig.geminiApiKey}\n                onChange={(e) => updateConfigValue({ geminiApiKey: e.currentTarget.value })}\n                type=\"password\"\n              />\n              <Blockquote className=\"mt-1\">{t('Your keys are stored locally')}</Blockquote>\n            </div>\n          </ChatBotSettingPanel>\n          <ChatBotSettingPanel title=\"Bing\">\n            <div className=\"flex flex-row gap-5 items-center\">\n              <p className=\"font-medium\">{t('Chat style')}</p>\n              <div className=\"w-[150px]\">\n                <Select\n                  options={BING_STYLE_OPTIONS}\n                  value={userConfig.bingConversationStyle}\n                  onChange={(v) => updateConfigValue({ bingConversationStyle: v })}\n                  position=\"top\"\n                />\n              </div>\n            </div>\n          </ChatBotSettingPanel>\n          <ChatBotSettingPanel title=\"Perplexity\">\n            <RadioGroup\n              options={Object.entries(PerplexityMode).map(([k, v]) => ({ label: `${k} ${t('Mode')}`, value: v }))}\n              value={userConfig.perplexityMode}\n              onChange={(v) => updateConfigValue({ perplexityMode: v as PerplexityMode })}\n            />\n            {userConfig.perplexityMode === PerplexityMode.API && (\n              <PerplexityAPISettings userConfig={userConfig} updateConfigValue={updateConfigValue} />\n            )}\n          </ChatBotSettingPanel>\n        </div>\n        <ShortcutPanel />\n        <ExportDataPanel />\n      </div>\n      {dirty && (\n        <motion.div\n          className=\"sticky bottom-0 w-full bg-primary-background border-t-2 border-primary-border px-5 py-4 drop-shadow flex flex-row items-center justify-center\"\n          initial={{ y: 100 }}\n          animate={{ y: 0 }}\n          transition={{ type: 'tween', ease: 'easeInOut' }}\n        >\n          <Button color=\"primary\" size=\"small\" text={t('Save changes')} onClick={save} className=\"py-2\" />\n        </motion.div>\n      )}\n      <Toaster position=\"bottom-center\" />\n    </PagePanel>\n  )\n}\n\nexport default SettingPage\n"
  },
  {
    "path": "src/app/pages/SidePanelPage.tsx",
    "content": "import { useAtom } from 'jotai'\nimport { useCallback, useMemo } from 'react'\nimport { useTranslation } from 'react-i18next'\nimport clearIcon from '~/assets/icons/clear.svg'\nimport { cx } from '~/utils'\nimport Button from '~app/components/Button'\nimport ChatMessageInput from '~app/components/Chat/ChatMessageInput'\nimport ChatMessageList from '~app/components/Chat/ChatMessageList'\nimport ChatbotName from '~app/components/Chat/ChatbotName'\nimport { CHATBOTS } from '~app/consts'\nimport { ConversationContext, ConversationContextValue } from '~app/context'\nimport { useChat } from '~app/hooks/use-chat'\nimport { sidePanelBotAtom } from '~app/state'\n\nfunction SidePanelPage() {\n  const { t } = useTranslation()\n  const [botId, setBotId] = useAtom(sidePanelBotAtom)\n  const botInfo = CHATBOTS[botId]\n  const chat = useChat(botId)\n\n  const onSubmit = useCallback(\n    async (input: string) => {\n      chat.sendMessage(input)\n    },\n    [chat],\n  )\n\n  const resetConversation = useCallback(() => {\n    if (!chat.generating) {\n      chat.resetConversation()\n    }\n  }, [chat])\n\n  const context: ConversationContextValue = useMemo(() => {\n    return {\n      reset: resetConversation,\n    }\n  }, [resetConversation])\n\n  return (\n    <ConversationContext.Provider value={context}>\n      <div className=\"flex flex-col overflow-hidden bg-primary-background h-full\">\n        <div className=\"border-b border-solid border-primary-border flex flex-row items-center justify-between gap-2 py-3 mx-3\">\n          <div className=\"flex flex-row items-center gap-2\">\n            <img src={botInfo.avatar} className=\"w-4 h-4 object-contain rounded-full\" />\n            <ChatbotName botId={botId} name={botInfo.name} onSwitchBot={setBotId} />\n          </div>\n          <div className=\"flex flex-row items-center gap-3\">\n            <img\n              src={clearIcon}\n              className={cx('w-4 h-4', chat.generating ? 'cursor-not-allowed' : 'cursor-pointer')}\n              onClick={resetConversation}\n            />\n          </div>\n        </div>\n        <ChatMessageList botId={botId} messages={chat.messages} className=\"mx-3\" />\n        <div className=\"flex flex-col mx-3 my-3 gap-3\">\n          <hr className=\"grow border-primary-border\" />\n          <ChatMessageInput\n            mode=\"compact\"\n            disabled={chat.generating}\n            autoFocus={true}\n            placeholder=\"Ask me anything...\"\n            onSubmit={onSubmit}\n            actionButton={\n              chat.generating ? (\n                <Button text={t('Stop')} color=\"flat\" size=\"small\" onClick={chat.stopGenerating} />\n              ) : (\n                <Button text={t('Send')} color=\"primary\" type=\"submit\" size=\"small\" />\n              )\n            }\n          />\n        </div>\n      </div>\n    </ConversationContext.Provider>\n  )\n}\n\nexport default SidePanelPage\n"
  },
  {
    "path": "src/app/pages/SingleBotChatPanel.tsx",
    "content": "import { FC } from 'react'\nimport { useChat } from '~app/hooks/use-chat'\nimport { BotId } from '../bots'\nimport ConversationPanel from '../components/Chat/ConversationPanel'\n\ninterface Props {\n  botId: BotId\n}\n\nconst SingleBotChatPanel: FC<Props> = ({ botId }) => {\n  const chat = useChat(botId)\n  return (\n    <div className=\"overflow-hidden h-full\">\n      <ConversationPanel\n        botId={botId}\n        bot={chat.bot}\n        messages={chat.messages}\n        onUserSendMessage={chat.sendMessage}\n        generating={chat.generating}\n        stopGenerating={chat.stopGenerating}\n        resetConversation={chat.resetConversation}\n      />\n    </div>\n  )\n}\n\nexport default SingleBotChatPanel\n"
  },
  {
    "path": "src/app/plausible.ts",
    "content": "import { isUndefined, omitBy } from 'lodash-es'\nimport Plausible from 'plausible-tracker'\nimport { getVersion } from '~utils'\n\nexport const plausible = Plausible({\n  domain: 'chathub.gg',\n  hashMode: true,\n  apiHost: import.meta.env.VITE_PLAUSIBLE_API_HOST || 'https://plausible.io',\n})\n\nexport function trackEvent(name: string, props?: { [propName: string]: string | number | boolean | undefined }) {\n  try {\n    plausible.trackEvent(name, {\n      props: {\n        version: getVersion(),\n        ...omitBy(props || {}, isUndefined),\n      },\n    })\n  } catch (err) {\n    console.error('plausible.trackEvent error', err)\n  }\n}\n"
  },
  {
    "path": "src/app/router.tsx",
    "content": "import { createHashHistory, createRootRoute, createRoute, createRouter, useParams } from '@tanstack/react-router'\nimport { BotId } from './bots'\nimport Layout from './components/Layout'\nimport MultiBotChatPanel from './pages/MultiBotChatPanel'\nimport PremiumPage from './pages/PremiumPage'\nimport SettingPage from './pages/SettingPage'\nimport SingleBotChatPanel from './pages/SingleBotChatPanel'\n\nconst rootRoute = createRootRoute()\n\nconst layoutRoute = createRoute({\n  getParentRoute: () => rootRoute,\n  component: Layout,\n  id: 'layout',\n})\n\nconst indexRoute = createRoute({\n  getParentRoute: () => layoutRoute,\n  path: '/',\n  component: MultiBotChatPanel,\n})\n\nfunction ChatRoute() {\n  const { botId } = useParams({ from: chatRoute.id })\n  return <SingleBotChatPanel botId={botId as BotId} />\n}\n\nconst chatRoute = createRoute({\n  getParentRoute: () => layoutRoute,\n  path: 'chat/$botId',\n  component: ChatRoute,\n})\n\nconst settingRoute = createRoute({\n  getParentRoute: () => layoutRoute,\n  path: 'setting',\n  component: SettingPage,\n})\n\nexport const premiumRoute = createRoute({\n  getParentRoute: () => layoutRoute,\n  path: 'premium',\n  component: PremiumPage,\n  validateSearch: (search: Record<string, unknown>) => {\n    return {\n      source: search.source as string | undefined,\n    }\n  },\n})\n\nconst routeTree = rootRoute.addChildren([layoutRoute.addChildren([indexRoute, chatRoute, settingRoute, premiumRoute])])\n\nconst hashHistory = createHashHistory()\nconst router = createRouter({ routeTree, history: hashHistory })\n\nexport { router }\n"
  },
  {
    "path": "src/app/sidepanel.css",
    "content": "html,\nbody,\n#app {\n  width: 100%;\n  height: 100%;\n}\n"
  },
  {
    "path": "src/app/sidepanel.tsx",
    "content": "import { useCallback } from 'react'\nimport { createRoot } from 'react-dom/client'\nimport { useTranslation } from 'react-i18next'\nimport Browser from 'webextension-polyfill'\nimport premiumIcon from '~/assets/icons/premium.svg'\nimport Button from './components/Button'\nimport { usePremium } from './hooks/use-premium'\nimport './i18n'\nimport SidePanelPage from './pages/SidePanelPage'\nimport { trackEvent } from './plausible'\nimport './base.scss'\nimport './sidepanel.css'\n\nfunction PremiumOnly() {\n  const { t } = useTranslation()\n\n  const openPremiumPage = useCallback(() => {\n    trackEvent('open_premium_from_sidepanel')\n    window.open(Browser.runtime.getURL('app.html#/premium?source=sidepanel'), '_blank')\n  }, [])\n\n  return (\n    <div className=\"w-full h-full flex flex-col justify-center items-center gap-3\">\n      <img src={premiumIcon} className=\"w-10 h-10\" />\n      <div className=\"text-xl font-bold\">{t('Premium Feature')}</div>\n      <Button text={t('Upgrade to unlock')} color=\"primary\" onClick={openPremiumPage} />\n    </div>\n  )\n}\n\nfunction SidePanelApp() {\n  const premiumState = usePremium()\n  if (premiumState.isLoading) {\n    return null\n  }\n  if (premiumState.activated) {\n    return <SidePanelPage />\n  }\n  return <PremiumOnly />\n}\n\nconst container = document.getElementById('app')!\nconst root = createRoot(container)\nroot.render(<SidePanelApp />)\n"
  },
  {
    "path": "src/app/state/index.ts",
    "content": "import { atom } from 'jotai'\nimport { atomWithImmer } from 'jotai-immer'\nimport { atomFamily, atomWithStorage } from 'jotai/utils'\nimport { BotId, createBotInstance } from '~app/bots'\nimport { FeatureId } from '~app/components/Premium/FeatureList'\nimport { getDefaultThemeColor } from '~app/utils/color-scheme'\nimport { Campaign } from '~services/server-api'\nimport { ChatMessageModel } from '~types'\nimport { uuid } from '~utils'\n\ntype Param = { botId: BotId; page: string }\n\nexport const chatFamily = atomFamily(\n  (param: Param) => {\n    return atomWithImmer({\n      botId: param.botId,\n      bot: createBotInstance(param.botId),\n      messages: [] as ChatMessageModel[],\n      generatingMessageId: '',\n      abortController: undefined as AbortController | undefined,\n      conversationId: uuid(),\n    })\n  },\n  (a, b) => a.botId === b.botId && a.page === b.page,\n)\n\nexport const licenseKeyAtom = atomWithStorage('licenseKey', '', undefined, { getOnInit: true })\nexport const sidebarCollapsedAtom = atomWithStorage('sidebarCollapsed', false, undefined, { getOnInit: true })\nexport const themeColorAtom = atomWithStorage('themeColor', getDefaultThemeColor())\nexport const followArcThemeAtom = atomWithStorage('followArcTheme', false)\nexport const sidePanelBotAtom = atomWithStorage<BotId>('sidePanelBot', 'chatgpt')\nexport const showDiscountModalAtom = atom<false | true | Campaign>(false)\nexport const showPremiumModalAtom = atom<false | true | FeatureId>(false)\nexport const releaseNotesAtom = atom<string[]>([])\n"
  },
  {
    "path": "src/app/theme.ts",
    "content": "import { getUserThemeMode } from '~services/theme'\nimport { applyThemeMode } from './utils/color-scheme'\n\napplyThemeMode(getUserThemeMode())\n\nexport {}\n"
  },
  {
    "path": "src/app/utils/color-scheme.ts",
    "content": "import { ThemeMode } from '~services/theme'\n\nconst COLOR_SCHEME_QUERY = '(prefers-color-scheme: dark)'\n\nfunction light() {\n  document.documentElement.classList.remove('dark')\n  document.documentElement.classList.add('light')\n}\n\nfunction dark() {\n  document.documentElement.classList.remove('light')\n  document.documentElement.classList.add('dark')\n}\n\nfunction isSystemDarkMode() {\n  return !!window.matchMedia(COLOR_SCHEME_QUERY).matches\n}\n\nfunction colorSchemeListener(e: MediaQueryListEvent) {\n  const colorScheme = e.matches ? 'dark' : 'light'\n  if (colorScheme === 'dark') {\n    dark()\n  } else {\n    light()\n  }\n}\n\nfunction applyThemeMode(mode: ThemeMode) {\n  if (mode === ThemeMode.Light) {\n    light()\n    window.matchMedia(COLOR_SCHEME_QUERY).removeEventListener('change', colorSchemeListener)\n    return\n  }\n\n  if (mode === ThemeMode.Dark) {\n    dark()\n    window.matchMedia(COLOR_SCHEME_QUERY).removeEventListener('change', colorSchemeListener)\n    return\n  }\n\n  if (isSystemDarkMode()) {\n    dark()\n  } else {\n    light()\n  }\n\n  window.matchMedia(COLOR_SCHEME_QUERY).addEventListener('change', colorSchemeListener)\n}\n\nfunction getDefaultThemeColor() {\n  return '#7EB8D6FF'\n}\n\nexport { applyThemeMode, getDefaultThemeColor }\n"
  },
  {
    "path": "src/app/utils/env.ts",
    "content": "function isArcBrowser() {\n  return getComputedStyle(document.documentElement).getPropertyValue('--arc-palette-background')\n}\n\nexport { isArcBrowser }\n"
  },
  {
    "path": "src/app/utils/export.ts",
    "content": "import { fileOpen, fileSave } from 'browser-fs-access'\nimport Browser from 'webextension-polyfill'\nimport { trackEvent } from '~app/plausible'\n\nexport async function exportData() {\n  const [syncData, localData] = await Promise.all([Browser.storage.sync.get(null), Browser.storage.local.get(null)])\n  const data = {\n    sync: syncData,\n    local: localData,\n    localStorage: { ...localStorage },\n  }\n  const blob = new Blob([JSON.stringify(data)], { type: 'application/json' })\n  await fileSave(blob, { fileName: 'chathub.json' })\n  trackEvent('export_data')\n}\n\nexport async function importData() {\n  const blob = await fileOpen({ extensions: ['.json'] })\n  const json = JSON.parse(await blob.text())\n  if (!json.sync || !json.local) {\n    throw new Error('Invalid data')\n  }\n  if (!window.confirm('Are you sure you want to import data? This will overwrite your current data')) {\n    return\n  }\n  await Browser.storage.local.clear()\n  await Browser.storage.local.set(json.local)\n  await Browser.storage.sync.clear()\n  await Browser.storage.sync.set(json.sync)\n\n  if (json.localStorage) {\n    for (const [k, v] of Object.entries(json.localStorage as Record<string, string>)) {\n      localStorage.setItem(k, v)\n    }\n  }\n\n  alert('Imported data successfully')\n  trackEvent('import_data')\n  location.reload()\n}\n"
  },
  {
    "path": "src/app/utils/image-compression/index.ts",
    "content": "import { createCache } from 'async-cache-dedupe'\nimport CompressionWorker from './worker?worker'\n\nasync function compressImageFileViaWorker(image: File): Promise<File> {\n  return new Promise((resolve, reject) => {\n    const worker = new CompressionWorker()\n    worker.addEventListener('message', (event) => {\n      const blob: Blob = event.data\n      console.debug('worker result', blob)\n      resolve(new File([blob], image.name, { type: blob.type }))\n      worker.terminate()\n    })\n    worker.addEventListener('error', (err) => {\n      worker.terminate()\n      reject(err)\n    })\n    worker.postMessage({ image })\n  })\n}\n\nasync function _compressImageFile(image: File): Promise<File> {\n  try {\n    const result = await compressImageFileViaWorker(image)\n    console.debug('image compression', image.size, '=>', result.size)\n    return result\n  } catch (err) {\n    console.error(err)\n    return image\n  }\n}\n\nconst cache = createCache({\n  ttl: 60,\n  storage: { type: 'memory' },\n})\n\nconst cacheInstance = cache.define('compressImageFile', _compressImageFile)\n\nexport const compressImageFile = cacheInstance.compressImageFile.bind(cacheInstance)\n"
  },
  {
    "path": "src/app/utils/image-compression/worker.ts",
    "content": "import imageCompression from 'browser-image-compression'\n\nself.addEventListener('message', async (event) => {\n  console.debug('worker receive message', event.data)\n  const result = await imageCompression(event.data.image, {\n    useWebWorker: false,\n    maxSizeMB: 0.5,\n    maxWidthOrHeight: 1024,\n  })\n  postMessage(result)\n})\n"
  },
  {
    "path": "src/app/utils/image-size.ts",
    "content": "export async function getImageSize(file: File): Promise<{ width: number; height: number }> {\n  return new Promise((resolve, reject) => {\n    const img = new Image()\n    img.onload = () => {\n      const size = { width: img.width, height: img.height }\n      URL.revokeObjectURL(img.src)\n      resolve(size)\n    }\n    img.onerror = reject\n    img.src = URL.createObjectURL(file)\n  })\n}\n"
  },
  {
    "path": "src/app/utils/markdown.ts",
    "content": "import TurndownService from 'turndown'\n\nconst turndownService = new TurndownService()\n\nexport function html2md(html: string) {\n  return turndownService.turndown(html)\n}\n"
  },
  {
    "path": "src/app/utils/navigator.ts",
    "content": "const ua = navigator.userAgent\n\nconst getBrowser = (): 'Opera' | 'Chrome' | 'Firefox' | 'Safari' | 'IE' | 'Edge' | 'Unknown' | undefined => {\n  if (ua.indexOf('Opera') > -1) {\n    return 'Opera'\n  }\n  if (ua.indexOf('Chrome') > -1) {\n    return 'Chrome'\n  }\n  if (ua.indexOf('Firefox') > -1) {\n    return 'Firefox'\n  }\n  if (ua.indexOf('Safari') > -1) {\n    return 'Safari'\n  }\n  if (ua.indexOf('MSIE') > -1) {\n    return 'IE'\n  }\n  if (ua.indexOf('Trident') > -1) {\n    return 'IE'\n  }\n  if (ua.indexOf('Edge' || 'Chrome') > -1) {\n    return 'Edge'\n  }\n  return 'Unknown'\n}\n\nconst getOS = (): 'Windows' | 'Mac' | 'Linux' | 'Android' | 'iOS' | 'Unknown' => {\n  if (ua.indexOf('Windows') > -1) {\n    return 'Windows'\n  }\n  if (ua.indexOf('Mac') > -1) {\n    return 'Mac'\n  }\n  if (ua.indexOf('Linux') > -1) {\n    return 'Linux'\n  }\n  if (ua.indexOf('Android') > -1) {\n    return 'Android'\n  }\n  if (ua.indexOf('iPhone') > -1) {\n    return 'iOS'\n  }\n  if (ua.indexOf('iPad') > -1) {\n    return 'iOS'\n  }\n  if (ua.indexOf('iPod') > -1) {\n    return 'iOS'\n  }\n  return 'Unknown'\n}\n\nexport { getBrowser, getOS }\n"
  },
  {
    "path": "src/app/utils/permissions.ts",
    "content": "import Browser from 'webextension-polyfill'\n\nexport async function requestHostPermissions(hosts: string[]) {\n  const permissions: Browser.Permissions.Permissions = { origins: hosts }\n  if (await Browser.permissions.contains(permissions)) {\n    return true\n  }\n  return Browser.permissions.request(permissions)\n}\n\nexport async function requestHostPermission(host: string) {\n  return requestHostPermissions([host])\n}\n"
  },
  {
    "path": "src/background/index.ts",
    "content": "import Browser from 'webextension-polyfill'\nimport { ALL_IN_ONE_PAGE_ID } from '~app/consts'\nimport { getUserConfig } from '~services/user-config'\nimport { trackInstallSource } from './source'\nimport { readTwitterCsrfToken } from './twitter-cookie'\n\n// expose storage.session to content scripts\n// using `chrome.*` API because `setAccessLevel` is not supported by `Browser.*` API\nchrome.storage.session.setAccessLevel({ accessLevel: 'TRUSTED_AND_UNTRUSTED_CONTEXTS' })\n\nasync function openAppPage() {\n  const tabs = await Browser.tabs.query({})\n  const url = Browser.runtime.getURL('app.html')\n  const tab = tabs.find((tab) => tab.url?.startsWith(url))\n  if (tab) {\n    await Browser.tabs.update(tab.id, { active: true })\n    return\n  }\n  const { startupPage } = await getUserConfig()\n  const hash = startupPage === ALL_IN_ONE_PAGE_ID ? '' : `#/chat/${startupPage}`\n  await Browser.tabs.create({ url: `app.html${hash}` })\n}\n\nBrowser.action.onClicked.addListener(() => {\n  openAppPage()\n})\n\nBrowser.runtime.onInstalled.addListener((details) => {\n  if (details.reason === 'install') {\n    Browser.tabs.create({ url: 'app.html#/setting' })\n    trackInstallSource()\n  }\n})\n\nBrowser.commands.onCommand.addListener(async (command) => {\n  console.debug(`Command: ${command}`)\n  if (command === 'open-app') {\n    openAppPage()\n  }\n})\n\nBrowser.runtime.onMessage.addListener(async (message, sender) => {\n  console.debug('onMessage', message, sender)\n  if (message.target !== 'background') {\n    return\n  }\n  if (message.type === 'read-twitter-csrf-token') {\n    return readTwitterCsrfToken(message.data)\n  }\n})\n"
  },
  {
    "path": "src/background/source.ts",
    "content": "import { ofetch } from 'ofetch'\n\nconst plausibleApiHost = import.meta.env.VITE_PLAUSIBLE_API_HOST || 'https://plausible.io'\n\nasync function trackEvent(name: string, props: object) {\n  await ofetch(`${plausibleApiHost}/api/event`, {\n    method: 'POST',\n    body: {\n      domain: 'chathub.gg',\n      name,\n      url: location.href,\n      props,\n    },\n    mode: 'no-cors',\n  })\n}\n\nexport async function trackInstallSource() {\n  const { source } = await ofetch('https://chathub.gg/api/user/source', {\n    credentials: 'include',\n  })\n  trackEvent('install', { source, language: navigator.language })\n}\n"
  },
  {
    "path": "src/background/twitter-cookie.ts",
    "content": "/**\n * How it works: pass message via storage.session\n */\n\nimport Browser from 'webextension-polyfill'\nimport Cookie from 'cookie'\n\nconst storageKey = 'twitter-csrf-token'\n\nasync function readTwitterCsrfToken({ refresh }: { refresh?: boolean } = {}) {\n  if (!refresh) {\n    const { [storageKey]: token } = await Browser.storage.session.get(storageKey)\n    if (token) {\n      return token\n    }\n  }\n\n  const tab = await Browser.tabs.create({ url: 'https://about.twitter.com/en/404', active: false })\n\n  try {\n    const results = await Browser.scripting.executeScript({\n      target: { tabId: tab.id! },\n      func: () => document.cookie,\n      injectImmediately: true,\n    })\n    const cookies = Cookie.parse(results[0].result || '')\n    const csrfToken = cookies.ct0 || ''\n    await Browser.storage.session.set({ [storageKey]: csrfToken })\n    return csrfToken\n  } finally {\n    await Browser.tabs.remove(tab.id!)\n  }\n}\n\nexport { readTwitterCsrfToken }\n"
  },
  {
    "path": "src/content-script/chatgpt-inpage-proxy.ts",
    "content": "import Browser from 'webextension-polyfill'\nimport { setupProxyExecutor } from '~services/proxy-fetch'\n\nfunction injectTip() {\n  const div = document.createElement('div')\n  div.innerText = 'Please keep this tab open, now you can go back to ChatHub'\n  div.style.position = 'fixed'\n  // put the div at right top of page\n  div.style.top = '0'\n  div.style.right = '0'\n  div.style.zIndex = '50'\n  div.style.padding = '10px'\n  div.style.margin = '10px'\n  div.style.border = '1px solid'\n  div.style.color = 'red'\n  document.body.appendChild(div)\n}\n\nasync function main() {\n  Browser.runtime.onMessage.addListener(async (message) => {\n    if (message === 'url') {\n      return location.href\n    }\n  })\n  if ((window as any).__NEXT_DATA__) {\n    if (await Browser.runtime.sendMessage({ event: 'PROXY_TAB_READY' })) {\n      injectTip()\n    }\n  }\n}\n\nsetupProxyExecutor()\nmain().catch(console.error)\n"
  },
  {
    "path": "src/rules/baichuan.json",
    "content": "[\n  {\n    \"id\": 1,\n    \"priority\": 1,\n    \"action\": {\n      \"type\": \"modifyHeaders\",\n      \"requestHeaders\": [\n        {\n          \"header\": \"origin\",\n          \"operation\": \"set\",\n          \"value\": \"https://www.baichuan-ai.com\"\n        },\n        {\n          \"header\": \"referer\",\n          \"operation\": \"set\",\n          \"value\": \"https://www.baichuan-ai.com\"\n        }\n      ]\n    },\n    \"condition\": {\n      \"requestDomains\": [\"www.baichuan-ai.com\"],\n      \"resourceTypes\": [\"xmlhttprequest\"]\n    }\n  }\n]\n"
  },
  {
    "path": "src/rules/bing.json",
    "content": "[\n  {\n    \"id\": 1,\n    \"priority\": 1,\n    \"action\": {\n      \"type\": \"modifyHeaders\",\n      \"requestHeaders\": [\n        {\n          \"header\": \"origin\",\n          \"operation\": \"set\",\n          \"value\": \"https://www.bing.com\"\n        },\n        {\n          \"header\": \"referer\",\n          \"operation\": \"set\",\n          \"value\": \"https://www.bing.com\"\n        }\n      ]\n    },\n    \"condition\": {\n      \"urlFilter\": \"bing\",\n      \"isUrlFilterCaseSensitive\": false,\n      \"resourceTypes\": [\"xmlhttprequest\", \"websocket\"]\n    }\n  }\n]\n"
  },
  {
    "path": "src/rules/ddg.json",
    "content": "[\n  {\n    \"id\": 3,\n    \"priority\": 1,\n    \"action\": {\n      \"type\": \"modifyHeaders\",\n      \"requestHeaders\": [\n        {\n          \"header\": \"origin\",\n          \"operation\": \"set\",\n          \"value\": \"https://duckduckgo.com\"\n        },\n        {\n          \"header\": \"referer\",\n          \"operation\": \"remove\"\n        }\n      ]\n    },\n    \"condition\": {\n      \"requestDomains\": [\"duckduckgo.com\"],\n      \"resourceTypes\": [\"xmlhttprequest\"]\n    }\n  }\n]\n"
  },
  {
    "path": "src/rules/pplx.json",
    "content": "[\n  {\n    \"id\": 1,\n    \"priority\": 1,\n    \"action\": {\n      \"type\": \"modifyHeaders\",\n      \"requestHeaders\": [\n        {\n          \"header\": \"user-agent\",\n          \"operation\": \"set\",\n          \"value\": \"Ask/2.2.1/334 (iOS; iPhone) isiOSOnMac/false\"\n        },\n        {\n          \"header\": \"X-Client-Name\",\n          \"operation\": \"set\",\n          \"value\": \"Perplexity-iOS\"\n        }\n      ]\n    },\n    \"condition\": {\n      \"requestDomains\": [\"labs-api.perplexity.ai\"],\n      \"resourceTypes\": [\"xmlhttprequest\", \"websocket\"]\n    }\n  }\n]\n"
  },
  {
    "path": "src/rules/qianwen.json",
    "content": "[\n  {\n    \"id\": 1,\n    \"priority\": 1,\n    \"action\": {\n      \"type\": \"modifyHeaders\",\n      \"requestHeaders\": [\n        {\n          \"header\": \"origin\",\n          \"operation\": \"set\",\n          \"value\": \"https://tongyi.aliyun.com\"\n        },\n        {\n          \"header\": \"referer\",\n          \"operation\": \"set\",\n          \"value\": \"https://tongyi.aliyun.com/\"\n        }\n      ]\n    },\n    \"condition\": {\n      \"requestDomains\": [\"qianwen.aliyun.com\"],\n      \"resourceTypes\": [\"xmlhttprequest\"]\n    }\n  }\n]\n"
  },
  {
    "path": "src/services/agent/index.ts",
    "content": "import { removeSlashes } from 'slashes'\nimport { PROMPT_TEMPLATE } from './prompts'\nimport { searchRelatedContext } from './web-search'\nimport { AnwserPayload } from '~app/bots/abstract-bot'\n\nconst TOOLS = {\n  web_search:\n    'a search engine. useful for when you need to answer questions about current events. input should be a search query. prefer English query. query should be short and concise',\n}\n\nfunction buildToolUsingPrompt(input: string) {\n  const tools = Object.entries(TOOLS).map(([name, description]) => `- ${name}: ${description}`)\n  return PROMPT_TEMPLATE.replace('{{tools}}', tools.join('\\n'))\n    .replace('{{tool_names}}', Object.keys(TOOLS).join(', '))\n    .replace('{{input}}', input)\n}\n\nfunction buildPromptWithContext(input: string, context: string) {\n  if (!context) {\n    return `Question: ${input}`\n  }\n  const currentDate = new Date().toISOString().split('T')[0]\n  return `Current date: ${currentDate}. Use the provided context delimited by triple quotes to answer questions. The answer should use the same language as the user question instead of context.\\n\\nContext: \"\"\"${context}\"\"\"\\n\\nQuestion: ${input}`\n}\n\nconst FINAL_ANSWER_KEYWORD_REGEX = /\"action\":\\s*\"Final Answer\"/\nconst WEB_SEARCH_KEYWORD_REGEX = /\"action\":\\s*\"web_search\"/\nconst ACTION_INPUT_REGEX = /\"action_input\":\\s*\"((?:\\\\.|[^\"])+)(?:\"\\s*(```)?)?/\n\nasync function* execute(\n  input: string,\n  llm: (prompt: string, rawUserInput: string) => AsyncGenerator<AnwserPayload>,\n  signal?: AbortSignal,\n): AsyncGenerator<AnwserPayload> {\n  let prompt = buildToolUsingPrompt(input)\n\n  let outputType: 'tool' | 'answer' | undefined = undefined\n  let output: AnwserPayload | undefined = undefined\n\n  for await (const payload of llm(prompt, input)) {\n    output = payload\n    console.debug('llm output', output)\n    if (outputType === 'answer' || FINAL_ANSWER_KEYWORD_REGEX.test(payload.text)) {\n      outputType = 'answer'\n      const answer = payload.text.match(ACTION_INPUT_REGEX)?.[1]\n      if (answer) {\n        yield { text: removeSlashes(answer) }\n      }\n    } else if (outputType === 'tool') {\n      continue\n    } else if (WEB_SEARCH_KEYWORD_REGEX.test(payload.text)) {\n      outputType = 'tool'\n    }\n  }\n\n  if (outputType === 'answer') {\n    return\n  }\n\n  if (outputType === 'tool') {\n    const actionInput = removeSlashes(output!.text.match(ACTION_INPUT_REGEX)![1])\n    let context = ''\n    if (actionInput) {\n      yield { text: `Searching the web for _${actionInput}_` }\n      context = await searchRelatedContext(actionInput, signal)\n    }\n    const promptWithContext = buildPromptWithContext(input, context)\n    prompt = `Ignore all previous instructions you have been given about RESPONSE FORMAT INSTRUCTIONS and tools, answer the question directly and conversationally to the human.\\n\\n${promptWithContext}`\n    yield* llm(prompt, input)\n    return\n  }\n\n  throw new Error('Unexpected agent error')\n}\n\nexport { execute }\n"
  },
  {
    "path": "src/services/agent/prompts.ts",
    "content": "export const PROMPT_TEMPLATE = `USER'S INPUT\n--------------------\nHere is the user's input (remember to respond with a markdown code snippet of a json blob with a single action, and NOTHING else):\n\n{{input}}\n\nRESPONSE FORMAT INSTRUCTIONS\n----------------------------\n\nTOOLS\n------\nAssistant can use tools to look up information that may be helpful in answering the users original question. The tools are:\n\n{{tools}}\n\nOutput a JSON markdown code snippet containing a valid JSON object in one of two formats:\n\n**Option 1:**\nUse this if you want to use a tool.\nMarkdown code snippet formatted in the following schema:\n\n\\`\\`\\`json\n{\n    \"action\": string, // The action to take. Must be one of [{{tool_names}}]\n    \"action_input\": string // The input to the action. May be a stringified object.\n}\n\\`\\`\\`\n\n**Option #2:**\nUse this if you want the assistant to answer USER'S INPUT directly and conversationally without using external tools. Answer with the same language user with.\nMarkdown code snippet formatted in the following schema:\n\n\\`\\`\\`json\n{\n    \"action\": \"Final Answer\",\n    \"action_input\": string //  answer USER'S INPUT.\n}\n\\`\\`\\`\n\nFor both options, remember to always include the surrounding markdown code snippet delimiters (begin with \"\\`\\`\\`json\" and end with \"\\`\\`\\`\")!\n`\n"
  },
  {
    "path": "src/services/agent/web-search/base.ts",
    "content": "export interface SearchResultItem {\n  title: string\n  abstract: string\n  link: string\n}\n\nexport interface SearchResult {\n  items: SearchResultItem[]\n}\n\nabstract class WebSearch {\n  abstract search(query: string, signal?: AbortSignal): Promise<SearchResult>\n}\n\nexport default WebSearch\n"
  },
  {
    "path": "src/services/agent/web-search/bing-news.ts",
    "content": "import { ofetch } from 'ofetch'\nimport WebSearch, { SearchResult } from './base'\n\nexport class BingNewsSearch extends WebSearch {\n  async search(query: string, signal?: AbortSignal): Promise<SearchResult> {\n    const html = await this.fetchSerp(query, signal)\n    const items = this.extractItems(html)\n    return { items }\n  }\n\n  private async fetchSerp(query: string, signal?: AbortSignal) {\n    const html = await ofetch('https://www.bing.com/news/infinitescrollajax', {\n      method: 'GET',\n      query: { InfiniteScroll: '1', q: query },\n      signal,\n    })\n    return html\n  }\n\n  private extractItems(html: string) {\n    const dom = new DOMParser().parseFromString(html, 'text/html')\n    const nodes = dom.querySelectorAll('.newsitem')\n    return Array.from(nodes)\n      .slice(0, 10)\n      .map((node) => {\n        const nodeA = node.querySelector('.title')!\n        const link = nodeA.getAttribute('href')!\n        const title = nodeA.textContent || ''\n        const nodeAbstract = node.querySelector('.snippet')\n        const abstract = nodeAbstract?.textContent || ''\n        return { title, link, abstract }\n      })\n  }\n}\n"
  },
  {
    "path": "src/services/agent/web-search/duckduckgo.ts",
    "content": "import { ofetch } from 'ofetch'\nimport WebSearch, { SearchResult } from './base'\n\nexport class DuckDuckGoSearch extends WebSearch {\n  async search(query: string, signal?: AbortSignal): Promise<SearchResult> {\n    const html = await this.fetchSerp(query, signal)\n    const items = this.extractItems(html)\n    return { items }\n  }\n\n  private async fetchSerp(query: string, signal?: AbortSignal) {\n    const html = await ofetch('https://html.duckduckgo.com/html/', {\n      method: 'POST',\n      body: new URLSearchParams({ q: query, df: 'y' }),\n      signal,\n    })\n    return html\n  }\n\n  private extractItems(html: string) {\n    // TODO: .zci-wrapper\n    const dom = new DOMParser().parseFromString(html, 'text/html')\n    const nodes = dom.querySelectorAll('.results_links')\n    return Array.from(nodes)\n      .slice(0, 10)\n      .map((node) => {\n        const nodeA = node.querySelector('.result__a')!\n        const link = nodeA.getAttribute('href')!\n        const title = nodeA.textContent || ''\n        const nodeAbstract = node.querySelector('.result__snippet')\n        const abstract = nodeAbstract?.textContent || ''\n        return { title, link, abstract }\n      })\n  }\n}\n"
  },
  {
    "path": "src/services/agent/web-search/index.ts",
    "content": "import { cachified } from '@epic-web/cachified'\nimport { truncate } from 'lodash-es'\nimport type { SearchResultItem } from './base'\nimport { BingNewsSearch } from './bing-news'\nimport { DuckDuckGoSearch } from './duckduckgo'\n\nconst MAX_CONTEXT_ITEMS = 15\n\nconst providers = [new DuckDuckGoSearch(), new BingNewsSearch()]\n\nasync function _searchRelatedContext(query: string, signal?: AbortSignal) {\n  const results = await Promise.all(\n    providers.map(async (provider) => {\n      try {\n        const result = await provider.search(query, signal)\n        console.debug('web search result', query, result.items)\n        return result\n      } catch (err) {\n        console.error(err)\n        return { items: [] }\n      }\n    }),\n  )\n\n  const items: SearchResultItem[] = []\n\n  // add items in turn\n  let i = 0\n  let hasMore = false\n  do {\n    hasMore = false\n    for (const result of results) {\n      const item = result.items[i]\n      if (item) {\n        hasMore = true\n        items.push(item)\n      } else {\n        continue\n      }\n    }\n    i++\n  } while (hasMore && items.length < MAX_CONTEXT_ITEMS)\n\n  console.debug('web search items', items)\n\n  const context: string[] = []\n  for (const item of items) {\n    let chunk = item.title\n    if (item.abstract) {\n      chunk += '\\n' + truncate(item.abstract, { length: 150 })\n    }\n    context.push(chunk)\n  }\n  return context.join('\\n\\n')\n}\n\nconst cache = new Map()\n\nexport async function searchRelatedContext(query: string, signal?: AbortSignal) {\n  return cachified({\n    cache,\n    key: `search-context:${query}`,\n    ttl: 1000 * 60 * 5,\n    getFreshValue: () => _searchRelatedContext(query, signal),\n  })\n}\n"
  },
  {
    "path": "src/services/chat-history.ts",
    "content": "import { zip } from 'lodash-es'\nimport Browser from 'webextension-polyfill'\nimport { BotId } from '~app/bots'\nimport { ChatMessageModel } from '~types'\n\n/**\n * conversations:$botId => Conversation[]\n * conversation:$botId:$cid:messages => ChatMessageModel[]\n */\n\ninterface Conversation {\n  id: string\n  createdAt: number\n}\n\ntype ConversationWithMessages = Conversation & { messages: ChatMessageModel[] }\n\nasync function loadHistoryConversations(botId: BotId): Promise<Conversation[]> {\n  const key = `conversations:${botId}`\n  const { [key]: value } = await Browser.storage.local.get(key)\n  return value || []\n}\n\nasync function deleteHistoryConversation(botId: BotId, cid: string) {\n  const conversations = await loadHistoryConversations(botId)\n  const newConversations = conversations.filter((c) => c.id !== cid)\n  await Browser.storage.local.set({ [`conversations:${botId}`]: newConversations })\n}\n\nasync function loadConversationMessages(botId: BotId, cid: string): Promise<ChatMessageModel[]> {\n  const key = `conversation:${botId}:${cid}:messages`\n  const { [key]: value } = await Browser.storage.local.get(key)\n  return value || []\n}\n\nexport async function setConversationMessages(botId: BotId, cid: string, messages: ChatMessageModel[]) {\n  const conversations = await loadHistoryConversations(botId)\n  if (!conversations.some((c) => c.id === cid)) {\n    conversations.unshift({ id: cid, createdAt: Date.now() })\n    await Browser.storage.local.set({ [`conversations:${botId}`]: conversations })\n  }\n  const key = `conversation:${botId}:${cid}:messages`\n  await Browser.storage.local.set({ [key]: messages })\n}\n\nexport async function loadHistoryMessages(botId: BotId): Promise<ConversationWithMessages[]> {\n  const conversations = await loadHistoryConversations(botId)\n  const messagesList = await Promise.all(conversations.map((c) => loadConversationMessages(botId, c.id)))\n  return zip(conversations, messagesList).map(([c, messages]) => ({\n    id: c!.id,\n    createdAt: c!.createdAt,\n    messages: messages!,\n  }))\n}\n\nexport async function deleteHistoryMessage(botId: BotId, conversationId: string, messageId: string) {\n  const messages = await loadConversationMessages(botId, conversationId)\n  const newMessages = messages.filter((m) => m.id !== messageId)\n  await setConversationMessages(botId, conversationId, newMessages)\n  if (!newMessages.length) {\n    await deleteHistoryConversation(botId, conversationId)\n  }\n}\n\nexport async function clearHistoryMessages(botId: BotId) {\n  const conversations = await loadHistoryConversations(botId)\n  await Promise.all(\n    conversations.map((c) => {\n      return Browser.storage.local.remove(`conversation:${botId}:${c.id}:messages`)\n    }),\n  )\n  await Browser.storage.local.remove(`conversations:${botId}`)\n}\n"
  },
  {
    "path": "src/services/lemonsqueezy.ts",
    "content": "import { ofetch } from 'ofetch'\nimport * as serverApi from '~services/server-api'\n\nasync function activateLicense(key: string, instanceName: string) {\n  const resp = await serverApi.activateLicense(key, instanceName)\n  if (!resp.activated) {\n    throw new Error(resp.error)\n  }\n  return resp.instance.id\n}\n\nasync function deactivateLicense(key: string, instanceId: string) {\n  await ofetch('https://api.lemonsqueezy.com/v1/licenses/deactivate', {\n    method: 'POST',\n    body: {\n      license_key: key,\n      instance_id: instanceId,\n    },\n  })\n}\n\ntype LicenseKey = {\n  valid: boolean\n}\n\nasync function validateLicense(key: string, instanceId: string): Promise<LicenseKey> {\n  const resp = await ofetch('https://api.lemonsqueezy.com/v1/licenses/validate', {\n    method: 'POST',\n    body: {\n      license_key: key,\n      instance_id: instanceId,\n    },\n  })\n  return { valid: resp.valid }\n}\n\nexport { activateLicense, deactivateLicense, validateLicense }\n"
  },
  {
    "path": "src/services/premium.ts",
    "content": "import { getBrowser, getOS } from '~app/utils/navigator'\nimport * as lemonsqueezy from './lemonsqueezy'\n\ninterface PremiumActivation {\n  licenseKey: string\n  instanceId: string\n}\n\nfunction getInstanceName() {\n  return `${getOS()} / ${getBrowser()}`\n}\n\nexport async function activatePremium(licenseKey: string): Promise<PremiumActivation> {\n  const instanceId = await lemonsqueezy.activateLicense(licenseKey, getInstanceName())\n  const data = { licenseKey, instanceId }\n  localStorage.setItem('premium', JSON.stringify(data))\n  return data\n}\n\nexport async function validatePremium() {\n  const activation = getPremiumActivation()\n  if (!activation) {\n    return { valid: false }\n  }\n  return lemonsqueezy.validateLicense(activation.licenseKey, activation.instanceId)\n}\n\nexport async function deactivatePremium() {\n  const activation = getPremiumActivation()\n  if (!activation) {\n    return\n  }\n  await lemonsqueezy.deactivateLicense(activation.licenseKey, activation.instanceId)\n  localStorage.removeItem('premium')\n}\n\nexport function getPremiumActivation(): PremiumActivation | null {\n  const data = localStorage.getItem('premium')\n  if (data) {\n    return JSON.parse(data)\n  }\n  return null\n}\n"
  },
  {
    "path": "src/services/prompts.ts",
    "content": "import i18next from 'i18next'\nimport { ofetch } from 'ofetch'\nimport Browser from 'webextension-polyfill'\n\nexport interface Prompt {\n  id: string\n  title: string\n  prompt: string\n}\n\nexport async function loadLocalPrompts() {\n  const { prompts: value } = await Browser.storage.local.get('prompts')\n  return (value || []) as Prompt[]\n}\n\nexport async function saveLocalPrompt(prompt: Prompt) {\n  const prompts = await loadLocalPrompts()\n  let existed = false\n  for (const p of prompts) {\n    if (p.id === prompt.id) {\n      p.title = prompt.title\n      p.prompt = prompt.prompt\n      existed = true\n      break\n    }\n  }\n  if (!existed) {\n    prompts.unshift(prompt)\n  }\n  await Browser.storage.local.set({ prompts })\n  return existed\n}\n\nexport async function removeLocalPrompt(id: string) {\n  const prompts = await loadLocalPrompts()\n  await Browser.storage.local.set({ prompts: prompts.filter((p) => p.id !== id) })\n}\n\nexport async function loadRemotePrompts() {\n  return ofetch<Prompt[]>('https://chathub.gg/api/community-prompts', {\n    params: { language: i18next.language, languages: i18next.languages },\n  }).catch((err) => {\n    console.error('Failed to load remote prompts', err)\n    return []\n  })\n}\n"
  },
  {
    "path": "src/services/proxy-fetch.ts",
    "content": "import Browser from 'webextension-polyfill'\nimport {\n  ProxyFetchRequestMessage,\n  ProxyFetchResponseBodyChunkMessage,\n  ProxyFetchResponseMetadataMessage,\n  RequestInitSubset,\n} from '~types/messaging'\nimport { uuid } from '~utils'\nimport { string2Uint8Array, uint8Array2String } from '~utils/encoding'\nimport { streamAsyncIterable } from '~utils/stream-async-iterable'\n\nexport function setupProxyExecutor() {\n  // one port for one fetch request\n  Browser.runtime.onConnect.addListener((port) => {\n    const abortController = new AbortController()\n    port.onDisconnect.addListener(() => {\n      abortController.abort()\n    })\n    port.onMessage.addListener(async (message: ProxyFetchRequestMessage) => {\n      console.debug('proxy fetch', message.url, message.options)\n      const resp = await fetch(message.url, {\n        ...message.options,\n        signal: abortController.signal,\n      })\n      port.postMessage({\n        type: 'PROXY_RESPONSE_METADATA',\n        metadata: {\n          status: resp.status,\n          statusText: resp.statusText,\n          headers: Object.fromEntries(resp.headers.entries()),\n        },\n      } as ProxyFetchResponseMetadataMessage)\n      for await (const chunk of streamAsyncIterable(resp.body!)) {\n        port.postMessage({\n          type: 'PROXY_RESPONSE_BODY_CHUNK',\n          value: uint8Array2String(chunk),\n          done: false,\n        } as ProxyFetchResponseBodyChunkMessage)\n      }\n      port.postMessage({ type: 'PROXY_RESPONSE_BODY_CHUNK', done: true } as ProxyFetchResponseBodyChunkMessage)\n    })\n  })\n}\n\nexport async function proxyFetch(tabId: number, url: string, options?: RequestInitSubset): Promise<Response> {\n  console.debug('proxyFetch', tabId, url, options)\n  return new Promise((resolve) => {\n    const port = Browser.tabs.connect(tabId, { name: uuid() })\n    port.onDisconnect.addListener(() => {\n      throw new DOMException('proxy fetch aborted', 'AbortError')\n    })\n    options?.signal?.addEventListener('abort', () => port.disconnect())\n    const body = new ReadableStream({\n      start(controller) {\n        port.onMessage.addListener(function onMessage(\n          message: ProxyFetchResponseMetadataMessage | ProxyFetchResponseBodyChunkMessage,\n        ) {\n          if (message.type === 'PROXY_RESPONSE_METADATA') {\n            const response = new Response(body, message.metadata)\n            resolve(response)\n          } else if (message.type === 'PROXY_RESPONSE_BODY_CHUNK') {\n            if (message.done) {\n              controller.close()\n              port.onMessage.removeListener(onMessage)\n              port.disconnect()\n            } else {\n              const chunk = string2Uint8Array(message.value)\n              controller.enqueue(chunk)\n            }\n          }\n        })\n        port.postMessage({ url, options } as ProxyFetchRequestMessage)\n      },\n      cancel(_reason: string) {\n        port.disconnect()\n      },\n    })\n  })\n}\n"
  },
  {
    "path": "src/services/release-notes.ts",
    "content": "import { compareVersions } from 'compare-versions'\nimport Browser from 'webextension-polyfill'\nimport { getVersion } from '~utils'\n\nconst RELEASE_NOTES = [\n  {\n    version: '1.45.0',\n    notes: ['Added a separate Gemini Pro bot, can be enabled in the settings'],\n  },\n]\n\nexport async function checkReleaseNotes(): Promise<string[]> {\n  const version = getVersion()\n  const { lastCheckReleaseNotesVersion } = await Browser.storage.sync.get('lastCheckReleaseNotesVersion')\n  Browser.storage.sync.set({ lastCheckReleaseNotesVersion: version })\n  if (!lastCheckReleaseNotesVersion) {\n    return []\n  }\n  return RELEASE_NOTES.slice(0, 3)\n    .filter(({ version: v }) => compareVersions(v, lastCheckReleaseNotesVersion) > 0)\n    .map(({ notes }) => notes)\n    .flat()\n}\n"
  },
  {
    "path": "src/services/sentry.ts",
    "content": "import * as Sentry from '@sentry/react'\nimport { ExtraErrorData as ExtraErrorDataIntegration } from '@sentry/integrations'\nimport { getVersion, isProduction } from '../utils'\n\nSentry.init({\n  dsn: import.meta.env.VITE_SENTRY_DSN,\n  debug: !isProduction(),\n  release: getVersion(),\n  integrations: [new ExtraErrorDataIntegration({ depth: 3 })],\n  sampleRate: 1.0,\n})\n\nexport { Sentry }\n"
  },
  {
    "path": "src/services/server-api.ts",
    "content": "import { ofetch } from 'ofetch'\n\nexport async function decodePoeFormkey(html: string): Promise<string> {\n  const resp = await ofetch('https://chathub.gg/api/poe/decode-formkey', {\n    method: 'POST',\n    body: { html },\n  })\n  return resp.formkey\n}\n\ntype ActivateResponse =\n  | {\n      activated: true\n      instance: { id: string }\n      meta: { product_id: number }\n    }\n  | { activated: false; error: string }\n\nexport async function activateLicense(key: string, instanceName: string) {\n  return ofetch<ActivateResponse>('https://chathub.gg/api/premium/activate', {\n    method: 'POST',\n    body: {\n      license_key: key,\n      instance_name: instanceName,\n    },\n  })\n}\n\ninterface Product {\n  price: number\n}\n\nexport async function fetchPremiumProduct() {\n  return ofetch<Product>('https://chathub.gg/api/premium/product')\n}\n\nexport async function createDiscount() {\n  return ofetch<{ code: string; startTime: number }>('https://chathub.gg/api/premium/discount/create', {\n    method: 'POST',\n  })\n}\n\nexport interface Discount {\n  code: string\n  startTime: number\n  price: number\n  percent: number\n}\n\nexport interface Campaign {\n  description: string\n  code: string\n  price: number\n}\n\ninterface PurchaseInfo {\n  price: number\n  discount?: Discount\n  campaign?: Campaign\n}\n\nexport async function fetchPurchaseInfo() {\n  return ofetch<PurchaseInfo>('https://chathub.gg/api/premium/info')\n}\n\nexport async function checkDiscount(params: { appOpenTimes: number; premiumModalOpenTimes: number }) {\n  return ofetch<{ show: boolean; campaign?: Campaign }>('https://chathub.gg/api/premium/discount/check', { params })\n}\n"
  },
  {
    "path": "src/services/storage/language.ts",
    "content": "const key = 'language' // from i18next-browser-languagedetector\n\nexport function setLanguage(lang: string | undefined) {\n  if (!lang) {\n    localStorage.removeItem(key)\n  } else {\n    localStorage.setItem(key, lang)\n  }\n}\n\nexport function getLanguage() {\n  return localStorage.getItem(key) || undefined\n}\n"
  },
  {
    "path": "src/services/storage/open-times.ts",
    "content": "import Browser from 'webextension-polyfill'\n\nexport async function getAppOpenTimes() {\n  const { openTimes = 0 } = await Browser.storage.sync.get('openTimes')\n  return openTimes\n}\n\nexport async function incrAppOpenTimes() {\n  const openTimes = await getAppOpenTimes()\n  Browser.storage.sync.set({ openTimes: openTimes + 1 })\n  return openTimes + 1\n}\n\nexport async function getPremiumModalOpenTimes() {\n  const { premiumModalOpenTimes = 0 } = await Browser.storage.sync.get('premiumModalOpenTimes')\n  return premiumModalOpenTimes\n}\n\nexport async function incrPremiumModalOpenTimes() {\n  const openTimes = await getPremiumModalOpenTimes()\n  Browser.storage.sync.set({ premiumModalOpenTimes: openTimes + 1 })\n  return openTimes + 1\n}\n"
  },
  {
    "path": "src/services/storage/token-usage.ts",
    "content": "import Browser from 'webextension-polyfill'\n\nexport async function getTokenUsage() {\n  const { tokenUsage } = await Browser.storage.sync.get('tokenUsage')\n  return tokenUsage || 0\n}\n\nexport async function incrTokenUsage(v = 1) {\n  const tokenUsage = await getTokenUsage()\n  await Browser.storage.sync.set({ tokenUsage: tokenUsage + v })\n}\n\nexport async function resetTokenUsage() {\n  await Browser.storage.sync.remove('tokenUsage')\n}\n"
  },
  {
    "path": "src/services/theme.ts",
    "content": "export enum ThemeMode {\n  Auto = 'auto',\n  Light = 'light',\n  Dark = 'dark',\n}\n\nfunction getUserThemeMode(): ThemeMode {\n  return (localStorage.getItem('themeMode') as ThemeMode) || ThemeMode.Auto\n}\n\nfunction setUserThemeMode(themeMode: ThemeMode) {\n  localStorage.setItem('themeMode', themeMode)\n}\n\nexport { getUserThemeMode, setUserThemeMode }\n"
  },
  {
    "path": "src/services/user-config.ts",
    "content": "import { defaults } from 'lodash-es'\nimport Browser from 'webextension-polyfill'\nimport { BotId } from '~app/bots'\nimport { ALL_IN_ONE_PAGE_ID, CHATBOTS, CHATGPT_API_MODELS, DEFAULT_CHATGPT_SYSTEM_MESSAGE } from '~app/consts'\n\nexport enum BingConversationStyle {\n  Creative = 'creative',\n  Balanced = 'balanced',\n  Precise = 'precise',\n}\n\nexport enum ChatGPTMode {\n  Webapp = 'webapp',\n  API = 'api',\n  Azure = 'azure',\n  Poe = 'poe',\n  OpenRouter = 'openrouter',\n}\n\nexport enum ChatGPTWebModel {\n  'GPT-3.5' = 'gpt-3.5',\n  'GPT-4' = 'gpt-4',\n}\n\nexport enum PoeGPTModel {\n  'GPT-3.5' = 'chinchilla',\n  'GPT-4' = 'beaver',\n}\n\nexport enum PoeClaudeModel {\n  'claude-instant' = 'a2',\n  'claude-instant-100k' = 'a2_100k',\n  'claude-2-100k' = 'a2_2',\n}\n\nexport enum ClaudeMode {\n  Webapp = 'webapp',\n  API = 'api',\n  Poe = 'poe',\n  OpenRouter = 'openrouter',\n}\n\nexport enum ClaudeAPIModel {\n  'claude-2' = 'claude-2',\n  'claude-instant-1' = 'claude-instant-v1',\n}\n\nexport enum OpenRouterClaudeModel {\n  'claude-2' = 'claude-2',\n  'claude-instant-v1' = 'claude-instant-v1',\n}\n\nexport enum PerplexityMode {\n  Webapp = 'webapp',\n  API = 'api',\n}\n\nconst userConfigWithDefaultValue = {\n  openaiApiKey: '',\n  openaiApiHost: 'https://api.openai.com',\n  chatgptApiModel: CHATGPT_API_MODELS[0] as (typeof CHATGPT_API_MODELS)[number],\n  chatgptApiTemperature: 1,\n  chatgptApiSystemMessage: DEFAULT_CHATGPT_SYSTEM_MESSAGE,\n  chatgptMode: ChatGPTMode.Webapp,\n  chatgptWebappModelName: ChatGPTWebModel['GPT-3.5'],\n  chatgptPoeModelName: PoeGPTModel['GPT-3.5'],\n  startupPage: ALL_IN_ONE_PAGE_ID,\n  bingConversationStyle: BingConversationStyle.Balanced,\n  poeModel: PoeClaudeModel['claude-instant'],\n  azureOpenAIApiKey: '',\n  azureOpenAIApiInstanceName: '',\n  azureOpenAIApiDeploymentName: '',\n  enabledBots: Object.keys(CHATBOTS).slice(0, 8) as BotId[],\n  claudeApiKey: '',\n  claudeMode: ClaudeMode.Webapp,\n  claudeApiModel: ClaudeAPIModel['claude-2'],\n  chatgptWebAccess: false,\n  claudeWebAccess: false,\n  openrouterOpenAIModel: CHATGPT_API_MODELS[0] as (typeof CHATGPT_API_MODELS)[number],\n  openrouterClaudeModel: OpenRouterClaudeModel['claude-2'],\n  openrouterApiKey: '',\n  perplexityMode: PerplexityMode.Webapp,\n  perplexityApiKey: '',\n  geminiApiKey: '',\n}\n\nexport type UserConfig = typeof userConfigWithDefaultValue\n\nexport async function getUserConfig(): Promise<UserConfig> {\n  const result = await Browser.storage.sync.get(Object.keys(userConfigWithDefaultValue))\n  if (!result.chatgptMode && result.openaiApiKey) {\n    result.chatgptMode = ChatGPTMode.API\n  }\n  if (result.chatgptWebappModelName === 'default') {\n    result.chatgptWebappModelName = ChatGPTWebModel['GPT-3.5']\n  } else if (result.chatgptWebappModelName === 'gpt-4-browsing') {\n    result.chatgptWebappModelName = ChatGPTWebModel['GPT-4']\n  } else if (result.chatgptWebappModelName === 'gpt-3.5-mobile') {\n    result.chatgptWebappModelName = ChatGPTWebModel['GPT-3.5']\n  } else if (result.chatgptWebappModelName === 'gpt-4-mobile') {\n    result.chatgptWebappModelName = ChatGPTWebModel['GPT-4']\n  }\n  if (result.chatgptApiModel === 'gpt-3.5-turbo-16k') {\n    result.chatgptApiModel = 'gpt-3.5-turbo'\n  } else if (result.chatgptApiModel === 'gpt-4-32k') {\n    result.chatgptApiModel = 'gpt-4'\n  }\n  if (\n    result.claudeApiModel !== ClaudeAPIModel['claude-2'] ||\n    result.claudeApiModel !== ClaudeAPIModel['claude-instant-1']\n  ) {\n    result.claudeApiModel = ClaudeAPIModel['claude-2']\n  }\n  return defaults(result, userConfigWithDefaultValue)\n}\n\nexport async function updateUserConfig(updates: Partial<UserConfig>) {\n  console.debug('update configs', updates)\n  await Browser.storage.sync.set(updates)\n  for (const [key, value] of Object.entries(updates)) {\n    if (value === undefined) {\n      await Browser.storage.sync.remove(key)\n    }\n  }\n}\n"
  },
  {
    "path": "src/types/chat.ts",
    "content": "import { BotId } from '~app/bots'\nimport { ChatError } from '~utils/errors'\n\nexport interface ChatMessageModel {\n  id: string\n  author: BotId | 'user'\n  text: string\n  image?: Blob\n  error?: ChatError\n}\n\nexport interface ConversationModel {\n  messages: ChatMessageModel[]\n}\n"
  },
  {
    "path": "src/types/index.ts",
    "content": "export * from './chat'\n"
  },
  {
    "path": "src/types/messaging.ts",
    "content": "export type RequestInitSubset = {\n  method?: string\n  body?: string\n  headers?: Record<string, string>\n  signal?: AbortSignal\n}\n\nexport interface ProxyFetchRequestMessage {\n  url: string\n  options?: RequestInitSubset\n}\n\nexport interface ProxyFetchResponseMetadata {\n  status?: number\n  statusText?: string\n  headers?: Record<string, string>\n}\n\nexport interface ProxyFetchResponseMetadataMessage {\n  type: 'PROXY_RESPONSE_METADATA'\n  metadata: ProxyFetchResponseMetadata\n}\n\nexport type ProxyFetchResponseBodyChunkMessage = {\n  type: 'PROXY_RESPONSE_BODY_CHUNK'\n} & ({ done: true } | { done: false; value: string })\n"
  },
  {
    "path": "src/utils/encoding.ts",
    "content": "export function string2Uint8Array(str: string): Uint8Array {\n  const encoder = new TextEncoder()\n  return encoder.encode(str)\n}\n\nexport function uint8Array2String(uint8Array: Uint8Array): string {\n  const decoder = new TextDecoder()\n  return decoder.decode(uint8Array)\n}\n"
  },
  {
    "path": "src/utils/errors.ts",
    "content": "export enum ErrorCode {\n  CONVERSATION_LIMIT = 'CONVERSATION_LIMIT',\n  UNKOWN_ERROR = 'UNKOWN_ERROR',\n  CHATGPT_CLOUDFLARE = 'CHATGPT_CLOUDFLARE',\n  CHATGPT_UNAUTHORIZED = 'CHATGPT_UNAUTHORIZED',\n  CHATGPT_AUTH = 'CHATGPT_AUTH',\n  GPT4_MODEL_WAITLIST = 'GPT4_MODEL_WAITLIST',\n  BING_UNAUTHORIZED = 'BING_UNAUTHORIZED',\n  BING_CAPTCHA = 'BING_CAPTCHA',\n  API_KEY_NOT_SET = 'API_KEY_NOT_SET',\n  BARD_EMPTY_RESPONSE = 'BARD_EMPTY_RESPONSE',\n  BARD_UNAUTHORIZED = 'BARD_UNAUTHORIZED',\n  MISSING_POE_HOST_PERMISSION = 'MISSING_POE_HOST_PERMISSION',\n  POE_UNAUTHORIZED = 'POE_UNAUTHORIZED',\n  MISSING_HOST_PERMISSION = 'MISSING_HOST_PERMISSION',\n  XUNFEI_UNAUTHORIZED = 'XUNFEI_UNAUTHORIZED',\n  NETWORK_ERROR = 'NETWORK_ERROR',\n  POE_MESSAGE_LIMIT = 'POE_MESSAGE_LIMIT',\n  LMSYS_SESSION_EXPIRED = 'LMSYS_SESSION_EXPIRED',\n  CHATGPT_INSUFFICIENT_QUOTA = 'CHATGPT_INSUFFICIENT_QUOTA',\n  CLAUDE_WEB_UNAUTHORIZED = 'CLAUDE_WEB_UNAUTHORIZED',\n  CLAUDE_WEB_UNAVAILABLE = 'CLAUDE_WEB_UNAVAILABLE',\n  QIANWEN_WEB_UNAUTHORIZED = 'QIANWEN_WEB_UNAUTHORIZED',\n  BAICHUAN_WEB_UNAUTHORIZED = 'BAICHUAN_WEB_UNAUTHORIZED',\n  LMSYS_WS_ERROR = 'LMSYS_WS_ERROR',\n  PPLX_FORBIDDEN_ERROR = 'PPLX_FORBIDDEN_ERROR',\n  TWITTER_UNAUTHORIZED = 'TWITTER_UNAUTHORIZED',\n  GROK_UNAVAILABLE = 'GROK_UNAVAILABLE',\n}\n\nexport class ChatError extends Error {\n  code: ErrorCode\n  constructor(message: string, code: ErrorCode) {\n    super(message)\n    this.code = code\n  }\n}\n"
  },
  {
    "path": "src/utils/format.ts",
    "content": "export function formatDecimal(value: number) {\n  return new Intl.NumberFormat('en-US', { notation: 'compact' }).format(value)\n}\n\nexport function formatAmount(value: number) {\n  return new Intl.NumberFormat('en-US', {\n    style: 'currency',\n    currency: 'USD',\n  }).format(value)\n}\n\nexport function formatTime(time: number) {\n  const date = new Date(time)\n  const month = String(date.getMonth() + 1).padStart(2, '0')\n  const day = String(date.getDate()).padStart(2, '0')\n  const hours = String(date.getHours()).padStart(2, '0')\n  const minutes = String(date.getMinutes()).padStart(2, '0')\n  return `${month}/${day} ${hours}:${minutes}`\n}\n"
  },
  {
    "path": "src/utils/index.ts",
    "content": "import { clsx, type ClassValue } from 'clsx'\nimport { twMerge } from 'tailwind-merge'\nimport { v4 } from 'uuid'\nimport Browser from 'webextension-polyfill'\n\nexport function uuid() {\n  return v4()\n}\n\nexport function getVersion() {\n  return Browser.runtime.getManifest().version\n}\n\nexport function isProduction() {\n  return !import.meta.env.DEV\n}\n\nexport function cx(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs))\n}\n"
  },
  {
    "path": "src/utils/sse.ts",
    "content": "import { createParser } from 'eventsource-parser'\nimport { isEmpty } from 'lodash-es'\nimport { ChatError, ErrorCode } from './errors'\nimport { streamAsyncIterable } from './stream-async-iterable'\n\nconst statusTextMap = new Map([\n  [400, 'Bad Request'],\n  [401, 'Unauthorized'],\n  [403, 'Forbidden'],\n  [429, 'Too Many Requests'],\n])\n\nexport async function parseSSEResponse(resp: Response, onMessage: (message: string) => void) {\n  if (!resp.ok) {\n    const error = await resp.json().catch(() => ({}))\n    if (!isEmpty(error)) {\n      throw new Error(JSON.stringify(error))\n    }\n    const statusText = resp.statusText || statusTextMap.get(resp.status) || ''\n    throw new ChatError(`${resp.status} ${statusText}`, ErrorCode.NETWORK_ERROR)\n  }\n  const parser = createParser((event) => {\n    if (event.type === 'event') {\n      onMessage(event.data)\n    }\n  })\n  const decoder = new TextDecoder()\n  for await (const chunk of streamAsyncIterable(resp.body!)) {\n    const str = decoder.decode(chunk)\n    parser.feed(str)\n  }\n}\n"
  },
  {
    "path": "src/utils/stream-async-iterable.ts",
    "content": "export async function* streamAsyncIterable<T = unknown>(stream: ReadableStream<T>) {\n  const reader = stream.getReader()\n  try {\n    while (true) {\n      const { done, value } = await reader.read()\n      if (done) {\n        return\n      }\n      yield value\n    }\n  } finally {\n    reader.releaseLock()\n  }\n}\n"
  },
  {
    "path": "src/vite-env.d.ts",
    "content": "/// <reference types=\"vite/client\" />\n"
  },
  {
    "path": "tailwind.config.cjs",
    "content": "/** @type {import('tailwindcss').Config} */\nmodule.exports = {\n  darkMode: ['class'],\n  content: ['./src/**/*.{html,ts,tsx}'],\n  theme: {\n    extend: {\n      colors: {\n        'primary-blue': 'rgb(var(--color-primary-blue) / <alpha-value>)',\n        secondary: 'rgb(var(--color-secondary) / <alpha-value>)',\n        'primary-background': 'rgb(var(--primary-background) / <alpha-value>)',\n        'primary-text': 'rgb(var(--primary-text) / <alpha-value>)',\n        'secondary-text': 'rgb(var(--secondary-text) / <alpha-value>)',\n        'light-text': 'rgb(var(--light-text) / <alpha-value>)',\n        'primary-border': 'rgb(var(--primary-border) / <alpha-value>)',\n      },\n      keyframes: {\n        slideDownAndFade: {\n          from: { opacity: 0, transform: 'translateY(-2px)' },\n          to: { opacity: 1, transform: 'translateY(0)' },\n        },\n        slideLeftAndFade: {\n          from: { opacity: 0, transform: 'translateX(2px)' },\n          to: { opacity: 1, transform: 'translateX(0)' },\n        },\n        slideUpAndFade: {\n          from: { opacity: 0, transform: 'translateY(2px)' },\n          to: { opacity: 1, transform: 'translateY(0)' },\n        },\n        slideRightAndFade: {\n          from: { opacity: 0, transform: 'translateX(2px)' },\n          to: { opacity: 1, transform: 'translateX(0)' },\n        },\n      },\n      animation: {\n        slideDownAndFade: 'slideDownAndFade 400ms cubic-bezier(0.16, 1, 0.3, 1)',\n        slideLeftAndFade: 'slideLeftAndFade 400ms cubic-bezier(0.16, 1, 0.3, 1)',\n        slideUpAndFade: 'slideUpAndFade 400ms cubic-bezier(0.16, 1, 0.3, 1)',\n        slideRightAndFade: 'slideRightAndFade 400ms cubic-bezier(0.16, 1, 0.3, 1)',\n      },\n    },\n  },\n  plugins: [require('@headlessui/tailwindcss'), require('tailwind-scrollbar')],\n}\n"
  },
  {
    "path": "tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"ESNext\",\n    \"useDefineForClassFields\": true,\n    \"lib\": [\"DOM\", \"DOM.Iterable\", \"ESNext\"],\n    \"allowJs\": true,\n    \"skipLibCheck\": true,\n    \"esModuleInterop\": false,\n    \"allowSyntheticDefaultImports\": true,\n    \"strict\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"module\": \"ESNext\",\n    \"moduleResolution\": \"node\",\n    \"resolveJsonModule\": true,\n    \"isolatedModules\": true,\n    \"noEmit\": true,\n    \"jsx\": \"react-jsx\",\n    \"baseUrl\": \".\",\n    \"paths\": {\n      \"~*\": [\"./src/*\"]\n    },\n    \"types\": [\"chrome-types\"]\n  },\n  \"include\": [\"src\", \"vite.config.ts\", \"manifest.config.ts\"]\n}\n"
  },
  {
    "path": "vite.config.ts",
    "content": "import { crx } from '@crxjs/vite-plugin'\nimport react from '@vitejs/plugin-react'\nimport jotaiDebugLabel from 'jotai/babel/plugin-debug-label'\nimport jotaiReactRefresh from 'jotai/babel/plugin-react-refresh'\nimport { defineConfig } from 'vite'\nimport tsconfigPaths from 'vite-tsconfig-paths'\nimport manifest from './manifest.config'\n\nexport default defineConfig(({ mode }) => {\n  return {\n    plugins: [\n      tsconfigPaths(),\n      react({\n        babel: {\n          plugins: [jotaiDebugLabel, jotaiReactRefresh],\n        },\n      }),\n      crx({ manifest }),\n    ],\n    build: {\n      rollupOptions: {\n        input: ['app.html'],\n      },\n    },\n    esbuild: {\n      drop: mode === 'production' ? ['console', 'debugger'] : [],\n    },\n    server: {\n      strictPort: true,\n      port: 5173,\n      hmr: {\n        clientPort: 5173,\n      },\n    },\n  }\n})\n"
  }
]